From f581c3238f992d2c25d20ca8d8d29aa1660c78fa Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 3 Sep 2014 04:36:02 +1000 Subject: [PATCH 1/8] Tweaked some TODO comments --- client/character.hpp | 2 +- client/scenes/in_world.cpp | 1 - client/scenes/in_world.hpp | 3 ++- common/network/packet_types/character_packet.cpp | 4 ++-- common/network/packet_types/character_packet.hpp | 2 +- common/utilities/config_utility.cpp | 1 - server/characters/character_manager.cpp | 4 ++-- todo.txt | 4 +++- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/client/character.hpp b/client/character.hpp index 23924a4..6be3cc6 100644 --- a/client/character.hpp +++ b/client/character.hpp @@ -75,7 +75,7 @@ private: //base statistics Statistics stats; - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... //metadata int owner; diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index d8b0d35..6e96e0d 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -366,7 +366,6 @@ void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) { localCharacter = &newCharacter; //setup the camera - //TODO: move this? camera.width = GetScreen()->w; camera.height = GetScreen()->h; diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 15fcdce..aceb189 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -113,7 +113,8 @@ protected: //UI Button disconnectButton; Button shutDownButton; - //TODO: Review the camera + + //the camera structure struct { int x = 0, y = 0; int width = 0, height = 0; diff --git a/common/network/packet_types/character_packet.cpp b/common/network/packet_types/character_packet.cpp index a66b330..7f6620c 100644 --- a/common/network/packet_types/character_packet.cpp +++ b/common/network/packet_types/character_packet.cpp @@ -46,7 +46,7 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) { //stats structure serializeStatistics(&buffer, &packet->stats); - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... } void deserializeCharacter(void* buffer, CharacterPacket* packet) { @@ -70,5 +70,5 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) { //stats structure deserializeStatistics(&buffer, &packet->stats); - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... } diff --git a/common/network/packet_types/character_packet.hpp b/common/network/packet_types/character_packet.hpp index 72a6fc4..5d94c16 100644 --- a/common/network/packet_types/character_packet.hpp +++ b/common/network/packet_types/character_packet.hpp @@ -44,7 +44,7 @@ struct CharacterPacket : SerialPacketBase { //gameplay Statistics stats; - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... }; void serializeCharacter(void* buffer, CharacterPacket* packet); diff --git a/common/utilities/config_utility.cpp b/common/utilities/config_utility.cpp index e34a2db..f761570 100644 --- a/common/utilities/config_utility.cpp +++ b/common/utilities/config_utility.cpp @@ -88,7 +88,6 @@ ConfigUtility::table_t ConfigUtility::Read(std::string fname) { is.close(); //load in any subordinate config files - //TODO: Possibility of nesting config levels? if (retTable.find("config.next") != retTable.end()) { table_t subTable = Read(retTable["config.next"]); retTable.insert(subTable.begin(), subTable.end()); diff --git a/server/characters/character_manager.cpp b/server/characters/character_manager.cpp index baabac1..3718dd6 100644 --- a/server/characters/character_manager.cpp +++ b/server/characters/character_manager.cpp @@ -157,7 +157,7 @@ int CharacterManager::LoadCharacter(int owner, std::string handle, std::string a newChar.baseStats.evasion = sqlite3_column_double(statement, 20); newChar.baseStats.luck = sqlite3_column_double(statement, 21); - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... //finish the routine sqlite3_finalize(statement); @@ -214,7 +214,7 @@ int CharacterManager::SaveCharacter(int uid) { ret |= sqlite3_bind_double(statement, 17, character.baseStats.evasion) != SQLITE_OK; ret |= sqlite3_bind_double(statement, 18, character.baseStats.luck) != SQLITE_OK; - //TODO: gameplay components: equipment, items, buffs, debuffs + //gameplay components: equipment, items, buffs, debuffs... //check for binding errors if (ret) { diff --git a/todo.txt b/todo.txt index e8af752..f7575db 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,11 @@ TODO: Rejection messages TODO: The error handling is terrible -TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times TODO: Get the rooms working, even if only via hotkeys TODO: Fix shoddy movement +TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times +TODO: Remove the big "Shut Down" button +TODO: Make a way for the server owner to control the server directly TODO: Move the map system into it's own namespace? TODO: The TileSheet class should implement the surface itself TODO: make the whole thing more fault tolerant From 4c882682ed49eb70cf8f5bcb94a2bd82a84b17a6 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 9 Sep 2014 08:05:50 +1000 Subject: [PATCH 2/8] Added TextPacket --- client/client_application.cpp | 3 ++ common/network/packet_types/text_packet.cpp | 40 +++++++++++++++++++++ common/network/packet_types/text_packet.hpp | 35 ++++++++++++++++++ common/network/serial_packet.hpp | 4 ++- common/network/serial_packet_type.hpp | 16 +++++++-- common/network/serial_utility.cpp | 17 ++++++--- server/server_logic.cpp | 3 ++ 7 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 common/network/packet_types/text_packet.cpp create mode 100644 common/network/packet_types/text_packet.hpp diff --git a/client/client_application.cpp b/client/client_application.cpp index 3c5ae4c..62e4d25 100644 --- a/client/client_application.cpp +++ b/client/client_application.cpp @@ -89,6 +89,7 @@ void ClientApplication::Init(int argc, char** argv) { std::cout << "Internal sizes:" << std::endl; + DEBUG_OUTPUT_VAR(NETWORK_VERSION); DEBUG_OUTPUT_VAR(sizeof(Region::type_t)); DEBUG_OUTPUT_VAR(sizeof(Region)); DEBUG_OUTPUT_VAR(REGION_WIDTH); @@ -96,8 +97,10 @@ void ClientApplication::Init(int argc, char** argv) { DEBUG_OUTPUT_VAR(REGION_DEPTH); DEBUG_OUTPUT_VAR(REGION_TILE_FOOTPRINT); DEBUG_OUTPUT_VAR(REGION_SOLID_FOOTPRINT); + DEBUG_OUTPUT_VAR(PACKET_STRING_SIZE); DEBUG_OUTPUT_VAR(PACKET_BUFFER_SIZE); DEBUG_OUTPUT_VAR(MAX_PACKET_SIZE); + DEBUG_OUTPUT_VAR(static_cast(SerialPacketType::LAST)); #undef DEBUG_OUTPUT_VAR diff --git a/common/network/packet_types/text_packet.cpp b/common/network/packet_types/text_packet.cpp new file mode 100644 index 0000000..fbe0d9f --- /dev/null +++ b/common/network/packet_types/text_packet.cpp @@ -0,0 +1,40 @@ +/* Copyright: (c) Kayne Ruse 2013, 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 "text_packet.hpp" + +#include "serial_utility.hpp" + +void serializeText(void* buffer, TextPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //content + serialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + serialCopy(&buffer, packet->text, PACKET_STRING_SIZE); +} + +void deserializeText(void* buffer, TextPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //content + deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE); + deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE); +} \ No newline at end of file diff --git a/common/network/packet_types/text_packet.hpp b/common/network/packet_types/text_packet.hpp new file mode 100644 index 0000000..8dfbe22 --- /dev/null +++ b/common/network/packet_types/text_packet.hpp @@ -0,0 +1,35 @@ +/* Copyright: (c) Kayne Ruse 2013, 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 TEXTPACKET_HPP_ +#define TEXTPACKET_HPP_ + +#include "serial_packet_base.hpp" + +struct TextPacket : SerialPacketBase { + char name[PACKET_STRING_SIZE]; + char text[PACKET_STRING_SIZE]; +}; + +void serializeText(void* buffer, TextPacket* packet); +void deserializeText(void* buffer, TextPacket* packet); + +#endif diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp index c767f6a..7dd6c81 100644 --- a/common/network/serial_packet.hpp +++ b/common/network/serial_packet.hpp @@ -27,18 +27,20 @@ #include "client_packet.hpp" #include "region_packet.hpp" #include "server_packet.hpp" +#include "text_packet.hpp" //SerialPacketBase is defined in serial_packet_base.hpp typedef SerialPacketBase SerialPacket; //DOCS: NETWORK_VERSION is used to discern compatible servers and clients -constexpr int NETWORK_VERSION = 20140831; +constexpr int NETWORK_VERSION = 20140909; union MaxPacket { CharacterPacket a; ClientPacket b; RegionPacket c; ServerPacket d; + TextPacket e; }; constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket); diff --git a/common/network/serial_packet_type.hpp b/common/network/serial_packet_type.hpp index cf9a4dd..1c517a8 100644 --- a/common/network/serial_packet_type.hpp +++ b/common/network/serial_packet_type.hpp @@ -52,7 +52,6 @@ enum class SerialPacketType { //Connecting to a server as a client JOIN_REQUEST, JOIN_RESPONSE, - JOIN_REJECTION, //client requests all information from the server SYNCHRONIZE, @@ -88,10 +87,23 @@ enum class SerialPacketType { CHARACTER_STATS_REQUEST, CHARACTER_STATS_RESPONSE, - //reject a character request + //------------------------- + //TextPacket + // name, text + //------------------------- + + //general speech + TEXT_BROADCAST, + + //rejection/error messages + SHUTDOWN_REJECTION, + JOIN_REJECTION, CHARACTER_REJECTION, + //------------------------- //not used + //------------------------- + LAST }; diff --git a/common/network/serial_utility.cpp b/common/network/serial_utility.cpp index 6f70999..1f943a6 100644 --- a/common/network/serial_utility.cpp +++ b/common/network/serial_utility.cpp @@ -26,6 +26,7 @@ #include "client_packet.hpp" #include "region_packet.hpp" #include "server_packet.hpp" +#include "text_packet.hpp" #include @@ -53,7 +54,6 @@ void serializePacket(void* buffer, SerialPacketBase* packet) { break; case SerialPacketType::JOIN_REQUEST: case SerialPacketType::JOIN_RESPONSE: - case SerialPacketType::JOIN_REJECTION: case SerialPacketType::SYNCHRONIZE: case SerialPacketType::DISCONNECT: case SerialPacketType::SHUTDOWN: @@ -68,9 +68,14 @@ void serializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::CHARACTER_UPDATE: case SerialPacketType::CHARACTER_STATS_REQUEST: case SerialPacketType::CHARACTER_STATS_RESPONSE: - case SerialPacketType::CHARACTER_REJECTION: serializeCharacter(buffer, static_cast(packet)); break; + case SerialPacketType::TEXT_BROADCAST: + case SerialPacketType::JOIN_REJECTION: + case SerialPacketType::SHUTDOWN_REJECTION: + case SerialPacketType::CHARACTER_REJECTION: + serializeText(buffer, static_cast(packet)); + break; } } @@ -88,7 +93,6 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { break; case SerialPacketType::JOIN_REQUEST: case SerialPacketType::JOIN_RESPONSE: - case SerialPacketType::JOIN_REJECTION: case SerialPacketType::SYNCHRONIZE: case SerialPacketType::DISCONNECT: case SerialPacketType::SHUTDOWN: @@ -103,8 +107,13 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::CHARACTER_UPDATE: case SerialPacketType::CHARACTER_STATS_REQUEST: case SerialPacketType::CHARACTER_STATS_RESPONSE: - case SerialPacketType::CHARACTER_REJECTION: deserializeCharacter(buffer, static_cast(packet)); break; + case SerialPacketType::TEXT_BROADCAST: + case SerialPacketType::JOIN_REJECTION: + case SerialPacketType::SHUTDOWN_REJECTION: + case SerialPacketType::CHARACTER_REJECTION: + serializeText(buffer, static_cast(packet)); + break; } } \ No newline at end of file diff --git a/server/server_logic.cpp b/server/server_logic.cpp index 281c5b2..bb86ed2 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -110,6 +110,7 @@ void ServerApplication::Init(int argc, char** argv) { std::cout << "Internal sizes:" << std::endl; + DEBUG_OUTPUT_VAR(NETWORK_VERSION); DEBUG_OUTPUT_VAR(sizeof(Region::type_t)); DEBUG_OUTPUT_VAR(sizeof(Region)); DEBUG_OUTPUT_VAR(REGION_WIDTH); @@ -117,8 +118,10 @@ void ServerApplication::Init(int argc, char** argv) { DEBUG_OUTPUT_VAR(REGION_DEPTH); DEBUG_OUTPUT_VAR(REGION_TILE_FOOTPRINT); DEBUG_OUTPUT_VAR(REGION_SOLID_FOOTPRINT); + DEBUG_OUTPUT_VAR(PACKET_STRING_SIZE); DEBUG_OUTPUT_VAR(PACKET_BUFFER_SIZE); DEBUG_OUTPUT_VAR(MAX_PACKET_SIZE); + DEBUG_OUTPUT_VAR(static_cast(SerialPacketType::LAST)); #undef DEBUG_OUTPUT_VAR From 2c06232264f0d6ce4398dcd4a88406ab35a2ee47 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 9 Sep 2014 08:39:36 +1000 Subject: [PATCH 3/8] JOIN_REJECTION works, ready for the rest --- client/scenes/lobby_menu.cpp | 9 +++++++++ client/scenes/lobby_menu.hpp | 1 + common/network/serial_utility.cpp | 4 ++-- server/server_methods.cpp | 11 +++++++---- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index 88d09e6..a6f5bac 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -25,6 +25,7 @@ #include "utility.hpp" #include +#include //------------------------- //Public access members @@ -192,6 +193,9 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) { case SerialPacketType::JOIN_RESPONSE: HandleJoinResponse(static_cast(argPacket)); break; + case SerialPacketType::JOIN_REJECTION: + HandleJoinRejection(static_cast(argPacket)); + break; //handle errors default: throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast(argPacket->type)) )); @@ -229,6 +233,11 @@ void LobbyMenu::HandleJoinResponse(ClientPacket* const argPacket) { network.SendTo(Channels::SERVER, &newPacket); } +void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { + //TODO: Better output + std::cerr << "Error: " << argPacket->text << std::endl; +} + //------------------------- //server control //------------------------- diff --git a/client/scenes/lobby_menu.hpp b/client/scenes/lobby_menu.hpp index e8a5d1c..1959c56 100644 --- a/client/scenes/lobby_menu.hpp +++ b/client/scenes/lobby_menu.hpp @@ -63,6 +63,7 @@ protected: void HandlePacket(SerialPacket* const); void HandleBroadcastResponse(ServerPacket* const); void HandleJoinResponse(ClientPacket* const); + void HandleJoinRejection(TextPacket* const); //server control void SendBroadcastRequest(); diff --git a/common/network/serial_utility.cpp b/common/network/serial_utility.cpp index 1f943a6..6572887 100644 --- a/common/network/serial_utility.cpp +++ b/common/network/serial_utility.cpp @@ -109,11 +109,11 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::CHARACTER_STATS_RESPONSE: deserializeCharacter(buffer, static_cast(packet)); break; - case SerialPacketType::TEXT_BROADCAST: + case SerialPacketType::TEXT_BROADCAST: case SerialPacketType::JOIN_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION: case SerialPacketType::CHARACTER_REJECTION: - serializeText(buffer, static_cast(packet)); + deserializeText(buffer, static_cast(packet)); break; } } \ No newline at end of file diff --git a/server/server_methods.cpp b/server/server_methods.cpp index bb3be96..766479d 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -67,9 +67,14 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { //load the user account //TODO: handle passwords int accountIndex = accountMgr.LoadAccount(argPacket->username, clientIndex); + + //Error checking if (accountIndex < 0) { - //TODO: send rejection packet - std::cerr << "Error: Account already loaded: " << accountIndex << std::endl; + TextPacket newPacket; + newPacket.type = SerialPacketType::JOIN_REJECTION; + std::string msg = std::string() + "Account already loaded: " + argPacket->username; + strncpy(newPacket.text, msg.c_str(), PACKET_STRING_SIZE); //BUG: If the name is too long this would truncate it + network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); return; } @@ -223,8 +228,6 @@ void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) //make a new character if this one doesn't exist if (!character) { - //this isn't normal - std::cerr << "Warning: HandleCharacterUpdate() is passing to HandleCharacterNew()" << std::endl; HandleCharacterNew(argPacket); return; } From 17b9eb7ad4610814fbe8ce97bdf6c0e4c2c99780 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 10 Sep 2014 16:06:01 +1000 Subject: [PATCH 4/8] Added more rejection packets, revised some logic --- client/scenes/in_world.cpp | 2 +- rsc/scripts/setup_server.lua | 2 +- server/characters/character_manager.cpp | 4 +- server/server_logic.cpp | 2 +- server/server_methods.cpp | 60 +++++++++++++++---------- todo.txt | 1 + 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 6e96e0d..8db57e1 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -142,7 +142,7 @@ void InWorld::Update() { camera.y = localCharacter->GetOrigin().y - camera.marginY; //check the connection - if (Clock::now() - lastBeat > std::chrono::seconds(5)) { + if (Clock::now() - lastBeat > std::chrono::seconds(3)) { if (attemptedBeats > 2) { throw(std::runtime_error("Connection lost")); } diff --git a/rsc/scripts/setup_server.lua b/rsc/scripts/setup_server.lua index 8b43720..6396596 100644 --- a/rsc/scripts/setup_server.lua +++ b/rsc/scripts/setup_server.lua @@ -17,7 +17,7 @@ tiles = { --custom generation systems here function islandGenerator(region) - io.write("Generating (", Region.GetX(region), ", ", Region.GetY(region), ")\n") +-- io.write("Generating (", Region.GetX(region), ", ", Region.GetY(region), ")\n") for i = 1, Region.GetWidth(region) do for j = 1, Region.GetHeight(region) do local dist = math.dist(0, 0, i + Region.GetX(region) -1, j + Region.GetY(region) -1) diff --git a/server/characters/character_manager.cpp b/server/characters/character_manager.cpp index 3718dd6..f24378f 100644 --- a/server/characters/character_manager.cpp +++ b/server/characters/character_manager.cpp @@ -225,7 +225,7 @@ int CharacterManager::SaveCharacter(int uid) { if (sqlite3_step(statement) != SQLITE_DONE) { //if this fails, than something went horribly wrong sqlite3_finalize(statement); - throw( std::runtime_error(std::string() + "Unknown SQL error when saving an account: " + sqlite3_errmsg(database)) ); + throw( std::runtime_error(std::string() + "Unknown SQL error when saving a character: " + sqlite3_errmsg(database)) ); } sqlite3_finalize(statement); @@ -258,7 +258,7 @@ void CharacterManager::DeleteCharacter(int uid) { if (sqlite3_step(statement) != SQLITE_DONE) { //if this fails, than something went horribly wrong sqlite3_finalize(statement); - throw( std::runtime_error(std::string() + "Unknown SQL error when deleting an account: " + sqlite3_errmsg(database)) ); + throw( std::runtime_error(std::string() + "Unknown SQL error when deleting a character: " + sqlite3_errmsg(database)) ); } //finish the routine diff --git a/server/server_logic.cpp b/server/server_logic.cpp index bb86ed2..b770cdf 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -151,7 +151,7 @@ void ServerApplication::Proc() { //TODO: This could be checked only every few seconds //Check connections for (auto& it : clientMap) { - if (std::chrono::steady_clock::now() - it.second.GetLastBeat() > std::chrono::seconds(5)) { + if (std::chrono::steady_clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) { ServerPacket newPacket; newPacket.type = SerialPacketType::PING; network.SendTo(it.second.GetAddress(), &newPacket); diff --git a/server/server_methods.cpp b/server/server_methods.cpp index 766479d..184dd28 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -60,19 +60,16 @@ void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) { } void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { - //create the new client - ClientData newClient; - newClient.SetAddress(argPacket->srcAddress); - //load the user account //TODO: handle passwords int accountIndex = accountMgr.LoadAccount(argPacket->username, clientIndex); - //Error checking + //Cannot load if (accountIndex < 0) { TextPacket newPacket; newPacket.type = SerialPacketType::JOIN_REJECTION; std::string msg = std::string() + "Account already loaded: " + argPacket->username; + memset(newPacket.name, 0, PACKET_STRING_SIZE); strncpy(newPacket.text, msg.c_str(), PACKET_STRING_SIZE); //BUG: If the name is too long this would truncate it network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); return; @@ -84,10 +81,14 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { newPacket.clientIndex = clientIndex; newPacket.accountIndex = accountIndex; - network.SendTo(newClient.GetAddress(), static_cast(&newPacket)); + network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); + + //register the client + ClientData newClient; + newClient.SetAddress(argPacket->srcAddress); + clientMap[clientIndex++] = newClient; //finished this routine - clientMap[clientIndex++] = newClient; std::cout << "New connection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl; } @@ -110,9 +111,9 @@ void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) { ); //save and unload this account's characters - //pump the unload message to all remaining clients characterMgr.UnloadCharacterIf([&](std::map::iterator it) -> bool { if (argPacket->accountIndex == it->second.GetOwner()) { + //pump the unload message to all remaining clients PumpCharacterUnload(it->first); return true; } @@ -172,23 +173,32 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { //BUG: #27 Characters can be created with an invalid account index + //TODO: Make sure that a character's owner's account is loaded before continuing + //NOTE: misnomer, try to load the character first int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar); - if (characterIndex == -1) { - //TODO: rejection packet - std::cerr << "Warning: Character already loaded" << std::endl; + //cannot load or create + if (characterIndex < 0) { + //build the error message + std::string msg; + if (characterIndex == -1) { + msg += "Character already loaded: "; + } + else if (characterIndex == -1) { + msg += "Character already exists: "; + } + msg += argPacket->handle; + + //create, fill and send the packet + TextPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_REJECTION; + memset(newPacket.name, 0, PACKET_STRING_SIZE); + strncpy(newPacket.text, msg.c_str(), PACKET_STRING_SIZE); + network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); return; } - if (characterIndex == -2) { - //TODO: rejection packet - std::cerr << "Warning: Character already exists" << std::endl; - return; - } - - //TODO: Make sure that a character's owner's account is loaded before continuing - //send this new character to all clients CharacterPacket newPacket; newPacket.type = SerialPacketType::CHARACTER_NEW; @@ -203,9 +213,13 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) 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; + if (characterIndex < 0 && characterMgr.GetCharacter(characterIndex)->GetOwner() != argPacket->accountIndex) { + //send the rejection packet + TextPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_REJECTION; + memset(newPacket.name, 0, PACKET_STRING_SIZE); + strncpy(newPacket.text, "Character cannot be deleted", PACKET_STRING_SIZE); + network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); //unload an unneeded character if (characterIndex != -1) { @@ -260,7 +274,6 @@ void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) { newPacket.type = SerialPacketType::CHARACTER_UPDATE; for (auto& it : *characterMgr.GetContainer()) { - newPacket.characterIndex = it.first; CopyCharacterToPacket(&newPacket, it.first); network.SendTo(client.GetAddress(), static_cast(&newPacket)); } @@ -323,6 +336,7 @@ void ServerApplication::PumpPacket(SerialPacket* const argPacket) { void ServerApplication::PumpCharacterUnload(int uid) { //delete the client-side character(s) + //NOTE: This is a strange function CharacterPacket newPacket; newPacket.type = SerialPacketType::CHARACTER_DELETE; newPacket.characterIndex = uid; diff --git a/todo.txt b/todo.txt index f7575db..77e8d80 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,4 @@ +TODO: Remove the BUGFIX tags TODO: Rejection messages TODO: The error handling is terrible TODO: Get the rooms working, even if only via hotkeys From 712d94d3b2dad5438a3447853cf4c78d370709d8 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 10 Sep 2014 16:57:35 +1000 Subject: [PATCH 5/8] Client now handles character rejections --- client/scenes/in_world.cpp | 18 +++++++++++++++++- client/scenes/in_world.hpp | 1 + client/scenes/lobby_menu.cpp | 8 -------- server/server_methods.cpp | 2 +- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 8db57e1..a79f3b3 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -73,6 +73,14 @@ InWorld::InWorld( //TODO: Tile size and tile sheet should be loaded elsewhere tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 32, 32); + //send this player's character info + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_NEW; + strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE); + strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE); + newPacket.accountIndex = accountIndex; + network.SendTo(Channels::SERVER, &newPacket); + //request a sync RequestSynchronize(); @@ -302,6 +310,9 @@ void InWorld::HandlePacket(SerialPacket* const argPacket) { case SerialPacketType::CHARACTER_UPDATE: HandleCharacterUpdate(static_cast(argPacket)); break; + case SerialPacketType::CHARACTER_REJECTION: + HandleCharacterRejection(static_cast(argPacket)); + break; case SerialPacketType::REGION_CONTENT: HandleRegionContent(static_cast(argPacket)); break; @@ -389,7 +400,6 @@ void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) { if (characterMap.find(argPacket->characterIndex) == characterMap.end()) { - std::cout << "Warning: HandleCharacterUpdate() is passing to HandleCharacterNew()" << std::endl; HandleCharacterNew(argPacket); return; } @@ -404,6 +414,12 @@ void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) { } } +void InWorld::HandleCharacterRejection(TextPacket* const argPacket) { + std::cerr << "Error: " << argPacket->text << std::endl; + RequestDisconnect(); + SetNextScene(SceneList::CLEANUP); +} + void InWorld::HandleRegionContent(RegionPacket* const argPacket) { //replace existing regions regionPager.UnloadRegion(argPacket->x, argPacket->y); diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index aceb189..010bea8 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -83,6 +83,7 @@ protected: void HandleCharacterNew(CharacterPacket* const); void HandleCharacterDelete(CharacterPacket* const); void HandleCharacterUpdate(CharacterPacket* const); + void HandleCharacterRejection(TextPacket* const); void HandleRegionContent(RegionPacket* const); //Server control diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index a6f5bac..8a1c4d1 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -223,14 +223,6 @@ void LobbyMenu::HandleJoinResponse(ClientPacket* const argPacket) { accountIndex = argPacket->accountIndex; network.Bind(argPacket->srcAddress, Channels::SERVER); SetNextScene(SceneList::INWORLD); - - //send this player's character info - CharacterPacket newPacket; - newPacket.type = SerialPacketType::CHARACTER_NEW; - strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE); - strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE); - newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &newPacket); } void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { diff --git a/server/server_methods.cpp b/server/server_methods.cpp index 184dd28..8c5a623 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -185,7 +185,7 @@ void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { if (characterIndex == -1) { msg += "Character already loaded: "; } - else if (characterIndex == -1) { + else if (characterIndex == -2) { msg += "Character already exists: "; } msg += argPacket->handle; From ad2c65dc67020e0a772824b8e9c6303a5eca6f20 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 10 Sep 2014 17:00:13 +1000 Subject: [PATCH 6/8] Remeved the commented BUGFIX tags --- client/scenes/clean_up.cpp | 2 +- client/scenes/lobby_menu.cpp | 2 +- common/network/udp_network_utility.cpp | 2 +- server/server_methods.cpp | 2 -- todo.txt | 2 -- 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/client/scenes/clean_up.cpp b/client/scenes/clean_up.cpp index 1be9e5c..c602014 100644 --- a/client/scenes/clean_up.cpp +++ b/client/scenes/clean_up.cpp @@ -85,7 +85,7 @@ void CleanUp::Update() { SetNextScene(SceneList::MAINMENU); } - //BUGFIX: Eat incoming packets + //Eat incoming packets while(network.Receive()); } diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index 8a1c4d1..92ce5d1 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -64,7 +64,7 @@ LobbyMenu::LobbyMenu(int* const argClientIndex, int* const argAccountIndex): //set the server list's position listBox = {300, 50, 200, font.GetCharH()}; - //BUGFIX: Eat incoming packets + //Eat incoming packets while(network.Receive()); //Initial broadcast diff --git a/common/network/udp_network_utility.cpp b/common/network/udp_network_utility.cpp index 6a2d243..e677854 100644 --- a/common/network/udp_network_utility.cpp +++ b/common/network/udp_network_utility.cpp @@ -26,7 +26,7 @@ #include -//BUGFIX: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network +//NOTE: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network //NOTE: don't confuse SerialPacketBase with UDPpacket void UDPNetworkUtility::Open(int port) { diff --git a/server/server_methods.cpp b/server/server_methods.cpp index 8c5a623..2cc3b31 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -35,8 +35,6 @@ void ServerApplication::HandlePing(ServerPacket* const argPacket) { void ServerApplication::HandlePong(ServerPacket* const argPacket) { //find and update the specified client - - //BUGFIX: running multiple clients on one computer will result in matching host values; check the ports too for (auto& it : clientMap) { if (it.second.GetAddress().host == argPacket->srcAddress.host && it.second.GetAddress().port == argPacket->srcAddress.port diff --git a/todo.txt b/todo.txt index 77e8d80..1583f88 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,3 @@ -TODO: Remove the BUGFIX tags -TODO: Rejection messages TODO: The error handling is terrible TODO: Get the rooms working, even if only via hotkeys TODO: Fix shoddy movement From 411687b41ce893d4cb02c95349acbe1f29a02182 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 10 Sep 2014 17:35:12 +1000 Subject: [PATCH 7/8] Added a proper disconnection message by hacking the config --- client/scenes/clean_up.cpp | 4 +++- client/scenes/in_world.cpp | 9 +++++++-- client/scenes/in_world.hpp | 1 + todo.txt | 1 - 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/scenes/clean_up.cpp b/client/scenes/clean_up.cpp index c602014..54ced25 100644 --- a/client/scenes/clean_up.cpp +++ b/client/scenes/clean_up.cpp @@ -90,8 +90,10 @@ void CleanUp::Update() { } void CleanUp::Render(SDL_Surface* const screen) { + ConfigUtility& config = ConfigUtility::GetSingleton(); + backButton.DrawTo(screen); - font.DrawStringTo("You have been disconnected.", screen, 50, 30); + font.DrawStringTo(config["client.disconnectMessage"], screen, 50, 30); } //------------------------- diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index a79f3b3..78cb8d8 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -152,7 +152,9 @@ void InWorld::Update() { //check the connection if (Clock::now() - lastBeat > std::chrono::seconds(3)) { if (attemptedBeats > 2) { - throw(std::runtime_error("Connection lost")); + RequestDisconnect(); + SetNextScene(SceneList::CLEANUP); + ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server"; } ServerPacket newPacket; @@ -341,6 +343,7 @@ void InWorld::HandlePong(ServerPacket* const argPacket) { void InWorld::HandleDisconnect(ClientPacket* const argPacket) { //TODO: More needed in the disconnection SetNextScene(SceneList::CLEANUP); + ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been disconnected"; } void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) { @@ -415,9 +418,11 @@ void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) { } void InWorld::HandleCharacterRejection(TextPacket* const argPacket) { - std::cerr << "Error: " << argPacket->text << std::endl; RequestDisconnect(); SetNextScene(SceneList::CLEANUP); + ConfigUtility& config = ConfigUtility::GetSingleton(); + config["client.disconnectMessage"] = "Error: "; + config["client.disconnectMessage"] += argPacket->text; } void InWorld::HandleRegionContent(RegionPacket* const argPacket) { diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 010bea8..d80659d 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -127,6 +127,7 @@ protected: Character* localCharacter = nullptr; //connections + //TODO: This needs it's own utility, for both InWorld and InCombat typedef std::chrono::steady_clock Clock; Clock::time_point lastBeat = Clock::now(); int attemptedBeats = 0; diff --git a/todo.txt b/todo.txt index 1583f88..bef95f3 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,3 @@ -TODO: The error handling is terrible TODO: Get the rooms working, even if only via hotkeys TODO: Fix shoddy movement TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times From 9367bd802fd079a735251dca7f7370c2edf294b1 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 13 Sep 2014 12:01:29 +1000 Subject: [PATCH 8/8] Tweaked todo.txt --- todo.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/todo.txt b/todo.txt index bef95f3..2098c57 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,6 @@ +TODO: Config switch for the debug output +TODO: A better way of handling the disconnection message +TODO: LobbyMenu::HandleJoinRejection() TODO: Get the rooms working, even if only via hotkeys TODO: Fix shoddy movement TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times