Compare commits
10 Commits
e43d142f6a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90c43b6d75 | ||
|
|
c5f9dfd628 | ||
|
|
72129de8f0 | ||
|
|
342162ba80 | ||
|
|
e6d262cfc0 | ||
|
|
6258ee9193 | ||
|
|
a83b544a3a | ||
|
|
473432d9bb | ||
|
|
84beaf7fd6 | ||
|
|
8ad1c7219d |
@@ -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}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
// #pragma once
|
|
||||||
|
|
||||||
// namespace constants {
|
|
||||||
|
|
||||||
// const int CLIENT_PORT = 9999;
|
|
||||||
// const int MAX_CLIENTS = 128;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
// };
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
// }
|
|
||||||
@@ -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);
|
|
||||||
// };
|
|
||||||
12
protocol.md
12
protocol.md
@@ -1,12 +0,0 @@
|
|||||||
## Loading Screen
|
|
||||||
|
|
||||||
- [Client]
|
|
||||||
Client sends unique UserID.
|
|
||||||
|
|
||||||
- [Server]
|
|
||||||
assign slot to Client
|
|
||||||
|
|
||||||
- [Client]
|
|
||||||
Send User Name
|
|
||||||
|
|
||||||
- [Server_START_UPDATE_ROUTINE]
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
42
src/commands/Command.cpp
Normal 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
94
src/commands/Command.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
14
src/commands/PlayerInputCommand.cpp
Normal file
14
src/commands/PlayerInputCommand.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/commands/SendTestCommand.cpp
Normal file
9
src/commands/SendTestCommand.cpp
Normal 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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
6
src/commands/StopCommand.cpp
Normal file
6
src/commands/StopCommand.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
void StopCommand::execute(GameServer *server)
|
||||||
|
{
|
||||||
|
server->m_running = false;
|
||||||
|
}
|
||||||
17
src/commands/TestCommand.cpp
Normal file
17
src/commands/TestCommand.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
18
src/core/systems/DebugPositionPrinter.h
Normal file
18
src/core/systems/DebugPositionPrinter.h
Normal 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;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
19
src/core/systems/InputProcessor.h
Normal file
19
src/core/systems/InputProcessor.h
Normal 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.
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
26
src/core/systems/PhysicSharer.h
Normal file
26
src/core/systems/PhysicSharer.h
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
20
src/network/ServerAdapter.cpp
Normal file
20
src/network/ServerAdapter.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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};
|
||||||
@@ -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)
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace constants {
|
|
||||||
|
|
||||||
const int CLIENT_PORT = 9999;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user