Compare commits

...

10 Commits

Author SHA1 Message Date
Julian
90c43b6d75 current stand 2021-05-21 14:14:55 +02:00
Julian
c5f9dfd628 Add current progression 2020-03-28 13:50:48 +01:00
Julian
72129de8f0 add multi config suppor 2020-03-28 13:50:16 +01:00
Julian Nießner
342162ba80 Add Physicsharer 2019-06-19 11:44:52 +02:00
Julian Nießner
e6d262cfc0 unify commands 2019-06-02 22:17:03 +02:00
Julian Nießner
6258ee9193 Move serveradapter in seperate cpp files 2019-06-02 18:02:51 +02:00
Julian Nießner
a83b544a3a Remove junk 2019-06-02 17:55:37 +02:00
Julian Nießner
473432d9bb change folder name 2019-06-02 17:54:50 +02:00
Julian Nießner
84beaf7fd6 Add internal command interpretation 2019-06-02 17:52:15 +02:00
Julian Nießner
8ad1c7219d Remove junk 2019-06-02 13:37:53 +02:00
34 changed files with 476 additions and 702 deletions

View File

@@ -3,12 +3,6 @@ project(DarkRP2D_DEDICATED_SERVER)
set (CMAKE_CXX_STANDARD 11) set (CMAKE_CXX_STANDARD 11)
include(ExternalProject) include(ExternalProject)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
add_definitions(-DNDEBUG)
endif(NOT CMAKE_BUILD_TYPE)
if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
MESSAGE( "64-Bit Compiler erkannt" ) MESSAGE( "64-Bit Compiler erkannt" )
SET( EX_PLATFORM 64 ) SET( EX_PLATFORM 64 )
@@ -19,11 +13,10 @@ else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
SET( EX_PLATFORM_NAME "x86" ) SET( EX_PLATFORM_NAME "x86" )
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# Download automatically, you can also just copy the conan.cmake file # Download automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.13/conan.cmake" file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.15/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake") "${CMAKE_BINARY_DIR}/conan.cmake")
endif() endif()
include(${CMAKE_BINARY_DIR}/conan.cmake) include(${CMAKE_BINARY_DIR}/conan.cmake)
@@ -31,13 +24,14 @@ include(${CMAKE_BINARY_DIR}/conan.cmake)
# Launch Conan Install # Launch Conan Install
conan_cmake_run(CONANFILE conanfile.txt conan_cmake_run(CONANFILE conanfile.txt
BASIC_SETUP CMAKE_TARGETS BASIC_SETUP CMAKE_TARGETS
BUILD missing) BUILD missing
CONFIGURATION_TYPES "Release;Debug")
MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} ) MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )
MESSAGE( STATUS "DarkRP2D_DEDICATED_SERVER_SOURCE_DIR: " ${DarkRP2D_DEDICATED_SERVER_SOURCE_DIR} ) MESSAGE( STATUS "DarkRP2D_DEDICATED_SERVER_SOURCE_DIR: " ${DarkRP2D_DEDICATED_SERVER_SOURCE_DIR} )
#Libs #Libs
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) include(${CMAKE_BINARY_DIR}/conanbuildinfo_multi.cmake)
conan_basic_setup() conan_basic_setup()
file(GLOB_RECURSE DarkRP2D_DEDICATED_SERVER_SOURCE_FILES ${DarkRP2D_DEDICATED_SERVER_SOURCE_DIR}/src/*.cpp) file(GLOB_RECURSE DarkRP2D_DEDICATED_SERVER_SOURCE_FILES ${DarkRP2D_DEDICATED_SERVER_SOURCE_DIR}/src/*.cpp)
@@ -48,7 +42,12 @@ MESSAGE( STATUS "Conan search Dirs: " "${CONAN_LIB_DIRS}")
MESSAGE( STATUS "Conan Libs: " "${CONAN_LIBS}") MESSAGE( STATUS "Conan Libs: " "${CONAN_LIBS}")
MESSAGE( STATUS "Conan Includes: " "${CONAN_INCLUDE_DIRS}") MESSAGE( STATUS "Conan Includes: " "${CONAN_INCLUDE_DIRS}")
target_link_libraries(DarkRP2DDServer ${CONAN_LIBS}) foreach(_LIB ${CONAN_LIBS_RELEASE})
target_link_libraries(DarkRP2DDServer optimized ${_LIB})
endforeach()
foreach(_LIB ${CONAN_LIBS_DEBUG})
target_link_libraries(DarkRP2DDServer debug ${_LIB})
endforeach()
#add_custom_target(CopyBinaries #add_custom_target(CopyBinaries
#COMMAND ${CMAKE_COMMAND} -E copy ${SDL2_DLL} ${CMAKE_BINARY_DIR} #COMMAND ${CMAKE_COMMAND} -E copy ${SDL2_DLL} ${CMAKE_BINARY_DIR}

View File

@@ -1,10 +1,12 @@
[requires] [requires]
box2d/2.3.1@conan/stable box2d/2.3.1@conan/stable
glm/0.9.9.1@g-truc/stable glm/0.9.9.1@g-truc/stable
EntityX/1.1.2@gulum/stable EntityX/1.3.0@gulum/stable
Yojimbo/1.2.1@gulum/stable Yojimbo/1.2.1@gulum/stable
vscodepropertiesgen/0.1@mkovalchik/stable vscodepropertiesgen/0.1@mkovalchik/stable
[options]
Entityx:shared=False
[generators] [generators]
cmake cmake

View File

@@ -1,9 +0,0 @@
// #pragma once
// namespace constants {
// const int CLIENT_PORT = 9999;
// const int MAX_CLIENTS = 128;
// }

View File

@@ -1,22 +0,0 @@
// #pragma once
// #define CONNECTION_REQUEST 0x01
// #define CONNECTION_ACCEPTED 0x02
// #define CONNECTION_DENIED 0x03
// struct ConnectionRequest {
// ConnectionRequest() : type(CONNECTION_REQUEST) {}
// char type = CONNECTION_REQUEST;
// };
// struct ConnectionAccepted {
// ConnectionAccepted() : type(CONNECTION_ACCEPTED) {}
// char type;
// int index;
// };
// struct ConnectionDenied {
// ConnectionDenied() : type(CONNECTION_DENIED) {}
// char type;
// };

View File

@@ -1,164 +0,0 @@
// #include "Server.h"
// #include "Protocoll.h"
// #include <string>
// #include <iostream>
// #include <thread>
// Server::Server(int port) : m_maxClients(constants::MAX_CLIENTS), m_clientConnected{0}
// {
// udpSocket = SDLNet_UDP_Open(port);
// if (udpSocket == nullptr)
// {
// std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
// }
// std::cout << "Server was started and is listening on port: " << port << std::endl;
// //Creating ConnectionAccepted packet!
// // Allocate udp packet with 512 byte size
// connectionAccepted = SDLNet_AllocPacket(512);
// if (connectionAccepted == nullptr)
// {
// std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
// }
// ConnectionAccepted conAcc = ConnectionAccepted();
// memcpy(connectionAccepted->data, &conAcc, sizeof(ConnectionAccepted));
// connectionAccepted->len = sizeof(ConnectionAccepted);
// connectionDenied = SDLNet_AllocPacket(512);
// if (connectionDenied == nullptr)
// {
// std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
// }
// ConnectionDenied conDen = ConnectionDenied();
// memcpy(connectionDenied->data, &conDen, sizeof(ConnectionDenied));
// connectionDenied->len = sizeof(ConnectionDenied);
// //Creating receiver packet!
// receivedPacket = SDLNet_AllocPacket(512);
// if (receivedPacket == nullptr)
// {
// std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
// }
// }
// int Server::FindFreeClientIndex() const
// {
// for (int i = 0; i < m_maxClients; ++i)
// {
// if (!m_clientConnected[i])
// return i;
// }
// return -1;
// }
// int Server::FindExistingClientIndex(const IPaddress &ip) const
// {
// for (int i = 0; i < m_maxClients; ++i)
// {
// if (m_clientConnected[i] && m_clients[i].host == ip.host && m_clients[i].port == ip.port)
// return i;
// }
// return -1;
// }
// bool Server::IsClientConnected(int clientIndex) const
// {
// return m_clientConnected[clientIndex];
// }
// const IPaddress &Server::GetClientAddress(int clientIndex) const
// {
// return m_clients[clientIndex];
// }
// void Server::update(unsigned int delta)
// {
// //Receive packages
// if (SDLNet_UDP_Recv(udpSocket, receivedPacket))
// {
// switch (*(receivedPacket->data))
// {
// case CONNECTION_REQUEST:
// std::cout << "Connection request package received\n";
// int freeIndex;
// if ((freeIndex = this->FindFreeClientIndex()) == -1)
// {
// std::cout << "Connection denied because server full" << std::endl;
// //Send Connection denied
// this->sendConnectionDenied(receivedPacket->address);
// break;
// }
// std::cout << "Free index found: " << freeIndex << std::endl;
// int indexOfExistingClient;
// if ((indexOfExistingClient = FindExistingClientIndex(receivedPacket->address)) == -1)
// {
// std::cout << "Client doesent exist create new" << std::endl;
// m_clients[freeIndex] = receivedPacket->address;
// m_clientConnected[freeIndex] = true;
// //Send connection accepted with index
// this->sendConnectionAccepted(receivedPacket->address, freeIndex);
// m_numConnectedClients++;
// break;
// }
// else
// {
// std::cout << "Client exist sending accepted" << std::endl;
// //Send connection accepted with index
// this->sendConnectionAccepted(receivedPacket->address, indexOfExistingClient);
// }
// break;
// default:
// break;
// }
// }
// //Wait 10 sec
// using namespace std::chrono_literals;
// std::this_thread::sleep_for(1s);
// //Send data
// /*for(auto &value: clients) {
// value.send(this->udpSocket,*helloWorldPacket);
// }
// std::cout << "Data was send!!" << std::endl;*/
// }
// bool Server::sendPacket(UDPpacket &packet)
// {
// // Send
// // SDLNet_UDP_Send returns number of packets sent. 0 means error
// if (SDLNet_UDP_Send(this->udpSocket, -1, &packet) == 0)
// {
// std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
// << "==========================================================================================================\n";
// return false;
// }
// return true;
// }
// bool Server::sendConnectionDenied(IPaddress dest)
// {
// this->connectionDenied->address.host = dest.host;
// this->connectionDenied->address.port = dest.port;
// return this->sendPacket(*connectionDenied);
// }
// bool Server::sendConnectionAccepted(IPaddress dest, int index)
// {
// this->connectionAccepted->address.host = dest.host;
// this->connectionAccepted->address.port = dest.port;
// ((ConnectionAccepted *) connectionAccepted->data)->index = index;
// return this->sendPacket(*connectionAccepted);
// }
// Server::~Server()
// {
// SDLNet_FreePacket(receivedPacket);
// SDLNet_FreePacket(connectionAccepted);
// SDLNet_UDP_Close(udpSocket);
// }

View File

@@ -1,36 +0,0 @@
// #pragma once
// #include <SDL_net.h>
// #include "Constants.h"
// class Server {
// public:
// Server(int port);
// ~Server();
// int FindFreeClientIndex() const;
// int FindExistingClientIndex( const IPaddress &ip ) const;
// bool IsClientConnected( int clientIndex ) const;
// const IPaddress & GetClientAddress( int clientIndex ) const;
// void update(unsigned int delta);
// void gameTick();
// private:
// UDPsocket udpSocket;
// UDPpacket *connectionDenied;
// UDPpacket *connectionAccepted;
// UDPpacket *receivedPacket;
// int m_maxClients;
// int m_numConnectedClients;
// bool m_clientConnected[constants::MAX_CLIENTS];
// IPaddress m_clients[constants::MAX_CLIENTS];
// bool sendPacket(UDPpacket &packet);
// bool sendConnectionDenied(IPaddress dest);
// bool sendConnectionAccepted(IPaddress dest, int index);
// };

View File

@@ -1,12 +0,0 @@
## Loading Screen
- [Client]
Client sends unique UserID.
- [Server]
assign slot to Client
- [Client]
Send User Name
- [Server_START_UPDATE_ROUTINE]

View File

@@ -1,6 +1,11 @@
//std
#include <signal.h> #include <signal.h>
#include <iostream> #include <iostream>
//thread
#include <atomic>
#include <thread>
// Vendor // Vendor
#include <yojimbo.h> #include <yojimbo.h>
@@ -18,7 +23,26 @@ static GameServer *serv;
void interrupt_handler(int /*dummy*/) 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);
}
}
}
void parseArguments() {
//TODO
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -29,12 +53,12 @@ int main(int argc, char *argv[])
DWORD prev_mode; DWORD prev_mode;
hInput = GetStdHandle(STD_INPUT_HANDLE); hInput = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hInput, &prev_mode); GetConsoleMode(hInput, &prev_mode);
SetConsoleMode(hInput, prev_mode & ENABLE_EXTENDED_FLAGS); prev_mode &= ~ENABLE_QUICK_EDIT_MODE;
SetConsoleMode(hInput, prev_mode);
#endif #endif
if (!InitializeYojimbo()) if (!InitializeYojimbo())
{ {
printf("error: failed to initialize Yojimbo!\n"); std::cout << "error: failed to initialize Yojimbo!" << std::endl;
return 1; return 1;
} }
yojimbo_log_level(YOJIMBO_LOG_LEVEL_INFO); yojimbo_log_level(YOJIMBO_LOG_LEVEL_INFO);
@@ -45,8 +69,15 @@ int main(int argc, char *argv[])
yojimbo::Address addr(127, 0, 0, 1, 9999); yojimbo::Address addr(127, 0, 0, 1, 9999);
GameServer server(addr); GameServer server(addr);
serv = &server; //For interrupt serv = &server; //For interrupt
std::atomic<bool> run(true);
std::thread cinThread(ReadCin, std::ref(run));
server.Run(); server.Run();
run.store(false);
cinThread.join();
ShutdownYojimbo(); ShutdownYojimbo();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -5,8 +5,9 @@
#include <memory> #include <memory>
//own //own
#include "messages/Command.h"
#include "core/Components.h" #include "core/Components.h"
#include "core/systems/PhysicSharer.h"
#include "core/systems/InputProcessor.h"
using namespace yojimbo; using namespace yojimbo;
@@ -18,7 +19,8 @@ GameServer::GameServer(const yojimbo::Address &address) : m_time(yojimbo_time())
m_connectionConfig, m_connectionConfig,
m_adapter, m_adapter,
m_time), m_time),
m_running(false) m_running(false),
world(b2Vec2(0.0, 0.0)) //2D top down gravity
{ {
// start the server // start the server
m_server.Start(MAX_PLAYERS); m_server.Start(MAX_PLAYERS);
@@ -32,12 +34,42 @@ GameServer::GameServer(const yojimbo::Address &address) : m_time(yojimbo_time())
m_server.GetAddress().ToString(buffer, sizeof(buffer)); m_server.GetAddress().ToString(buffer, sizeof(buffer));
// ... load game ... // ... load game ...
ex.systems.add<PhysicsShareSystem>(this);
ex.systems.add<InputProcessor>(this);
ex.systems.configure();
// load an custom object
// entityx::Entity entity = ex.entities.create();
// b2BodyDef playerBodyDef;
// playerBodyDef.type = b2_kinematicBody;
// playerBodyDef.position.Set(0.0f, 0.0f);
// b2Body *bod = this->world.CreateBody(&playerBodyDef);
// b2PolygonShape hitbox;
// hitbox.SetAsBox(5.0f, 5.0f);
// bod->CreateFixture(&hitbox, 0.0f);
// entity.assign<PhysicBody>(bod);
//TODO: -- add box2d components --
} }
void GameServer::ClientConnected(int clientIndex) void GameServer::ClientConnected(int clientIndex)
{ {
entityx::Entity entity = ex.entities.create(); entityx::Entity entity = ex.entities.create();
entity.assign<NetworkPlayerProperties>(); //---Add network info
entity.assign<NetworkPlayerProperties>(clientIndex);
//---Add networked physics
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_kinematicBody;
playerBodyDef.position.Set(0.0f, 0.0f);
b2Body *bod = this->world.CreateBody(&playerBodyDef);
b2PolygonShape hitbox;
hitbox.SetAsBox(5.0f, 5.0f);
bod->CreateFixture(&hitbox, 0.0f);
entity.assign<PhysicBody>(bod);
entity.assign<InputVelocity>(0.0f,0.0f);
//--Usual continue
serverToEntityX.insert(std::pair<int, entityx::Entity>(clientIndex, entity)); serverToEntityX.insert(std::pair<int, entityx::Entity>(clientIndex, entity));
std::cout << "client " << clientIndex << " connected" << std::endl; std::cout << "client " << clientIndex << " connected" << std::endl;
} }
@@ -86,12 +118,38 @@ void GameServer::Update(float dt)
ProcessMessages(); ProcessMessages();
// ... process client inputs ... // ... 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 ... // ... update game ...
int velocityIterations = 6;
int positionIterations = 2;
this->world.Step(dt, velocityIterations, positionIterations);
// ... send game state to clients ... // ... send game state to clients ...
ex.systems.update<InputProcessor>(dt);
// ex.systems.update<PhysicsShareSystem>(dt);
m_server.SendPackets(); 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() void GameServer::ProcessMessages()
{ {
for (int i = 0; i < MAX_PLAYERS; i++) for (int i = 0; i < MAX_PLAYERS; i++)
@@ -106,7 +164,9 @@ void GameServer::ProcessMessages()
std::unique_ptr<Command> command(Command::create(i, message)); std::unique_ptr<Command> command(Command::create(i, message));
if (command) if (command)
{ {
command->execute(this); this->m_commandQueueMutex.lock();
this->commandQueue.push(std::move(command));
this->m_commandQueueMutex.unlock();
} }
m_server.ReleaseMessage(i, message); m_server.ReleaseMessage(i, message);
message = m_server.ReceiveMessage(i, j); message = m_server.ReceiveMessage(i, j);
@@ -115,21 +175,3 @@ void GameServer::ProcessMessages()
} }
} }
} }
ServerAdapter::ServerAdapter(GameServer *server) : m_server(server) {}
void ServerAdapter::OnServerClientConnected(int clientIndex)
{
if (m_server != NULL)
{
m_server->ClientConnected(clientIndex);
}
}
void ServerAdapter::OnServerClientDisconnected(int clientIndex)
{
if (m_server != NULL)
{
m_server->ClientDisconnected(clientIndex);
}
}

View File

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

42
src/commands/Command.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include "Command.h"
#include "../network/Shared.h"
#include <iostream>
#include <sstream>
Command *Command::create(int clientIndex, yojimbo::Message *message)
{
switch (message->GetType())
{
case (int)GameMessageType::TEST:
return new TestCommand(clientIndex, ((TestMessage *)message)->m_data);
case (int)GameMessageType::SETNAME:
return new SetNameCommand(clientIndex, std::string(((SetNameMessage *)message)->buffer));
case (int)GameMessageType::INPUTSTATEMESSAGE:
return new PlayerInputCommand(clientIndex, ((InputStateMessage *) message)->m_vel_x, ((InputStateMessage *) message)->m_vel_y);
default:
std::cout << "Unknown message type received over network!" << std::endl;
return nullptr;
}
}
Command *Command::create(std::string command)
{
std::stringstream ss(command);
std::string token;
ss >>
token;
if (token == "stop")
{
return new StopCommand();
}
else if (token == "test")
{
return new TestCommand(-1, 100);
} else if (token == "sendTest")
{
return new SendTestCommand(0, 42);
}
std::cout << "Local command don't exists: " << command << std::endl;
return nullptr;
}

94
src/commands/Command.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
//Vendor
#include <yojimbo.h>
class Command;
#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 internal (Limited list)
static Command *create(std::string);
virtual void execute(GameServer *server) = 0;
};
// --- Classes Network:
class TestCommand : public Command
{
public:
TestCommand(int clientIndex, int data)
: m_clientIndex(clientIndex),
m_data(data)
{
}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
int m_data;
};
class SetNameCommand : public Command
{
public:
SetNameCommand(int clientIndex, std::string name)
: m_clientIndex(clientIndex),
m_name(name)
{
}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
std::string m_name;
};
// --- Classes local:
class StopCommand : public Command
{
public:
virtual void execute(GameServer *server) override;
};
class SendTestCommand : public Command
{
public:
SendTestCommand(int clientIndex, int data)
: m_clientIndex(clientIndex),
m_data(data)
{
}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
int m_data;
};
class PlayerInputCommand : public Command
{
public:
PlayerInputCommand(int clientIndex, float vel_x, float vel_y)
: m_clientIndex(clientIndex),
m_vel_x(vel_x),
m_vel_y(vel_y)
{
}
virtual void execute(GameServer *server) override;
private:
int m_clientIndex;
float m_vel_x, m_vel_y;
};

View File

@@ -0,0 +1,14 @@
#include "Command.h"
#include "../core/Components.h"
void PlayerInputCommand::execute(GameServer *server)
{
entityx::Entity entity = server->serverToEntityX.at(m_clientIndex);
entityx::ComponentHandle<InputVelocity> iVel = entity.component<InputVelocity>();
if (iVel)
{
iVel->m_vel_x = this->m_vel_x;
iVel->m_vel_y = this->m_vel_y;
}
}

View File

@@ -0,0 +1,9 @@
#include "Command.h"
void SendTestCommand::execute(GameServer *server)
{
std::cout << "Sending Test command to ClientID: " << this->m_clientIndex << " with data: " << this->m_data << std::endl;
TestMessage *msg = (TestMessage *)server->m_server.CreateMessage(this->m_clientIndex, (int)GameMessageType::TEST);
msg->m_data = this->m_data;
server->m_server.SendMessage(this->m_clientIndex, (int)GameChannel::RELIABLE, msg);
}

View File

@@ -8,7 +8,7 @@ void SetNameCommand::execute(GameServer *server)
entityx::ComponentHandle<NetworkPlayerProperties> playerproperties = entity.component<NetworkPlayerProperties>(); entityx::ComponentHandle<NetworkPlayerProperties> playerproperties = entity.component<NetworkPlayerProperties>();
if (playerproperties) 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 StopCommand::execute(GameServer *server)
{
server->m_running = false;
}

View File

@@ -0,0 +1,17 @@
#include "Command.h"
#include "../core/Components.h"
void TestCommand::execute(GameServer *server)
{
if (m_clientIndex == -1)
{
std::cout << "Test message received from server cmd :" << m_clientIndex << " with data: " << m_data << std::endl;
}
else
{
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_data << std::endl;
}
}

View File

@@ -4,8 +4,29 @@
struct NetworkPlayerProperties struct NetworkPlayerProperties
{ {
NetworkPlayerProperties(std::string name = "unknown") NetworkPlayerProperties(int clientIndex,std::string name = "unknown")
: name(name) {} : name(name),
m_clientIndex(clientIndex)
{}
std::string name; std::string name;
int m_clientIndex;
};
#include <Box2D/Box2D.h>
struct PhysicBody
{
PhysicBody(b2Body* b) : body(b) {}
b2Body* body;
};
struct InputVelocity
{
InputVelocity(float vel_x, float vel_y)
: m_vel_x(vel_x), m_vel_y(vel_y)
{}
float m_vel_x, m_vel_y;
}; };

View File

@@ -0,0 +1,18 @@
#pragma once
#include <entityx/entityx.h>
#include "../../GameServer.h"
#include "../Components.h"
struct DebugPositionPrinter : public entityx::System<DebugPositionPrinter>
{
DebugPositionPrinter(GameServer *server) : m_gserver(server) {}
GameServer *m_gserver;
void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override
{
es.each<NetworkPlayerProperties, PhysicBody>([](entityx::Entity entity, NetworkPlayerProperties &nProp, PhysicBody &bod) {
std::cout << "Client " << nProp.name << ":" << nProp.m_clientIndex << " Pos: " << bod.body->GetPosition << std::endl;
});
};
};

View File

@@ -0,0 +1,19 @@
#pragma once
#include <entityx/entityx.h>
#include "../../GameServer.h"
#include "../Components.h"
struct InputProcessor : public entityx::System<InputProcessor>
{
InputProcessor(GameServer *server) : m_gserver(server) {}
GameServer *m_gserver;
void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override
{
//For each with input component look for id
es.each<InputVelocity, PhysicBody>([](entityx::Entity entity, InputVelocity &iVel, PhysicBody &bod) {
// Do things with entity, position and direction.
});
};
};

View File

@@ -0,0 +1,26 @@
#pragma once
#include <entityx/entityx.h>
#include "../../GameServer.h"
#include "../Components.h"
struct PhysicsShareSystem : public entityx::System<PhysicsShareSystem>
{
PhysicsShareSystem(GameServer *server) : m_gserver(server) {}
GameServer *m_gserver;
void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override
{
es.each<PhysicBody>([&es, dt, this](entityx::Entity entity, PhysicBody &body) { //For every phyicbody filter networked kinematic bodys
//ONLY 10 TIMES PER SECOND
//body.body->IsActive
es.each<NetworkPlayerProperties>([body, dt, this](entityx::Entity entity, NetworkPlayerProperties &net) { //For every networkplayer
PhysicStateMessage *msg = (PhysicStateMessage *)this->m_gserver->m_server.CreateMessage(net.m_clientIndex, (int)GameMessageType::PHYSICSTATEMESSAGE);
msg->isActive = body.body->IsActive();
msg->m_posX = body.body->GetPosition().x;
msg->m_posY = body.body->GetPosition().y;
this->m_gserver->m_server.SendMessage(net.m_clientIndex, (int)GameChannel::UNRELIABLE, msg);
});
});
};
};

View File

@@ -1,21 +0,0 @@
#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;
}
}

View File

@@ -1,44 +0,0 @@
#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;
};

View File

@@ -1,12 +0,0 @@
#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;
}

View File

@@ -0,0 +1,20 @@
#include "../GameServer.h"
ServerAdapter::ServerAdapter(GameServer *server) : m_server(server) {}
void ServerAdapter::OnServerClientConnected(int clientIndex)
{
if (m_server != NULL)
{
m_server->ClientConnected(clientIndex);
}
}
void ServerAdapter::OnServerClientDisconnected(int clientIndex)
{
if (m_server != NULL)
{
m_server->ClientDisconnected(clientIndex);
}
}

View File

@@ -3,14 +3,6 @@
#include <yojimbo.h> #include <yojimbo.h>
// a simple test message
enum class GameMessageType
{
TEST,
SETNAME,
COUNT
};
// two channels, one for each type that Yojimbo supports // two channels, one for each type that Yojimbo supports
enum class GameChannel enum class GameChannel
{ {
@@ -30,6 +22,16 @@ struct GameConnectionConfig : yojimbo::ClientServerConfig
} }
}; };
// message types
enum class GameMessageType
{
TEST,
SETNAME,
PHYSICSTATEMESSAGE,
INPUTSTATEMESSAGE,
COUNT
};
class TestMessage : public yojimbo::Message class TestMessage : public yojimbo::Message
{ {
public: public:
@@ -51,8 +53,7 @@ class SetNameMessage : public yojimbo::Message
{ {
public: public:
char buffer[yojimbo::MaxAddressLength]; char buffer[yojimbo::MaxAddressLength];
SetNameMessage() { SetNameMessage() {}
}
template <typename Stream> template <typename Stream>
bool Serialize(Stream &stream) bool Serialize(Stream &stream)
@@ -64,22 +65,62 @@ public:
YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS(); YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS();
}; };
class PhysicStateMessage : public yojimbo::Message
{
public:
int m_objectID;
float m_posX;
float m_posY;
bool isActive;
PhysicStateMessage() : m_objectID(0), m_posX(0), m_posY(0), isActive(false) {}
template <typename Stream>
bool Serialize(Stream &stream)
{
serialize_int(stream, m_objectID, 0, 512);
serialize_float(stream, m_posX);
serialize_float(stream, m_posY);
serialize_bool(stream, isActive);
return true;
}
YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS();
};
class InputStateMessage : public yojimbo::Message
{
public:
float m_vel_x, m_vel_y;
InputStateMessage() : m_vel_x(0), m_vel_y(0) {}
template <typename Stream>
bool Serialize(Stream &stream)
{
serialize_float(stream, m_vel_x);
serialize_float(stream, m_vel_y);
return true;
}
YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS();
};
// the message factory // the message factory
YOJIMBO_MESSAGE_FACTORY_START(GameMessageFactory, (int)GameMessageType::COUNT); YOJIMBO_MESSAGE_FACTORY_START(GameMessageFactory, (int)GameMessageType::COUNT);
YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::TEST, TestMessage); YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::TEST, TestMessage);
YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::SETNAME, SetNameMessage); YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::SETNAME, SetNameMessage);
YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::PHYSICSTATEMESSAGE, PhysicStateMessage);
YOJIMBO_DECLARE_MESSAGE_TYPE((int)GameMessageType::INPUTSTATEMESSAGE, InputStateMessage);
YOJIMBO_MESSAGE_FACTORY_FINISH(); YOJIMBO_MESSAGE_FACTORY_FINISH();
// the adapter // the adapter
class SharedAdapter : public yojimbo::Adapter class SharedAdapter : public yojimbo::Adapter
{ {
public: public:
yojimbo::MessageFactory *CreateMessageFactory(yojimbo::Allocator &allocator) override yojimbo::MessageFactory *CreateMessageFactory(yojimbo::Allocator &allocator) override
{ {
return YOJIMBO_NEW(allocator, GameMessageFactory, allocator); return YOJIMBO_NEW(allocator, GameMessageFactory, allocator);
} }
}; };
static const uint8_t DEFAULT_PRIVATE_KEY[yojimbo::KeyBytes] = {0}; static const uint8_t DEFAULT_PRIVATE_KEY[yojimbo::KeyBytes] = {0};

View File

@@ -1,41 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project(DarkRP2D_TEST_CLIENT)
set (CMAKE_CXX_STANDARD 11)
include(ExternalProject)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RELEASE)
add_definitions(-DNDEBUG)
endif(NOT CMAKE_BUILD_TYPE)
MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )
MESSAGE( STATUS "DarkRP2D_TEST_CLIENT_SOURCE_DIR: " ${DarkRP2D_TEST_CLIENT_SOURCE_DIR} )
set(DarkRP2D_EXTERNAL_DIR ${DarkRP2D_TEST_CLIENT_SOURCE_DIR}/../external)
set(SDL2_net_DIR ${DarkRP2D_EXTERNAL_DIR}/SDL2_net-2.0.1)
set(SDL2_DIR ${DarkRP2D_EXTERNAL_DIR}/SDL2-2.0.8)
#Libs
find_package(SDL2 REQUIRED CONFIG)
include_directories(${SDL2_INCLUDE_DIRS})
find_package(SDL2_net REQUIRED CONFIG)
include_directories(${SDL2_NET_INCLUDE_DIRS})
MESSAGE( STATUS "SDL2 Lib: " ${SDL2_LIBRARIES} )
MESSAGE( STATUS "SDL2_NET Lib: " ${SDL2_NET_LIBRARIES} )
file(GLOB_RECURSE DarkRP2D_TEST_CLIENT_SOURCE_FILES ${DarkRP2D_TEST_CLIENT_SOURCE_DIR}/src/*.cpp)
add_executable(DarkRP2DTestClient ${DarkRP2D_TEST_CLIENT_SOURCE_FILES})
target_link_libraries(DarkRP2DTestClient ${SDL2_LIBRARIES}
${SDL2_NET_LIBRARIES} )
add_custom_target(CopyBinaries
COMMAND ${CMAKE_COMMAND} -E copy ${SDL2_DLL} ${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${SDL2_NET_DLL} ${CMAKE_BINARY_DIR}
)
add_dependencies(DarkRP2DTestClient CopyBinaries)

View File

@@ -1,87 +0,0 @@
#include "Client.h"
#include "Constants.h"
#include "Protocoll.h"
#include <iostream>
#include <thread>
Client::Client(std::string _serverIP, int port) : connected(new Connected(this)),
connecting(new Connecting(this)),
disconnected(new Disconnected(this))
{
udpSocket = SDLNet_UDP_Open(constants::CLIENT_PORT);
if (udpSocket == nullptr)
{
std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
}
// Set IP and port number with correct endianess
if (SDLNet_ResolveHost(&serverIP, _serverIP.c_str(), port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
}
connectionRequest = SDLNet_AllocPacket(512);
if (connectionRequest == nullptr)
{
std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
}
ConnectionRequest conReq = ConnectionRequest();
memcpy(connectionRequest->data, &conReq, sizeof(ConnectionRequest));
connectionRequest->len = sizeof(ConnectionRequest);
receivedPacket = SDLNet_AllocPacket(512);
if (receivedPacket == nullptr)
{
std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
}
this->setClientState(connecting);
}
void Client::setClientState(ClientState *state)
{
std::cout << "State changed!" << std::endl;
currentState = state;
}
void Client::update(unsigned int delta)
{
currentState->update(delta);
using namespace std::chrono_literals;
std::this_thread::sleep_for(2s);
}
bool Client::sendConnectionRequest(IPaddress dest)
{
connectionRequest->address.host = dest.host;
connectionRequest->address.port = dest.port;
return this->sendPacket(*connectionRequest);
}
bool Client::sendPacket(UDPpacket &packet)
{
// Send
// SDLNet_UDP_Send returns number of packets sent. 0 means error
if (SDLNet_UDP_Send(this->udpSocket, -1, &packet) == 0)
{
std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
<< "==========================================================================================================\n";
return false;
}
return true;
}
Client::~Client()
{
delete connected;
delete connecting;
delete disconnected;
SDLNet_FreePacket(connectionRequest);
SDLNet_FreePacket(receivedPacket);
SDLNet_UDP_Close(udpSocket);
}

View File

@@ -1,37 +0,0 @@
#pragma once
#include <SDL_net.h>
#include <string>
class Client;
#include "ClientStates.h"
class Client {
public:
Client(std::string serverIP, int port);
~Client();
Client(const Client&) = delete;
void setClientState(ClientState *state);
void update(unsigned int delta);
bool sendConnectionRequest(IPaddress dest);
bool sendPacket(UDPpacket &packet);
UDPsocket udpSocket;
IPaddress serverIP;
UDPpacket *connectionRequest;
UDPpacket *receivedPacket;
ClientState *currentState;
Connected *connected;
Connecting *connecting;
Disconnected *disconnected;
};

View File

@@ -1,40 +0,0 @@
#include "ClientStates.h"
#include "Protocoll.h"
#include <iostream>
void Connecting::update(unsigned int delta)
{
std::cout << "Connecting.. (Sending Request)" << std::endl;
m_client->sendConnectionRequest(m_client->serverIP);
if (SDLNet_UDP_Recv(m_client->udpSocket, m_client->receivedPacket))
{
std::cout << "Something received.." << std::endl;
switch (*(m_client->receivedPacket->data))
{
case CONNECTION_ACCEPTED:
{
int index = ((ConnectionAccepted *)(m_client->receivedPacket->data))->index;
std::cout << "Server accepted Connection! My Index ist: " << index << std::endl;
m_client->setClientState(m_client->connected);
}
break;
case CONNECTION_DENIED:
std::cout << "Server denied Connection!" << std::endl;
m_client->setClientState(m_client->disconnected);
default:
break;
}
}
}
void Connected::update(unsigned int delta)
{
std::cout << "I AM IN CONNECTED STATE!" << std::endl;
}
void Disconnected::update(unsigned int delta)
{
std::cout << "I AM IN DISCONNECTED STATE!" << std::endl;
}

View File

@@ -1,47 +0,0 @@
#pragma once
class ClientState;
class Connecting;
class Connected;
class Disconnected;
#include "Client.h"
class ClientState
{
public:
virtual void update(unsigned int delta) = 0;
};
class Connecting : public ClientState {
public:
Connecting(Client *client) : m_client(client) {}
virtual void update(unsigned int delta) override;
private:
Client *m_client;
};
class Connected : public ClientState
{
public:
Connected(Client *client) : m_client(client) {}
virtual void update(unsigned int delta) override;
private:
Client *m_client;
};
class Disconnected : public ClientState
{
public:
Disconnected(Client *client) : m_client(client) {}
virtual void update(unsigned int delta) override;
private:
Client *m_client;
};

View File

@@ -1,8 +0,0 @@
#pragma once
namespace constants {
const int CLIENT_PORT = 9999;
}

View File

@@ -1,22 +0,0 @@
#pragma once
#define CONNECTION_REQUEST 0x01
#define CONNECTION_ACCEPTED 0x02
#define CONNECTION_DENIED 0x03
struct ConnectionRequest {
ConnectionRequest() : type(CONNECTION_REQUEST) {}
char type = CONNECTION_REQUEST;
};
struct ConnectionAccepted {
ConnectionAccepted() : type(CONNECTION_ACCEPTED) {}
char type;
int index;
};
struct ConnectionDenied {
ConnectionDenied() : type(CONNECTION_DENIED) {}
char type;
};

View File

@@ -1,33 +0,0 @@
#include <SDL_net.h>
#include <iostream>
#include "Client.h"
int main(int argc, char *argv[])
{
std::cout << "Starting DarkRP2D Client..." << std::endl;
if (SDLNet_Init() < 0)
{
fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
exit(EXIT_FAILURE);
}
bool clientQuit = false;
{
Client client("127.0.0.1",12000);
unsigned int lastTime = SDL_GetTicks(), currentTime, elapsedTime;
while (!clientQuit)
{
currentTime = SDL_GetTicks();
elapsedTime = currentTime - lastTime;
lastTime = currentTime;
client.update(elapsedTime);
}
}
SDLNet_Quit();
std::cout << "Client closed!" << std::endl;
return EXIT_SUCCESS;
}