diff --git a/common/gameplay/character_data.hpp b/common/gameplay/character_data.hpp index ff129b2..361788b 100644 --- a/common/gameplay/character_data.hpp +++ b/common/gameplay/character_data.hpp @@ -45,7 +45,7 @@ struct CharacterData { std::string avatar; //world position - int mapIndex = 0; + int roomIndex = 0; Vector2 origin = {0.0,0.0}; Vector2 motion = {0.0,0.0}; Vector2 bounds = {0.0,0.0}; diff --git a/common/map/map_file_format.hpp b/common/map/map_file_format.hpp index 92f0c8d..75f5204 100644 --- a/common/map/map_file_format.hpp +++ b/common/map/map_file_format.hpp @@ -28,6 +28,8 @@ #include +//TODO: I'm unhappy with using this system, there needs to be a way to handle saving/loading better + class DummyFormat { public: void Load(Region** const, int x, int y); diff --git a/common/map/region.hpp b/common/map/region.hpp index 560161b..4c0d2cd 100644 --- a/common/map/region.hpp +++ b/common/map/region.hpp @@ -22,9 +22,9 @@ #ifndef REGION_HPP_ #define REGION_HPP_ -#define REGION_WIDTH 20 -#define REGION_HEIGHT 20 -#define REGION_DEPTH 3 +constexpr int REGION_WIDTH = 20; +constexpr int REGION_HEIGHT = 20; +constexpr int REGION_DEPTH = 3; class Region { public: diff --git a/common/script/map_api.cpp b/common/script/map_api.cpp index 9ecfea4..0bcaf80 100644 --- a/common/script/map_api.cpp +++ b/common/script/map_api.cpp @@ -27,6 +27,8 @@ #include "region_pager.hpp" //NOTE: When operating on a region, setTile() & getTile() *are not* zero indexed, but when operating on the entire map they *are* zero indexed. +//TODO: enforce all possible parameter counts +//TODO: update the map API to handle multiple rooms static int setTile(lua_State* L) { if (lua_gettop(L) == 5) { diff --git a/rsc/scripts/setup_server.sql b/rsc/scripts/setup_server.sql index 04a6aab..88d0a82 100644 --- a/rsc/scripts/setup_server.sql +++ b/rsc/scripts/setup_server.sql @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS Characters ( birth timestamp NOT NULL DEFAULT (datetime()), --position - mapIndex INTEGER DEFAULT 0, + roomIndex INTEGER DEFAULT 0, originX INTEGER DEFAULT 0, originY INTEGER DEFAULT 0, diff --git a/server/character_manager.cpp b/server/character_manager.cpp index 34310c9..5767e60 100644 --- a/server/character_manager.cpp +++ b/server/character_manager.cpp @@ -33,7 +33,7 @@ static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, av static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;"; static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET " - "mapIndex = ?2," + "roomIndex = ?2," "originX = ?3," "originY = ?4," "level = ?5," @@ -148,7 +148,7 @@ int CharacterManager::LoadCharacter(int owner, std::string handle, std::string a //Don't cache the birth //world origin - newChar.mapIndex = sqlite3_column_int(statement, 5); + newChar.roomIndex = sqlite3_column_int(statement, 5); newChar.origin.x = (double)sqlite3_column_int(statement, 6); newChar.origin.y = (double)sqlite3_column_int(statement, 7); @@ -208,7 +208,7 @@ int CharacterManager::SaveCharacter(int uid) { //parameters bool ret = false; ret |= sqlite3_bind_int(statement, 1, uid) != SQLITE_OK; - ret |= sqlite3_bind_int(statement, 2, character.mapIndex) != SQLITE_OK; + ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK; diff --git a/server/room_data.hpp b/server/room_data.hpp index 6826314..c436d54 100644 --- a/server/room_data.hpp +++ b/server/room_data.hpp @@ -22,6 +22,11 @@ #ifndef ROOMDATA_HPP_ #define ROOMDATA_HPP_ +//map system +#include "map_allocator.hpp" +#include "map_file_format.hpp" +#include "region_pager.hpp" + struct RoomData { enum class RoomType { OVERWORLD, @@ -31,11 +36,12 @@ struct RoomData { CAVES, }; - /* TODO: more - * "multiple rooms system" using this structure - * Pager - * collision map - */ + //members + RegionPager pager; + RoomType type; + + //TODO: collision map + //TODO: NPCs? }; #endif diff --git a/server/room_manager.hpp b/server/room_manager.hpp index 9b1dfc6..2caadaa 100644 --- a/server/room_manager.hpp +++ b/server/room_manager.hpp @@ -35,6 +35,7 @@ public: //public access methods //TODO + //TODO: setup the pagers and functors of each room object //accessors and mutators RoomData* GetRoom(int uid); diff --git a/server/server_application.cpp b/server/server_application.cpp index 7ef5f45..836af2b 100644 --- a/server/server_application.cpp +++ b/server/server_application.cpp @@ -174,14 +174,14 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) { //character management case SerialPacketType::CHARACTER_NEW: - HandleCharacterNew(dynamic_cast(argPacket)); + HandleCharacterNew(dynamic_cast(argPacket)); break; case SerialPacketType::CHARACTER_DELETE: - HandleCharacterDelete(dynamic_cast(argPacket)); + HandleCharacterDelete(dynamic_cast(argPacket)); break; case SerialPacketType::CHARACTER_UPDATE: case SerialPacketType::CHARACTER_STATS_REQUEST: //TODO: ? - HandleCharacterUpdate(dynamic_cast(argPacket)); + HandleCharacterUpdate(dynamic_cast(argPacket)); break; //enemy management @@ -189,7 +189,7 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) { //mismanagement case SerialPacketType::SYNCHRONIZE: - HandleSynchronize(dynamic_cast(argPacket)); + HandleSynchronize(dynamic_cast(argPacket)); break; //handle errors @@ -296,7 +296,7 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { newPacket.x = argPacket->x; newPacket.y = argPacket->y; - newPacket.region = roomMgr.GetRoom(argPacket->roomIndex)->GetPager()->GetRegion(argPacket->x, argPacket->y); + newPacket.region = roomMgr.GetRoom(argPacket->roomIndex)->pager.GetRegion(argPacket->x, argPacket->y); //send the content network.SendTo(&argPacket->srcAddress, dynamic_cast(argPacket)); @@ -312,25 +312,46 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { //Character Management //------------------------- -void ServerApplication::HandleCharacterNew(SerialPacket) { +void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { //TODO: fill this } -void ServerApplication::HandleCharacterDelete(SerialPacket) { +void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) { //TODO: fill this } -void ServerApplication::HandleCharacterUpdate(SerialPacket packet) { - //TODO: this should be moved elsewhere - if (characterMap.find(packet.characterInfo.characterIndex) == characterMap.end()) { - throw(std::runtime_error("Cannot update a non-existant character")); +void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) { + CharacterData* character = characterMgr.GetCharacter(argPacket->characterIndex); + + //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; } - //TODO: the server needs it's own movement system too - characterMap[packet.characterInfo.characterIndex].origin = packet.characterInfo.origin; - characterMap[packet.characterInfo.characterIndex].motion = packet.characterInfo.motion; + /* 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. + */ + character->roomIndex = argPacket->roomIndex; + character->origin = argPacket->origin; + character->motion = argPacket->motion; - PumpPacket(packet); + character->stats = argPacket->stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + PumpPacket(argPacket); } //------------------------- @@ -343,26 +364,29 @@ void ServerApplication::HandleCharacterUpdate(SerialPacket packet) { //mismanagement //------------------------- -void ServerApplication::HandleSynchronize(SerialPacket packet) { +void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) { //TODO: compensate for large distances + //TODO: I quite dislike this function //send all the server's data to this client - SerialPacket newPacket; + CharacterPacket characterPacket; //characters - newPacket.meta.type = SerialPacket::Type::CHARACTER_UPDATE; - for (auto& it : characterMap) { + characterPacket.type = SerialPacketType::CHARACTER_UPDATE; + for (auto& it : *characterMgr.GetContainer()) { //TODO: update this for the expanded CharacterData structure - newPacket.characterInfo.characterIndex = it.first; - snprintf(newPacket.characterInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); - snprintf(newPacket.characterInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); - newPacket.characterInfo.mapIndex = it.second.mapIndex; - newPacket.characterInfo.origin = it.second.origin; - newPacket.characterInfo.motion = it.second.motion; - newPacket.characterInfo.stats = it.second.stats; + characterPacket.characterIndex = it.first; + snprintf(characterPacket.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); + snprintf(characterPacket.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); + characterPacket.roomIndex = it.second.roomIndex; + characterPacket.origin = it.second.origin; + characterPacket.motion = it.second.motion; + characterPacket.stats = it.second.stats; - network.SendTo(&clientMap[packet.clientInfo.clientIndex].address, &newPacket); + network.SendTo(&clientMap[argPacket->clientIndex].address, dynamic_cast(&characterPacket)); } + + //TODO: more } //------------------------- @@ -371,17 +395,16 @@ void ServerApplication::HandleSynchronize(SerialPacket packet) { //TODO: a function that only sends to characters in a certain proximity -void ServerApplication::PumpPacket(SerialPacket packet) { - //NOTE: I don't really like this, but it'll do for now +void ServerApplication::PumpPacket(SerialPacket* const argPacket) { for (auto& it : clientMap) { - network.SendTo(&it.second.address, &packet); + network.SendTo(&it.second.address, argPacket); } } void ServerApplication::PumpCharacterUnload(int uid) { //delete the client-side character(s) - SerialPacket delPacket; - delPacket.meta.type = SerialPacket::Type::CHARACTER_DELETE; - delPacket.characterInfo.characterIndex = uid; - PumpPacket(delPacket); + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_DELETE; + newPacket.characterIndex = uid; + PumpPacket(dynamic_cast(&newPacket)); } diff --git a/server/server_application.hpp b/server/server_application.hpp index a0cb9b3..05168df 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -30,11 +30,6 @@ #include "enemy_manager.hpp" #include "room_manager.hpp" -//maps -#include "map_allocator.hpp" -#include "map_file_format.hpp" -#include "region_pager.hpp" - //common utilities #include "udp_network_utility.hpp" #include "config_utility.hpp" @@ -76,15 +71,15 @@ private: //TODO: combat management //character management - void HandleCharacterNew(SerialPacket* const); - void HandleCharacterDelete(SerialPacket* const); - void HandleCharacterUpdate(SerialPacket* const); + void HandleCharacterNew(CharacterPacket* const); + void HandleCharacterDelete(CharacterPacket* const); + void HandleCharacterUpdate(CharacterPacket* const); //enemy management //TODO: enemy management //mismanagement - void HandleSynchronize(SerialPacket* const); + void HandleSynchronize(ClientPacket* const); //utility methods //TODO: a function that only sends to characters in a certain proximity