diff --git a/protocol.md b/protocol.md new file mode 100644 index 0000000..e79d670 --- /dev/null +++ b/protocol.md @@ -0,0 +1,12 @@ +## Loading Screen + +- [Client] +Client sends unique UserID. + +- [Server] +assign slot to Client + +- [Client] +Send User Name + +- [Server_START_UPDATE_ROUTINE] diff --git a/src/DarkRP2DDedicatedServer.cpp b/src/DarkRP2DDedicatedServer.cpp index c6bcc8e..9d6735f 100644 --- a/src/DarkRP2DDedicatedServer.cpp +++ b/src/DarkRP2DDedicatedServer.cpp @@ -1,31 +1,48 @@ #include #include +// Vendor #include + +// Own #include "GameServer.h" +// Windows +#ifdef _WIN32 +#include +#endif + using namespace yojimbo; static GameServer *serv; -void interrupt_handler( int /*dummy*/ ) +void interrupt_handler(int /*dummy*/) { serv->m_running = false; } int main(int argc, char *argv[]) { - if ( !InitializeYojimbo() ) + //--- Setup CMD +#ifdef _WIN32 + HANDLE hInput; + DWORD prev_mode; + hInput = GetStdHandle(STD_INPUT_HANDLE); + GetConsoleMode(hInput, &prev_mode); + SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS); +#endif + + if (!InitializeYojimbo()) { - printf( "error: failed to initialize Yojimbo!\n" ); + printf("error: failed to initialize Yojimbo!\n"); return 1; } - yojimbo_log_level( YOJIMBO_LOG_LEVEL_INFO ); + yojimbo_log_level(YOJIMBO_LOG_LEVEL_INFO); std::cout << "Yojimbo lives!" << std::endl; - signal( SIGINT, interrupt_handler ); + signal(SIGINT, interrupt_handler); - yojimbo::Address addr(127,0,0,1,9999); + yojimbo::Address addr(127, 0, 0, 1, 9999); GameServer server(addr); serv = &server; //For interrupt server.Run(); diff --git a/src/GameServer.cpp b/src/GameServer.cpp index 4d7422b..0ccefaf 100644 --- a/src/GameServer.cpp +++ b/src/GameServer.cpp @@ -1,36 +1,23 @@ #include "Gameserver.h" +//std #include +#include + +//own +#include "messages/Command.h" +#include "core/Components.h" using namespace yojimbo; -yojimbo::MessageFactory *GameAdapter::CreateMessageFactory(yojimbo::Allocator &allocator) -{ - return YOJIMBO_NEW(allocator, GameMessageFactory, allocator); -} - -void GameAdapter::OnServerClientConnected(int clientIndex) -{ - if (m_server != NULL) - { - m_server->ClientConnected(clientIndex); - } -} - -void GameAdapter::OnServerClientDisconnected(int clientIndex) -{ - if (m_server != NULL) - { - m_server->ClientDisconnected(clientIndex); - } -} - -GameServer::GameServer(const yojimbo::Address &address) : m_adapter(this), +GameServer::GameServer(const yojimbo::Address &address) : m_time(yojimbo_time()), + m_adapter(this), m_server(yojimbo::GetDefaultAllocator(), DEFAULT_PRIVATE_KEY, address, m_connectionConfig, - m_adapter, 0.0), + m_adapter, + m_time), m_running(false) { // start the server @@ -49,11 +36,17 @@ GameServer::GameServer(const yojimbo::Address &address) : m_adapter(this), void GameServer::ClientConnected(int clientIndex) { + entityx::Entity entity = ex.entities.create(); + entity.assign(); + serverToEntityX.insert(std::pair(clientIndex, entity)); std::cout << "client " << clientIndex << " connected" << std::endl; } void GameServer::ClientDisconnected(int clientIndex) { + entityx::Entity entity = serverToEntityX.at(clientIndex); + entity.destroy(); + serverToEntityX.erase(clientIndex); std::cout << "client " << clientIndex << " disconnected" << std::endl; } @@ -110,7 +103,11 @@ void GameServer::ProcessMessages() yojimbo::Message *message = m_server.ReceiveMessage(i, j); while (message != NULL) { - ProcessMessage(i, message); + std::unique_ptr command(Command::create(i, message)); + if (command) + { + command->execute(this); + } m_server.ReleaseMessage(i, message); message = m_server.ReceiveMessage(i, j); } @@ -119,19 +116,20 @@ void GameServer::ProcessMessages() } } -void GameServer::ProcessMessage(int clientIndex, yojimbo::Message *message) +ServerAdapter::ServerAdapter(GameServer *server) : m_server(server) {} + +void ServerAdapter::OnServerClientConnected(int clientIndex) { - switch (message->GetType()) + if (m_server != NULL) { - case (int)GameMessageType::TEST: - ProcessTestMessage(clientIndex, (TestMessage *)message); - break; - default: - break; + m_server->ClientConnected(clientIndex); } } -void GameServer::ProcessTestMessage(int clientIndex, TestMessage *message) +void ServerAdapter::OnServerClientDisconnected(int clientIndex) { - // ... process test message ... + if (m_server != NULL) + { + m_server->ClientDisconnected(clientIndex); + } } \ No newline at end of file diff --git a/src/GameServer.h b/src/GameServer.h index 7f5b268..b920cb7 100644 --- a/src/GameServer.h +++ b/src/GameServer.h @@ -1,98 +1,60 @@ -#pragma once +#ifndef GAMESERVER_H +#define GAMESERVER_H -#include +//Std #include +#include + +//Vendor +#include +#include + +//Own +#include "Shared.h" + +static const int MAX_PLAYERS = 64; class GameServer; -// a simple test message -enum class GameMessageType +class ServerAdapter : public SharedAdapter { - TEST, - COUNT +public: + explicit ServerAdapter(GameServer *server); + + void OnServerClientConnected(int clientIndex) override; + + void OnServerClientDisconnected(int clientIndex) override; + +private: + GameServer *m_server; }; -// two channels, one for each type that Yojimbo supports -enum class GameChannel -{ - RELIABLE, - UNRELIABLE, - COUNT -}; - -// the client and server config -struct GameConnectionConfig : yojimbo::ClientServerConfig -{ - GameConnectionConfig() - { - numChannels = 2; - channel[(int)GameChannel::RELIABLE].type = yojimbo::CHANNEL_TYPE_RELIABLE_ORDERED; - channel[(int)GameChannel::UNRELIABLE].type = yojimbo::CHANNEL_TYPE_UNRELIABLE_UNORDERED; - } -}; - -class TestMessage : public yojimbo::Message -{ - public: - int m_data; - - TestMessage() : m_data(0) {} - - template - bool Serialize(Stream &stream) - { - serialize_int(stream, m_data, 0, 512); - return true; - } - - YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS(); -}; - -// the adapter -class GameAdapter : public yojimbo::Adapter -{ - public: - explicit GameAdapter(GameServer *server = NULL) : m_server(server) {} - - void OnServerClientConnected(int clientIndex) override; - - void OnServerClientDisconnected(int clientIndex) override; - - yojimbo::MessageFactory* CreateMessageFactory(yojimbo::Allocator& allocator) override; - - private: - GameServer *m_server; -}; - -// the message factory -YOJIMBO_MESSAGE_FACTORY_START(GameMessageFactory, (int)GameMessageType::COUNT); -YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::TEST, TestMessage); -YOJIMBO_MESSAGE_FACTORY_FINISH(); - -static const uint8_t DEFAULT_PRIVATE_KEY[yojimbo::KeyBytes] = {0}; -static const int MAX_PLAYERS = 64; - class GameServer { - public: - GameServer(const yojimbo::Address &address); +public: + GameServer(const yojimbo::Address &address); - void ClientConnected(int clientIndex); - void ClientDisconnected(int clientIndex); + void ClientConnected(int clientIndex); + void ClientDisconnected(int clientIndex); - void ProcessMessages(); - void ProcessMessage(int clientIndex, yojimbo::Message *message); - void ProcessTestMessage(int clientIndex, TestMessage *message); + void ProcessCommand(std::string command); + void ProcessMessages(); + void ProcessMessage(int clientIndex, yojimbo::Message *message); - void Run(); - void Update(float dt); + void Run(); + void Update(float dt); - bool m_running; + bool m_running; - private: - GameConnectionConfig m_connectionConfig; - yojimbo::Server m_server; - GameAdapter m_adapter; + entityx::EntityX ex; + std::map serverToEntityX; - double m_time; +private: + double m_time; + + GameConnectionConfig m_connectionConfig; + ServerAdapter m_adapter; + yojimbo::Server m_server; }; + +#endif //GAMESERVER_H \ No newline at end of file diff --git a/src/Shared.h b/src/Shared.h new file mode 100644 index 0000000..b6e2f95 --- /dev/null +++ b/src/Shared.h @@ -0,0 +1,87 @@ +#ifndef SHARED_H +#define SHARED_H + +#include + +// a simple test message +enum class GameMessageType +{ + TEST, + SETNAME, + COUNT +}; + +// two channels, one for each type that Yojimbo supports +enum class GameChannel +{ + RELIABLE, + UNRELIABLE, + COUNT +}; + +// the client and server config +struct GameConnectionConfig : yojimbo::ClientServerConfig +{ + GameConnectionConfig() + { + numChannels = 2; + channel[(int)GameChannel::RELIABLE].type = yojimbo::CHANNEL_TYPE_RELIABLE_ORDERED; + channel[(int)GameChannel::UNRELIABLE].type = yojimbo::CHANNEL_TYPE_UNRELIABLE_UNORDERED; + } +}; + +class TestMessage : public yojimbo::Message +{ +public: + int m_data; + + TestMessage() : m_data(0) {} + + template + bool Serialize(Stream &stream) + { + serialize_int(stream, m_data, 0, 512); + return true; + } + + YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS(); +}; + +class SetNameMessage : public yojimbo::Message +{ +public: + char buffer[yojimbo::MaxAddressLength]; + SetNameMessage() { + } + + template + bool Serialize(Stream &stream) + { + serialize_string(stream, buffer, sizeof(buffer)); + return true; + } + + YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS(); +}; + +// the message factory +YOJIMBO_MESSAGE_FACTORY_START(GameMessageFactory, (int)GameMessageType::COUNT); + YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::TEST, TestMessage); + YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::SETNAME, SetNameMessage); +YOJIMBO_MESSAGE_FACTORY_FINISH(); + +// the adapter +class SharedAdapter : public yojimbo::Adapter +{ +public: + + yojimbo::MessageFactory *CreateMessageFactory(yojimbo::Allocator &allocator) override + { + return YOJIMBO_NEW(allocator, GameMessageFactory, allocator); + } + +}; + +static const uint8_t DEFAULT_PRIVATE_KEY[yojimbo::KeyBytes] = {0}; + +#endif //SHARED_H \ No newline at end of file diff --git a/src/core/Components.h b/src/core/Components.h new file mode 100644 index 0000000..10ab372 --- /dev/null +++ b/src/core/Components.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct NetworkPlayerProperties +{ + NetworkPlayerProperties(std::string name = "unknown") + : name(name) {} + + std::string name; +}; \ No newline at end of file diff --git a/src/messages/Command.cpp b/src/messages/Command.cpp new file mode 100644 index 0000000..0c9be88 --- /dev/null +++ b/src/messages/Command.cpp @@ -0,0 +1,21 @@ +#include "Command.h" +#include "../Shared.h" + +#include + +Command *Command::create(int clientIndex, yojimbo::Message *message) +{ + switch (message->GetType()) + { + case (int)GameMessageType::TEST: + return new TestCommand(clientIndex, message); + break; + case (int)GameMessageType::SETNAME: + return new SetNameCommand(clientIndex, message); + break; + default: + std::cout << "Unknown message type received!" << std::endl; + return nullptr; + break; + } +} \ No newline at end of file diff --git a/src/messages/Command.h b/src/messages/Command.h new file mode 100644 index 0000000..120151e --- /dev/null +++ b/src/messages/Command.h @@ -0,0 +1,44 @@ +#pragma once + +//Vendor +#include +#include "../GameServer.h" + +// ---- Interface: + +class Command +{ +public: + // Create Commands from Network messages (Limited list) + static Command *create(int clientIndex, yojimbo::Message *message); + // Create Commands from Strings (Limited list) + virtual void execute(GameServer *server) = 0; +}; + +// --- implemented Classes: + +class TestCommand : public Command +{ +public: + TestCommand(int clientIndex, yojimbo::Message *message) + : m_clientIndex(clientIndex), m_message((TestMessage *)message) {} + + virtual void execute(GameServer *server) override; + +private: + int m_clientIndex; + TestMessage *m_message; +}; + +class SetNameCommand : public Command +{ +public: + SetNameCommand(int clientIndex, yojimbo::Message *message) + : m_clientIndex(clientIndex), m_message((SetNameMessage *)message) {} + + virtual void execute(GameServer *server) override; + +private: + int m_clientIndex; + SetNameMessage *m_message; +}; \ No newline at end of file diff --git a/src/messages/SetNameCommand.cpp b/src/messages/SetNameCommand.cpp new file mode 100644 index 0000000..9fa62fc --- /dev/null +++ b/src/messages/SetNameCommand.cpp @@ -0,0 +1,14 @@ +#include "Command.h" + +#include "../core/Components.h" + +void SetNameCommand::execute(GameServer *server) +{ + entityx::Entity entity = server->serverToEntityX.at(m_clientIndex); + entityx::ComponentHandle playerproperties = entity.component(); + if (playerproperties) + { + playerproperties->name = std::string(m_message->buffer); + } + std::cout << "Entity name changed to " << playerproperties->name << " Buffer content: " << std::string(m_message->buffer) << std::endl; +} \ No newline at end of file diff --git a/src/messages/TestCommand.cpp b/src/messages/TestCommand.cpp new file mode 100644 index 0000000..86e782c --- /dev/null +++ b/src/messages/TestCommand.cpp @@ -0,0 +1,12 @@ +#include "Command.h" + +#include "../core/Components.h" + +void TestCommand::execute(GameServer *server) +{ + // ... process test message ... + entityx::Entity entity = server->serverToEntityX.at(m_clientIndex); + entityx::ComponentHandle playerproperties = entity.component(); + + std::cout << "Test message received from client " << playerproperties->name << ":" << m_clientIndex << " with data: " << m_message->m_data << std::endl; +}