From be26c9d103ae7651c4db2e1a83abcfdf51f89881 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 8 Dec 2013 15:55:49 +1100 Subject: [PATCH] Started working on multithreaded rooms --- server/client.hpp | 38 +++++++++++++++ server/player.hpp | 39 +++++++++++++++ server/server_application.cpp | 39 +++++++-------- server/server_application.hpp | 31 +++++------- server/thread_safe_queue.hpp | 92 +++++++++++++++++++++++++++++++++++ server/world_room.cpp | 91 ++++++++++++++++++++++++++++++++++ server/world_room.hpp | 65 +++++++++++++++++++++++++ 7 files changed, 356 insertions(+), 39 deletions(-) create mode 100644 server/client.hpp create mode 100644 server/player.hpp create mode 100644 server/thread_safe_queue.hpp create mode 100644 server/world_room.cpp create mode 100644 server/world_room.hpp diff --git a/server/client.hpp b/server/client.hpp new file mode 100644 index 0000000..c2d2194 --- /dev/null +++ b/server/client.hpp @@ -0,0 +1,38 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef CLIENT_HPP_ +#define CLIENT_HPP_ + +#include "SDL/SDL_net.h" + +#include + +/* Hold the client info. +*/ + +struct Client { + IPaddress address; +}; + +typedef std::map ClientMap; + +#endif diff --git a/server/player.hpp b/server/player.hpp new file mode 100644 index 0000000..fa015ab --- /dev/null +++ b/server/player.hpp @@ -0,0 +1,39 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef PLAYER_HPP_ +#define PLAYER_HPP_ + +#include +#include + +/* Hold the player info. +*/ + +struct Player { + int clientIndex; + std::string handle; + std::string avatar; +}; + +typedef std::map PlayerMap; + +#endif diff --git a/server/server_application.cpp b/server/server_application.cpp index 7b6da76..800f02f 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -32,13 +32,6 @@ using namespace std; -//------------------------- -//Declarations -//------------------------- - -int Client::counter = 0; -int Player::counter = 0; - //------------------------- //Define the ServerApplication //------------------------- @@ -54,6 +47,12 @@ ServerApplication::~ServerApplication() { void ServerApplication::Init(int argc, char** argv) { //TODO: proper command line option parsing + //Check prerequisites + if (!sqlite3_threadsafe()) { + throw(runtime_error("Cannot run without thread safety")); + } + cout << "Thread safety confirmed" << endl; + //load config config.Load("rsc\\config.cfg"); @@ -180,15 +179,15 @@ void ServerApplication::HandleJoinRequest(NetworkPacket packet) { newClient.address = packet.meta.srcAddress; //push the new client - clientMap[Client::counter] = newClient; + clientMap[clientCounter] = newClient; //send the client their info packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; - packet.clientInfo.index = Client::counter; + packet.clientInfo.index = clientCounter; network.Send(&newClient.address, &packet, sizeof(NetworkPacket)); //finished this routine - Client::counter++; + clientCounter++; cout << "connect, total: " << clientMap.size() << endl; } @@ -227,8 +226,8 @@ void ServerApplication::HandleSynchronize(NetworkPacket packet) { newPacket.playerInfo.playerIndex = it.first; snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); - newPacket.playerInfo.position = it.second.position; - newPacket.playerInfo.motion = it.second.motion; + newPacket.playerInfo.position = {0,0}; + newPacket.playerInfo.motion = {0,0}; network.Send(&clientMap[packet.clientInfo.index].address, &newPacket, sizeof(NetworkPacket)); } } @@ -250,22 +249,20 @@ void ServerApplication::HandlePlayerNew(NetworkPacket packet) { newPlayer.clientIndex = packet.playerInfo.clientIndex; newPlayer.handle = packet.playerInfo.handle; newPlayer.avatar = packet.playerInfo.avatar; - newPlayer.position = {(rand() % config.Int("screen.w")),(rand() % config.Int("screen.h"))}; - newPlayer.motion = {0,0}; //push this player - playerMap[Player::counter] = newPlayer; + playerMap[playerCounter] = newPlayer; //send the client their info - packet.playerInfo.playerIndex = Player::counter; - packet.playerInfo.position = newPlayer.position; - packet.playerInfo.motion = newPlayer.motion; + packet.playerInfo.playerIndex = playerCounter; + packet.playerInfo.position = {0,0}; + packet.playerInfo.motion = {0,0}; //actually send to everyone PumpPacket(packet); //finish this routine - Player::counter++; + playerCounter++; } void ServerApplication::HandlePlayerDelete(NetworkPacket packet) { @@ -297,8 +294,8 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { } //server is the slave to the clients, but only for now - playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position; - playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion; +// playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position; +// playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion; PumpPacket(packet); } diff --git a/server/server_application.hpp b/server/server_application.hpp index 1aaad4f..a8318fe 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -34,26 +34,15 @@ #include "config_utility.hpp" #include "vector2.hpp" +#include "client.hpp" +#include "player.hpp" + +#include "world_room.hpp" + //STL #include #include -//hold the client info -struct Client { - static int counter; - IPaddress address; -}; - -//hold the player info -struct Player { - static int counter; - int clientIndex; - std::string handle; - std::string avatar; - Vector2 position; - Vector2 motion; -}; - //The main application class class ServerApplication { public: @@ -90,8 +79,14 @@ private: bool running = true; ConfigUtility config; - std::map clientMap; - std::map playerMap; + //global lists + ClientMap clientMap; + PlayerMap playerMap; + WorldRoomMap worldRoomMap; + + int clientCounter = 0; + int playerCounter = 0; + int worldRoomCounter = 0; }; #endif diff --git a/server/thread_safe_queue.hpp b/server/thread_safe_queue.hpp new file mode 100644 index 0000000..37555ae --- /dev/null +++ b/server/thread_safe_queue.hpp @@ -0,0 +1,92 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef THREADSAFEQUEUE_HPP_ +#define THREADSAFEQUEUE_HPP_ + +#include "SDL/SDL_thread.h" + +#include +#include + +/* This container is a thread safe reimplementation of std::queue. +*/ + +template> +class ThreadSafeQueue { +public: + ThreadSafeQueue() { + lock = SDL_CreateSemaphore(1); + if (!lock) { + throw(std::runtime_error("Failed to create ThreadSafeQueue::lock")); + } + } + + ~ThreadSafeQueue() { + SDL_SemWait(lock); + container.clear(); + SDL_SemPost(lock); + SDL_DestroySemaphore(lock); + } + + T PushBack(T t) { + SDL_SemWait(lock); + container.push_back(t); + SDL_SemPost(lock); + return t; + } + + T PeekFront() { + T t; + SDL_SemWait(lock); + if (container.size() > 0) { + t = container[0]; + } + SDL_SemPost(lock); + return t; + } + + T PopFront() { + T t; + SDL_SemWait(lock); + if (container.size() > 0) { + t = container[0]; + container.pop_front(); + } + SDL_SemPost(lock); + return t; + } + + int Size() { + //can't be sure if std::deque::size() is thread safe + int ret; + SDL_SemWait(lock); + ret = container.size(); + SDL_SemPost(lock); + return ret; + } + +private: + Container container; + SDL_sem* lock; +}; + +#endif diff --git a/server/world_room.cpp b/server/world_room.cpp new file mode 100644 index 0000000..fd034d7 --- /dev/null +++ b/server/world_room.cpp @@ -0,0 +1,91 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "world_room.hpp" + +#include +#include + +using namespace std; + +int worldRoomThread(void* arg) { + WorldRoom* room = reinterpret_cast(arg); + try { + room->Init(); + room->Loop(); + room->Quit(); + } + catch(exception& e) { + cerr << "Fatal room error: " << e.what() << endl; + return 1; + } + return 0; +} + +WorldRoom::WorldRoom(PlayerMap const& arg1): + playerMap(arg1) +{ + // +} + +WorldRoom::~WorldRoom() { + // +} + +void WorldRoom::OpenRoom() { + if (running) { + throw(std::runtime_error("Cannot open a room that is already running")); + } + + running = true; + thread = SDL_CreateThread(worldRoomThread, this); +} + +void WorldRoom::CloseRoom() { + running = false; + SDL_WaitThread(thread, nullptr); +} + +void WorldRoom::KillRoom() { + running = false; + SDL_KillThread(thread); +} + +void WorldRoom::Init() { + // +} + +void WorldRoom::Loop() { + while(running) { + while(networkInQueue.Size() > 0) { + HandlePacket(networkInQueue.PopFront()); + } + SDL_Delay(10); + } +} + +void WorldRoom::Quit() { + // +} + +void WorldRoom::HandlePacket(NetworkPacket packet) { + cout << "packet received" << endl; +} diff --git a/server/world_room.hpp b/server/world_room.hpp new file mode 100644 index 0000000..dfea084 --- /dev/null +++ b/server/world_room.hpp @@ -0,0 +1,65 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef WORLDROOM_HPP_ +#define WORLDROOM_HPP_ + +#include "network_packet.hpp" +#include "thread_safe_queue.hpp" +#include "player.hpp" + +#include "SDL/SDL_thread.h" + +#include + +class WorldRoom { +public: + WorldRoom(PlayerMap const&); + ~WorldRoom(); + + void OpenRoom(); + void CloseRoom(); + void KillRoom(); + + ThreadSafeQueue* GetInQueue() { return &networkInQueue; }; + ThreadSafeQueue* GetOutQueue() { return &networkOutQueue; }; +private: + + friend int worldRoomThread(void* arg); + + void Init(); + void Loop(); + void Quit(); + + void HandlePacket(NetworkPacket); + + SDL_Thread* thread = nullptr; + bool running = false; + + ThreadSafeQueue networkInQueue; + ThreadSafeQueue networkOutQueue; + + PlayerMap playerMap; +}; + +typedef std::map WorldRoomMap; + +#endif