Started working on multithreaded rooms

This commit is contained in:
Kayne Ruse
2013-12-08 15:55:49 +11:00
parent a448c8fb68
commit be26c9d103
7 changed files with 356 additions and 39 deletions
+38
View File
@@ -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 <map>
/* Hold the client info.
*/
struct Client {
IPaddress address;
};
typedef std::map<int, Client> ClientMap;
#endif
+39
View File
@@ -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 <string>
#include <map>
/* Hold the player info.
*/
struct Player {
int clientIndex;
std::string handle;
std::string avatar;
};
typedef std::map<int, Player> PlayerMap;
#endif
+18 -21
View File
@@ -32,13 +32,6 @@
using namespace std; using namespace std;
//-------------------------
//Declarations
//-------------------------
int Client::counter = 0;
int Player::counter = 0;
//------------------------- //-------------------------
//Define the ServerApplication //Define the ServerApplication
//------------------------- //-------------------------
@@ -54,6 +47,12 @@ ServerApplication::~ServerApplication() {
void ServerApplication::Init(int argc, char** argv) { void ServerApplication::Init(int argc, char** argv) {
//TODO: proper command line option parsing //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 //load config
config.Load("rsc\\config.cfg"); config.Load("rsc\\config.cfg");
@@ -180,15 +179,15 @@ void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
newClient.address = packet.meta.srcAddress; newClient.address = packet.meta.srcAddress;
//push the new client //push the new client
clientMap[Client::counter] = newClient; clientMap[clientCounter] = newClient;
//send the client their info //send the client their info
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = Client::counter; packet.clientInfo.index = clientCounter;
network.Send(&newClient.address, &packet, sizeof(NetworkPacket)); network.Send(&newClient.address, &packet, sizeof(NetworkPacket));
//finished this routine //finished this routine
Client::counter++; clientCounter++;
cout << "connect, total: " << clientMap.size() << endl; cout << "connect, total: " << clientMap.size() << endl;
} }
@@ -227,8 +226,8 @@ void ServerApplication::HandleSynchronize(NetworkPacket packet) {
newPacket.playerInfo.playerIndex = it.first; newPacket.playerInfo.playerIndex = it.first;
snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); 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()); snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
newPacket.playerInfo.position = it.second.position; newPacket.playerInfo.position = {0,0};
newPacket.playerInfo.motion = it.second.motion; newPacket.playerInfo.motion = {0,0};
network.Send(&clientMap[packet.clientInfo.index].address, &newPacket, sizeof(NetworkPacket)); 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.clientIndex = packet.playerInfo.clientIndex;
newPlayer.handle = packet.playerInfo.handle; newPlayer.handle = packet.playerInfo.handle;
newPlayer.avatar = packet.playerInfo.avatar; newPlayer.avatar = packet.playerInfo.avatar;
newPlayer.position = {(rand() % config.Int("screen.w")),(rand() % config.Int("screen.h"))};
newPlayer.motion = {0,0};
//push this player //push this player
playerMap[Player::counter] = newPlayer; playerMap[playerCounter] = newPlayer;
//send the client their info //send the client their info
packet.playerInfo.playerIndex = Player::counter; packet.playerInfo.playerIndex = playerCounter;
packet.playerInfo.position = newPlayer.position; packet.playerInfo.position = {0,0};
packet.playerInfo.motion = newPlayer.motion; packet.playerInfo.motion = {0,0};
//actually send to everyone //actually send to everyone
PumpPacket(packet); PumpPacket(packet);
//finish this routine //finish this routine
Player::counter++; playerCounter++;
} }
void ServerApplication::HandlePlayerDelete(NetworkPacket packet) { 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 //server is the slave to the clients, but only for now
playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position; // playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position;
playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion; // playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion;
PumpPacket(packet); PumpPacket(packet);
} }
+13 -18
View File
@@ -34,26 +34,15 @@
#include "config_utility.hpp" #include "config_utility.hpp"
#include "vector2.hpp" #include "vector2.hpp"
#include "client.hpp"
#include "player.hpp"
#include "world_room.hpp"
//STL //STL
#include <map> #include <map>
#include <string> #include <string>
//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 //The main application class
class ServerApplication { class ServerApplication {
public: public:
@@ -90,8 +79,14 @@ private:
bool running = true; bool running = true;
ConfigUtility config; ConfigUtility config;
std::map<int, Client> clientMap; //global lists
std::map<int, Player> playerMap; ClientMap clientMap;
PlayerMap playerMap;
WorldRoomMap worldRoomMap;
int clientCounter = 0;
int playerCounter = 0;
int worldRoomCounter = 0;
}; };
#endif #endif
+92
View File
@@ -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 <deque>
#include <stdexcept>
/* This container is a thread safe reimplementation of std::queue.
*/
template<typename T, class Container = std::deque<T>>
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
+91
View File
@@ -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 <iostream>
#include <stdexcept>
using namespace std;
int worldRoomThread(void* arg) {
WorldRoom* room = reinterpret_cast<WorldRoom*>(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;
}
+65
View File
@@ -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 <map>
class WorldRoom {
public:
WorldRoom(PlayerMap const&);
~WorldRoom();
void OpenRoom();
void CloseRoom();
void KillRoom();
ThreadSafeQueue<NetworkPacket>* GetInQueue() { return &networkInQueue; };
ThreadSafeQueue<NetworkPacket>* 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<NetworkPacket> networkInQueue;
ThreadSafeQueue<NetworkPacket> networkOutQueue;
PlayerMap playerMap;
};
typedef std::map<int, WorldRoom> WorldRoomMap;
#endif