From 962f3f5dd0368257cf17d9783213a17418ebe191 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sat, 5 Apr 2014 01:56:05 +1100 Subject: [PATCH 1/7] Added "camera" --- client/player_character.hpp | 2 +- client/scenes/in_world.cpp | 36 ++++++++++++++++++++++++++++++------ client/scenes/in_world.hpp | 4 ++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/client/player_character.hpp b/client/player_character.hpp index b33baca..1f6bc7a 100644 --- a/client/player_character.hpp +++ b/client/player_character.hpp @@ -36,7 +36,7 @@ public: void Update(double delta); - void DrawTo(SDL_Surface* const dest) { sprite.DrawTo(dest, position.x, position.y); } + void DrawTo(SDL_Surface* const dest, int camX, int camY) { sprite.DrawTo(dest, position.x - camX, position.y - camY); } //clunky code results in smooth movement and controls void AdjustDirection(Direction); diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 1c25bf6..cc8776c 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -88,8 +88,20 @@ void InWorld::FrameStart() { } void InWorld::Update(double delta) { - //suck in all waiting packets NetworkPacket packet; + + //update the camera + if(localCharacter) { + int marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); + int marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); + camera.x = localCharacter->GetPosition().x - marginX; + camera.y = localCharacter->GetPosition().y - marginY; + } + + //check the map + UpdateMap(); + + //suck in all waiting packets while(network.Receive()) { deserialize(&packet, network.GetInData()); packet.meta.srcAddress = network.GetInPacket()->address; @@ -107,7 +119,7 @@ void InWorld::FrameEnd() { void InWorld::Render(SDL_Surface* const screen) { for (auto& it : playerCharacters) { - it.second.DrawTo(screen); + it.second.DrawTo(screen, camera.x, camera.y); } disconnectButton.DrawTo(screen); shutDownButton.DrawTo(screen); @@ -212,24 +224,24 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { } } +//------------------------- +//Network handlers +//------------------------- + void InWorld::HandlePacket(NetworkPacket packet) { switch(packet.meta.type) { case NetworkPacket::Type::DISCONNECT: HandleDisconnect(packet); break; - case NetworkPacket::Type::PLAYER_NEW: HandlePlayerNew(packet); break; - case NetworkPacket::Type::PLAYER_DELETE: HandlePlayerDelete(packet); break; - case NetworkPacket::Type::PLAYER_UPDATE: HandlePlayerUpdate(packet); break; - //handle errors default: throw(std::runtime_error("Unknown NetworkPacket::Type encountered")); @@ -288,6 +300,10 @@ void InWorld::HandlePlayerUpdate(NetworkPacket packet) { playerCharacters[packet.playerInfo.playerIndex].ResetDirection(); } +//------------------------- +//Server control +//------------------------- + void InWorld::SendState() { NetworkPacket packet; char buffer[PACKET_BUFFER_SIZE]; @@ -325,4 +341,12 @@ void InWorld::RequestShutDown() { packet.clientInfo.index = clientIndex; serialize(&packet, buffer); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); +} + +void InWorld::UpdateMap() { + // +} + +void InWorld::RequestRegion(int x, int y) { + // } \ No newline at end of file diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index c6ecd72..b50850c 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -68,15 +68,19 @@ protected: void KeyDown(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&); + //Network handlers void HandlePacket(NetworkPacket); void HandleDisconnect(NetworkPacket); void HandlePlayerNew(NetworkPacket); void HandlePlayerDelete(NetworkPacket); void HandlePlayerUpdate(NetworkPacket); + //Server control void SendState(); void RequestDisconnect(); void RequestShutDown(); + void UpdateMap(); + void RequestRegion(int x, int y); //globals ConfigUtility& config; From 27bda5dc2817194ab08c1f9b6943347eed6d6190 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 6 Apr 2014 02:25:55 +1100 Subject: [PATCH 2/7] Working on the client side map code (read more) I've also added in some debug code to the map classes, because I was hunting down a std::bad_alloc beingthrown. Turns out I forgot to set the map sizes in the client's InWorld constructor. I'm committing the fix, and the debug code. --- client/scenes/in_world.cpp | 64 +++++++++++++++++++++++++++------- client/scenes/in_world.hpp | 2 ++ common/map/map_file_format.cpp | 4 +-- common/map/region.cpp | 12 +++++-- common/map/region_pager.cpp | 46 +++++++++++++++++++++--- common/map/region_pager.hpp | 7 +++- server/server_application.cpp | 2 +- 7 files changed, 113 insertions(+), 24 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index cc8776c..695b54a 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -55,6 +55,11 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet disconnectButton.SetText("Disconnect"); shutDownButton.SetText("Shut Down"); + //setup the map object + mapPager.SetRegionWidth(REGION_WIDTH); + mapPager.SetRegionHeight(REGION_HEIGHT); + mapPager.SetRegionDepth(REGION_DEPTH); + //create the server-side player object NetworkPacket packet; packet.meta.type = NetworkPacket::Type::PLAYER_NEW; @@ -73,6 +78,9 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet packet.meta.type = NetworkPacket::Type::SYNCHRONIZE; serialize(&packet, buffer); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); + + //debug + mapPager.GetRegion(0, 0); } InWorld::~InWorld() { @@ -90,17 +98,6 @@ void InWorld::FrameStart() { void InWorld::Update(double delta) { NetworkPacket packet; - //update the camera - if(localCharacter) { - int marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); - int marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); - camera.x = localCharacter->GetPosition().x - marginX; - camera.y = localCharacter->GetPosition().y - marginY; - } - - //check the map - UpdateMap(); - //suck in all waiting packets while(network.Receive()) { deserialize(&packet, network.GetInData()); @@ -108,9 +105,20 @@ void InWorld::Update(double delta) { HandlePacket(packet); } + //update the characters for (auto& it : playerCharacters) { it.second.Update(delta); } + //TODO: sort the players and entities by Y position + + //update the camera + if(localCharacter) { + camera.x = localCharacter->GetPosition().x - camera.marginX; + camera.y = localCharacter->GetPosition().y - camera.marginY; + } + + //check the map + UpdateMap(); } void InWorld::FrameEnd() { @@ -118,9 +126,15 @@ void InWorld::FrameEnd() { } void InWorld::Render(SDL_Surface* const screen) { + //draw the map + //TODO + + //draw characters for (auto& it : playerCharacters) { it.second.DrawTo(screen, camera.x, camera.y); } + + //draw UI disconnectButton.DrawTo(screen); shutDownButton.DrawTo(screen); } @@ -242,6 +256,9 @@ void InWorld::HandlePacket(NetworkPacket packet) { case NetworkPacket::Type::PLAYER_UPDATE: HandlePlayerUpdate(packet); break; + case NetworkPacket::Type::REGION_CONTENT: + HandleRegionContent(packet); + break; //handle errors default: throw(std::runtime_error("Unknown NetworkPacket::Type encountered")); @@ -269,6 +286,9 @@ void InWorld::HandlePlayerNew(NetworkPacket packet) { if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) { playerIndex = packet.playerInfo.playerIndex; localCharacter = &playerCharacters[playerIndex]; + //center on the player's character + camera.marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); + camera.marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); } } @@ -300,6 +320,15 @@ void InWorld::HandlePlayerUpdate(NetworkPacket packet) { playerCharacters[packet.playerInfo.playerIndex].ResetDirection(); } +void InWorld::HandleRegionContent(NetworkPacket packet) { + //replace existing regions + if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) { + mapPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y); + } + mapPager.PushRegion(packet.regionInfo.region); + packet.regionInfo.region = nullptr; +} + //------------------------- //Server control //------------------------- @@ -348,5 +377,16 @@ void InWorld::UpdateMap() { } void InWorld::RequestRegion(int x, int y) { - // + NetworkPacket packet; + char buffer[PACKET_BUFFER_SIZE]; + + //pack the region's data + packet.meta.type = NetworkPacket::Type::REGION_REQUEST; + packet.regionInfo.width = mapPager.GetRegionWidth(); + packet.regionInfo.height = mapPager.GetRegionHeight(); + packet.regionInfo.depth = mapPager.GetRegionDepth(); + packet.regionInfo.x = x; + packet.regionInfo.y = y; + serialize(&packet, buffer); + network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); } \ No newline at end of file diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index b50850c..c1cd032 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -74,6 +74,7 @@ protected: void HandlePlayerNew(NetworkPacket); void HandlePlayerDelete(NetworkPacket); void HandlePlayerUpdate(NetworkPacket); + void HandleRegionContent(NetworkPacket); //Server control void SendState(); @@ -99,6 +100,7 @@ protected: Button shutDownButton; struct { int x = 0, y = 0; + int marginX = 0, marginY = 0; } camera; //game diff --git a/common/map/map_file_format.cpp b/common/map/map_file_format.cpp index 879d14e..cc9aa7f 100644 --- a/common/map/map_file_format.cpp +++ b/common/map/map_file_format.cpp @@ -24,11 +24,11 @@ #include void DummyFormat::Load(Region** const ptr, int width, int height, int depth, int x, int y) { - //TODO + //EMPTY } void DummyFormat::Save(Region* const ptr) { - //TODO + //EMPTY } /* void VerboseFormat::Load(Region** const ptr, int x, int y) { diff --git a/common/map/region.cpp b/common/map/region.cpp index 8dd701b..e47100c 100644 --- a/common/map/region.cpp +++ b/common/map/region.cpp @@ -21,6 +21,12 @@ */ #include "region.hpp" +#include +#include + +//decorator +#define TRY(x) try { x } catch(std::exception& e) { throw std::runtime_error(std::string() + e.what() + ": " + #x); } + Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY): width(argWidth), height(argHeight), @@ -28,11 +34,11 @@ Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY): x(argX), y(argY) { - tiles = new type_t**[width]; + TRY(tiles = new type_t**[width];) for (register int i = 0; i < width; ++i) { - tiles[i] = new type_t*[height]; + TRY(tiles[i] = new type_t*[height];) for (register int j = 0; j < height; ++j) { - tiles[i][j] = new type_t[depth]; + TRY(tiles[i][j] = new type_t[depth];) for (register int k = 0; k < depth; ++k) { tiles[i][j][k] = 0; } diff --git a/common/map/region_pager.cpp b/common/map/region_pager.cpp index bbef22d..9589b3c 100644 --- a/common/map/region_pager.cpp +++ b/common/map/region_pager.cpp @@ -23,6 +23,11 @@ #include "utility.hpp" +#include +#include + +using namespace std; + RegionPagerBase::RegionPagerBase(int argWidth, int argHeight, int argDepth): regionWidth(argWidth), regionHeight(argHeight), @@ -50,15 +55,46 @@ Region* RegionPagerBase::GetRegion(int x, int y) { x = snapToBase(regionWidth, x); y = snapToBase(regionHeight, y); + //get the region by various means + + //TODO: revert this try/catch point + Region* ptr = nullptr; + try { + ptr = FindRegion(x, y); + if (ptr) return ptr; + } + catch(exception& e) { + cerr << "FindRegion Error: " << e.what() << endl; + } + + try { + ptr = LoadRegion(x, y); + if (ptr) return ptr; + } + catch(exception& e) { + cerr << "LoadRegion Error: " << e.what() << endl; + } + + try { + return CreateRegion(x, y); + } + catch(exception& e) { + cerr << "CreateRegion Error: " << e.what() << endl; + } + return nullptr; +} + +Region* RegionPagerBase::FindRegion(int x, int y) { //find the region for (std::list::iterator it = regionList.begin(); it != regionList.end(); it++) { if ((*it)->GetX() == x && (*it)->GetY() == y) { return *it; } } - - //get the region by other means - Region* ptr = LoadRegion(x, y); - if (ptr) return ptr; - return CreateRegion(x, y); + return nullptr; } + +Region* RegionPagerBase::PushRegion(Region* ptr) { + regionList.push_front(ptr); + return regionList.front(); +} \ No newline at end of file diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp index 016cab9..da07cea 100644 --- a/common/map/region_pager.hpp +++ b/common/map/region_pager.hpp @@ -33,18 +33,23 @@ public: RegionPagerBase(int regionWidth, int regionHeight, int regionDepth); virtual ~RegionPagerBase(); + //tile manipulation Region::type_t SetTile(int x, int y, int z, Region::type_t v); Region::type_t GetTile(int x, int y, int z); + //region manipulation Region* GetRegion(int x, int y); + Region* FindRegion(int x, int y); + Region* PushRegion(Region*); //interface virtual Region* LoadRegion(int x, int y) = 0; 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? - //accessors + //accessors & mutators //NOTE: don't change the sizes mid-program, it will cause issues int SetRegionWidth(int i) { return regionWidth = i; } int SetRegionHeight(int i) { return regionHeight = i; } diff --git a/server/server_application.cpp b/server/server_application.cpp index 9466ce8..3532a63 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -114,7 +114,7 @@ void ServerApplication::Init(int argc, char** argv) { cout << "Startup completed successfully" << endl; //debugging - // + mapPager.GetRegion(0, 0); } void ServerApplication::Loop() { From 99aecbfdbb17b1dcd06ac75ddd7a08140c48c82e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 6 Apr 2014 02:48:43 +1100 Subject: [PATCH 3/7] The client->server->client region protocol is working --- client/scenes/in_world.cpp | 21 ++++++++++++++++----- common/map/region.cpp | 12 +++--------- common/map/region_pager.cpp | 33 +++++---------------------------- server/server_application.cpp | 13 ++++++++++++- server/server_application.hpp | 1 + 5 files changed, 37 insertions(+), 43 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 695b54a..aee7d6b 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -25,6 +25,11 @@ #include +//debugging +#include +using std::cout; +using std::endl; + //------------------------- //Public access members //------------------------- @@ -80,7 +85,7 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); //debug - mapPager.GetRegion(0, 0); + RequestRegion(0, 0); } InWorld::~InWorld() { @@ -327,6 +332,15 @@ void InWorld::HandleRegionContent(NetworkPacket packet) { } mapPager.PushRegion(packet.regionInfo.region); packet.regionInfo.region = nullptr; + + //debugging + cout << "Received region: " << packet.regionInfo.x << ", " << packet.regionInfo.y << endl; + if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) { + cout << "Success" << endl; + } + else { + cout << "Failure" << endl; + } } //------------------------- @@ -373,7 +387,7 @@ void InWorld::RequestShutDown() { } void InWorld::UpdateMap() { - // + //TODO } void InWorld::RequestRegion(int x, int y) { @@ -382,9 +396,6 @@ void InWorld::RequestRegion(int x, int y) { //pack the region's data packet.meta.type = NetworkPacket::Type::REGION_REQUEST; - packet.regionInfo.width = mapPager.GetRegionWidth(); - packet.regionInfo.height = mapPager.GetRegionHeight(); - packet.regionInfo.depth = mapPager.GetRegionDepth(); packet.regionInfo.x = x; packet.regionInfo.y = y; serialize(&packet, buffer); diff --git a/common/map/region.cpp b/common/map/region.cpp index e47100c..8dd701b 100644 --- a/common/map/region.cpp +++ b/common/map/region.cpp @@ -21,12 +21,6 @@ */ #include "region.hpp" -#include -#include - -//decorator -#define TRY(x) try { x } catch(std::exception& e) { throw std::runtime_error(std::string() + e.what() + ": " + #x); } - Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY): width(argWidth), height(argHeight), @@ -34,11 +28,11 @@ Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY): x(argX), y(argY) { - TRY(tiles = new type_t**[width];) + tiles = new type_t**[width]; for (register int i = 0; i < width; ++i) { - TRY(tiles[i] = new type_t*[height];) + tiles[i] = new type_t*[height]; for (register int j = 0; j < height; ++j) { - TRY(tiles[i][j] = new type_t[depth];) + tiles[i][j] = new type_t[depth]; for (register int k = 0; k < depth; ++k) { tiles[i][j][k] = 0; } diff --git a/common/map/region_pager.cpp b/common/map/region_pager.cpp index 9589b3c..8b2517a 100644 --- a/common/map/region_pager.cpp +++ b/common/map/region_pager.cpp @@ -23,11 +23,6 @@ #include "utility.hpp" -#include -#include - -using namespace std; - RegionPagerBase::RegionPagerBase(int argWidth, int argHeight, int argDepth): regionWidth(argWidth), regionHeight(argHeight), @@ -59,29 +54,11 @@ Region* RegionPagerBase::GetRegion(int x, int y) { //TODO: revert this try/catch point Region* ptr = nullptr; - try { - ptr = FindRegion(x, y); - if (ptr) return ptr; - } - catch(exception& e) { - cerr << "FindRegion Error: " << e.what() << endl; - } - - try { - ptr = LoadRegion(x, y); - if (ptr) return ptr; - } - catch(exception& e) { - cerr << "LoadRegion Error: " << e.what() << endl; - } - - try { - return CreateRegion(x, y); - } - catch(exception& e) { - cerr << "CreateRegion Error: " << e.what() << endl; - } - return nullptr; + ptr = FindRegion(x, y); + if (ptr) return ptr; + ptr = LoadRegion(x, y); + if (ptr) return ptr; + return CreateRegion(x, y); } Region* RegionPagerBase::FindRegion(int x, int y) { diff --git a/server/server_application.cpp b/server/server_application.cpp index 3532a63..890809d 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -114,7 +114,7 @@ void ServerApplication::Init(int argc, char** argv) { cout << "Startup completed successfully" << endl; //debugging - mapPager.GetRegion(0, 0); + // } void ServerApplication::Loop() { @@ -180,6 +180,9 @@ void ServerApplication::HandlePacket(NetworkPacket packet) { case NetworkPacket::Type::PLAYER_UPDATE: HandlePlayerUpdate(packet); break; + case NetworkPacket::Type::REGION_REQUEST: + HandleRegionRequest(packet); + break; //handle errors default: throw(runtime_error("Unknown NetworkPacket::Type encountered")); @@ -340,6 +343,14 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { PumpPacket(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); + serialize(&packet, buffer); + network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE); +} + void ServerApplication::PumpPacket(NetworkPacket packet) { //I don't really like this, but it'll do for now char buffer[PACKET_BUFFER_SIZE]; diff --git a/server/server_application.hpp b/server/server_application.hpp index d3d30fa..97610cf 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -81,6 +81,7 @@ private: void HandlePlayerNew(NetworkPacket); void HandlePlayerDelete(NetworkPacket); void HandlePlayerUpdate(NetworkPacket); + void HandleRegionRequest(NetworkPacket); void PumpPacket(NetworkPacket); From 2bacdcdab78016f67cdde4e6fb36445ac1d464b8 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 6 Apr 2014 03:38:58 +1000 Subject: [PATCH 4/7] The basic server map is being displayed in the client --- client/scenes/in_world.cpp | 40 ++++++++++++++++++++++++++++------ client/scenes/in_world.hpp | 9 +++++++- common/graphics/makefile | 2 +- common/graphics/tile_sheet.cpp | 26 +++++++++++++++++++--- common/graphics/tile_sheet.hpp | 5 ++++- editor/editor_scene.cpp | 13 ++++++++--- rsc/scripts/setup_server.lua | 10 +++++++++ 7 files changed, 89 insertions(+), 16 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index aee7d6b..92eacc1 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -60,6 +60,9 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet disconnectButton.SetText("Disconnect"); shutDownButton.SetText("Shut Down"); + //load the tilesheet + tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15); + //setup the map object mapPager.SetRegionWidth(REGION_WIDTH); mapPager.SetRegionHeight(REGION_HEIGHT); @@ -132,7 +135,9 @@ void InWorld::FrameEnd() { void InWorld::Render(SDL_Surface* const screen) { //draw the map - //TODO + ForNearbyRegions([&](Region* const region) { + tileSheet.DrawRegionTo(screen, region, camera.x, camera.y); + }); //draw characters for (auto& it : playerCharacters) { @@ -291,6 +296,9 @@ void InWorld::HandlePlayerNew(NetworkPacket packet) { if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) { playerIndex = packet.playerInfo.playerIndex; localCharacter = &playerCharacters[playerIndex]; + //setup the camera + camera.width = GetScreen()->w; + camera.height = GetScreen()->h; //center on the player's character camera.marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); camera.marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); @@ -355,8 +363,6 @@ void InWorld::SendState() { packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE; packet.playerInfo.clientIndex = clientIndex; packet.playerInfo.playerIndex = playerIndex; -// snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str()); -// snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str()); packet.playerInfo.position = localCharacter->GetPosition(); packet.playerInfo.motion = localCharacter->GetMotion(); @@ -386,10 +392,6 @@ void InWorld::RequestShutDown() { network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); } -void InWorld::UpdateMap() { - //TODO -} - void InWorld::RequestRegion(int x, int y) { NetworkPacket packet; char buffer[PACKET_BUFFER_SIZE]; @@ -400,4 +402,28 @@ void InWorld::RequestRegion(int x, int y) { packet.regionInfo.y = y; serialize(&packet, buffer); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); +} + +//------------------------- +//Utilities +//------------------------- + +void InWorld::UpdateMap() { + //TODO +} + +void InWorld::ForNearbyRegions(std::function func) { + //TODO: switch this to "is nearby" + //this is ugly + for (int i = snapToBase(mapPager.GetRegionWidth() * tileSheet.GetTileW(), camera.x); + i < camera.x + camera.width; + i += mapPager.GetRegionWidth() * tileSheet.GetTileW() + ) { + for (int j = snapToBase(mapPager.GetRegionHeight() * tileSheet.GetTileH(), camera.y); + j < camera.y + camera.height; + j += mapPager.GetRegionHeight() * tileSheet.GetTileH() + ) { + func(mapPager.GetRegion(i, j)); + } + } } \ No newline at end of file diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index c1cd032..b7aa50d 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -36,6 +36,7 @@ #include "image.hpp" #include "raster_font.hpp" #include "button.hpp" +#include "tile_sheet.hpp" //common #include "config_utility.hpp" @@ -45,6 +46,7 @@ #include "player_character.hpp" //STL +#include #include class InWorld : public BaseScene { @@ -80,9 +82,12 @@ protected: void SendState(); void RequestDisconnect(); void RequestShutDown(); - void UpdateMap(); void RequestRegion(int x, int y); + //utilities + void UpdateMap(); + void ForNearbyRegions(std::function func); + //globals ConfigUtility& config; UDPNetworkUtility& network; @@ -91,6 +96,7 @@ protected: //graphics Image buttonImage; RasterFont font; + TileSheet tileSheet; //map RegionPager mapPager; @@ -100,6 +106,7 @@ protected: Button shutDownButton; struct { int x = 0, y = 0; + int width = 0, height = 0; int marginX = 0, marginY = 0; } camera; diff --git a/common/graphics/makefile b/common/graphics/makefile index fb50dee..c1b2927 100644 --- a/common/graphics/makefile +++ b/common/graphics/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. .. +INCLUDES+=. .. ../map LIBS+= CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES)) CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES)) diff --git a/common/graphics/tile_sheet.cpp b/common/graphics/tile_sheet.cpp index ef3153d..cc96ec5 100644 --- a/common/graphics/tile_sheet.cpp +++ b/common/graphics/tile_sheet.cpp @@ -34,8 +34,28 @@ void TileSheet::Unload() { XCount = YCount = 0; } -void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, int tile) { - image.SetClipX(tile % XCount * image.GetClipW()); - image.SetClipY(tile / XCount * image.GetClipH()); +void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile) { + //0 is invisible + if (tile == 0) return; + image.SetClipX((tile-1) % XCount * image.GetClipW()); + image.SetClipY((tile-1) / XCount * image.GetClipH()); image.DrawTo(dest, x, y); } + +void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) { + Region::type_t tile = 0; + for (register int i = 0; i < region->GetWidth(); ++i) { + for (register int j = 0; j < region->GetHeight(); ++j) { + for (register int k = 0; k < region->GetDepth(); ++k) { + tile = region->GetTile(i, j, k); + //0 is invisible + if (tile == 0) continue; + 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); + } + } + } +} \ No newline at end of file diff --git a/common/graphics/tile_sheet.hpp b/common/graphics/tile_sheet.hpp index ce60989..368fcec 100644 --- a/common/graphics/tile_sheet.hpp +++ b/common/graphics/tile_sheet.hpp @@ -22,6 +22,8 @@ #ifndef TILESHEET_HPP_ #define TILESHEET_HPP_ +#include "region.hpp" + #include "image.hpp" #include @@ -35,7 +37,8 @@ public: void Load(std::string fname, int XCount, int YCount); void Unload(); - void DrawTo(SDL_Surface* const dest, int x, int y, int tile); + void DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile); + void DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY); //accessors Image* GetImage() { return ℑ } diff --git a/editor/editor_scene.cpp b/editor/editor_scene.cpp index 19d414b..af3a42c 100644 --- a/editor/editor_scene.cpp +++ b/editor/editor_scene.cpp @@ -61,7 +61,13 @@ EditorScene::EditorScene(ConfigUtility* const arg1): pager.SetRegionDepth(REGION_DEPTH); //debug - tsheet.Load(config["dir.tilesets"] + "sand.bmp", 12, 3); + tsheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15); + for (int i = 0; i < REGION_WIDTH; i++) { + for (int j = 0; j < REGION_HEIGHT; j++) { + pager.SetTile(i, j, 0, 14); + } + } + pager.SetTile(5, 10, 1, 48); } EditorScene::~EditorScene() { @@ -85,7 +91,8 @@ void EditorScene::FrameEnd() { } void EditorScene::Render(SDL_Surface* const screen) { - //debug + tsheet.DrawRegionTo(screen, pager.GetRegion(0, 0), camera.x, camera.y); +/* //debug for (int i = 0; i < pager.GetRegionWidth()*2; i++) { for (int j = 0; j < pager.GetRegionHeight()*2; j++) { for (int k = 0; k < pager.GetRegionDepth(); k++) { @@ -99,7 +106,7 @@ void EditorScene::Render(SDL_Surface* const screen) { } } } - +*/ //draw a big bar across the top (hackish) buttonImage.SetClipY(0); for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) { diff --git a/rsc/scripts/setup_server.lua b/rsc/scripts/setup_server.lua index 4daf1f4..c201054 100644 --- a/rsc/scripts/setup_server.lua +++ b/rsc/scripts/setup_server.lua @@ -2,6 +2,16 @@ print("Lua script check OK (./rsc)") function Region.Create(r) print("Region:Create(r", Region.GetX(r), Region.GetY(r), ")") + for i = 1, Region.GetWidth(r) do + for j = 1, Region.GetHeight(r) do + if math.abs(i) == math.abs(j) then + Region.SetTile(r, i, j, 1, 50) + else + Region.SetTile(r, i, j, 1, 14) + end + end + end + print("done") end function Region.Unload(r) From 553f8dbfa522388ac48a776895b3b3a3245aadc1 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 6 Apr 2014 20:53:51 +1000 Subject: [PATCH 5/7] Fixed some framerate issues --- client/client_application.cpp | 11 +++----- client/scenes/in_world.cpp | 10 ++++++++ client/scenes/in_world.hpp | 3 +++ common/frame_rate.hpp | 48 +++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 common/frame_rate.hpp diff --git a/client/client_application.cpp b/client/client_application.cpp index 2bf9203..c8603b0 100644 --- a/client/client_application.cpp +++ b/client/client_application.cpp @@ -62,7 +62,7 @@ void ClientApplication::Init() { if (SDL_Init(SDL_INIT_VIDEO)) { throw(std::runtime_error("Failed to initialize SDL")); } - BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF : SDL_HWSURFACE); + BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN : SDL_HWSURFACE|SDL_DOUBLEBUF); //initialize SDL_net if (SDLNet_Init()) { @@ -77,7 +77,7 @@ void ClientApplication::Proc() { //prepare the time system typedef std::chrono::steady_clock Clock; - Clock::duration delta(16 * Clock::duration::period::den / std::milli::den); + std::chrono::duration delta(16); Clock::time_point simTime = Clock::now(); Clock::time_point realTime; @@ -95,15 +95,12 @@ void ClientApplication::Proc() { //simulate game time while (simTime < realTime) { //call each user defined function - activeScene->RunFrame(double(delta.count()) / Clock::duration::period::den); + activeScene->RunFrame(double(delta.count()) / std::chrono::duration::period::den); simTime += delta; } //draw the game to the screen activeScene->RenderFrame(); - - //give the computer a break - SDL_Delay(10); } UnloadScene(); @@ -121,7 +118,6 @@ void ClientApplication::Quit() { void ClientApplication::LoadScene(SceneList sceneIndex) { UnloadScene(); - switch(sceneIndex) { //add scene creation calls here case SceneList::FIRST: @@ -143,7 +139,6 @@ void ClientApplication::LoadScene(SceneList sceneIndex) { case SceneList::INCOMBAT: activeScene = new InCombat(); break; - default: throw(std::logic_error("Failed to recognize the scene index")); } diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 92eacc1..2f9cf60 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -133,6 +133,12 @@ void InWorld::FrameEnd() { // } +void InWorld::RenderFrame() { +// SDL_FillRect(GetScreen(), 0, 0); + Render(GetScreen()); + SDL_Flip(GetScreen()); +} + void InWorld::Render(SDL_Surface* const screen) { //draw the map ForNearbyRegions([&](Region* const region) { @@ -147,6 +153,10 @@ void InWorld::Render(SDL_Surface* const screen) { //draw UI disconnectButton.DrawTo(screen); shutDownButton.DrawTo(screen); + + font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0); + + fps.Calculate(); } //------------------------- diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index b7aa50d..41c9082 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -40,6 +40,7 @@ //common #include "config_utility.hpp" +#include "frame_rate.hpp" //client #include "base_scene.hpp" @@ -60,6 +61,7 @@ protected: void FrameStart(); void Update(double delta); void FrameEnd(); + void RenderFrame(); void Render(SDL_Surface* const); //Event handlers @@ -90,6 +92,7 @@ protected: //globals ConfigUtility& config; + FrameRate fps; UDPNetworkUtility& network; int& clientIndex; diff --git a/common/frame_rate.hpp b/common/frame_rate.hpp new file mode 100644 index 0000000..f9b0a6d --- /dev/null +++ b/common/frame_rate.hpp @@ -0,0 +1,48 @@ +/* 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 FRAMERATE_HPP_ +#define FRAMERATE_HPP_ + +#include + +class FrameRate { +public: + typedef std::chrono::high_resolution_clock Clock; + + FrameRate() = default; + int Calculate() { + frameCount++; + if (Clock::now() - tick >= std::chrono::duration(1)) { + lastFrameRate = frameCount; + frameCount = 0; + tick = Clock::now(); + } + return lastFrameRate; + } + int GetFrameRate() { return lastFrameRate; } +private: + int frameCount = 0; + int lastFrameRate = 0; + Clock::time_point tick = Clock::now(); +}; + +#endif From c8a58ab515bb7fac8bedc3e3747feedd8369f59e Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 7 Apr 2014 01:24:05 +1000 Subject: [PATCH 6/7] Wrote a potentially buggy algorithm This algorithm is designed to find the distance of a certain region, however it may have been better to do a quick check, rather than worrying how many regions were loaded at once. --- client/scenes/in_world.cpp | 50 ++++++++++++++++++++++++++++++++++++++ client/scenes/in_world.hpp | 1 + 2 files changed, 51 insertions(+) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 2f9cf60..7d53da4 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -23,6 +23,8 @@ #include "channels.hpp" +#include +#include #include //debugging @@ -418,6 +420,54 @@ void InWorld::RequestRegion(int x, int y) { //Utilities //------------------------- +int InWorld::CheckBufferDistance(Region* const region) { + /* 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 >= -mapPager.GetRegionWidth() * tileSheet.GetTileW() && x < camera.width && + y >= -mapPager.GetRegionHeight() * tileSheet.GetTileH() && y < camera.height) { + return -1; + } + + //prune the screen's area from the algorithm; get the pseudo-indexes + if (x < 0) x /= (mapPager.GetRegionWidth() * tileSheet.GetTileW()); + if (y < 0) y /= (mapPager.GetRegionHeight() * tileSheet.GetTileH()); + if (x > 0) x = (x - camera.width) / (mapPager.GetRegionWidth() * tileSheet.GetTileW()) + 1; + if (y > 0) y = (y - camera.height) / (mapPager.GetRegionHeight() * tileSheet.GetTileH()) + 1; + + //return the pseudo-index with the greatest magnitude + return std::max(abs(x), abs(y)); +} + void InWorld::UpdateMap() { //TODO } diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 41c9082..10fd02b 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -87,6 +87,7 @@ protected: void RequestRegion(int x, int y); //utilities + int CheckBufferDistance(Region* const); void UpdateMap(); void ForNearbyRegions(std::function func); From 0453f6becf6b53687244e04a4b4862b998a3f0c2 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 7 Apr 2014 02:56:48 +1000 Subject: [PATCH 7/7] The map paging is functional --- client/scenes/in_world.cpp | 48 ++++++++++++++++++++++--------------- client/scenes/in_world.hpp | 2 -- common/map/region_pager.hpp | 2 ++ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp index 7d53da4..2f72466 100644 --- a/client/scenes/in_world.cpp +++ b/client/scenes/in_world.cpp @@ -90,7 +90,7 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); //debug - RequestRegion(0, 0); +// RequestRegion(0, 0); } InWorld::~InWorld() { @@ -143,9 +143,9 @@ void InWorld::RenderFrame() { void InWorld::Render(SDL_Surface* const screen) { //draw the map - ForNearbyRegions([&](Region* const region) { - tileSheet.DrawRegionTo(screen, region, camera.x, camera.y); - }); + for (auto it = mapPager.GetContainer()->begin(); it != mapPager.GetContainer()->end(); it++) { + tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y); + } //draw characters for (auto& it : playerCharacters) { @@ -469,21 +469,31 @@ int InWorld::CheckBufferDistance(Region* const region) { } void InWorld::UpdateMap() { - //TODO -} + //prune distant regions + for (auto it = mapPager.GetContainer()->begin(); it != mapPager.GetContainer()->end(); /* EMPTY */) { + if (CheckBufferDistance(*it) > 2) { + //debugging + cout << "unloading: " << (*it)->GetX() << ", " << (*it)->GetY() << endl; -void InWorld::ForNearbyRegions(std::function func) { - //TODO: switch this to "is nearby" - //this is ugly - for (int i = snapToBase(mapPager.GetRegionWidth() * tileSheet.GetTileW(), camera.x); - i < camera.x + camera.width; - i += mapPager.GetRegionWidth() * tileSheet.GetTileW() - ) { - for (int j = snapToBase(mapPager.GetRegionHeight() * tileSheet.GetTileH(), camera.y); - j < camera.y + camera.height; - j += mapPager.GetRegionHeight() * tileSheet.GetTileH() - ) { - func(mapPager.GetRegion(i, j)); + mapPager.UnloadRegion((*it)->GetX(), (*it)->GetY()); + + //reset + it = mapPager.GetContainer()->begin(); + continue; + } + ++it; + } + + //TODO: make the region units official + int regionUnitX = mapPager.GetRegionWidth() * tileSheet.GetTileW(); + int regionUnitY = mapPager.GetRegionHeight() * 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) { + if (!mapPager.FindRegion(i, j)) { + RequestRegion(i, j); + } } } -} \ No newline at end of file +} diff --git a/client/scenes/in_world.hpp b/client/scenes/in_world.hpp index 10fd02b..278c007 100644 --- a/client/scenes/in_world.hpp +++ b/client/scenes/in_world.hpp @@ -47,7 +47,6 @@ #include "player_character.hpp" //STL -#include #include class InWorld : public BaseScene { @@ -89,7 +88,6 @@ protected: //utilities int CheckBufferDistance(Region* const); void UpdateMap(); - void ForNearbyRegions(std::function func); //globals ConfigUtility& config; diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp index da07cea..bc48505 100644 --- a/common/map/region_pager.hpp +++ b/common/map/region_pager.hpp @@ -58,6 +58,8 @@ public: int GetRegionWidth() const { return regionWidth; } int GetRegionHeight() const { return regionHeight; } int GetRegionDepth() const { return regionDepth; } + + std::list* GetContainer() { return ®ionList; } protected: int regionWidth; int regionHeight;