diff --git a/common/bbox.hpp b/common/bbox.hpp index ca08e3e..5b29944 100644 --- a/common/bbox.hpp +++ b/common/bbox.hpp @@ -26,6 +26,7 @@ #include #include +//TODO: This is supposed to interact with the vector class BBox { public: double x, y; diff --git a/common/network/network_packet.hpp b/common/network/network_packet.hpp index f9b4894..4933591 100644 --- a/common/network/network_packet.hpp +++ b/common/network/network_packet.hpp @@ -31,6 +31,7 @@ #pragma pack(push, 0) +//TODO: update the code here to match the entity code union NetworkPacket { //types of packets enum class Type { diff --git a/server/client.cpp b/server/client.cpp index 9ca11b4..7321482 100644 --- a/server/client.cpp +++ b/server/client.cpp @@ -26,4 +26,4 @@ //This is explicitly a POD static_assert(std::is_pod::value, "Client is not a POD"); -unsigned int Client::uidCounter; \ No newline at end of file +unsigned int Client::uidCounter; diff --git a/server/client.hpp b/server/client.hpp index 658030c..cf4105e 100644 --- a/server/client.hpp +++ b/server/client.hpp @@ -26,7 +26,6 @@ struct Client { IPaddress address; - unsigned int uid; static unsigned int uidCounter; }; diff --git a/server/entity.cpp b/server/entity.cpp index abb22ed..bfc6061 100644 --- a/server/entity.cpp +++ b/server/entity.cpp @@ -26,4 +26,4 @@ //This is explicitly a POD static_assert(std::is_pod::value, "Entity is not a POD"); -unsigned int Entity::uidCounter; \ No newline at end of file +unsigned int Entity::uidCounter; diff --git a/server/entity.hpp b/server/entity.hpp index e7308df..59296ba 100644 --- a/server/entity.hpp +++ b/server/entity.hpp @@ -40,7 +40,7 @@ struct Entity { Vector2 position; Vector2 motion; BBox bbox; - unsigned int uid; + unsigned int externalID; static unsigned int uidCounter; }; diff --git a/server/player_entity.cpp b/server/player_entity.cpp new file mode 100644 index 0000000..ccc49b3 --- /dev/null +++ b/server/player_entity.cpp @@ -0,0 +1,24 @@ +/* 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 "player_entity.hpp" + +unsigned int PlayerEntity::uidCounter; diff --git a/server/player_entity.hpp b/server/player_entity.hpp index 675f66f..2a5a6e6 100644 --- a/server/player_entity.hpp +++ b/server/player_entity.hpp @@ -25,9 +25,12 @@ #include struct PlayerEntity { + //metadata int clientIndex; std::string handle; std::string avatar; + + //statistics int level; int exp; int maxHP; @@ -41,6 +44,9 @@ struct PlayerEntity { float accuracy; float evasion; float luck; + + //uid + static unsigned int uidCounter; }; #endif diff --git a/server/server_application.cpp b/server/server_application.cpp index a794c3e..f90fffe 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -51,11 +51,11 @@ int runSQLScript(sqlite3* db, std::string fname) { void ServerApplication::Init(int argc, char** argv) { cout << "Beginning startup" << endl; - int ret = 0; //initial setup Client::uidCounter = 0; Entity::uidCounter = 0; + PlayerEntity::uidCounter = 0; config.Load("rsc\\config.cfg"); //Init SDL @@ -72,7 +72,7 @@ void ServerApplication::Init(int argc, char** argv) { cout << "Initialized SDL_net" << endl; //Init SQL - ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr); + int 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(string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) )); } @@ -99,13 +99,13 @@ void ServerApplication::Init(int argc, char** argv) { cout << "Initialized lua's setup script" << endl; //setup the map object - mapPager.SetRegionWidth(REGION_WIDTH); - mapPager.SetRegionHeight(REGION_HEIGHT); - mapPager.SetRegionDepth(REGION_DEPTH); - mapPager.GetGenerator()->SetLuaState(luaState); - mapPager.GetFormat()->SetLuaState(luaState); + regionPager.SetRegionWidth(REGION_WIDTH); + regionPager.SetRegionHeight(REGION_HEIGHT); + regionPager.SetRegionDepth(REGION_DEPTH); + regionPager.GetGenerator()->SetLuaState(luaState); + regionPager.GetFormat()->SetLuaState(luaState); //TODO: config parameter - mapPager.GetFormat()->SetSaveDir("save/mapname/"); + regionPager.GetFormat()->SetSaveDir("save/mapname/"); //TODO: pass args to the generator & format as needed //NOTE: I might need to rearrange the init process so that lua & SQL can interact // with the map system as needed. @@ -133,6 +133,7 @@ void ServerApplication::Loop() { HandlePacket(packet); } //give the computer a break + //TODO: remove this? SDL_Delay(10); } } @@ -140,9 +141,7 @@ void ServerApplication::Loop() { void ServerApplication::Quit() { cout << "Shutting down" << endl; //empty the members - mapPager.UnloadAll(); - //TODO: player manager - //TODO: client manager + regionPager.UnloadAll(); //APIs lua_close(luaState); @@ -210,44 +209,54 @@ void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) { void ServerApplication::HandleJoinRequest(NetworkPacket packet) { //register the new client - Client c; - c.address = packet.meta.srcAddress; - clientMap[Client::uidCounter] = c; + clientMap[Client::uidCounter] = {packet.meta.srcAddress}; - //send the client their info + //send the client their index char buffer[PACKET_BUFFER_SIZE]; - packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; packet.clientInfo.index = Client::uidCounter; serialize(&packet, buffer); - network.Send(&clientMap[Client::uidCounter].address, buffer, PACKET_BUFFER_SIZE); + //bounce this packet + network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE); - //finished this routine+ + //finished this routine Client::uidCounter++; cout << "Connect, total: " << clientMap.size() << endl; } void ServerApplication::HandleDisconnect(NetworkPacket packet) { - //disconnect the specified client //TODO: authenticate who is disconnecting/kicking + + //disconnect the specified client char buffer[PACKET_BUFFER_SIZE]; serialize(&packet, buffer); network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE); clientMap.erase(packet.clientInfo.index); - //delete players from all clients + //prep the delete packet NetworkPacket delPacket; delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE; - erase_if(playerMap, [&](std::pair it) -> bool { + //TODO: can this use DeletePlayer() instead? + //delete PlayerEntity, Entity, and client side players + erase_if(playerMap, [&](std::pair playerIter) -> bool { //find the internal players to delete - if (it.second.clientIndex == packet.clientInfo.index) { - delPacket.playerInfo.playerIndex = it.first; + if (playerIter.second.clientIndex == packet.clientInfo.index) { //send the delete player command to all clients + delPacket.playerInfo.playerIndex = playerIter.first; PumpPacket(delPacket); + + //erase the corresponding Entity + erase_if(entityMap, [&](std::pair entityIter) -> bool { + return entityIter.second.type == Entity::Type::PLAYER && entityIter.second.externalID == playerIter.first; + }); + + //delete this player object return true; } + + //don't delete this player object return false; }); @@ -256,19 +265,40 @@ void ServerApplication::HandleDisconnect(NetworkPacket packet) { } void ServerApplication::HandleSynchronize(NetworkPacket packet) { - //send all the server's data to this client //TODO: compensate for large distances + + //send all the server's data to this client NetworkPacket newPacket; char buffer[PACKET_BUFFER_SIZE]; - //players - newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE; - for (auto& it : playerMap) { - 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; + //TODO: map? + + //entities + for (auto& it : entityMap) { + //what are we sending? + switch(it.second.type) { + case Entity::Type::PLAYER: + //TODO: update the network code to match the entity code + newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE; + newPacket.playerInfo.playerIndex = it.first; + snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", playerMap[it.second.externalID].handle.c_str()); + snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", playerMap[it.second.externalID].avatar.c_str()); + newPacket.playerInfo.position = it.second.position; + newPacket.playerInfo.motion = it.second.motion; + break; + case Entity::Type::PORTAL: + //TODO + break; + case Entity::Type::ITEMS: + //TODO + break; + case Entity::Type::CHEST: + //TODO + break; + case Entity::Type::DOOR: + //TODO + break; + } serialize(&newPacket, buffer); network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE); } @@ -287,47 +317,70 @@ void ServerApplication::HandleShutdown(NetworkPacket packet) { } void ServerApplication::HandlePlayerNew(NetworkPacket packet) { - //create the new player object - PlayerEntry newPlayer; - newPlayer.clientIndex = packet.playerInfo.clientIndex; - newPlayer.mapIndex = 0; - newPlayer.handle = packet.playerInfo.handle; - newPlayer.avatar = packet.playerInfo.avatar; - newPlayer.position = {0,0}; - newPlayer.motion = {0,0}; + //register the new Entity + entityMap[Entity::uidCounter] = { + Entity::Type::PLAYER, + 0, + {0, 0}, + {0, 0}, + {0, 0, 0, 0}, + PlayerEntity::uidCounter + }; - //push this player - playerMap[playerCounter] = newPlayer; + //register the new PlayerEntity + playerMap[PlayerEntity::uidCounter] = { + packet.playerInfo.clientIndex, + packet.playerInfo.handle, + packet.playerInfo.avatar, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.0, + 0.0, + 0.0 + }; //send the client their info - packet.playerInfo.playerIndex = playerCounter; - packet.playerInfo.position = playerMap[playerCounter].position; - packet.playerInfo.motion = playerMap[playerCounter].motion; + packet.playerInfo.playerIndex = PlayerEntity::uidCounter; + packet.playerInfo.position = entityMap[Entity::uidCounter].position; + packet.playerInfo.motion = entityMap[Entity::uidCounter].motion; //actually send to everyone PumpPacket(packet); //finish this routine - playerCounter++; + Entity::uidCounter++; + PlayerEntity::uidCounter++; } void ServerApplication::HandlePlayerDelete(NetworkPacket packet) { - if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) { + //TODO: remove this? + if (entityMap.find(packet.playerInfo.playerIndex) == entityMap.end()) { throw(std::runtime_error("Cannot delete a non-existant player")); } - //delete players - erase_if(playerMap, [&](pair it) -> bool { - if (it.first == packet.playerInfo.playerIndex) { - NetworkPacket delPacket; - - //data to delete one specific player - delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE; - delPacket.playerInfo.playerIndex = it.first; + //prep the delete packet + NetworkPacket delPacket; + delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE; + //delete the specified Entity, PlayerEntity + erase_if(entityMap, [&](std::pair entityIter) -> bool { + //find the specified Entity + if (entityIter.first == packet.playerInfo.playerIndex) { //send to all + delPacket.playerInfo.playerIndex = entityIter.first; PumpPacket(delPacket); - + //erase matching PlayerEntity + erase_if(playerMap, [&](std::pair playerIter) -> bool { + return playerIter.first == entityIter.second.externalID; + }); return true; } return false; @@ -335,13 +388,14 @@ void ServerApplication::HandlePlayerDelete(NetworkPacket packet) { } void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { - if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) { + //TODO: Lookup the reference once, and operate on that instead of looking it up 3 times + if (entityMap.find(packet.playerInfo.playerIndex) == entityMap.end()) { throw(std::runtime_error("Cannot update a non-existant player")); } - //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; + //TODO: the server needs it's own movement system too + entityMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position; + entityMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion; PumpPacket(packet); } @@ -349,7 +403,7 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { void ServerApplication::HandleRegionRequest(NetworkPacket packet) { char buffer[PACKET_BUFFER_SIZE]; packet.meta.type = NetworkPacket::Type::REGION_CONTENT; - packet.regionInfo.region = mapPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y); + packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y); serialize(&packet, buffer); network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE); } diff --git a/server/server_application.hpp b/server/server_application.hpp index 8b81c61..4b19910 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -75,22 +75,22 @@ private: void HandlePlayerUpdate(NetworkPacket); void HandleRegionRequest(NetworkPacket); + //TODO: a function that sends to players in a certain proximity void PumpPacket(NetworkPacket); //APIs - std::map clientMap; + UDPNetworkUtility network; + sqlite3* database = nullptr; + lua_State* luaState = nullptr; + + //server tables + std::map clientMap; + std::map entityMap; + std::map playerMap; //maps - RegionPager mapPager; - - //networking - UDPNetworkUtility network; - - //database - sqlite3* database = nullptr; - - //lua - lua_State* luaState = nullptr; + //TODO: I need to handle multiple map objects + RegionPager regionPager; //misc bool running = true;