Using Command pattern andEntityX
This commit is contained in:
12
protocol.md
Normal file
12
protocol.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## Loading Screen
|
||||
|
||||
- [Client]
|
||||
Client sends unique UserID.
|
||||
|
||||
- [Server]
|
||||
assign slot to Client
|
||||
|
||||
- [Client]
|
||||
Send User Name
|
||||
|
||||
- [Server_START_UPDATE_ROUTINE]
|
||||
@@ -1,9 +1,17 @@
|
||||
#include <signal.h>
|
||||
#include <iostream>
|
||||
|
||||
// Vendor
|
||||
#include <yojimbo.h>
|
||||
|
||||
// Own
|
||||
#include "GameServer.h"
|
||||
|
||||
// Windows
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace yojimbo;
|
||||
|
||||
static GameServer *serv;
|
||||
@@ -15,6 +23,15 @@ void interrupt_handler( int /*dummy*/ )
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//--- 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");
|
||||
|
||||
@@ -1,36 +1,23 @@
|
||||
#include "Gameserver.h"
|
||||
|
||||
//std
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
//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<NetworkPlayerProperties>();
|
||||
serverToEntityX.insert(std::pair<int, entityx::Entity>(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(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);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +1,34 @@
|
||||
#pragma once
|
||||
#ifndef GAMESERVER_H
|
||||
#define GAMESERVER_H
|
||||
|
||||
#include <yojimbo.h>
|
||||
//Std
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
//Vendor
|
||||
#include <yojimbo.h>
|
||||
#include <entityx/entityx.h>
|
||||
|
||||
//Own
|
||||
#include "Shared.h"
|
||||
|
||||
static const int MAX_PLAYERS = 64;
|
||||
|
||||
class GameServer;
|
||||
|
||||
// a simple test message
|
||||
enum class GameMessageType
|
||||
{
|
||||
TEST,
|
||||
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
|
||||
class ServerAdapter : public SharedAdapter
|
||||
{
|
||||
public:
|
||||
int m_data;
|
||||
|
||||
TestMessage() : m_data(0) {}
|
||||
|
||||
template <typename Stream>
|
||||
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) {}
|
||||
explicit ServerAdapter(GameServer *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:
|
||||
@@ -80,19 +37,24 @@ class GameServer
|
||||
void ClientConnected(int clientIndex);
|
||||
void ClientDisconnected(int clientIndex);
|
||||
|
||||
void ProcessCommand(std::string command);
|
||||
void ProcessMessages();
|
||||
void ProcessMessage(int clientIndex, yojimbo::Message *message);
|
||||
void ProcessTestMessage(int clientIndex, TestMessage *message);
|
||||
|
||||
void Run();
|
||||
void Update(float dt);
|
||||
|
||||
bool m_running;
|
||||
|
||||
private:
|
||||
GameConnectionConfig m_connectionConfig;
|
||||
yojimbo::Server m_server;
|
||||
GameAdapter m_adapter;
|
||||
entityx::EntityX ex;
|
||||
std::map<int, entityx::Entity> serverToEntityX;
|
||||
|
||||
private:
|
||||
double m_time;
|
||||
|
||||
GameConnectionConfig m_connectionConfig;
|
||||
ServerAdapter m_adapter;
|
||||
yojimbo::Server m_server;
|
||||
};
|
||||
|
||||
#endif //GAMESERVER_H
|
||||
87
src/Shared.h
Normal file
87
src/Shared.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef SHARED_H
|
||||
#define SHARED_H
|
||||
|
||||
#include <yojimbo.h>
|
||||
|
||||
// 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 <typename Stream>
|
||||
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 <typename Stream>
|
||||
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
|
||||
11
src/core/Components.h
Normal file
11
src/core/Components.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct NetworkPlayerProperties
|
||||
{
|
||||
NetworkPlayerProperties(std::string name = "unknown")
|
||||
: name(name) {}
|
||||
|
||||
std::string name;
|
||||
};
|
||||
21
src/messages/Command.cpp
Normal file
21
src/messages/Command.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "Command.h"
|
||||
#include "../Shared.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
44
src/messages/Command.h
Normal file
44
src/messages/Command.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
//Vendor
|
||||
#include <yojimbo.h>
|
||||
#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;
|
||||
};
|
||||
14
src/messages/SetNameCommand.cpp
Normal file
14
src/messages/SetNameCommand.cpp
Normal file
@@ -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<NetworkPlayerProperties> playerproperties = entity.component<NetworkPlayerProperties>();
|
||||
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;
|
||||
}
|
||||
12
src/messages/TestCommand.cpp
Normal file
12
src/messages/TestCommand.cpp
Normal file
@@ -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<NetworkPlayerProperties> playerproperties = entity.component<NetworkPlayerProperties>();
|
||||
|
||||
std::cout << "Test message received from client " << playerproperties->name << ":" << m_clientIndex << " with data: " << m_message->m_data << std::endl;
|
||||
}
|
||||
Reference in New Issue
Block a user