diff --git a/external/gamekit b/external/gamekit index 3f7da2f37..5de0b17f4 160000 --- a/external/gamekit +++ b/external/gamekit @@ -1 +1 @@ -Subproject commit 3f7da2f37c26c3f2cc14b14e53d0e3774570974c +Subproject commit 5de0b17f4b58a83c0cda4da70ff6bc5b6738b073 diff --git a/source/client/network/Client.hpp b/source/client/network/Client.hpp index 5269c23e4..2873fc646 100644 --- a/source/client/network/Client.hpp +++ b/source/client/network/Client.hpp @@ -69,6 +69,14 @@ class Client { u16 id() const { return m_id; } + sf::IpAddress serverAddress() const { return m_serverAddress; } + u16 serverPort() const { return m_serverPort; } + + // FIXME: This should move elsewhere, see command callback + // in ClientCommandHandler for ServerClosed + const std::string &texturePack() const { return m_texturePack; } + void setTexturePack(const std::string &texturePack) { m_texturePack = texturePack; } + private: bool m_isConnected = false; bool m_isSingleplayer = false; @@ -83,6 +91,8 @@ class Client { gk::Timer m_keyUpdateTimer; std::unordered_map m_commands; + + std::string m_texturePack; }; #endif // CLIENT_HPP_ diff --git a/source/client/network/ClientCommandHandler.cpp b/source/client/network/ClientCommandHandler.cpp index 3c106ba69..3bc20e186 100644 --- a/source/client/network/ClientCommandHandler.cpp +++ b/source/client/network/ClientCommandHandler.cpp @@ -34,6 +34,7 @@ #include "ClientPlayer.hpp" #include "ClientWorld.hpp" #include "ClientCommandHandler.hpp" +#include "ConnectionErrorState.hpp" #include "DrawableComponent.hpp" #include "DrawableDef.hpp" #include "LuaGUIState.hpp" @@ -136,6 +137,15 @@ void ClientCommandHandler::setupCallbacks() { m_playerBoxes.erase(it); }); + m_client.setCommandCallback(Network::Command::ServerClosed, [this](Network::Packet &packet) { + std::string message; + packet >> message; + + gk::ApplicationStateStack::getInstance().pop(); + gk::ApplicationStateStack::getInstance().pop(); + gk::ApplicationStateStack::getInstance().push(message, m_client.serverAddress().toString(), m_client.serverPort(), m_client.texturePack(), &gk::ApplicationStateStack::getInstance().top()); + }); + m_client.setCommandCallback(Network::Command::RegistryData, [this](Network::Packet &packet) { // FIXME: This is a quick fix for concurrency between client and server in singleplayer if (!m_isSingleplayer) diff --git a/source/client/states/ServerLoadingState.cpp b/source/client/states/ServerLoadingState.cpp index 51b117e1f..be0674489 100644 --- a/source/client/states/ServerLoadingState.cpp +++ b/source/client/states/ServerLoadingState.cpp @@ -114,6 +114,11 @@ void ServerLoadingState::update() { } } +void ServerLoadingState::setTexturePack(const std::string &texturePack) { + m_game.client().setTexturePack(texturePack); + m_texturePack = texturePack; +} + void ServerLoadingState::onServerOnlineEvent(const ServerOnlineEvent &event) { m_isServerOnline = event.isOnline; m_port = event.port; diff --git a/source/client/states/ServerLoadingState.hpp b/source/client/states/ServerLoadingState.hpp index db8b6ae21..0af02d65d 100644 --- a/source/client/states/ServerLoadingState.hpp +++ b/source/client/states/ServerLoadingState.hpp @@ -45,7 +45,7 @@ class ServerLoadingState : public InterfaceState { void update() override; - void setTexturePack(const std::string &texturePack) { m_texturePack = texturePack; } + void setTexturePack(const std::string &texturePack); private: void onServerOnlineEvent(const ServerOnlineEvent &event); diff --git a/source/common/network/Network.cpp b/source/common/network/Network.cpp index 24ce708db..0c9eb45d0 100644 --- a/source/common/network/Network.cpp +++ b/source/common/network/Network.cpp @@ -37,6 +37,8 @@ std::string Network::commandToString(Network::Command command) { {Network::Command::ClientOk, "ClientOk"}, {Network::Command::ClientRefused, "ClientRefused"}, + {Network::Command::ServerClosed, "ServerClosed"}, + {Network::Command::ChunkData, "ChunkData"}, {Network::Command::ChunkRequest, "ChunkRequest"}, diff --git a/source/common/network/Network.hpp b/source/common/network/Network.hpp index 00ed14371..27c4116cb 100644 --- a/source/common/network/Network.hpp +++ b/source/common/network/Network.hpp @@ -39,40 +39,43 @@ namespace Network { ClientOk = 0x02, // [NetworkCommand][u16 client id][bool isSingleplayer] (from Server only) ClientRefused = 0x03, // [NetworkCommand] (from Server only) + // Server commands + ServerClosed = 0x04, // [NetworkCommand][string message] (from Server only) + // Chunk commands - ChunkData = 0x04, // [NetworkCommand][s32 cx, cy, cz][u32...] (from Server only) - ChunkRequest = 0x05, // [NetworkCommand][s32 cx, cy, cz] (from Client only) + ChunkData = 0x05, // [NetworkCommand][s32 cx, cy, cz][u32...] (from Server only) + ChunkRequest = 0x06, // [NetworkCommand][s32 cx, cy, cz] (from Client only) // Player commands - PlayerPlaceBlock = 0x06, // [NetworkCommand][s32 x, y, z][u32 block] (from Client only) - PlayerDigBlock = 0x07, // [NetworkCommand][s32 x, y, z] (from Client only) - PlayerInvUpdate = 0x08, // [NetworkCommand][u16 client id][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME] - PlayerPosUpdate = 0x09, // [NetworkCommand][u16 client id][s32 x, y, z][bool isTeleportation] (both) // FIXME - PlayerSpawn = 0x0a, // [NetworkCommand][u16 client id][s32 x, y, z] (from Server only) - PlayerInventory = 0x0b, // [NetworkCommand][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) - PlayerCreativeWindow = 0x0c, // [NetworkCommand][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) - PlayerChangeDimension = 0x0d, // [NetworkCommand][u16 client id][s32 x, y, z][u16 dimension] (from Server only) + PlayerPlaceBlock = 0x07, // [NetworkCommand][s32 x, y, z][u32 block] (from Client only) + PlayerDigBlock = 0x08, // [NetworkCommand][s32 x, y, z] (from Client only) + PlayerInvUpdate = 0x09, // [NetworkCommand][u16 client id][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME] + PlayerPosUpdate = 0x0a, // [NetworkCommand][u16 client id][s32 x, y, z][bool isTeleportation] (both) // FIXME + PlayerSpawn = 0x0b, // [NetworkCommand][u16 client id][s32 x, y, z] (from Server only) + PlayerInventory = 0x0c, // [NetworkCommand][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) + PlayerCreativeWindow = 0x0d, // [NetworkCommand][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) + PlayerChangeDimension = 0x0e, // [NetworkCommand][u16 client id][s32 x, y, z][u16 dimension] (from Server only) // Block commands - BlockUpdate = 0x0e, // [NetworkCommand][s32 x, y, z][u32 block] (from Server only) - BlockActivated = 0x0f, // [NetworkCommand][s32 x, y, z][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) - BlockGUIData = 0x10, // [NetworkCommand][LuaGUIData data] (from Server only) - BlockInvUpdate = 0x11, // [NetworkCommand][s32 x, y, z][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME] - BlockDataUpdate = 0x12, // [NetworkCommand][s32 x, y, z][u64 data] (both) [FIXME] + BlockUpdate = 0x0f, // [NetworkCommand][s32 x, y, z][u32 block] (from Server only) + BlockActivated = 0x10, // [NetworkCommand][s32 x, y, z][u16 screenWidth, screenHeight][u8 guiScale] (from Client only) + BlockGUIData = 0x11, // [NetworkCommand][LuaGUIData data] (from Server only) + BlockInvUpdate = 0x12, // [NetworkCommand][s32 x, y, z][[std::string item][u16 amount][u8 x, y]...] (both) [FIXME] + BlockDataUpdate = 0x13, // [NetworkCommand][s32 x, y, z][u64 data] (both) [FIXME] // Registry commands - RegistryData = 0x13, // [NetworkCommand][Block block] (from Server only) + RegistryData = 0x14, // [NetworkCommand][Block block] (from Server only) // Chat commands - ChatMessage = 0x14, // [NetworkCommand][u16 client id][std::string message] (both) + ChatMessage = 0x15, // [NetworkCommand][u16 client id][std::string message] (both) // Entity commands - EntitySpawn = 0x15, // [NetworkCommand][u32 entity id] (from Server only) - EntityDespawn = 0x16, // [NetworkCommand][u32 entity id] (from Server only) - EntityPosition = 0x17, // [NetworkCommand][u32 entity id][double x, double y, double z] (from Server only) - EntityRotation = 0x18, // [NetworkCommand][u32 entity id][float w, float x, float y, float z] (from Server only) - EntityAnimation = 0x19, // [NetworkCommand][u32 entity id][AnimationComponent anim] (from Server only) - EntityDrawableDef = 0x1a, // [NetworkCommand][u32 entity id][DrawableDef def] (from Server only) + EntitySpawn = 0x16, // [NetworkCommand][u32 entity id] (from Server only) + EntityDespawn = 0x17, // [NetworkCommand][u32 entity id] (from Server only) + EntityPosition = 0x18, // [NetworkCommand][u32 entity id][double x, double y, double z] (from Server only) + EntityRotation = 0x19, // [NetworkCommand][u32 entity id][float w, float x, float y, float z] (from Server only) + EntityAnimation = 0x1a, // [NetworkCommand][u32 entity id][AnimationComponent anim] (from Server only) + EntityDrawableDef = 0x1b, // [NetworkCommand][u32 entity id][DrawableDef def] (from Server only) }; std::string commandToString(Command command); diff --git a/source/server/core/ServerApplication.cpp b/source/server/core/ServerApplication.cpp index 0aa775129..e8166ebf4 100644 --- a/source/server/core/ServerApplication.cpp +++ b/source/server/core/ServerApplication.cpp @@ -33,7 +33,24 @@ namespace fs = ghc::filesystem; +static bool hasBeenInterrupted = false; + +#ifdef SFML_SYSTEM_LINUX + +#include +#include + +static void sigintHandler(int) { + signal(SIGINT, sigintHandler); + hasBeenInterrupted = true; +} + +#endif // SFML_SYSTEM_LINUX + ServerApplication::ServerApplication(int argc, char **argv) : m_argumentParser(argc, argv) { +#ifdef SFML_SYSTEM_LINUX + signal(SIGINT, sigintHandler); +#endif } ServerApplication::ServerApplication(gk::EventHandler &eventHandler) { @@ -97,7 +114,7 @@ int ServerApplication::run(bool isProtected) { std::cerr << "Fatal error " << e.what() << std::endl; - // TODO: Send server offline event here + m_serverCommandHandler.sendServerClosed(std::string("Server error ") + e.what()); m_registry.clear(); m_worldController.clearEntities(); @@ -110,7 +127,7 @@ int ServerApplication::run(bool isProtected) { mainLoop(); } - // TODO: Send server offline event here + m_serverCommandHandler.sendServerClosed("Server closed."); m_registry.clear(); m_worldController.clearEntities(); @@ -129,7 +146,7 @@ void ServerApplication::update() { } void ServerApplication::mainLoop() { - while (m_server.isRunning()) { + while (!hasBeenInterrupted && m_server.isRunning()) { m_server.handleGameEvents(); m_clock.updateGame([this] { diff --git a/source/server/core/ServerApplication.hpp b/source/server/core/ServerApplication.hpp index 5b57d458e..d7a04c719 100644 --- a/source/server/core/ServerApplication.hpp +++ b/source/server/core/ServerApplication.hpp @@ -45,10 +45,6 @@ struct ServerOnlineEvent { int port; }; -// TODO: Add server offline event to tell the clients that the server is closed -// The best way would be to create a dedicated state displaying the error message -// allowing to reconnect or to go back to title screen - class ServerApplication { public: ServerApplication(int argc = 0, char **argv = nullptr); diff --git a/source/server/network/ServerCommandHandler.cpp b/source/server/network/ServerCommandHandler.cpp index 9ad1391a8..554437965 100644 --- a/source/server/network/ServerCommandHandler.cpp +++ b/source/server/network/ServerCommandHandler.cpp @@ -36,6 +36,16 @@ #include "ServerCommandHandler.hpp" #include "WorldController.hpp" +void ServerCommandHandler::sendServerClosed(const std::string &message, const ClientInfo *client) const { + Network::Packet packet; + packet << Network::Command::ServerClosed << message; + + if (!client) + m_server.sendToAllClients(packet); + else + client->tcpSocket->send(packet); +} + void ServerCommandHandler::sendBlockDataUpdate(s32 x, s32 y, s32 z, const BlockData *blockData, const ClientInfo *client) const { Network::Packet packet; packet << Network::Command::BlockDataUpdate << x << y << z diff --git a/source/server/network/ServerCommandHandler.hpp b/source/server/network/ServerCommandHandler.hpp index 7e520b899..a85cddcec 100644 --- a/source/server/network/ServerCommandHandler.hpp +++ b/source/server/network/ServerCommandHandler.hpp @@ -61,6 +61,7 @@ class ServerCommandHandler { ServerCommandHandler(ScriptEngine &scriptEngine, Server &server, WorldController &worldController, PlayerList &players, Registry ®istry) : m_scriptEngine(scriptEngine), m_server(server), m_worldController(worldController), m_players(players), m_registry(registry) {} + void sendServerClosed(const std::string &message, const ClientInfo *client = nullptr) const; void sendBlockDataUpdate(s32 x, s32 y, s32 z, const BlockData *blockData, const ClientInfo *client = nullptr) const; void sendBlockInvUpdate(s32 x, s32 y, s32 z, const Inventory &inventory, const ClientInfo *client = nullptr) const; void sendPlayerPosUpdate(u16 clientID, bool isTeleportation = false, const ClientInfo *client = nullptr) const;