diff --git a/client/in_combat.hpp b/client/in_combat.hpp index d345037..6b31bc6 100644 --- a/client/in_combat.hpp +++ b/client/in_combat.hpp @@ -75,14 +75,12 @@ protected: //Network handlers void HandlePacket(SerialPacket* const); void HandleDisconnect(SerialPacket* const); - //TODO: more network handlers //Server control void RequestSynchronize(); void SendPlayerUpdate(); void RequestDisconnect(); void RequestShutdown(); - //TODO: more //shared parameters ConfigUtility& config; diff --git a/client/in_world.cpp b/client/in_world.cpp index 4557a9b..5301aa8 100644 --- a/client/in_world.cpp +++ b/client/in_world.cpp @@ -24,9 +24,10 @@ #include "channels.hpp" #include "utility.hpp" +#include #include #include -#include +#include //------------------------- //Public access members @@ -106,6 +107,8 @@ void InWorld::Update(double delta) { it.second.Update(delta); } + //TODO: Check collisions here + //update the camera if(localCharacter) { camera.x = localCharacter->origin.x - camera.marginX; @@ -288,15 +291,20 @@ void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) { //create the character object CharacterData& character = characterMap[argPacket->characterIndex]; - //set the members + //fill out the character's members character.handle = argPacket->handle; character.avatar = argPacket->avatar; + character.sprite.LoadSurface(config["dir.sprites"] + character.avatar, 4, 4); + character.bounds = {CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}; + character.roomIndex = argPacket->roomIndex; character.origin = argPacket->origin; character.motion = argPacket->motion; + character.stats = argPacket->stats; + //bookkeeping code character.CorrectSprite(); //catch this client's player object @@ -316,6 +324,7 @@ void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) { void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { //TODO: authenticate when own character is being deleted (linked to a TODO in the server) + //catch this client's player object if (argPacket->characterIndex == characterIndex) { characterIndex = -1; @@ -327,6 +336,7 @@ 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; } @@ -364,6 +374,8 @@ void InWorld::RequestSynchronize() { newPacket.clientIndex = clientIndex; newPacket.accountIndex = accountIndex; + //TODO: location, range for sync request + network.SendTo(Channels::SERVER, &newPacket); } @@ -374,7 +386,7 @@ void InWorld::SendPlayerUpdate() { newPacket.type = SerialPacketType::CHARACTER_UPDATE; newPacket.characterIndex = characterIndex; - //handle, avatar + //NOTE: omitting the handle and avatar here newPacket.accountIndex = accountIndex; newPacket.roomIndex = localCharacter->roomIndex; newPacket.origin = localCharacter->origin; @@ -435,7 +447,7 @@ void InWorld::UpdateMap() { //prune distant regions for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { - //check if the region is outside off this area + //check if the region is outside of this area if (it->GetX() < xStart || it->GetX() > xEnd || it->GetY() < yStart || it->GetY() > yEnd) { //clunky, but the alternative was time consuming diff --git a/common/gameplay/character_data.hpp b/common/gameplay/character_data.hpp index 46452b4..fd9f553 100644 --- a/common/gameplay/character_data.hpp +++ b/common/gameplay/character_data.hpp @@ -38,6 +38,10 @@ constexpr double CHARACTER_WALKING_SPEED = 140.0; constexpr double CHARACTER_WALKING_MOD = 1.0/sqrt(2.0); +//the bounding boxes for the characters +constexpr double CHARACTER_BOUNDS_WIDTH = 32.0; +constexpr double CHARACTER_BOUNDS_HEIGHT = 32.0; + struct CharacterData { //metadata int owner; @@ -48,7 +52,6 @@ struct CharacterData { int roomIndex = 0; Vector2 origin = {0.0,0.0}; Vector2 motion = {0.0,0.0}; - Vector2 bounds = {0.0,0.0}; //base statistics Statistics stats; @@ -65,6 +68,7 @@ struct CharacterData { //active gameplay members //NOTE: these are lost when unloaded #ifdef GRAPHICS + Vector2 bounds = {0.0,0.0}; SpriteSheet sprite; #endif bool inCombat = false; diff --git a/common/map/region.cpp b/common/map/region.cpp index 8de957b..c4fb712 100644 --- a/common/map/region.cpp +++ b/common/map/region.cpp @@ -35,6 +35,7 @@ Region::Region(int argX, int argY): x(argX), y(argY) { Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) { memcpy(tiles, rhs.tiles, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t)); + solid = rhs.solid; } Region::type_t Region::SetTile(int x, int y, int z, type_t v) { @@ -44,3 +45,11 @@ Region::type_t Region::SetTile(int x, int y, int z, type_t v) { Region::type_t Region::GetTile(int x, int y, int z) { return tiles[x][y][z]; } + +bool Region::SetSolid(int x, int y, bool b) { + return solid[x * REGION_WIDTH + y] = b; +} + +bool Region::GetSolid(int x, int y) { + return solid[x * REGION_WIDTH + y]; +} \ No newline at end of file diff --git a/common/map/region.hpp b/common/map/region.hpp index 74fc013..0571c09 100644 --- a/common/map/region.hpp +++ b/common/map/region.hpp @@ -22,10 +22,17 @@ #ifndef REGION_HPP_ #define REGION_HPP_ +#include +#include + +//the region's storage format constexpr int REGION_WIDTH = 20; constexpr int REGION_HEIGHT = 20; constexpr int REGION_DEPTH = 3; +//the size of the solid map +constexpr int REGION_SOLID_FOOTPRINT = ceil(REGION_WIDTH * REGION_HEIGHT / 8.0); + class Region { public: typedef unsigned char type_t; @@ -38,14 +45,23 @@ public: type_t SetTile(int x, int y, int z, type_t v); type_t GetTile(int x, int y, int z); + bool SetSolid(int x, int y, bool b); + bool GetSolid(int x, int y); + //accessors int GetX() const { return x; } int GetY() const { return y; } + + std::bitset* GetSolidBitset() { return &solid; } private: const int x; const int y; type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH]; + std::bitset solid; }; +//the memory footprint of the tile and solid data; not including any metadata +constexpr int REGION_FOOTPRINT = REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + REGION_SOLID_FOOTPRINT; + #endif diff --git a/common/map/region_api.cpp b/common/map/region_api.cpp index fdff4f7..014a873 100644 --- a/common/map/region_api.cpp +++ b/common/map/region_api.cpp @@ -37,6 +37,20 @@ static int getTile(lua_State* L) { return 1; } +static int setSolid(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = region->SetSolid(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_toboolean(L, 4)); + lua_pushboolean(L, ret); + return 1; +} + +static int getSolid(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = region->GetSolid(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1); + lua_pushboolean(L, ret); + return 1; +} + static int getX(lua_State* L) { Region* region = reinterpret_cast(lua_touserdata(L, 1)); lua_pushinteger(L, region->GetX()); @@ -85,9 +99,12 @@ static int onUnload(lua_State* L) { return 0; } +//TODO: wrappers for the collision map static const luaL_Reg regionLib[] = { {"SetTile",setTile}, {"GetTile",getTile}, + {"SetSolid",setSolid}, + {"GetSolid",getSolid}, {"GetX",getX}, {"GetY",getY}, {"GetWidth",getWidth}, diff --git a/common/map/region_pager_api.cpp b/common/map/region_pager_api.cpp index f38d1e2..40c4d76 100644 --- a/common/map/region_pager_api.cpp +++ b/common/map/region_pager_api.cpp @@ -43,6 +43,20 @@ static int getTile(lua_State* L) { return 1; } +static int setSolid(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = pager->SetSolid(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_toboolean(L, 4)); + lua_pushboolean(L, ret); + return 1; +} + +static int getSolid(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + bool ret = pager->GetSolid(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushboolean(L, ret); + return 1; +} + static int getRegion(lua_State* L) { RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); @@ -94,6 +108,8 @@ static int unloadRegion(lua_State* L) { static const luaL_Reg pagerlib[] = { {"SetTile", setTile}, {"GetTile", getTile}, + {"SetSolid", setSolid}, + {"GetSolid", getSolid}, {"GetRegion", getRegion}, {"SetDirectory", setDirectory}, {"GetDirectory", getDirectory}, diff --git a/common/map/region_pager_base.cpp b/common/map/region_pager_base.cpp index a8ad76f..fbe633d 100644 --- a/common/map/region_pager_base.cpp +++ b/common/map/region_pager_base.cpp @@ -36,6 +36,16 @@ Region::type_t RegionPagerBase::GetTile(int x, int y, int z) { return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z); } +bool RegionPagerBase::SetSolid(int x, int y, int b) { + Region* ptr = GetRegion(x, y); + return ptr->SetSolid(x - ptr->GetX(), y - ptr->GetY(), b); +} + +bool RegionPagerBase::GetSolid(int x, int y) { + Region* ptr = GetRegion(x, y); + return ptr->GetSolid(x - ptr->GetX(), y - ptr->GetY()); +} + Region* RegionPagerBase::GetRegion(int x, int y) { //get the region by various means Region* ptr = nullptr; diff --git a/common/map/region_pager_base.hpp b/common/map/region_pager_base.hpp index 004faa4..53bb097 100644 --- a/common/map/region_pager_base.hpp +++ b/common/map/region_pager_base.hpp @@ -35,6 +35,10 @@ public: virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v); virtual Region::type_t GetTile(int x, int y, int z); + //solid manipulation + virtual bool SetSolid(int x, int y, int b); + virtual bool GetSolid(int x, int y); + //region manipulation virtual Region* GetRegion(int x, int y); virtual Region* FindRegion(int x, int y); diff --git a/common/network/packet/serial_packet_base.hpp b/common/network/packet/serial_packet_base.hpp index 156d1e5..2f82092 100644 --- a/common/network/packet/serial_packet_base.hpp +++ b/common/network/packet/serial_packet_base.hpp @@ -30,7 +30,7 @@ #include "SDL/SDL_net.h" -constexpr int NETWORK_VERSION = 20140607; +constexpr int NETWORK_VERSION = 20140701; constexpr int PACKET_STRING_SIZE = 100; struct SerialPacketBase { diff --git a/common/network/serial/serial.hpp b/common/network/serial/serial.hpp index 02d5dba..2a948bd 100644 --- a/common/network/serial/serial.hpp +++ b/common/network/serial/serial.hpp @@ -53,13 +53,15 @@ void deserializeRegionContent(RegionPacket*, void*); void deserializeServer(ServerPacket*, void*); void deserializeStatistics(Statistics*, void*); -/* DOCS: Keep the PACKET_BUFFER_SIZE up to date - * DOCS: REGION_CONTENT is currently the largest type of packet, read more - * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t) - * map format: sizeof(int) * 3 - * metadata: sizeof(SerialPacket::Type) +/* DOCS: Keep PACKET_BUFFER_SIZE up to date + * DOCS: SerialPacketType::REGION_CONTENT is currently the largest type of packet, read more + * The metadata used are: + * SerialPacketType + * room index + * X & Y positon + * The rest is taken up by the Regions's content. */ -constexpr int PACKET_BUFFER_SIZE = REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacketType); +constexpr int PACKET_BUFFER_SIZE = sizeof(SerialPacketType) + sizeof(int) * 3 + REGION_FOOTPRINT; #endif \ No newline at end of file diff --git a/common/network/serial/serial_region.cpp b/common/network/serial/serial_region.cpp index 31145bd..5aec454 100644 --- a/common/network/serial/serial_region.cpp +++ b/common/network/serial/serial_region.cpp @@ -40,7 +40,7 @@ void serializeRegionContent(RegionPacket* packet, void* buffer) { SERIALIZE(buffer, &packet->x, sizeof(int)); SERIALIZE(buffer, &packet->y, sizeof(int)); - //content + //tiles for (register int i = 0; i < REGION_WIDTH; i++) { for (register int j = 0; j < REGION_HEIGHT; j++) { for (register int k = 0; k < REGION_DEPTH; k++) { @@ -49,6 +49,9 @@ void serializeRegionContent(RegionPacket* packet, void* buffer) { } } } + + //solids + SERIALIZE(buffer, packet->region->GetSolidBitset(), REGION_SOLID_FOOTPRINT); } void deserializeRegionFormat(RegionPacket* packet, void* buffer) { @@ -71,7 +74,7 @@ void deserializeRegionContent(RegionPacket* packet, void* buffer) { //an object to work on packet->region = new Region(packet->x, packet->y); - //content + //tiles for (register int i = 0; i < REGION_WIDTH; i++) { for (register int j = 0; j < REGION_HEIGHT; j++) { for (register int k = 0; k < REGION_DEPTH; k++) { @@ -80,4 +83,7 @@ void deserializeRegionContent(RegionPacket* packet, void* buffer) { } } } + + //solids + DESERIALIZE(buffer, packet->region->GetSolidBitset(), REGION_SOLID_FOOTPRINT); } \ No newline at end of file diff --git a/rsc/scripts/setup_server.lua b/rsc/scripts/setup_server.lua index 6bc65f0..582cacf 100644 --- a/rsc/scripts/setup_server.lua +++ b/rsc/scripts/setup_server.lua @@ -1,4 +1,4 @@ -print("Lua script check (./rsc)") +print("Lua script check") --uber lazy declarations function square(x) return x*x end @@ -19,10 +19,13 @@ Region.OnCreate = function(region) local ret = Region.hcOnCreate(region) --best practices for i = 1, Region.GetWidth() do for j = 1, Region.GetHeight() do - if distance(0, 0, i + Region.GetX(region) -1, j + Region.GetY(region) -1) > 10 then - Region.SetTile(region, i, j, 1, water) - else + local dist = distance(0, 0, i + Region.GetX(region) -1, j + Region.GetY(region) -1) + if dist < 10 then Region.SetTile(region, i, j, 1, plains) + elseif dist < 12 then + Region.SetTile(region, i, j, 1, sand) + else + Region.SetTile(region, i, j, 1, water) end end end @@ -33,10 +36,10 @@ end newRoom = RoomMgr.CreateRoom("overworld") pager = Room.GetPager(newRoom) regionTable = { - RegionPager.GetRegion(pager, 0, 0), - RegionPager.GetRegion(pager, 0, -20), - RegionPager.GetRegion(pager, -20, 0), - RegionPager.GetRegion(pager, -20, -20) + RegionPager.GetRegion(pager, Region.GetWidth() * 0, Region.GetHeight() * 0), + RegionPager.GetRegion(pager, Region.GetWidth() *-1, Region.GetHeight() * 0), + RegionPager.GetRegion(pager, Region.GetWidth() * 0, Region.GetHeight() *-1), + RegionPager.GetRegion(pager, Region.GetWidth() *-1, Region.GetHeight() *-1) } print("Finished the lua script") \ No newline at end of file diff --git a/server/server_application.cpp b/server/server_application.cpp index d9d763e..7396cda 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -113,12 +113,23 @@ void ServerApplication::Init(int argc, char** argv) { //debug output //------------------------- + //TODO: put these outputs into the client too + //TODO: enable/disable these with a switch +#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl; + std::cout << "Internal sizes:" << std::endl; - std::cout << "\tTile Size: " << sizeof(Region::type_t) << std::endl; - std::cout << "\tRegion Format: " << REGION_WIDTH << ", " << REGION_HEIGHT << ", " << REGION_DEPTH << std::endl; - std::cout << "\tRegion Content Footprint: " << REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) << std::endl; - std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl; - std::cout << "\tMAX_PACKET_SIZE: " << MAX_PACKET_SIZE << std::endl; + + DEBUG_OUTPUT_VAR(sizeof(Region::type_t)); + DEBUG_OUTPUT_VAR(sizeof(Region)); + DEBUG_OUTPUT_VAR(REGION_WIDTH); + DEBUG_OUTPUT_VAR(REGION_HEIGHT); + DEBUG_OUTPUT_VAR(REGION_DEPTH); + DEBUG_OUTPUT_VAR(REGION_SOLID_FOOTPRINT); + DEBUG_OUTPUT_VAR(REGION_FOOTPRINT); + DEBUG_OUTPUT_VAR(PACKET_BUFFER_SIZE); + DEBUG_OUTPUT_VAR(MAX_PACKET_SIZE); + +#undef DEBUG_OUTPUT_VAR //------------------------- //finalize the startup @@ -141,7 +152,8 @@ void ServerApplication::Proc() { HandlePacket(packetBuffer); } //update the internals - //TODO: update the internals i.e. player positions + //BUG: #30 Update the internals i.e. player positions + //give the computer a break SDL_Delay(10); } @@ -269,6 +281,16 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) { //TODO: authenticate who is disconnecting/kicking + /*Pseudocode: + if sender's account index -> client index -> address == sender's address then + continue + end + if sender's account index -> admin == true OR sender's account index -> mod == true then + continue + end + if neither of the above is true, then output a warning to the console, and return + */ + //forward to the specified client network.SendTo( @@ -296,6 +318,12 @@ void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) { void ServerApplication::HandleShutdown(SerialPacket* const argPacket) { //TODO: authenticate who is shutting the server down + /*Pseudocode: + if sender's account -> admin is not true then + print a warning + return + end + */ //end the server running = false; @@ -399,15 +427,7 @@ void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) return; } - /* TODO: rewrite this design flaw, read more - * Slaving the client to the server here is a terrible idea, instead there - * needs to be a utility function to update and send the server-side character - * to the clients. - * - * Other things to consider include functionality to reequip the character, - * apply status effects and to change the stats as well. These should all be - * handled server-side. - */ + //accept client-side logic character->roomIndex = argPacket->roomIndex; character->origin = argPacket->origin; character->motion = argPacket->motion;