diff --git a/server/character_manager.cpp b/server/character_manager.cpp index 5767e60..0a1d4d7 100644 --- a/server/character_manager.cpp +++ b/server/character_manager.cpp @@ -68,7 +68,6 @@ CharacterManager::~CharacterManager() { } } -//TODO: should statistics be stored separately? //TODO: default stats as a parameter? This would be good for differing beggining states or multiple classes int CharacterManager::CreateCharacter(int owner, std::string handle, std::string avatar) { //Create the character, failing if it exists diff --git a/server/server_application.cpp b/server/server_application.cpp index f4dd348..44467a0 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -195,7 +195,7 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) { HandleCharacterDelete(dynamic_cast(argPacket)); break; case SerialPacketType::CHARACTER_UPDATE: - case SerialPacketType::CHARACTER_STATS_REQUEST: //TODO: ? + case SerialPacketType::CHARACTER_STATS_REQUEST: HandleCharacterUpdate(dynamic_cast(argPacket)); break; @@ -328,11 +328,52 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { //------------------------- void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { - //TODO: fill this + int characterIndex = characterMgr.CreateCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar); + + if (characterIndex == -1) { + //TODO: rejection packet + std::cerr << "Warning: Character already loaded" << std::endl; + return; + } + + if (characterIndex == -2) { + //TODO: rejection packet + std::cerr << "Warning: Character already exists" << std::endl; + return; + } + + //send this new character to all clients + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_NEW; + CopyCharacterToPacket(&newPacket, characterIndex); + PumpPacket(&newPacket); } void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) { - //TODO: fill this + //NOTE: Disconnecting only unloads a character, this explicitly deletes it + + //Authenticate the owner is doing this + int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar); + + //if this is not your character + if (characterIndex == -2) { + //TODO: rejection packet + std::cerr << "Warning: Character cannot be deleted" << std::endl; + + //unload an unneeded character + if (characterIndex != -1) { + characterMgr.UnloadCharacter(characterIndex); + } + return; + } + + //delete it + characterMgr.DeleteCharacter(characterIndex); + + //TODO: success packet + + //Unload this character from all clients + PumpCharacterUnload(characterIndex); } void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) { @@ -381,27 +422,22 @@ void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) { //TODO: compensate for large distances - //TODO: I quite dislike this function + //NOTE: I quite dislike this function - //send all the server's data to this client - CharacterPacket characterPacket; + //send all of the server's data to this client + ClientData& client = clientMap[argPacket->clientIndex]; + + //send all characters + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_UPDATE; - //characters - characterPacket.type = SerialPacketType::CHARACTER_UPDATE; for (auto& it : *characterMgr.GetContainer()) { - //TODO: update this for the expanded CharacterData structure - characterPacket.characterIndex = it.first; - snprintf(characterPacket.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); - snprintf(characterPacket.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); - characterPacket.roomIndex = it.second.roomIndex; - characterPacket.origin = it.second.origin; - characterPacket.motion = it.second.motion; - characterPacket.stats = it.second.stats; - - network.SendTo(&clientMap[argPacket->clientIndex].address, dynamic_cast(&characterPacket)); + newPacket.characterIndex = it.first; + CopyCharacterToPacket(&newPacket, it.first); + network.SendTo(&client.address, dynamic_cast(&newPacket)); } - //TODO: more + //TODO: more in HandleSynchronize() } //------------------------- @@ -423,3 +459,20 @@ void ServerApplication::PumpCharacterUnload(int uid) { newPacket.characterIndex = uid; PumpPacket(dynamic_cast(&newPacket)); } + +void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) { + CharacterData* character = characterMgr.GetCharacter(characterIndex); + if (!character) { + throw(std::runtime_error("Failed to copy a character to a packet")); + } + + //TODO: keep this up to date when the character changes + packet->characterIndex = characterIndex; + snprintf(packet->handle, PACKET_STRING_SIZE, "%s", character->handle.c_str()); + snprintf(packet->avatar, PACKET_STRING_SIZE, "%s", character->avatar.c_str()); + packet->accountIndex = character->owner; + packet->roomIndex = character->roomIndex; + packet->origin = character->origin; + packet->motion = character->motion; + packet->stats = character->stats; +} \ No newline at end of file diff --git a/server/server_application.hpp b/server/server_application.hpp index 05168df..ca2129b 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -85,6 +85,7 @@ private: //TODO: a function that only sends to characters in a certain proximity void PumpPacket(SerialPacket* const); void PumpCharacterUnload(int uid); + void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex); //APIs and utilities sqlite3* database = nullptr; diff --git a/todo.txt b/todo.txt index fa7d60d..605e60a 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,11 @@ -TODO: Modulate this god class -TODO: Segment SerialPacket? -TODO: Not all structures in common/gameplay are needed by the client +TODO: MapLoader, in place of FileFormat +TODO: Get the rooms working +TODO: update the map API to handle multiple rooms + +TODO: Rejection packets +TODO: Authentication +TODO: server is slaved to the client + TODO: I need to keep the documentation up to date. Namely, the GDD is getting out of date. TODO: I completely forgot about status ailments TODO: Time delay for requesting region packets