diff --git a/include/client/Client.h b/include/client/Client.h index f1c18e8..836aea8 100644 --- a/include/client/Client.h +++ b/include/client/Client.h @@ -15,6 +15,8 @@ class Client : public StateMachine { public: Client(const std::shared_ptr& a_Socket) : m_Socket(a_Socket) {} + void SendPacket(const protocol::PacketBase& a_Packet); + friend class ClientState; }; diff --git a/include/client/state/GameState.h b/include/client/state/GameState.h index 3f484bf..b4fcacd 100644 --- a/include/client/state/GameState.h +++ b/include/client/state/GameState.h @@ -10,6 +10,7 @@ namespace client { class GameState : public ClientState { private: std::shared_ptr m_World; + // sim::ClientSimulation m_Simulation; public: GameState(Client& a_Client, const std::shared_ptr& a_World); diff --git a/include/server/socket/FakeSocket.h b/include/server/socket/FakeSocket.h index 8f14e94..3601cf4 100644 --- a/include/server/socket/FakeSocket.h +++ b/include/server/socket/FakeSocket.h @@ -9,7 +9,7 @@ namespace server { class FakeSocket : public IServerSocket { private: - std::vector>> m_Clients; + std::vector>> m_Clients; public: FakeSocket() {} diff --git a/include/td/common/StateMachine.h b/include/td/common/StateMachine.h index c17a84a..f4adc8e 100644 --- a/include/td/common/StateMachine.h +++ b/include/td/common/StateMachine.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace td { @@ -19,16 +20,17 @@ class StateMachine { }; StateMachine() {} + StateMachine(StateMachine&&) = default; virtual ~StateMachine() {} - TReturn Update(TArgs... args) { - assert(m_State); + virtual TReturn Update(TArgs... args) { + assert(m_State && "You must change state at least once before updating !"); return m_State->Update(args...); } template void ChangeState(Args&&... args) { - m_State = std::make_unique(static_cast(*this), args...); + m_State = std::make_unique(static_cast(*this), std::forward(args)...); } private: diff --git a/include/td/input/Display.h b/include/td/display/Display.h similarity index 82% rename from include/td/input/Display.h rename to include/td/display/Display.h index 7d1bf87..8bc90aa 100644 --- a/include/td/input/Display.h +++ b/include/td/display/Display.h @@ -2,39 +2,14 @@ #include -#include #include +#include +#include #include namespace td { -class Display { - public: - utils::Signal OnAspectRatioChange; - utils::Signal OnKeyDown; - - Display(int a_Width, int a_Height, const std::string& a_Title); - ~Display(); - - void PollEvents(); - void Update(); - - bool IsCloseRequested() { - return m_ShouldClose; - } - - float GetAspectRatio() { - return m_AspectRatio; - } - - int GetWindowWidth() { - return m_LastWidth; - } - - int GetWindowHeight() { - return m_LastHeight; - } - +class Display : public StateMachine { private: SDL_Window* m_Window; SDL_GLContext m_GLContext; @@ -43,6 +18,33 @@ class Display { float m_AspectRatio; bool m_ShouldClose; + + public: + utils::Signal OnAspectRatioChange; + utils::Signal OnKeyDown; + + Display(int a_Width, int a_Height, const std::string& a_Title); + ~Display(); + + void PollEvents(); + void Update(float a_Delta) override; + void Close(); + + bool IsCloseRequested() { + return m_ShouldClose; + } + + float GetAspectRatio() { + return m_AspectRatio; + } + + int GetWindowWidth() { + return m_LastWidth; + } + + int GetWindowHeight() { + return m_LastHeight; + } }; } // namespace td \ No newline at end of file diff --git a/include/td/display/DisplayState.h b/include/td/display/DisplayState.h new file mode 100644 index 0000000..0ad0790 --- /dev/null +++ b/include/td/display/DisplayState.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace td { +class DisplayState : public Display::State, private utils::SlotGuard { + public: + DisplayState(Display& a_Display); + virtual ~DisplayState() {} + + protected: + virtual void OnAspectRatioChange(float a_Ratio) {} + virtual void OnKeyDown(SDL_Keycode a_Key) {} +}; +} // namespace td diff --git a/include/td/display/state/DebugWorldState.h b/include/td/display/state/DebugWorldState.h new file mode 100644 index 0000000..e9a1a64 --- /dev/null +++ b/include/td/display/state/DebugWorldState.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace td { + +class ClientHandler; + +class DebugWorldState : public DisplayState { + private: + render::RenderPipeline m_Renderer; + std::unique_ptr m_Client; + std::unique_ptr m_Server; + std::unique_ptr m_Simulation; + render::Camera m_Camera; + std::unique_ptr m_ClientHandler; + + public: + DebugWorldState(Display& a_Display); + ~DebugWorldState(); + + virtual void Update(float a_Delta) override; + + protected: + virtual void OnAspectRatioChange(float a_Ratio) override; + virtual void OnKeyDown(SDL_Keycode a_Key) override; +}; + +} // namespace td diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 277b956..8c98606 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -3,7 +3,9 @@ namespace td { namespace client { - +void Client::SendPacket(const protocol::PacketBase& a_Packet) { + m_Socket->Send(a_Packet); +} } // namespace client } // namespace td diff --git a/src/main.cpp b/src/main.cpp index 5062e30..7850dcd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,107 +1,5 @@ #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -class WorldApply : public td::protocol::PacketHandler { - private: - td::game::World& m_World; - using td::protocol::PacketHandler::Handle; - - public: - WorldApply(td::game::World& a_World) : m_World(a_World) {} - - void Handle(const td::protocol::packets::WorldHeaderPacket& a_Header) override { - m_World.LoadMap(*a_Header); - } - - void Handle(const td::protocol::packets::WorldDataPacket& a_Data) override { - m_World.LoadMap(*a_Data); - } -}; - -class ClientHandler : public td::protocol::PacketHandler { - private: - td::sim::ClientSimulation& m_Simulation; - - using td::protocol::PacketHandler::Handle; - - public: - ClientHandler(td::sim::ClientSimulation& a_Simulation) : m_Simulation(a_Simulation) {} - - void Handle(const td::protocol::packets::LockStepsPacket& a_LockStep) { - m_Simulation.Handle(a_LockStep); - } - - void Handle(const td::protocol::packets::LockStepResponsePacket& a_LockStep) { - m_Simulation.Handle(a_LockStep); - } -}; - -void Save(const td::protocol::PacketBase& header, const td::protocol::PacketBase& data) { - auto comp = std::make_shared(); - - std::ofstream fStream("test/tdmap.tdmap3"); - auto out = std::make_shared(fStream); - - sp::MessageStream stream(std::move(out), std::move(comp)); - - stream.WriteMessage(header, false); - stream.WriteMessage(data, false); -} - -td::game::WorldPtr GetWorld() { - auto comp = std::make_shared(); - - std::ifstream fStream("test/tdmap.tdmap2"); - auto out = std::make_shared(fStream); - - sp::MessageStream stream(std::move(out), std::move(comp)); - - auto header = stream.ReadMessage(td::protocol::PacketID::WorldHeader); - auto data = stream.ReadMessage(td::protocol::PacketID::WorldData); - - auto w = std::make_shared(); - auto wa = std::make_shared(*w); - - td::protocol::PacketDispatcher d; - d.RegisterHandler(wa); - - d.Dispatch(*header); - d.Dispatch(*data); - - Save(*header, *data); - - return w; -} - -void FastForward(td::game::World& a_World, const td::sim::GameHistory& a_LockSteps) { - const td::FpFloat delta = td::FpFloat(1) / td::FpFloat(75); - for (const auto& lockstep : a_LockSteps) { - a_World.Tick(lockstep, delta); - } -} +#include float GetDelta() { static std::chrono::time_point m_LastTime = std::chrono::system_clock::now(); @@ -112,65 +10,15 @@ float GetDelta() { } int main(int argc, char** argv) { - td::game::WorldPtr serverWorld = GetWorld(); - - // server - auto serverFakeSocket = std::make_shared(); - td::server::Server server(serverFakeSocket); - - // client - auto clientFakeSocket = td::client::FakeSocket::Connect(serverFakeSocket); - td::client::Client client(clientFakeSocket); - // init GL context td::Display display(1920, 1080, "Tower-Defense 2"); - td::render::Camera cam; - - display.OnAspectRatioChange.Connect([&cam](float a_AspectRatio) { cam.UpdatePerspective(a_AspectRatio); }); - - td::game::WorldPtr clientWorld = GetWorld(); - - td::render::RenderPipeline renderer; - renderer.AddRenderer(cam, *clientWorld); - renderer.AddRenderer(cam, *clientWorld); - renderer.AddRenderer(cam, *clientWorld); - - cam.SetCamPos({77, 7, 13}); - cam.UpdatePerspective(display.GetAspectRatio()); - - td::sim::ClientSimulation simulation(*clientWorld, td::STEP_TIME); - ClientHandler clientHandler(simulation); - - // packets from the server to the client - clientFakeSocket->OnReceive.Connect([&clientHandler](const td::protocol::PacketBase& a_Packet) { - a_Packet.Dispatch(clientHandler); - }); - - simulation.OnMissingLockSteps.Connect([&clientFakeSocket](const std::vector& a_MissingSteps) { - clientFakeSocket->Send(td::protocol::packets::LockStepRequestPacket(a_MissingSteps)); - }); - - // temporary tests - display.OnKeyDown.Connect([&clientFakeSocket](SDL_Keycode key) { - if (key == SDLK_A) { - clientFakeSocket->Send(td::protocol::packets::SpawnTroopPacket(td::EntityType::Zombie, 1)); - } else if (key == SDLK_Z) { - clientFakeSocket->Send(td::protocol::packets::PlaceTowerPacket(td::TowerType::Archer, td::TowerCoords(77, 13))); - } - }); - - server.ChangeState(serverWorld); - client.ChangeState(clientWorld); + display.ChangeState(); while (!display.IsCloseRequested()) { display.PollEvents(); float delta = GetDelta(); - server.Update(delta); - client.Update(delta); - float lerp = simulation.Update(delta); - renderer.Render(lerp); - display.Update(); + display.Update(delta); } return 0; diff --git a/src/server/socket/FakeSocket.cpp b/src/server/socket/FakeSocket.cpp index 1b58cb7..f968bd4 100644 --- a/src/server/socket/FakeSocket.cpp +++ b/src/server/socket/FakeSocket.cpp @@ -6,7 +6,8 @@ namespace server { void FakeSocket::SendPeer(PeerID a_Peer, const protocol::PacketBase& a_Packet) { auto socket = m_Clients.at(a_Peer); assert(socket.has_value()); - socket.value()->OnReceive(a_Packet); + assert(!socket.value().expired()); + socket.value().lock()->OnReceive(a_Packet); } void FakeSocket::ReceiveFromFakePeer(PeerID a_Peer, const protocol::PacketBase& a_Packet) { @@ -29,7 +30,8 @@ PeerID FakeSocket::ConnectFakePeer(const std::shared_ptr& a_ void FakeSocket::DisconnectFakePeer(PeerID a_Peer) { auto socket = m_Clients.at(a_Peer); assert(socket.has_value()); - socket.value()->OnDisconnect(); + assert(!socket.value().expired()); + socket.value().lock()->OnDisconnect(); OnDisconnectPeer(a_Peer); } diff --git a/src/td/input/Display.cpp b/src/td/display/Display.cpp similarity index 97% rename from src/td/input/Display.cpp rename to src/td/display/Display.cpp index ec32934..88499b8 100644 --- a/src/td/input/Display.cpp +++ b/src/td/display/Display.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -125,6 +125,9 @@ Display::Display(int a_Width, int a_Height, const std::string& a_Title) : ImGui_ImplOpenGL3_Init("#version 330"); } +void Display::Close() { + m_ShouldClose = true; +} void Display::PollEvents() { SDL_Event event; @@ -161,7 +164,8 @@ void Display::PollEvents() { ImGui::NewFrame(); } -void Display::Update() { +void Display::Update(float a_Delta) { + StateMachine::Update(a_Delta); ImGui::Render(); ImGuiIO& io = ImGui::GetIO(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); diff --git a/src/td/display/DisplayState.cpp b/src/td/display/DisplayState.cpp new file mode 100644 index 0000000..c40e53a --- /dev/null +++ b/src/td/display/DisplayState.cpp @@ -0,0 +1,10 @@ +#include + +namespace td { + +DisplayState::DisplayState(Display& a_Display) : Display::State(a_Display) { + Connect(m_StateMachine.OnKeyDown, std::bind(&DisplayState::OnKeyDown, this, std::placeholders::_1)); + Connect(m_StateMachine.OnAspectRatioChange, std::bind(&DisplayState::OnAspectRatioChange, this, std::placeholders::_1)); +} + +} // namespace td diff --git a/src/td/display/state/DebugWorldState.cpp b/src/td/display/state/DebugWorldState.cpp new file mode 100644 index 0000000..559a7ab --- /dev/null +++ b/src/td/display/state/DebugWorldState.cpp @@ -0,0 +1,162 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace td { + +class ClientHandler : public protocol::PacketHandler { + private: + sim::ClientSimulation& m_Simulation; + + using protocol::PacketHandler::Handle; + + public: + ClientHandler(sim::ClientSimulation& a_Simulation) : m_Simulation(a_Simulation) {} + + void Handle(const protocol::packets::LockStepsPacket& a_LockStep) { + m_Simulation.Handle(a_LockStep); + } + + void Handle(const protocol::packets::LockStepResponsePacket& a_LockStep) { + m_Simulation.Handle(a_LockStep); + } +}; + +class WorldApply : public protocol::PacketHandler { + private: + game::World& m_World; + using protocol::PacketHandler::Handle; + + public: + WorldApply(game::World& a_World) : m_World(a_World) {} + + void Handle(const protocol::packets::WorldHeaderPacket& a_Header) override { + m_World.LoadMap(*a_Header); + } + + void Handle(const protocol::packets::WorldDataPacket& a_Data) override { + m_World.LoadMap(*a_Data); + } +}; + +void Save(const protocol::PacketBase& header, const protocol::PacketBase& data) { + auto comp = std::make_shared(); + + std::ofstream fStream("test/tdmap.tdmap3"); + auto out = std::make_shared(fStream); + + sp::MessageStream stream(std::move(out), std::move(comp)); + + stream.WriteMessage(header, false); + stream.WriteMessage(data, false); +} + +game::WorldPtr GetWorld() { + auto comp = std::make_shared(); + + std::ifstream fStream("test/tdmap.tdmap2"); + auto out = std::make_shared(fStream); + + sp::MessageStream stream(std::move(out), std::move(comp)); + + auto header = stream.ReadMessage(protocol::PacketID::WorldHeader); + auto data = stream.ReadMessage(protocol::PacketID::WorldData); + + auto w = std::make_shared(); + auto wa = std::make_shared(*w); + + protocol::PacketDispatcher d; + d.RegisterHandler(wa); + + d.Dispatch(*header); + d.Dispatch(*data); + + Save(*header, *data); + + return w; +} + +DebugWorldState::DebugWorldState(Display& a_Display) : DisplayState(a_Display) { + game::WorldPtr serverWorld = GetWorld(); + + // server + auto serverFakeSocket = std::make_shared(); + m_Server = std::make_unique(serverFakeSocket); + + // client + auto clientFakeSocket = client::FakeSocket::Connect(serverFakeSocket); + m_Client = std::make_unique(clientFakeSocket); + + game::WorldPtr clientWorld = GetWorld(); + + m_Renderer.AddRenderer(m_Camera, *clientWorld); + m_Renderer.AddRenderer(m_Camera, *clientWorld); + m_Renderer.AddRenderer(m_Camera, *clientWorld); + + m_Camera.SetCamPos({77, 7, 13}); + m_Camera.UpdatePerspective(m_StateMachine.GetAspectRatio()); + + m_Simulation = std::make_unique(*clientWorld, STEP_TIME); + + m_ClientHandler = std::make_unique(*m_Simulation); + + // packets from the server to the client + clientFakeSocket->OnReceive.Connect([this](const protocol::PacketBase& a_Packet) { a_Packet.Dispatch(*m_ClientHandler); }); + + m_Simulation->OnMissingLockSteps.Connect([clientFakeSocket](const std::vector& a_MissingSteps) { + clientFakeSocket->Send(protocol::packets::LockStepRequestPacket(a_MissingSteps)); + }); + + m_Server->ChangeState(serverWorld); + m_Client->ChangeState(clientWorld); +} + +void DebugWorldState::Update(float a_Delta) { + m_Server->Update(a_Delta); + m_Client->Update(a_Delta); + float lerp = m_Simulation->Update(a_Delta); + m_Renderer.Render(lerp); +} + +void DebugWorldState::OnAspectRatioChange(float a_Ratio) { + m_Camera.UpdatePerspective(a_Ratio); +} + +void DebugWorldState::OnKeyDown(SDL_Keycode a_Key) { + // temporary tests + if (a_Key == SDLK_A) { + m_Client->SendPacket(td::protocol::packets::SpawnTroopPacket(td::EntityType::Zombie, 1)); + } else if (a_Key == SDLK_Z) { + m_Client->SendPacket(td::protocol::packets::PlaceTowerPacket(td::TowerType::Archer, td::TowerCoords(77, 13))); + } +} + +DebugWorldState::~DebugWorldState() {} + +} // namespace td