From 60edc97ea570dda4ea739775ead9d7c574d9558c Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 21 Apr 2014 01:38:28 +1000 Subject: [PATCH 1/3] Added rejections for incompatible servers --- client/scenes/lobby_menu.cpp | 28 ++++++++++++++++++++++++++-- client/scenes/lobby_menu.hpp | 18 ++++++++++++++---- common/network/serial.cpp | 26 ++++++++++++++++++++++++++ common/network/serial_packet.hpp | 8 ++++++-- server/server_application.cpp | 10 ++++++++-- 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index 2e738b4..24c5b5c 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -22,6 +22,7 @@ #include "lobby_menu.hpp" #include "channels.hpp" +#include "utility.hpp" #include @@ -91,9 +92,13 @@ void LobbyMenu::FrameEnd() { } void LobbyMenu::Render(SDL_Surface* const screen) { + //TODO: I need a proper UI system for the entire client and the editor + //UI search.DrawTo(screen); join.DrawTo(screen); back.DrawTo(screen); + + //TODO: draw headers for the server list for (int i = 0; i < serverInfo.size(); i++) { //draw the selected server's highlight if (selection == &serverInfo[i]) { @@ -104,6 +109,16 @@ void LobbyMenu::Render(SDL_Surface* const screen) { //draw the server name font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h); + + //draw the player count + font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h); + + //compatible? + if (!serverInfo[i].compatible) { + font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h); + } + + //TODO: ping? } } @@ -139,7 +154,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { selection = nullptr; } - else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) { + else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) { //the vars SerialPacket packet; char buffer[PACKET_BUFFER_SIZE]; @@ -184,9 +199,18 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) { void LobbyMenu::HandlePacket(SerialPacket packet) { switch(packet.meta.type) { case SerialPacket::Type::BROADCAST_RESPONSE: { + //extract the data ServerInformation server; - server.name = packet.serverInfo.name; server.address = packet.meta.srcAddress; + server.name = packet.serverInfo.name; + server.playerCount = packet.serverInfo.playerCount; + + //NOTE: Check compatibility here + server.compatible = packet.serverInfo.regionWidth == REGION_WIDTH && + packet.serverInfo.regionHeight == REGION_HEIGHT && + packet.serverInfo.regionDepth == REGION_DEPTH; + + //push serverInfo.push_back(server); } break; diff --git a/client/scenes/lobby_menu.hpp b/client/scenes/lobby_menu.hpp index b231d16..53808bb 100644 --- a/client/scenes/lobby_menu.hpp +++ b/client/scenes/lobby_menu.hpp @@ -22,17 +22,24 @@ #ifndef LOBBYMENU_HPP_ #define LOBBYMENU_HPP_ -#include "base_scene.hpp" - +//graphics & utilities #include "image.hpp" #include "raster_font.hpp" #include "button.hpp" - #include "config_utility.hpp" + +//map +#include "region.hpp" + +//network #include "udp_network_utility.hpp" #include "serial_packet.hpp" #include "serial.hpp" +//client +#include "base_scene.hpp" + +//STL #include class LobbyMenu : public BaseScene { @@ -71,8 +78,11 @@ protected: //server list struct ServerInformation { - std::string name; IPaddress address; + //TODO: version info + std::string name; + int playerCount; + bool compatible; }; std::vector serverInfo; diff --git a/common/network/serial.cpp b/common/network/serial.cpp index 8ad8a89..ee88937 100644 --- a/common/network/serial.cpp +++ b/common/network/serial.cpp @@ -36,7 +36,20 @@ void serializeType(SerialPacket* packet, char* buffer) { void serializeServer(SerialPacket* packet, char* buffer) { memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); buffer += sizeof(SerialPacket::Type); + + //server info + //Note: version info serialization goes here memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE); + buffer += PACKET_STRING_SIZE; + memcpy(buffer, &packet->serverInfo.playerCount, sizeof(int)); + buffer += sizeof(int); + + //map format + memcpy(buffer, &packet->serverInfo.regionWidth, sizeof(int)); + buffer += sizeof(int); + memcpy(buffer, &packet->serverInfo.regionHeight, sizeof(int)); + buffer += sizeof(int); + memcpy(buffer, &packet->serverInfo.regionDepth, sizeof(int)); } void serializeClient(SerialPacket* packet, char* buffer) { @@ -114,7 +127,20 @@ void deserializeType(SerialPacket* packet, char* buffer) { void deserializeServer(SerialPacket* packet, char* buffer) { memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); buffer += sizeof(SerialPacket::Type); + + //server info + //Note: version info deserialization goes here memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE); + buffer += PACKET_STRING_SIZE; + memcpy(&packet->serverInfo.playerCount, buffer, sizeof(int)); + buffer += sizeof(int); + + //map format + memcpy(&packet->serverInfo.regionWidth, buffer, sizeof(int)); + buffer += sizeof(int); + memcpy(&packet->serverInfo.regionHeight, buffer, sizeof(int)); + buffer += sizeof(int); + memcpy(&packet->serverInfo.regionDepth, buffer, sizeof(int)); } void deserializeClient(SerialPacket* packet, char* buffer) { diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp index 8c023d5..84f4a39 100644 --- a/common/network/serial_packet.hpp +++ b/common/network/serial_packet.hpp @@ -79,8 +79,12 @@ union SerialPacket { Metadata meta; //TODO: version info char name[PACKET_STRING_SIZE]; - //TODO: player count - //TODO: map format + int playerCount; + + //map format + int regionWidth; + int regionHeight; + int regionDepth; }serverInfo; //information about the client diff --git a/server/server_application.cpp b/server/server_application.cpp index 390a347..bba6c26 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -176,10 +176,16 @@ void ServerApplication::HandlePacket(SerialPacket packet) { void ServerApplication::HandleBroadcastRequest(SerialPacket packet) { //send back the server's metadata packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE; + + //pack the data //TODO: version info snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str()); - //TODO: player count - //TODO: map format + packet.serverInfo.playerCount = playerMap.size(); + packet.serverInfo.regionWidth = REGION_WIDTH; + packet.serverInfo.regionHeight = REGION_HEIGHT; + packet.serverInfo.regionDepth = REGION_DEPTH; + + //send the data char buffer[PACKET_BUFFER_SIZE]; serialize(&packet, buffer); network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE); From 6c6a025f2a1e8c543e9efe01b7f31b209d93873c Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 21 Apr 2014 02:13:00 +1000 Subject: [PATCH 2/3] Adjusted a few comments --- client/scenes/in_world.cpp | 2 +- client/scenes/lobby_menu.cpp | 1 + common/map/region_pager.hpp | 2 +- common/network/serial.hpp | 2 +- common/network/serial_packet.hpp | 3 +-- server/server_application.cpp | 8 +++++--- server/server_application.hpp | 2 +- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 4f9e002..d6cb5a5 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -453,7 +453,7 @@ int InWorld::CheckBufferDistance(Region* const region) { return std::max(abs(x), abs(y)); } -//TODO: eew ugly +//TODO: Revise InWorld::UpdateMap() after InWorld::CheckBufferDistance() void InWorld::UpdateMap() { //prune distant regions for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index 24c5b5c..1000af4 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -155,6 +155,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { } else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) { + //TODO: The player login information should be collected by the lobby screen //the vars SerialPacket packet; char buffer[PACKET_BUFFER_SIZE]; diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp index 0bf035e..9b3b991 100644 --- a/common/map/region_pager.hpp +++ b/common/map/region_pager.hpp @@ -46,7 +46,7 @@ public: virtual Region* SaveRegion(int x, int y) = 0; virtual Region* CreateRegion(int x, int y) = 0; virtual void UnloadRegion(int x, int y) = 0; - //TODO: delete? + //TODO: delete existing regions //accessors & mutators std::list* GetContainer() { return ®ionList; } diff --git a/common/network/serial.hpp b/common/network/serial.hpp index 5f002e7..b532bb8 100644 --- a/common/network/serial.hpp +++ b/common/network/serial.hpp @@ -24,7 +24,7 @@ #include "serial_packet.hpp" -/* TODO: Keep the PACKET_BUFFER_SIZE up to date +/* NOTE: Keep the PACKET_BUFFER_SIZE up to date * NOTE: REGION_CONTENT is currently the largest type of packet * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t) * map format: sizeof(int) * 2 diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp index 84f4a39..35f117e 100644 --- a/common/network/serial_packet.hpp +++ b/common/network/serial_packet.hpp @@ -99,8 +99,7 @@ union SerialPacket { Metadata meta; int clientIndex; int playerIndex; - //TODO: should probably move these into the client info - //TODO: these might actually do better during the login system + //TODO: should move handle/avatar into clientInfo; these might actually do better during the login system char handle[PACKET_STRING_SIZE]; char avatar[PACKET_STRING_SIZE]; Vector2 position; diff --git a/server/server_application.cpp b/server/server_application.cpp index bba6c26..7317058 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -110,7 +110,7 @@ void ServerApplication::Proc() { HandlePacket(packet); } //give the computer a break - //TODO: remove this? + //TODO: remove this delay? SDL_Delay(10); } } @@ -252,7 +252,7 @@ void ServerApplication::HandleSynchronize(SerialPacket packet) { SerialPacket newPacket; char buffer[PACKET_BUFFER_SIZE]; - //TODO: map? + //TODO: syncronize the map? //players newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE; @@ -314,13 +314,15 @@ void ServerApplication::HandlePlayerNew(SerialPacket packet) { PlayerEntry::uidCounter++; } +//TODO: differentiate between delete and unload void ServerApplication::HandlePlayerDelete(SerialPacket packet) { - //TODO: remove this? //TODO: authenticate who is deleting this player if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) { throw(std::runtime_error("Cannot delete a non-existant player")); } + //TODO: remove the deleted player from the database? + //prep the delete packet SerialPacket delPacket; delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE; diff --git a/server/server_application.hpp b/server/server_application.hpp index b0b3fe6..c34172e 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -74,7 +74,7 @@ private: void HandlePlayerUpdate(SerialPacket); void HandleRegionRequest(SerialPacket); - //TODO: a function that sends to players in a certain proximity + //TODO: a function that only sends to players in a certain proximity void PumpPacket(SerialPacket); //APIs From b47191a0c1f6b242c9e48545caad4f31dc8fa665 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 21 Apr 2014 03:56:48 +1000 Subject: [PATCH 3/3] Fixed a horrible region coordinate bug Coordinates are supposed to be stored by their x & y, but the sizes of the tile sheets were getting mixed in as well. When trying to store a region at (0, 20), it was being stored at (0, 260). Another visual bug inside the tile sheet's rendering function masked this issue until now. Another thing to note is that I've removed an incredibly complex system for updating the client's map. The new system may seem complex at first, but it is straight forward compared to what it replaced. I've also fixed a few logarithmic lagging points in the code. --- client/player_character.hpp | 1 + client/scenes/in_world.cpp | 80 ++++++++-------------------------- client/scenes/in_world.hpp | 1 - common/graphics/tile_sheet.cpp | 4 +- common/map/region_pager.hpp | 5 +-- 5 files changed, 23 insertions(+), 68 deletions(-) diff --git a/client/player_character.hpp b/client/player_character.hpp index 1f6bc7a..9dde742 100644 --- a/client/player_character.hpp +++ b/client/player_character.hpp @@ -25,6 +25,7 @@ #include "vector2.hpp" #include "sprite_sheet.hpp" +//TODO: correct the PlayerCharacter class and it's movement system class PlayerCharacter { public: enum class Direction { diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index d6cb5a5..936be7d 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -404,76 +404,34 @@ void InWorld::RequestRegion(int x, int y) { //Utilities //------------------------- -int InWorld::CheckBufferDistance(Region* const region) { - /* TODO: Remove InWorld::CheckBufferDistance(), and replace it with a simpler system - * DOCUMENTATION - * This algorithm is extremely complex and involed, but initial tests show - * that it gives the right answers. The purpose is to determine how far off screen - * a certain region is, so that it can be unloaded when necessary. - * - * If the region is actually onscreen, then there's no reason to run the rest, so - * the algorithm corrects for the camera's location, before checking the bounds of - * the screen. - * - * The next part is tricky. If X or Y is negative, then it is divided by the - * graphical size of the regions, resulting in a usable integer, representing how - * far from the screen it is in "region units". If, however, X or Y is larger than - * 0, than first, the size of the screen is subtracted from that variable, before - * it is then divided by the graphical size of a region. Finally, to compensate for - * the off by one error, 1 is added at the end. - * - * Since only the magnitude of the distance in either direction is needed, this - * method returns the largest absolute value of X or Y. - * - * The final result of this algorithm is an integer representing how far, rounded - * up, a certain region is from the screen's edges in any direction, measured in - * "region units". This algorithm may be flawed, in which case, I recommend simply - * replacing it with a boolean check, to see if the region's distance from the player - * is larger than a certain value. This algorithm lacks the advantages I initially - * expected, so that may be beneficial at some point. - */ - - //locations relative to the camera - int x = region->GetX() - camera.x; - int y = region->GetY() - camera.y; - - //if the region is visible, return -1 - if (x >= -REGION_WIDTH * tileSheet.GetTileW() && x < camera.width && - y >= -REGION_HEIGHT * tileSheet.GetTileH() && y < camera.height) { - return -1; - } - - //prune the screen's area from the algorithm; get the pseudo-indexes - if (x < 0) x /= (REGION_WIDTH * tileSheet.GetTileW()); - if (y < 0) y /= (REGION_HEIGHT * tileSheet.GetTileH()); - if (x > 0) x = (x - camera.width) / (REGION_WIDTH * tileSheet.GetTileW()) + 1; - if (y > 0) y = (y - camera.height) / (REGION_HEIGHT * tileSheet.GetTileH()) + 1; - - //return the pseudo-index with the greatest magnitude - return std::max(abs(x), abs(y)); -} - -//TODO: Revise InWorld::UpdateMap() after InWorld::CheckBufferDistance() +//TODO: convert this into a more generic function?; using parameters for the bounds void InWorld::UpdateMap() { + //these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1) + int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH; + int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH; + + int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT; + int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT; + //prune distant regions for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { - if (CheckBufferDistance(*it) > 2) { - regionPager.UnloadRegion((*it)->GetX(), (*it)->GetY()); + //check if the region is outside off this area + if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) { - //reset - it = regionPager.GetContainer()->begin(); + //clunky, but the alternative was time consuming + int tmpX = (*it)->GetX(); + int tmpY = (*it)->GetY(); + ++it; + + regionPager.UnloadRegion(tmpX, tmpY); continue; } ++it; } - //TODO: make the region units official? - int regionUnitX = REGION_WIDTH * tileSheet.GetTileW(); - int regionUnitY = REGION_HEIGHT * tileSheet.GetTileH(); - - //request empty regions, including buffers (-1 & +1 region unit) - for (int i = snapToBase(regionUnitX, camera.x - regionUnitX); i <= snapToBase(regionUnitX, camera.x + camera.width + regionUnitX); i += regionUnitX) { - for (int j = snapToBase(regionUnitY, camera.y - regionUnitY); j <= snapToBase(regionUnitY, camera.y + camera.height + regionUnitY); j += regionUnitY) { + //request empty regions within this zone + for (int i = xStart; i <= xEnd; i += REGION_WIDTH) { + for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) { if (!regionPager.FindRegion(i, j)) { RequestRegion(i, j); } diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 899ee8a..bb0cc5c 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -86,7 +86,6 @@ protected: void RequestRegion(int x, int y); //utilities - int CheckBufferDistance(Region* const); void UpdateMap(); //globals diff --git a/common/graphics/tile_sheet.cpp b/common/graphics/tile_sheet.cpp index e1b9ea2..bb9a4cb 100644 --- a/common/graphics/tile_sheet.cpp +++ b/common/graphics/tile_sheet.cpp @@ -53,8 +53,8 @@ void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int image.SetClipX((tile-1) % XCount * image.GetClipW()); image.SetClipY((tile-1) / XCount * image.GetClipH()); image.DrawTo(dest, - region->GetX() + i * image.GetClipW() - camX, - region->GetY() + j * image.GetClipH() - camY); + (region->GetX() + i) * image.GetClipW() - camX, + (region->GetY() + j) * image.GetClipH() - camY); } } } diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp index 9b3b991..95864f0 100644 --- a/common/map/region_pager.hpp +++ b/common/map/region_pager.hpp @@ -109,10 +109,7 @@ public: for (std::list::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) { if ((*it)->GetX() == x && (*it)->GetY() == y) { allocator.Unload(*it); - regionList.erase(it); - - //reset the loop, because of reasons - it = regionList.begin(); + it = regionList.erase(it); continue; } ++it;