diff --git a/common/network/network_packet.hpp b/common/network/network_packet.hpp index 27c5bee..a031f00 100644 --- a/common/network/network_packet.hpp +++ b/common/network/network_packet.hpp @@ -94,6 +94,9 @@ union NetworkPacket { Vector2 motion; }playerInfo; + //map data + //... + //defaults NetworkPacket() { meta.type = Type::NONE; diff --git a/rsc/scripts/setup_room.lua b/rsc/scripts/setup_room.lua deleted file mode 100644 index e69de29..0000000 diff --git a/rsc/scripts/setup_server.lua b/rsc/scripts/setup_server.lua index e69de29..a2cf14a 100644 --- a/rsc/scripts/setup_server.lua +++ b/rsc/scripts/setup_server.lua @@ -0,0 +1 @@ +print("Lua script check OK") \ No newline at end of file diff --git a/server/client_manager.cpp b/server/client_manager.cpp new file mode 100644 index 0000000..a4d9800 --- /dev/null +++ b/server/client_manager.cpp @@ -0,0 +1,64 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * 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 "client_manager.hpp" + +int ClientManager::HandleConnection(IPaddress add) { + ClientEntry c; + c.address = add; + clientMap[counter] = c; + return counter++; +} + +int ClientManager::HandleDisconnection(int i) { + for (auto& it : clientMap) { + if (it.first == i) { + clientMap.erase(it.first); + return 0; + } + } + return -1; +} + +void ClientManager::ForEach(Lambda fn) { + for(Iterator it = clientMap.begin(); it != clientMap.end(); it++) { + fn(it); + } +} + +ClientEntry* ClientManager::GetClient(int i) { + for (auto& it : clientMap) { + if (it.first == i) { + return &it.second; + } + } + return nullptr; +} + +ClientEntry* ClientManager::GetClient(IPaddress add) { + for (auto& it : clientMap) { + if (it.second.address.host == add.host && + it.second.address.port == add.port) { + return &it.second; + } + } + return nullptr; +} diff --git a/server/client.hpp b/server/client_manager.hpp similarity index 60% rename from server/client.hpp rename to server/client_manager.hpp index c2d2194..946c946 100644 --- a/server/client.hpp +++ b/server/client_manager.hpp @@ -1,4 +1,4 @@ -/* Copyright: (c) Kayne Ruse 2013 +/* Copyright: (c) Kayne Ruse 2014 * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -19,20 +19,39 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef CLIENT_HPP_ -#define CLIENT_HPP_ +#ifndef CLIENTMANAGER_HPP_ +#define CLIENTMANAGER_HPP_ #include "SDL/SDL_net.h" +#include #include -/* Hold the client info. -*/ - -struct Client { +struct ClientEntry { IPaddress address; }; -typedef std::map ClientMap; +class ClientManager { +public: + //clarity typedefs + typedef std::map Container; + typedef Container::iterator Iterator; + typedef std::function Lambda; + + //returns the internal index + int HandleConnection(IPaddress); + int HandleDisconnection(int i); + + //lambdas + void ForEach(Lambda); + + //accessors + ClientEntry* GetClient(int i); + ClientEntry* GetClient(IPaddress); + int Size() { return clientMap.size(); } +private: + Container clientMap; + int counter = 0; +}; #endif diff --git a/server/player.hpp b/server/player_manager.cpp similarity index 53% rename from server/player.hpp rename to server/player_manager.cpp index e709ba4..d5bfebe 100644 --- a/server/player.hpp +++ b/server/player_manager.cpp @@ -1,4 +1,4 @@ -/* Copyright: (c) Kayne Ruse 2013 +/* Copyright: (c) Kayne Ruse 2014 * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -19,25 +19,41 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef PLAYER_HPP_ -#define PLAYER_HPP_ +#include "player_manager.hpp" -#include "vector2.hpp" +int PlayerManager::HandlePlayerCreation(std::string name, std::string avatar) { + // +} -#include -#include +int PlayerManager::HandlePlayerDeletion(int uniqueID) { + // +} -/* Hold the player info. -*/ +int PlayerManager::HandlePlayerLoad(int uniqueID, int clientIndex) { + // +} -struct Player { - int clientIndex; - std::string handle; - std::string avatar; - Vector2 position; - Vector2 motion; -}; +int PlayerManager::HandlePlayerUnload(int uniqueID) { + // +} -typedef std::map PlayerMap; +void PlayerManager::ForEach(Lambda fn) { + for(Iterator it = playerMap.begin(); it != playerMap.end(); it++) { + fn(it); + } +} -#endif +PlayerEntry* PlayerManager::GetPlayer(int uniqueID) { + for (auto& it : playerMap) { + if (it.first == uniqueID) { + return &it.second; + } + } + return nullptr; +} + +void PlayerManager::Update(double delta) { + for (auto& it : playerMap) { + it.second.position += it.second.motion * delta; + } +} diff --git a/server/player_manager.hpp b/server/player_manager.hpp new file mode 100644 index 0000000..d4051bd --- /dev/null +++ b/server/player_manager.hpp @@ -0,0 +1,71 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * 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 PLAYERMANAGER_HPP_ +#define PLAYERMANAGER_HPP_ + +#include "vector2.hpp" + +#include "sqlite3/sqlite3.h" + +#include +#include +#include + +struct PlayerEntry { + int clientIndex; + int mapIndex; + Vector2 position; + Vector2 motion; +}; + +class PlayerManager { +public: + //clarity typedefs + typedef std::map Container; + typedef Container::iterator Iterator; + typedef std::function Lambda; + + //These functions interact with the database + //*Deletion, *Load and *Unload returns: 0 success, -1 failure + //*Creation returns the uniqueID, but doesn't load + // that object; call *Load directly afterward + int HandlePlayerCreation (std::string name, std::string avatar); + int HandlePlayerDeletion (int uniqueID); + int HandlePlayerLoad (int uniqueID, int clientIndex); + int HandlePlayerUnload (int uniqueID); + + //lambdas + void ForEach(Lambda); + + //accessors + PlayerEntry* GetPlayer(int uniqueID); + sqlite3* SetDatabase(sqlite3* db) { return database = db; } + sqlite3* GetDatabase() { return database; } + + //update each player's position + void Update(double delta); +private: + Container playerMap; + sqlite3* database = nullptr; +}; + +#endif diff --git a/server/server_application.cpp b/server/server_application.cpp index 9136327..b7d7a00 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -30,20 +30,28 @@ using namespace std; -//------------------------- -//Define the ServerApplication -//------------------------- - -ServerApplication::ServerApplication() { - // +int runSQLScript(sqlite3* db, std::string fname) { + ifstream is(fname); + if (!is.is_open()) { + return -1; + } + string script; + getline(is, script, '\0'); + is.close(); + //TODO: flesh out this error if needed + if (sqlite3_exec(db, script.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) { + return -2; + } + return 0; } -ServerApplication::~ServerApplication() { - // -} +//------------------------- +//Define the public members +//------------------------- void ServerApplication::Init(int argc, char** argv) { - //TODO: proper command line option parsing + cout << "Beginning startup" << endl; + int ret = 0; //load config config.Load("rsc\\config.cfg"); @@ -52,101 +60,110 @@ void ServerApplication::Init(int argc, char** argv) { if (SDL_Init(0)) { throw(runtime_error("Failed to initialize SDL")); } - cout << "initialized SDL" << endl; + cout << "Initialized SDL" << endl; //Init SDL_net if (SDLNet_Init()) { - throw(runtime_error("Failed to init SDL_net")); + throw(runtime_error("Failed to initialize SDL_net")); } network.Open(config.Int("server.port"), sizeof(NetworkPacket)); - cout << "initialized SDL_net" << endl; + cout << "Initialized SDL_net" << endl; //Init SQL - string dbname = (config["server.dbname"].size()) ? config["server.dbname"] : std::string(argv[0]) + ".db"; //fancy and unnecessary - int ret = sqlite3_open_v2(dbname.c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, nullptr); + ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr); if (ret != SQLITE_OK || !database) { - throw(runtime_error("Failed to open the server database")); + throw(runtime_error(string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) )); } - cout << "initialized SQL" << endl; - cout << "Database filename: " << dbname << endl; + playerMgr.SetDatabase(database); + cout << "Initialized SQL" << endl; - //TODO: move this into a function? - //Run setup scripts - ifstream is("rsc\\scripts\\setup_server.sql"); - if (!is.is_open()) { - throw(runtime_error("Failed to run database setup script")); + //setup the database + if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) { + throw(runtime_error("Failed to initialize SQL's setup script")); } - string script; - getline(is, script, '\0'); - is.close(); - sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr); + cout << "Initialized SQL's setup script" << endl; + + //lua + luaState = luaL_newstate(); + if (!luaState) { + throw(runtime_error("Failed to initialize lua")); + } + luaL_openlibs(luaState); + cout << "Initialized lua" << endl; + + //run the startup script + if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) { + throw(runtime_error(string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) )); + } + cout << "Initialized lua's setup script" << endl; + + //finalize the startup + cout << "Startup completed successfully" << endl; } void ServerApplication::Loop() { NetworkPacket packet; - while(running) { //suck in the waiting packets & process them - try { - while(network.Receive()) { - deserialize(&packet, network.GetInData()); - packet.meta.srcAddress = network.GetInPacket()->address; - HandlePacket(packet); - } + while(network.Receive()) { + //get the packet + deserialize(&packet, network.GetInData()); + //cache the source address + packet.meta.srcAddress = network.GetInPacket()->address; + //we need to go deeper + HandlePacket(packet); } - catch(exception& e) { - cerr << "Network Error: " << e.what() << endl; - } - //give the computer a break SDL_Delay(10); } } void ServerApplication::Quit() { - //members - network.Close(); + cout << "Shutting down" << endl; + //empty the members + //TODO: player manager + //TODO: client manager //APIs + lua_close(luaState); + playerMgr.SetDatabase(nullptr); sqlite3_close_v2(database); + network.Close(); SDLNet_Quit(); SDL_Quit(); + cout << "Shutdown finished" << endl; } +//------------------------- +//Define the uber switch +//------------------------- + void ServerApplication::HandlePacket(NetworkPacket packet) { switch(packet.meta.type) { case NetworkPacket::Type::BROADCAST_REQUEST: HandleBroadcastRequest(packet); break; - case NetworkPacket::Type::JOIN_REQUEST: HandleJoinRequest(packet); break; - case NetworkPacket::Type::DISCONNECT: HandleDisconnect(packet); break; - case NetworkPacket::Type::SYNCHRONIZE: - HandleSynchronize(packet); +// HandleSynchronize(packet); break; - case NetworkPacket::Type::SHUTDOWN: HandleShutdown(packet); break; - case NetworkPacket::Type::PLAYER_NEW: - HandlePlayerNew(packet); +// HandlePlayerNew(packet); break; - case NetworkPacket::Type::PLAYER_DELETE: - HandlePlayerDelete(packet); +// HandlePlayerDelete(packet); break; - case NetworkPacket::Type::PLAYER_UPDATE: - HandlePlayerUpdate(packet); +// HandlePlayerUpdate(packet); break; - //handle errors default: throw(runtime_error("Unknown NetworkPacket::Type encountered")); @@ -154,45 +171,45 @@ void ServerApplication::HandlePacket(NetworkPacket packet) { } } +//------------------------- +//Handle various network input +//------------------------- + void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) { - //send back the server's name + //send back the server's metadata packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE; + //TODO: version info snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str()); + //TODO: player count char buffer[sizeof(NetworkPacket)]; serialize(&packet, buffer); network.Send(&packet.meta.srcAddress, buffer, sizeof(NetworkPacket)); } void ServerApplication::HandleJoinRequest(NetworkPacket packet) { - //TODO: prevent duplicate logins from the same address? - - //create the new client, filling it with the correct info - Client newClient; - newClient.address = packet.meta.srcAddress; - - //push the new client - clientMap[clientCounter] = newClient; + //register the new client + int index = clientMgr.HandleConnection(packet.meta.srcAddress); //send the client their info packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; - packet.clientInfo.index = clientCounter; + packet.clientInfo.index = index; + char buffer[sizeof(NetworkPacket)]; serialize(&packet, buffer); - network.Send(&newClient.address, buffer, sizeof(NetworkPacket)); + network.Send(&clientMgr.GetClient(index)->address, buffer, sizeof(NetworkPacket)); //finished this routine - clientCounter++; - cout << "connect, total: " << clientMap.size() << endl; + cout << "connect, total: " << clientMgr.Size() << endl; } void ServerApplication::HandleDisconnect(NetworkPacket packet) { //disconnect the specified client char buffer[sizeof(NetworkPacket)]; serialize(&packet, buffer); - network.Send(&clientMap[packet.clientInfo.index].address, buffer, sizeof(NetworkPacket)); - clientMap.erase(packet.clientInfo.index); + network.Send(&clientMgr.GetClient(packet.clientInfo.index)->address, buffer, sizeof(NetworkPacket)); + clientMgr.HandleDisconnection(packet.clientInfo.index); - //delete players +/* //delete players erase_if(playerMap, [&](pair it) -> bool { if (it.second.clientIndex == packet.clientInfo.index) { NetworkPacket delPacket; @@ -208,10 +225,12 @@ void ServerApplication::HandleDisconnect(NetworkPacket packet) { } return false; }); +*/ - cout << "disconnect, total: " << clientMap.size() << endl; + //finished this routine + cout << "disconnect, total: " << clientMgr.Size() << endl; } - +/* void ServerApplication::HandleSynchronize(NetworkPacket packet) { //send all the server's data to this client NetworkPacket newPacket; @@ -229,18 +248,21 @@ void ServerApplication::HandleSynchronize(NetworkPacket packet) { network.Send(&clientMap[packet.clientInfo.index].address, buffer, sizeof(NetworkPacket)); } } - +*/ void ServerApplication::HandleShutdown(NetworkPacket packet) { //end the server running = false; //disconnect all clients packet.meta.type = NetworkPacket::Type::DISCONNECT; - PumpPacket(packet); + clientMgr.ForEach([&](ClientManager::Iterator it) -> void { + this->network.Send(&it->second.address, &packet, sizeof(NetworkPacket)); + }); + //finished this routine cout << "shutting down" << endl; } - +/* void ServerApplication::HandlePlayerNew(NetworkPacket packet) { //create the new player object Player newPlayer; @@ -299,12 +321,4 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { PumpPacket(packet); } - -void ServerApplication::PumpPacket(NetworkPacket packet) { - //send this packet to all clients - char buffer[sizeof(NetworkPacket)]; - serialize(&packet, buffer); - for (auto& it : clientMap) { - network.Send(&it.second.address, buffer, sizeof(NetworkPacket)); - } -} \ No newline at end of file +*/ diff --git a/server/server_application.hpp b/server/server_application.hpp index a339c77..2733623 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -28,16 +28,18 @@ #include "serial.hpp" //APIs +#include "lua/lua.hpp" #include "sqlite3/sqlite3.h" #include "SDL/SDL.h" //misc +#include "client_manager.hpp" +#include "player_manager.hpp" + +//common #include "config_utility.hpp" #include "vector2.hpp" -#include "client.hpp" -#include "player.hpp" - //STL #include #include @@ -46,8 +48,8 @@ class ServerApplication { public: //standard functions - ServerApplication(); - ~ServerApplication(); + ServerApplication() = default; + ~ServerApplication() = default; void Init(int argc, char** argv); void Loop(); @@ -60,13 +62,11 @@ private: void HandleBroadcastRequest(NetworkPacket); void HandleJoinRequest(NetworkPacket); void HandleDisconnect(NetworkPacket); - void HandleSynchronize(NetworkPacket); +// void HandleSynchronize(NetworkPacket); void HandleShutdown(NetworkPacket); - void HandlePlayerNew(NetworkPacket); - void HandlePlayerDelete(NetworkPacket); - void HandlePlayerUpdate(NetworkPacket); - - void PumpPacket(NetworkPacket); +// void HandlePlayerNew(NetworkPacket); +// void HandlePlayerDelete(NetworkPacket); +// void HandlePlayerUpdate(NetworkPacket); //networking UDPNetworkUtility network; @@ -74,16 +74,15 @@ private: //database sqlite3* database = nullptr; + //lua + lua_State* luaState = nullptr; + //misc bool running = true; ConfigUtility config; - //global lists - ClientMap clientMap; - PlayerMap playerMap; - - int clientCounter = 0; - int playerCounter = 0; + ClientManager clientMgr; + PlayerManager playerMgr; }; #endif