Add internal command interpretation

This commit is contained in:
Julian Nießner
2019-06-02 17:52:15 +02:00
parent 8ad1c7219d
commit 84beaf7fd6
9 changed files with 128 additions and 20 deletions

View File

@@ -1,6 +1,12 @@
//std
#include <signal.h>
#include <iostream>
//thread
#include <atomic>
#include <thread>
// Vendor
#include <yojimbo.h>
@@ -18,7 +24,22 @@ static GameServer *serv;
void interrupt_handler(int /*dummy*/)
{
serv->m_running = false;
serv->dispatchCommand("stop");
}
void ReadCin(std::atomic<bool> &run)
{
std::string buffer;
while (run.load())
{
std::getline(std::cin, buffer);
serv->dispatchCommand(buffer);
if (buffer == "stop")
{
run.store(false);
}
}
}
int main(int argc, char *argv[])
@@ -29,12 +50,13 @@ int main(int argc, char *argv[])
DWORD prev_mode;
hInput = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hInput, &prev_mode);
SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS);
prev_mode &= ~ENABLE_QUICK_EDIT_MODE;
SetConsoleMode(hInput, prev_mode);
#endif
if (!InitializeYojimbo())
{
printf("error: failed to initialize Yojimbo!\n");
std::cout << "error: failed to initialize Yojimbo!" << std::endl;
;
return 1;
}
yojimbo_log_level(YOJIMBO_LOG_LEVEL_INFO);
@@ -45,8 +67,15 @@ int main(int argc, char *argv[])
yojimbo::Address addr(127, 0, 0, 1, 9999);
GameServer server(addr);
serv = &server; //For interrupt
std::atomic<bool> run(true);
std::thread cinThread(ReadCin, std::ref(run));
server.Run();
run.store(false);
cinThread.join();
ShutdownYojimbo();
return EXIT_SUCCESS;
}

View File

@@ -5,7 +5,6 @@
#include <memory>
//own
#include "messages/Command.h"
#include "core/Components.h"
using namespace yojimbo;
@@ -86,12 +85,32 @@ void GameServer::Update(float dt)
ProcessMessages();
// ... process client inputs ...
this->m_commandQueueMutex.lock(); //As long as the server is processing the que the adding is blocked
while (!this->commandQueue.empty())
{
std::unique_ptr<Command> command_ptr = std::move(commandQueue.front());
commandQueue.pop();
command_ptr->execute(this);
}
this->m_commandQueueMutex.unlock();
// ... update game ...
// ... send game state to clients ...
m_server.SendPackets();
}
void GameServer::dispatchCommand(std::string commandStr) //thread safe
{
std::unique_ptr<Command> u_ptr(Command::create(commandStr));
if (u_ptr)
{
this->m_commandQueueMutex.lock();
this->commandQueue.push(std::move(u_ptr));
this->m_commandQueueMutex.unlock();
}
}
void GameServer::ProcessMessages()
{
for (int i = 0; i < MAX_PLAYERS; i++)
@@ -106,7 +125,9 @@ void GameServer::ProcessMessages()
std::unique_ptr<Command> command(Command::create(i, message));
if (command)
{
command->execute(this);
this->m_commandQueueMutex.lock();
this->commandQueue.push(std::move(command));
this->m_commandQueueMutex.unlock();
}
m_server.ReleaseMessage(i, message);
message = m_server.ReceiveMessage(i, j);

View File

@@ -4,17 +4,22 @@
//Std
#include <string>
#include <map>
#include <mutex>
#include <queue>
//Vendor
#include <yojimbo.h>
#include <entityx/entityx.h>
class GameServer;
//Own
#include "Shared.h"
#include "messages/Command.h"
static const int MAX_PLAYERS = 64;
class GameServer;
class ServerAdapter : public SharedAdapter
{
@@ -37,20 +42,21 @@ public:
void ClientConnected(int clientIndex);
void ClientDisconnected(int clientIndex);
void ProcessCommand(std::string command);
void dispatchCommand(std::string commandStr); //thread safe
void ProcessMessages();
void ProcessMessage(int clientIndex, yojimbo::Message *message);
void Run();
void Update(float dt);
bool m_running;
std::queue<std::unique_ptr<Command>> commandQueue;
entityx::EntityX ex;
std::map<int, entityx::Entity> serverToEntityX;
private:
double m_time;
std::mutex m_commandQueueMutex;
GameConnectionConfig m_connectionConfig;
ServerAdapter m_adapter;

View File

@@ -2,6 +2,7 @@
#include "../Shared.h"
#include <iostream>
#include <sstream>
Command *Command::create(int clientIndex, yojimbo::Message *message)
{
@@ -9,13 +10,28 @@ Command *Command::create(int clientIndex, yojimbo::Message *message)
{
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;
}
}
Command *Command::create(std::string command)
{
std::stringstream ss(command);
std::string token;
ss >>
token;
if (token == "stop")
{
return new StopCommandInternal();
}
else if (token == "test")
{
return new TestCommandInternal();
}
std::cout << "Internal commando don't exists: " << command << std::endl;
return nullptr;
}

View File

@@ -2,6 +2,8 @@
//Vendor
#include <yojimbo.h>
class Command;
#include "../GameServer.h"
// ---- Interface:
@@ -12,33 +14,53 @@ public:
// Create Commands from Network messages (Limited list)
static Command *create(int clientIndex, yojimbo::Message *message);
// Create Commands from Strings (Limited list)
static Command *create(std::string);
virtual void execute(GameServer *server) = 0;
};
// --- implemented Classes:
// --- Classes Network:
class TestCommand : public Command
{
public:
TestCommand(int clientIndex, yojimbo::Message *message)
: m_clientIndex(clientIndex), m_message((TestMessage *)message) {}
: m_clientIndex(clientIndex),
m_data(((TestMessage *)message)->m_data)
{}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
TestMessage *m_message;
int m_data;
};
class SetNameCommand : public Command
{
public:
SetNameCommand(int clientIndex, yojimbo::Message *message)
: m_clientIndex(clientIndex), m_message((SetNameMessage *)message) {}
: m_clientIndex(clientIndex),
m_name(std::string(((SetNameMessage *)message)->buffer))
{}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
SetNameMessage *m_message;
std::string m_name;
};
// --- Classes Internal:
class TestCommandInternal : public Command
{
public:
virtual void execute(GameServer *server) override;
};
class StopCommandInternal : public Command
{
public:
virtual void execute(GameServer *server) override;
};

View File

@@ -8,7 +8,7 @@ void SetNameCommand::execute(GameServer *server)
entityx::ComponentHandle<NetworkPlayerProperties> playerproperties = entity.component<NetworkPlayerProperties>();
if (playerproperties)
{
playerproperties->name = std::string(m_message->buffer);
playerproperties->name = m_name;
}
std::cout << "Entity name changed to " << playerproperties->name << " Buffer content: " << std::string(m_message->buffer) << std::endl;
std::cout << "Entity name changed to " << playerproperties->name << " Buffer content: " << m_name << std::endl;
}

View File

@@ -0,0 +1,6 @@
#include "Command.h"
void StopCommandInternal::execute(GameServer *server)
{
server->m_running = false;
}

View File

@@ -8,5 +8,5 @@ void TestCommand::execute(GameServer *server)
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;
std::cout << "Test message received from client " << playerproperties->name << ":" << m_clientIndex << " with data: " << m_data << std::endl;
}

View File

@@ -0,0 +1,8 @@
#include "Command.h"
#include <iostream>
void TestCommandInternal::execute(GameServer *server)
{
std::cout << "Internal testcommand launched!" << std::endl;
}