diff --git a/client/scenes/base_scene.cpp b/client/base_scene.cpp similarity index 98% rename from client/scenes/base_scene.cpp rename to client/base_scene.cpp index ba62b4c..816f80b 100644 --- a/client/scenes/base_scene.cpp +++ b/client/base_scene.cpp @@ -127,7 +127,7 @@ void BaseScene::HandleEvents() { break; #ifdef USE_EVENT_JOYSTICK - //TODO: joystick/gamepad support + //EMPTY #endif #ifdef USE_EVENT_UNKNOWN diff --git a/client/scenes/base_scene.hpp b/client/base_scene.hpp similarity index 98% rename from client/scenes/base_scene.hpp rename to client/base_scene.hpp index 453ab75..aae6161 100644 --- a/client/scenes/base_scene.hpp +++ b/client/base_scene.hpp @@ -59,7 +59,7 @@ protected: virtual void KeyUp(SDL_KeyboardEvent const&) {} #ifdef USE_EVENT_JOYSTICK - //TODO: joystick/gamepad support + //EMPTY #endif #ifdef USE_EVENT_UNKNOWN diff --git a/client/client_application.cpp b/client/client_application.cpp index 70957fe..caf465d 100644 --- a/client/client_application.cpp +++ b/client/client_application.cpp @@ -37,7 +37,7 @@ #include "main_menu.hpp" #include "options_menu.hpp" #include "lobby_menu.hpp" -#include "in_world.hpp" +#include "world.hpp" #include "disconnected_screen.hpp" //------------------------- @@ -83,7 +83,6 @@ void ClientApplication::Init(int argc, char* argv[]) { //debug output //------------------------- - //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; @@ -186,8 +185,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) { case SceneList::LOBBYMENU: activeScene = new LobbyMenu(&clientIndex, &accountIndex); break; - case SceneList::INWORLD: - activeScene = new InWorld(&clientIndex, &accountIndex); + case SceneList::WORLD: + activeScene = new World(&clientIndex, &accountIndex); break; case SceneList::DISCONNECTEDSCREEN: activeScene = new DisconnectedScreen(); diff --git a/client/entities/base_monster.cpp b/client/entities/base_monster.cpp index 2eaa513..c268021 100644 --- a/client/entities/base_monster.cpp +++ b/client/entities/base_monster.cpp @@ -21,3 +21,26 @@ */ #include "base_monster.hpp" +#include "config_utility.hpp" + +void BaseMonster::CorrectSprite() { + //TODO: (9) empty +} + +std::string BaseMonster::SetHandle(std::string s) { + return handle = s; +} + +std::string BaseMonster::GetHandle() const { + return handle; +} + +std::string BaseMonster::SetAvatar(std::string s) { + avatar = s; + sprite.LoadSurface(ConfigUtility::GetSingleton()["dir.sprites"] + avatar, 4, 1); + return avatar; +} + +std::string BaseMonster::GetAvatar() const { + return avatar; +} \ No newline at end of file diff --git a/client/entities/base_monster.hpp b/client/entities/base_monster.hpp index c9b7bb3..328008a 100644 --- a/client/entities/base_monster.hpp +++ b/client/entities/base_monster.hpp @@ -29,8 +29,17 @@ public: BaseMonster() = default; virtual ~BaseMonster() = default; + void CorrectSprite(); + + std::string SetHandle(std::string s); + std::string GetHandle() const; + std::string SetAvatar(std::string s); + std::string GetAvatar() const; + protected: - // + //metadata + std::string handle; + std::string avatar; }; #endif \ No newline at end of file diff --git a/client/scenes/makefile b/client/gameplay_scenes/makefile similarity index 100% rename from client/scenes/makefile rename to client/gameplay_scenes/makefile diff --git a/client/scenes/in_world.hpp b/client/gameplay_scenes/world.hpp similarity index 66% rename from client/scenes/in_world.hpp rename to client/gameplay_scenes/world.hpp index 7ce1288..bb57f75 100644 --- a/client/scenes/in_world.hpp +++ b/client/gameplay_scenes/world.hpp @@ -49,11 +49,11 @@ #include -class InWorld : public BaseScene { +class World: public BaseScene { public: //Public access members - InWorld(int* const argClientIndex, int* const argAccountIndex); - ~InWorld(); + World(int* const argClientIndex, int* const argAccountIndex); + ~World(); protected: //Frame loop @@ -71,37 +71,57 @@ protected: void KeyDown(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&); - //Basic connections + //handle incoming traffic void HandlePacket(SerialPacket* const); - void HandlePing(ServerPacket* const); - void HandlePong(ServerPacket* const); - //Connection control - void SendLogoutRequest(); - void SendDisconnectRequest(); - void SendShutdownRequest(); - - void HandleLogoutResponse(ClientPacket* const); - void HandleDisconnectResponse(ClientPacket* const); - void HandleDisconnectForced(ClientPacket* const); + //heartbeat system + void hPing(ServerPacket* const); + void hPong(ServerPacket* const); void CheckHeartBeat(); + //basic connections + void SendLogoutRequest(); + void SendDisconnectRequest(); + void SendAdminDisconnectForced(); + void SendAdminShutdownRequest(); + + void hLogoutResponse(ClientPacket* const); + void hDisconnectResponse(ClientPacket* const); + void hAdminDisconnectForced(ClientPacket* const); + //map management void SendRegionRequest(int roomIndex, int x, int y); - void HandleRegionContent(RegionPacket* const); + void hRegionContent(RegionPacket* const); void UpdateMap(); //character management - void HandleCharacterCreate(CharacterPacket* const); - void HandleCharacterDelete(CharacterPacket* const); - void HandleCharacterQueryExists(CharacterPacket* const); - void HandleCharacterSetRoom(CharacterPacket* const); - void HandleCharacterSetOrigin(CharacterPacket* const); - void HandleCharacterSetMotion(CharacterPacket* const); + void hCharacterCreate(CharacterPacket* const); + void hCharacterDelete(CharacterPacket* const); + void hQueryCharacterExists(CharacterPacket* const); + void hQueryCharacterStats(CharacterPacket* const); + void hQueryCharacterLocation(CharacterPacket* const); + void hCharacterMovement(CharacterPacket* const); + void hCharacterAttack(CharacterPacket* const); + void hCharacterDamage(CharacterPacket* const); - //player movement - void SendLocalCharacterMotion(); + //monster management + void hMonsterCreate(MonsterPacket* const); + void hMonsterDelete(MonsterPacket* const); + void hQueryMonsterExists(MonsterPacket* const); + void hQueryMonsterStats(MonsterPacket* const); + void hQueryMonsterLocation(MonsterPacket* const); + void hMonsterMovement(MonsterPacket* const); + void hMonsterAttack(MonsterPacket* const); + void hMonsterDamage(MonsterPacket* const); + + //chat + void hTextBroadcast(TextPacket* const); + void hTextSpeech(TextPacket* const); + void hTextWhisper(TextPacket* const); + + //general gameplay + void SendLocalCharacterMovement(); std::list GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight); //indexes @@ -136,7 +156,7 @@ protected: LocalCharacter* localCharacter = nullptr; //heartbeat - //TODO: Heartbeat needs it's own utility + //TODO: (2) Heartbeat needs it's own utility typedef std::chrono::steady_clock Clock; Clock::time_point lastBeat = Clock::now(); int attemptedBeats = 0; diff --git a/client/gameplay_scenes/world_characters.cpp b/client/gameplay_scenes/world_characters.cpp new file mode 100644 index 0000000..4091824 --- /dev/null +++ b/client/gameplay_scenes/world_characters.cpp @@ -0,0 +1,207 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "world.hpp" + +#include "channels.hpp" + +#include +#include +#include + +//------------------------- +//character management +//------------------------- + +//DOCS: preexisting characters will result in query responses +//DOCS: new characters will result in create messages +//DOCS: this client's character will exist in both (skipped) + +void World::hCharacterCreate(CharacterPacket* const argPacket) { + //prevent double message + if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { + std::ostringstream msg; + msg << "Double character creation event; "; + msg << "Index: " << argPacket->characterIndex << "; "; + msg << "Handle: " << argPacket->handle; + throw(std::runtime_error(msg.str())); + } + + //implicity create and retrieve the entity + BaseCharacter* character = &characterMap[argPacket->characterIndex]; + + //fill the character's info + character->SetOrigin(argPacket->origin); + character->SetMotion(argPacket->motion); + character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); //TODO: (1) send the bounds from the server + character->SetHandle(argPacket->handle); + character->SetAvatar(argPacket->avatar); + character->SetOwner(argPacket->accountIndex); + character->CorrectSprite(); + + //check for this player's character + if (character->GetOwner() == accountIndex) { + localCharacter = static_cast(character); + + //focus the camera on this character + camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); + camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); + + //focus on this character's info + characterIndex = argPacket->characterIndex; + roomIndex = argPacket->roomIndex; + } + + //debug + std::cout << "Character Create, total: " << characterMap.size() << std::endl; +} + +void World::hCharacterDelete(CharacterPacket* const argPacket) { + //ignore if this character doesn't exist + std::map::iterator characterIt = characterMap.find(argPacket->characterIndex); + if (characterIt == characterMap.end()) { + return; + } + + //check for this player's character + if ((*characterIt).second.GetOwner() == accountIndex) { + localCharacter = nullptr; + + //clear the camera + camera.marginX = 0; + camera.marginY = 0; + + //clear the room + roomIndex = -1; + } + + //remove this character + characterMap.erase(characterIt); + + //debug + std::cout << "Character Delete, total: " << characterMap.size() << std::endl; +} + +void World::hQueryCharacterExists(CharacterPacket* const argPacket) { + //prevent a double message about this player's character + if (argPacket->accountIndex == accountIndex) { + return; + } + + //ignore characters in a different room (sub-optimal) + if (argPacket->roomIndex != roomIndex) { + return; + } + + //implicitly construct the character if it doesn't exist + BaseCharacter* character = &characterMap[argPacket->characterIndex]; + + //set/update the character's info + character->SetOrigin(argPacket->origin); + character->SetMotion(argPacket->motion); + character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); + character->SetHandle(argPacket->handle); + character->SetAvatar(argPacket->avatar); + character->SetOwner(argPacket->accountIndex); + character->CorrectSprite(); + + //debug + std::cout << "Character Query, total: " << characterMap.size() << std::endl; +} + +void World::hQueryCharacterStats(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hQueryCharacterLocation(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hCharacterMovement(CharacterPacket* const argPacket) { + //TODO: (1) Authentication + if (argPacket->characterIndex == characterIndex) { + return; + } + + //check that this character exists + std::map::iterator characterIt = characterMap.find(argPacket->characterIndex); + if (characterIt != characterMap.end()) { + //set the origin and motion + characterIt->second.SetOrigin(argPacket->origin); + characterIt->second.SetMotion(argPacket->motion); + characterIt->second.CorrectSprite(); + } +} + +void World::hCharacterAttack(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hCharacterDamage(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +//------------------------- +//player movement & collision +//------------------------- + +void World::SendLocalCharacterMovement() { + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; + + newPacket.accountIndex = accountIndex; + newPacket.characterIndex = characterIndex; + newPacket.roomIndex = roomIndex; + newPacket.origin = localCharacter->GetOrigin(); + newPacket.motion = localCharacter->GetMotion(); + + network.SendTo(Channels::SERVER, &newPacket); +} + +std::list World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) { + //prepare for collisions + BoundingBox wallBounds = {0, 0, tileWidth, tileHeight}; + std::list boxList; + + //NOTE: for loops were too dense to work with, so I've just used while loops + + //outer loop + wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x); + while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) { + //inner loop + wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y); + while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) { + //check to see if this tile is solid + if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) { + //push onto the box set + boxList.push_front(wallBounds); + } + + //increment + wallBounds.y += wallBounds.h; + } + + //increment + wallBounds.x += wallBounds.w; + } + + return std::move(boxList); +} \ No newline at end of file diff --git a/common/utilities/utility.cpp b/client/gameplay_scenes/world_chat.cpp similarity index 64% rename from common/utilities/utility.cpp rename to client/gameplay_scenes/world_chat.cpp index 64b135b..3a29d21 100644 --- a/common/utilities/utility.cpp +++ b/client/gameplay_scenes/world_chat.cpp @@ -19,30 +19,21 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "utility.hpp" +#include "world.hpp" -#include +//------------------------- +//chat +//------------------------- -std::string truncatePath(std::string pathname) { - return std::string( - std::find_if( - pathname.rbegin(), - pathname.rend(), - [](char ch) -> bool { - //windows & unix tested - return ch == '/' || ch == '\\'; - }).base(), - pathname.end()); +void World::hTextBroadcast(TextPacket* const argPacket) { + //TODO: (9) empty } -std::string to_string_custom(int i) { - char buffer[20]; - snprintf(buffer, 20, "%d", i); - return std::string(buffer); +void World::hTextSpeech(TextPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hTextWhisper(TextPacket* const argPacket) { + //TODO: (9) empty } -int to_integer_custom(std::string s) { - int ret = 0; - sscanf(s.c_str(), "%d", &ret); - return ret; -} \ No newline at end of file diff --git a/client/gameplay_scenes/world_connections.cpp b/client/gameplay_scenes/world_connections.cpp new file mode 100644 index 0000000..7ace62d --- /dev/null +++ b/client/gameplay_scenes/world_connections.cpp @@ -0,0 +1,135 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "world.hpp" + +#include "channels.hpp" +#include "ip_operators.hpp" + +#include +#include +#include + +//------------------------- +//heartbeat system +//------------------------- + +void World::hPing(ServerPacket* const argPacket) { + ServerPacket newPacket; + newPacket.type = SerialPacketType::PONG; + network.SendTo(argPacket->srcAddress, &newPacket); +} + +void World::hPong(ServerPacket* const argPacket) { + if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) { + throw(std::runtime_error("Heartbeat message received from an unknown source")); + } + attemptedBeats = 0; + lastBeat = Clock::now(); +} + +void World::CheckHeartBeat() { + //check the connection (heartbeat) + if (Clock::now() - lastBeat > std::chrono::seconds(3)) { + if (attemptedBeats > 2) { + //escape to the disconnect screen + SendDisconnectRequest(); + SetNextScene(SceneList::DISCONNECTEDSCREEN); + ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server"; + } + else { + ServerPacket newPacket; + newPacket.type = SerialPacketType::PING; + network.SendTo(Channels::SERVER, &newPacket); + + attemptedBeats++; + lastBeat = Clock::now(); + } + } +} + +//------------------------- +//Connection control +//------------------------- + +void World::SendLogoutRequest() { + ClientPacket newPacket; + + //send a logout request + newPacket.type = SerialPacketType::LOGOUT_REQUEST; + newPacket.accountIndex = accountIndex; + + network.SendTo(Channels::SERVER, &newPacket); +} + +void World::SendDisconnectRequest() { + ClientPacket newPacket; + + //send a disconnect request + newPacket.type = SerialPacketType::DISCONNECT_REQUEST; + newPacket.clientIndex = clientIndex; + + network.SendTo(Channels::SERVER, &newPacket); +} + +void World::SendAdminDisconnectForced() { + //TODO: (9) empty +} + + +void World::SendAdminShutdownRequest() { + ClientPacket newPacket; + + //send a shutdown request + newPacket.type = SerialPacketType::ADMIN_SHUTDOWN_REQUEST; + newPacket.accountIndex = accountIndex; + + network.SendTo(Channels::SERVER, &newPacket); +} + +void World::hLogoutResponse(ClientPacket* const argPacket) { + if (localCharacter) { + characterMap.erase(characterIndex); + localCharacter = nullptr; + } + + accountIndex = -1; + characterIndex = -1; + + //reset the camera + camera.marginX = camera.marginY = 0; + + //because, why not? I guess... + SendDisconnectRequest(); +} + +void World::hDisconnectResponse(ClientPacket* const argPacket) { + hLogoutResponse(argPacket);//shortcut + SetNextScene(SceneList::DISCONNECTEDSCREEN); + ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out"; +} + +void World::hAdminDisconnectForced(ClientPacket* const argPacket) { + hDisconnectResponse(argPacket);//shortcut + SetNextScene(SceneList::DISCONNECTEDSCREEN); + ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server"; +} + diff --git a/client/gameplay_scenes/world_logic.cpp b/client/gameplay_scenes/world_logic.cpp new file mode 100644 index 0000000..dcb74d0 --- /dev/null +++ b/client/gameplay_scenes/world_logic.cpp @@ -0,0 +1,418 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "world.hpp" + +#include "channels.hpp" + +#include "terminal_error.hpp" +#include +#include +#include +#include +#include + +//------------------------- +//Public access members +//------------------------- + +World::World(int* const argClientIndex, int* const argAccountIndex): + clientIndex(*argClientIndex), + accountIndex(*argAccountIndex) +{ + //setup the utility objects + buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp"); + buttonImage.SetClipH(buttonImage.GetClipH()/3); + font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp"); + + //pass the utility objects + disconnectButton.SetImage(&buttonImage); + disconnectButton.SetFont(&font); + shutDownButton.SetImage(&buttonImage); + shutDownButton.SetFont(&font); + + //set the button positions + disconnectButton.SetX(50); + disconnectButton.SetY(50 + buttonImage.GetClipH() * 0); + shutDownButton.SetX(50); + shutDownButton.SetY(50 + buttonImage.GetClipH() * 1); + + //set the button texts + disconnectButton.SetText("Disconnect"); + shutDownButton.SetText("Shut Down"); + + //load the tilesheet + //TODO: (1) Tile size and tile sheet should be loaded elsewhere + tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32); + + //Send the character data + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_LOAD; + 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); + + //query the world state + memset(&newPacket, 0, MAX_PACKET_SIZE); + newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS; + network.SendTo(Channels::SERVER, &newPacket); + newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS; + network.SendTo(Channels::SERVER, &newPacket); + + //set the camera's values + camera.width = GetScreen()->w; + camera.height = GetScreen()->h; + + //debug + // +} + +World::~World() { + //unload the local data + characterMap.clear(); + monsterMap.clear(); +} + +//------------------------- +//Frame loop +//------------------------- + +void World::FrameStart() { + // +} + +void World::Update() { + //create and zero the buffer + SerialPacket* packetBuffer = reinterpret_cast(new char[MAX_PACKET_SIZE]); + memset(packetBuffer, 0, MAX_PACKET_SIZE); + + try { + //suck in and process all waiting packets + while(network.Receive(packetBuffer)) { + HandlePacket(packetBuffer); + } + } + catch(terminal_error& e) { + throw(e); + } + catch(std::exception& e) { + std::cerr << "HandlePacket Error: " << e.what() << std::endl; + } + + //free the buffer + delete reinterpret_cast(packetBuffer); + + //heartbeat system + CheckHeartBeat(); + + //update all entities + for (auto& it : characterMap) { + it.second.Update(); + } + for (auto& it : monsterMap) { + it.second.Update(); + } + + //update the map + UpdateMap(); + + //skip the rest without a local character + if (!localCharacter) { + return; + } + + //get the collidable boxes + std::list boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH()); + + //process the collisions + if (localCharacter->ProcessCollisionGrid(boxList)) { + localCharacter->CorrectSprite(); + SendLocalCharacterMovement(); + } + + //update the camera + camera.x = localCharacter->GetOrigin().x - camera.marginX; + camera.y = localCharacter->GetOrigin().y - camera.marginY; +} + +void World::FrameEnd() { + // +} + +void World::RenderFrame() { +// SDL_FillRect(GetScreen(), 0, 0); + Render(GetScreen()); + SDL_Flip(GetScreen()); + fps.Calculate(); +} + +void World::Render(SDL_Surface* const screen) { + //draw the map + for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { + tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y); + } + + //draw the entities + for (auto& it : characterMap) { + //TODO: (1) depth ordering + it.second.DrawTo(screen, camera.x, camera.y); + } + for (auto& it : monsterMap) { + it.second.DrawTo(screen, camera.x, camera.y); + } + + //draw UI + disconnectButton.DrawTo(screen); + shutDownButton.DrawTo(screen); + std::ostringstream msg; + msg << fps.GetFrameRate(); + font.DrawStringTo(msg.str(), screen, 0, 0); +} + +//------------------------- +//Event handlers +//------------------------- + +void World::QuitEvent() { + //two-step logout + SendDisconnectRequest(); + SetNextScene(SceneList::QUIT); +} + +void World::MouseMotion(SDL_MouseMotionEvent const& motion) { + disconnectButton.MouseMotion(motion); + shutDownButton.MouseMotion(motion); +} + +void World::MouseButtonDown(SDL_MouseButtonEvent const& button) { + disconnectButton.MouseButtonDown(button); + shutDownButton.MouseButtonDown(button); +} + +void World::MouseButtonUp(SDL_MouseButtonEvent const& button) { + if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { + SendLogoutRequest(); + } + if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { + SendAdminShutdownRequest(); + } +} + +void World::KeyDown(SDL_KeyboardEvent const& key) { + //hotkeys + switch(key.keysym.sym) { + case SDLK_ESCAPE: + //TODO: (1) the escape key should actually control menus and stuff + SendLogoutRequest(); + return; + } + + //character movement + if (!localCharacter) { + return; + } + Vector2 motion = localCharacter->GetMotion(); + switch(key.keysym.sym) { + case SDLK_w: + motion.y -= CHARACTER_WALKING_SPEED; + break; + case SDLK_a: + motion.x -= CHARACTER_WALKING_SPEED; + break; + case SDLK_s: + motion.y += CHARACTER_WALKING_SPEED; + break; + case SDLK_d: + motion.x += CHARACTER_WALKING_SPEED; + break; + default: + //DOCS: prevents wrong keys screwing with character movement + return; + } + //handle diagonals + if (motion.x != 0 && motion.y != 0) { + motion *= CHARACTER_WALKING_MOD; + } + //set the info + localCharacter->SetMotion(motion); + localCharacter->CorrectSprite(); + SendLocalCharacterMovement(); +} + +void World::KeyUp(SDL_KeyboardEvent const& key) { + //character movement + if (!localCharacter) { + return; + } + Vector2 motion = localCharacter->GetMotion(); + switch(key.keysym.sym) { + case SDLK_w: + motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED); + break; + case SDLK_a: + motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED); + break; + case SDLK_s: + motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED); + break; + case SDLK_d: + motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED); + break; + default: + //DOCS: prevents wrong keys screwing with character movement + return; + } + //BUGFIX: reset cardinal direction speed on key release + if (motion.x > 0) { + motion.x = CHARACTER_WALKING_SPEED; + } + else if (motion.x < 0) { + motion.x = -CHARACTER_WALKING_SPEED; + } + if (motion.y > 0) { + motion.y = CHARACTER_WALKING_SPEED; + } + else if (motion.y < 0) { + motion.y = -CHARACTER_WALKING_SPEED; + } + //handle diagonals + if (motion.x != 0 && motion.y != 0) { + motion *= CHARACTER_WALKING_MOD; + } + //set the info + localCharacter->SetMotion(motion); + localCharacter->CorrectSprite(); + SendLocalCharacterMovement(); +} + +//------------------------- +//Direct incoming traffic +//------------------------- + +void World::HandlePacket(SerialPacket* const argPacket) { + switch(argPacket->type) { + //heartbeat system + case SerialPacketType::PING: + hPing(static_cast(argPacket)); + break; + case SerialPacketType::PONG: + hPong(static_cast(argPacket)); + break; + + //game server connections + case SerialPacketType::LOGOUT_RESPONSE: + hLogoutResponse(static_cast(argPacket)); + break; + case SerialPacketType::DISCONNECT_RESPONSE: + hDisconnectResponse(static_cast(argPacket)); + break; + case SerialPacketType::ADMIN_DISCONNECT_FORCED: + hAdminDisconnectForced(static_cast(argPacket)); + break; + + //map management + case SerialPacketType::REGION_CONTENT: + hRegionContent(static_cast(argPacket)); + break; + + //character management + case SerialPacketType::CHARACTER_CREATE: + hCharacterCreate(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_DELETE: + hCharacterDelete(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_CHARACTER_EXISTS: + hQueryCharacterExists(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_CHARACTER_STATS: + hQueryCharacterStats(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_CHARACTER_LOCATION: + hQueryCharacterLocation(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_MOVEMENT: + hCharacterMovement(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_ATTACK: + hCharacterAttack(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_DAMAGE: + hCharacterDamage(static_cast(argPacket)); + break; + + //monster management + case SerialPacketType::MONSTER_CREATE: + hMonsterCreate(static_cast(argPacket)); + break; + case SerialPacketType::MONSTER_DELETE: + hMonsterDelete(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_MONSTER_EXISTS: + hQueryMonsterExists(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_MONSTER_STATS: + hQueryMonsterStats(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_MONSTER_LOCATION: + hQueryMonsterLocation(static_cast(argPacket)); + break; + case SerialPacketType::MONSTER_MOVEMENT: + hMonsterMovement(static_cast(argPacket)); + break; + case SerialPacketType::MONSTER_ATTACK: + hMonsterAttack(static_cast(argPacket)); + break; + case SerialPacketType::MONSTER_DAMAGE: + hMonsterDamage(static_cast(argPacket)); + break; + + //chat + case SerialPacketType::TEXT_BROADCAST: + hTextBroadcast(static_cast(argPacket)); + break; + case SerialPacketType::TEXT_SPEECH: + hTextSpeech(static_cast(argPacket)); + break; + case SerialPacketType::TEXT_WHISPER: + hTextWhisper(static_cast(argPacket)); + break; + + //general rejection messages + case SerialPacketType::REGION_REJECTION: + case SerialPacketType::CHARACTER_REJECTION: + case SerialPacketType::QUERY_REJECTION: + throw(terminal_error(static_cast(argPacket)->text)); + break; + case SerialPacketType::SHUTDOWN_REJECTION: + throw(std::runtime_error(static_cast(argPacket)->text)); + break; + + //errors + default: { + std::ostringstream msg; + msg << "Unknown SerialPacketType encountered in World: " << static_cast(argPacket->type); + throw(std::runtime_error(msg.str())); + } + break; + } +} \ No newline at end of file diff --git a/client/gameplay_scenes/world_map.cpp b/client/gameplay_scenes/world_map.cpp new file mode 100644 index 0000000..592c8e9 --- /dev/null +++ b/client/gameplay_scenes/world_map.cpp @@ -0,0 +1,79 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "world.hpp" + +#include "channels.hpp" + +//------------------------- +//map management +//------------------------- + +void World::SendRegionRequest(int roomIndex, int x, int y) { + RegionPacket packet; + + //pack the region's data + packet.type = SerialPacketType::REGION_REQUEST; + packet.roomIndex = roomIndex; + packet.x = x; + packet.y = y; + + network.SendTo(Channels::SERVER, &packet); +} + +void World::hRegionContent(RegionPacket* const argPacket) { + //replace existing regions + regionPager.UnloadIf([&](Region const& region) -> bool { + return region.GetX() == argPacket->x && region.GetY() == argPacket->y; + }); + regionPager.PushRegion(argPacket->region); + + //clean up after the serial code + delete argPacket->region; + argPacket->region = nullptr; +} + +void World::UpdateMap() { + if (roomIndex == -1) { + return; + } + + //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 + regionPager.GetContainer()->remove_if([&](Region const& region) -> bool { + return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd; + }); + + //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)) { + SendRegionRequest(roomIndex, i, j); + } + } + } +} \ No newline at end of file diff --git a/client/gameplay_scenes/world_monsters.cpp b/client/gameplay_scenes/world_monsters.cpp new file mode 100644 index 0000000..8891fad --- /dev/null +++ b/client/gameplay_scenes/world_monsters.cpp @@ -0,0 +1,126 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "world.hpp" + +#include "channels.hpp" + +#include +#include +#include + +//------------------------- +//monster management +//------------------------- + +void World::hMonsterCreate(MonsterPacket* const argPacket) { + //check for logic errors + if (monsterMap.find(argPacket->monsterIndex) != monsterMap.end()) { + std::ostringstream msg; + msg << "Double monster creation event; "; + msg << "Index: " << argPacket->monsterIndex << "; "; + msg << "Handle: " << argPacket->handle; + throw(std::runtime_error(msg.str())); + } + + //ignore monsters from other rooms + if (roomIndex != argPacket->roomIndex) { + //temporary error checking + std::ostringstream msg; + msg << "Monster from the wrong room received: "; + msg << "monsterIndex: " << argPacket->monsterIndex << ", roomIndex: " << argPacket->roomIndex; + throw(std::runtime_error(msg.str())); + } + + //implicitly create the element + BaseMonster* monster = &monsterMap[argPacket->monsterIndex]; + + //fill the monster's info + monster->SetHandle(argPacket->handle); + monster->SetAvatar(argPacket->avatar); + monster->SetBounds(argPacket->bounds); + monster->SetOrigin(argPacket->origin); + monster->SetMotion(argPacket->motion); + + //debug + std::cout << "Monster Create, total: " << monsterMap.size() << std::endl; +} + +void World::hMonsterDelete(MonsterPacket* const argPacket) { + //ignore if this monster doesn't exist + std::map::iterator monsterIt = monsterMap.find(argPacket->monsterIndex); + if (monsterIt == monsterMap.end()) { + return; + } + + //remove this monster + monsterMap.erase(monsterIt); + + //debug + std::cout << "Monster Delete, total: " << monsterMap.size() << std::endl; +} + +void World::hQueryMonsterExists(MonsterPacket* const argPacket) { + //ignore monsters in a different room (sub-optimal) + if (argPacket->roomIndex != roomIndex) { + return; + } + + //implicitly create the element + BaseMonster* monster = &monsterMap[argPacket->monsterIndex]; + + //fill the monster's info + monster->SetHandle(argPacket->handle); + monster->SetAvatar(argPacket->avatar); + monster->SetBounds(argPacket->bounds); + monster->SetOrigin(argPacket->origin); + monster->SetMotion(argPacket->motion); + + //debug + std::cout << "Monster Query, total: " << monsterMap.size() << std::endl; +} + +void World::hQueryMonsterStats(MonsterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hQueryMonsterLocation(MonsterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hMonsterMovement(MonsterPacket* const argPacket) { + //ignore if this monster doesn't exist + std::map::iterator monsterIt = monsterMap.find(argPacket->monsterIndex); + if (monsterIt == monsterMap.end()) { + return; + } + + monsterIt->second.SetOrigin(argPacket->origin); + monsterIt->second.SetOrigin(argPacket->motion); +} + +void World::hMonsterAttack(MonsterPacket* const argPacket) { + //TODO: (9) empty +} + +void World::hMonsterDamage(MonsterPacket* const argPacket) { + //TODO: (9) empty +} \ No newline at end of file diff --git a/client/makefile b/client/makefile index 68ce8d9..b931b13 100644 --- a/client/makefile +++ b/client/makefile @@ -1,5 +1,5 @@ #include directories -INCLUDES+=. client_utilities entities scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities +INCLUDES+=. client_utilities entities gameplay_scenes menu_scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities #libraries #the order of the $(LIBS) is important, at least for MinGW @@ -27,7 +27,8 @@ OUT=$(addprefix $(OUTDIR)/,client) all: $(OBJ) $(OUT) $(MAKE) -C client_utilities $(MAKE) -C entities - $(MAKE) -C scenes + $(MAKE) -C gameplay_scenes + $(MAKE) -C menu_scenes $(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS) $(OBJ): | $(OBJDIR) diff --git a/client/scenes/disconnected_screen.cpp b/client/menu_scenes/disconnected_screen.cpp similarity index 100% rename from client/scenes/disconnected_screen.cpp rename to client/menu_scenes/disconnected_screen.cpp diff --git a/client/scenes/disconnected_screen.hpp b/client/menu_scenes/disconnected_screen.hpp similarity index 100% rename from client/scenes/disconnected_screen.hpp rename to client/menu_scenes/disconnected_screen.hpp diff --git a/client/scenes/lobby_menu.cpp b/client/menu_scenes/lobby_menu.cpp similarity index 92% rename from client/scenes/lobby_menu.cpp rename to client/menu_scenes/lobby_menu.cpp index 0776242..8ebc361 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/menu_scenes/lobby_menu.cpp @@ -22,9 +22,9 @@ #include "lobby_menu.hpp" #include "channels.hpp" -#include "utility.hpp" #include +#include //------------------------- //Public access members @@ -100,14 +100,14 @@ void LobbyMenu::FrameEnd() { } void LobbyMenu::Render(SDL_Surface* const screen) { - //TODO: I need a proper UI system for the entire client and the editor + //TODO: (2) 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 + //TODO: (1) draw headers for the server list for (int i = 0; i < serverInfo.size(); i++) { //draw the selected server's highlight if (selection == &serverInfo[i]) { @@ -123,14 +123,14 @@ void LobbyMenu::Render(SDL_Surface* const screen) { 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); + std::ostringstream msg; + msg << serverInfo[i].playerCount; + font.DrawStringTo(msg.str(), 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/delay? } } @@ -210,8 +210,11 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) { break; //handle errors - default: - throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast(argPacket->type)) )); + default: { + std::ostringstream msg; + msg << "Unknown SerialPacketType encountered in LobbyMenu: " << static_cast(argPacket->type); + throw(std::runtime_error( msg.str() )); + } break; } } @@ -245,15 +248,15 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) { throw(std::runtime_error("Client index invalid during login")); } accountIndex = argPacket->accountIndex; - SetNextScene(SceneList::INWORLD); + SetNextScene(SceneList::WORLD); } void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { - //TODO: Better output for join rejection + //TODO: (9) empty } void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) { - //TODO: Better output for login rejection + //TODO: (9) empty } //------------------------- diff --git a/client/scenes/lobby_menu.hpp b/client/menu_scenes/lobby_menu.hpp similarity index 100% rename from client/scenes/lobby_menu.hpp rename to client/menu_scenes/lobby_menu.hpp diff --git a/client/scenes/main_menu.cpp b/client/menu_scenes/main_menu.cpp similarity index 93% rename from client/scenes/main_menu.cpp rename to client/menu_scenes/main_menu.cpp index 064b485..e6735d1 100644 --- a/client/scenes/main_menu.cpp +++ b/client/menu_scenes/main_menu.cpp @@ -88,8 +88,7 @@ void MainMenu::Render(SDL_Surface* const screen) { //text font.DrawStringTo("Thanks for playing!", screen, 50, screen->h - 50 - image.GetClipH() * 2); font.DrawStringTo("You can get the latest version at: ", screen, 50, screen->h - 50 - image.GetClipH() * 1); - font.DrawStringTo("https://github.com/Ratstail91/Tortuga", screen, 50, screen->h - 50 - image.GetClipH() * 0); - //TODO: replace this with a website address + font.DrawStringTo("krgamestudios.com", screen, 50, screen->h - 50 - image.GetClipH() * 0); } //------------------------- @@ -109,7 +108,7 @@ void MainMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) { } void MainMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { - //TODO: Buttons should only register as "selected" when the left button is used + //TODO: (2) Buttons should only register as "selected" when the left button is used if (startButton.MouseButtonUp(button) == Button::State::HOVER) { SetNextScene(SceneList::LOBBYMENU); } @@ -126,5 +125,9 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) { } void MainMenu::KeyUp(SDL_KeyboardEvent const& key) { - // + switch(key.keysym.sym) { + case SDLK_ESCAPE: + QuitEvent(); + break; + } } diff --git a/client/scenes/main_menu.hpp b/client/menu_scenes/main_menu.hpp similarity index 100% rename from client/scenes/main_menu.hpp rename to client/menu_scenes/main_menu.hpp diff --git a/client/menu_scenes/makefile b/client/menu_scenes/makefile new file mode 100644 index 0000000..24dfb60 --- /dev/null +++ b/client/menu_scenes/makefile @@ -0,0 +1,37 @@ +#config +INCLUDES+=. .. ../../common/graphics ../../common/map ../../common/network ../../common/network/packet_types ../../common/ui ../../common/utilities +LIBS+= +CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) + +#source +CXXSRC=$(wildcard *.cpp) + +#objects +OBJDIR=obj +OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) + +#output +OUTDIR=.. +OUT=$(addprefix $(OUTDIR)/,client.a) + +#targets +all: $(OBJ) $(OUT) + ar -crs $(OUT) $(OBJ) + +$(OBJ): | $(OBJDIR) + +$(OUT): | $(OUTDIR) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OUTDIR): + mkdir $(OUTDIR) + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +clean: + $(RM) *.o *.a *.exe + +rebuild: clean all diff --git a/client/scenes/options_menu.cpp b/client/menu_scenes/options_menu.cpp similarity index 100% rename from client/scenes/options_menu.cpp rename to client/menu_scenes/options_menu.cpp diff --git a/client/scenes/options_menu.hpp b/client/menu_scenes/options_menu.hpp similarity index 97% rename from client/scenes/options_menu.hpp rename to client/menu_scenes/options_menu.hpp index bb15569..a828627 100644 --- a/client/scenes/options_menu.hpp +++ b/client/menu_scenes/options_menu.hpp @@ -28,7 +28,7 @@ #include "raster_font.hpp" #include "button.hpp" -//TODO: The options screen needs to be USED +//NOTE: The options screen needs to be USED class OptionsMenu : public BaseScene { public: //Public access members diff --git a/client/scenes/splash_screen.cpp b/client/menu_scenes/splash_screen.cpp similarity index 100% rename from client/scenes/splash_screen.cpp rename to client/menu_scenes/splash_screen.cpp diff --git a/client/scenes/splash_screen.hpp b/client/menu_scenes/splash_screen.hpp similarity index 100% rename from client/scenes/splash_screen.hpp rename to client/menu_scenes/splash_screen.hpp diff --git a/client/scene_list.hpp b/client/scene_list.hpp index 475e5bb..2db5145 100644 --- a/client/scene_list.hpp +++ b/client/scene_list.hpp @@ -33,7 +33,7 @@ enum class SceneList { MAINMENU, OPTIONSMENU, LOBBYMENU, - INWORLD, + WORLD, DISCONNECTEDSCREEN, }; diff --git a/client/scenes/in_world.cpp b/client/scenes/in_world.cpp deleted file mode 100644 index ec03408..0000000 --- a/client/scenes/in_world.cpp +++ /dev/null @@ -1,755 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2013-2015 - * - * 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 "in_world.hpp" - -#include "channels.hpp" -#include "utility.hpp" - -#include "terminal_error.hpp" -#include -#include -#include -#include -#include - -//------------------------- -//these should've come standard -//------------------------- - -bool operator==(IPaddress lhs, IPaddress rhs) { - return lhs.host == rhs.host && lhs.port == rhs.port; -} - -bool operator!=(IPaddress lhs, IPaddress rhs) { - return !(lhs == rhs); -} - -//------------------------- -//Public access members -//------------------------- - -InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): - clientIndex(*argClientIndex), - accountIndex(*argAccountIndex) -{ - //setup the utility objects - buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp"); - buttonImage.SetClipH(buttonImage.GetClipH()/3); - font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp"); - - //pass the utility objects - disconnectButton.SetImage(&buttonImage); - disconnectButton.SetFont(&font); - shutDownButton.SetImage(&buttonImage); - shutDownButton.SetFont(&font); - - //set the button positions - disconnectButton.SetX(50); - disconnectButton.SetY(50 + buttonImage.GetClipH() * 0); - shutDownButton.SetX(50); - shutDownButton.SetY(50 + buttonImage.GetClipH() * 1); - - //set the button texts - disconnectButton.SetText("Disconnect"); - shutDownButton.SetText("Shut Down"); - - //load the tilesheet - //TODO: add the tilesheet to the map system - //TODO: Tile size and tile sheet should be loaded elsewhere - tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32); - - //Send the character data - //TODO: login scene, prompt, etc. - CharacterPacket newPacket; - newPacket.type = SerialPacketType::CHARACTER_LOAD; - 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); - - //query the world state - memset(&newPacket, 0, MAX_PACKET_SIZE); - newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS; - network.SendTo(Channels::SERVER, &newPacket); - - //set the camera's values - camera.width = GetScreen()->w; - camera.height = GetScreen()->h; - - //debug - // -} - -InWorld::~InWorld() { - //unload the local data - characterMap.clear(); - monsterMap.clear(); -} - -//------------------------- -//Frame loop -//------------------------- - -void InWorld::FrameStart() { - // -} - -void InWorld::Update() { - //create and zero the buffer - SerialPacket* packetBuffer = reinterpret_cast(new char[MAX_PACKET_SIZE]); - memset(packetBuffer, 0, MAX_PACKET_SIZE); - - try { - //suck in and process all waiting packets - while(network.Receive(packetBuffer)) { - HandlePacket(packetBuffer); - } - } - catch(terminal_error& e) { - throw(e); - } - catch(std::exception& e) { - std::cerr << "HandlePacket Error: " << e.what() << std::endl; - } - - //free the buffer - delete reinterpret_cast(packetBuffer); - - //heartbeat system - CheckHeartBeat(); - - //update all entities - for (auto& it : characterMap) { - it.second.Update(); - } - for (auto& it : monsterMap) { - it.second.Update(); - } - - //update the map - UpdateMap(); - - //skip the rest without a local character - if (!localCharacter) { - return; - } - - //get the collidable boxes - std::list boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH()); - - //process the collisions - if (localCharacter->ProcessCollisionGrid(boxList)) { - localCharacter->CorrectSprite(); - SendLocalCharacterMotion(); - } - - //update the camera - camera.x = localCharacter->GetOrigin().x - camera.marginX; - camera.y = localCharacter->GetOrigin().y - camera.marginY; -} - -void InWorld::FrameEnd() { - // -} - -void InWorld::RenderFrame() { - SDL_FillRect(GetScreen(), 0, 0); - Render(GetScreen()); - SDL_Flip(GetScreen()); - fps.Calculate(); -} - -void InWorld::Render(SDL_Surface* const screen) { - //draw the map - for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { - tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y); - } - - //draw the entities - for (auto& it : characterMap) { - //TODO: depth ordering - it.second.DrawTo(screen, camera.x, camera.y); - } - for (auto& it : monsterMap) { - //TODO: depth ordering - it.second.DrawTo(screen, camera.x, camera.y); - } - - //draw UI - disconnectButton.DrawTo(screen); - shutDownButton.DrawTo(screen); - font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0); -} - -//------------------------- -//Event handlers -//------------------------- - -void InWorld::QuitEvent() { - //two-step logout - SendDisconnectRequest(); - SetNextScene(SceneList::QUIT); -} - -void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) { - disconnectButton.MouseMotion(motion); - shutDownButton.MouseMotion(motion); -} - -void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) { - disconnectButton.MouseButtonDown(button); - shutDownButton.MouseButtonDown(button); -} - -void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) { - if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { - SendLogoutRequest(); - } - if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { - SendShutdownRequest(); - } -} - -void InWorld::KeyDown(SDL_KeyboardEvent const& key) { - //hotkeys - switch(key.keysym.sym) { - case SDLK_ESCAPE: - //TODO: the escape key should actually control menus and stuff - SendLogoutRequest(); - return; - } - - //character movement - if (!localCharacter) { - return; - } - Vector2 motion = localCharacter->GetMotion(); - switch(key.keysym.sym) { - case SDLK_w: - motion.y -= CHARACTER_WALKING_SPEED; - break; - case SDLK_a: - motion.x -= CHARACTER_WALKING_SPEED; - break; - case SDLK_s: - motion.y += CHARACTER_WALKING_SPEED; - break; - case SDLK_d: - motion.x += CHARACTER_WALKING_SPEED; - break; - default: - //DOCS: prevents wrong keys screwing with character movement - return; - } - //handle diagonals - if (motion.x != 0 && motion.y != 0) { - motion *= CHARACTER_WALKING_MOD; - } - //set the info - localCharacter->SetMotion(motion); - localCharacter->CorrectSprite(); - SendLocalCharacterMotion(); -} - -void InWorld::KeyUp(SDL_KeyboardEvent const& key) { - //character movement - if (!localCharacter) { - return; - } - Vector2 motion = localCharacter->GetMotion(); - switch(key.keysym.sym) { - case SDLK_w: - motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED); - break; - case SDLK_a: - motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED); - break; - case SDLK_s: - motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED); - break; - case SDLK_d: - motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED); - break; - default: - //DOCS: prevents wrong keys screwing with character movement - return; - } - //BUGFIX: reset cardinal direction speed on key release - if (motion.x > 0) { - motion.x = CHARACTER_WALKING_SPEED; - } - else if (motion.x < 0) { - motion.x = -CHARACTER_WALKING_SPEED; - } - if (motion.y > 0) { - motion.y = CHARACTER_WALKING_SPEED; - } - else if (motion.y < 0) { - motion.y = -CHARACTER_WALKING_SPEED; - } - //handle diagonals - if (motion.x != 0 && motion.y != 0) { - motion *= CHARACTER_WALKING_MOD; - } - //set the info - localCharacter->SetMotion(motion); - localCharacter->CorrectSprite(); - SendLocalCharacterMotion(); -} - -//------------------------- -//Basic connections -//------------------------- - -void InWorld::HandlePacket(SerialPacket* const argPacket) { - switch(argPacket->type) { - //heartbeat system - case SerialPacketType::PING: - HandlePing(static_cast(argPacket)); - break; - case SerialPacketType::PONG: - HandlePong(static_cast(argPacket)); - break; - - //game server connections - case SerialPacketType::LOGOUT_RESPONSE: - HandleLogoutResponse(static_cast(argPacket)); - break; - case SerialPacketType::DISCONNECT_RESPONSE: - HandleDisconnectResponse(static_cast(argPacket)); - break; - case SerialPacketType::DISCONNECT_FORCED: - HandleDisconnectForced(static_cast(argPacket)); - break; - - //map management - case SerialPacketType::REGION_CONTENT: - HandleRegionContent(static_cast(argPacket)); - break; - - //character management - case SerialPacketType::CHARACTER_CREATE: - HandleCharacterCreate(static_cast(argPacket)); - break; - case SerialPacketType::CHARACTER_DELETE: - HandleCharacterDelete(static_cast(argPacket)); - break; - case SerialPacketType::QUERY_CHARACTER_EXISTS: - HandleCharacterQueryExists(static_cast(argPacket)); - break; - - //character movement - case SerialPacketType::CHARACTER_SET_ROOM: - HandleCharacterSetRoom(static_cast(argPacket)); - break; - case SerialPacketType::CHARACTER_SET_ORIGIN: - HandleCharacterSetOrigin(static_cast(argPacket)); - break; - case SerialPacketType::CHARACTER_SET_MOTION: - HandleCharacterSetMotion(static_cast(argPacket)); - break; - - //rejection messages - case SerialPacketType::REGION_REJECTION: - case SerialPacketType::CHARACTER_REJECTION: - throw(terminal_error(static_cast(argPacket)->text)); - break; - case SerialPacketType::SHUTDOWN_REJECTION: - throw(std::runtime_error(static_cast(argPacket)->text)); - break; - - //errors - default: { - std::ostringstream msg; - msg << "Unknown SerialPacketType encountered in InWorld: " << static_cast(argPacket->type); - throw(std::runtime_error(msg.str())); - } - break; - } -} - -void InWorld::HandlePing(ServerPacket* const argPacket) { - ServerPacket newPacket; - newPacket.type = SerialPacketType::PONG; - network.SendTo(argPacket->srcAddress, &newPacket); -} - -void InWorld::HandlePong(ServerPacket* const argPacket) { - if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) { - throw(std::runtime_error("Heartbeat message received from an unknown source")); - } - attemptedBeats = 0; - lastBeat = Clock::now(); -} - -//------------------------- -//Connection control -//------------------------- - -void InWorld::SendLogoutRequest() { - ClientPacket newPacket; - - //send a logout request - newPacket.type = SerialPacketType::LOGOUT_REQUEST; - newPacket.accountIndex = accountIndex; - - network.SendTo(Channels::SERVER, &newPacket); -} - -void InWorld::SendDisconnectRequest() { - ClientPacket newPacket; - - //send a disconnect request - newPacket.type = SerialPacketType::DISCONNECT_REQUEST; - newPacket.clientIndex = clientIndex; - - network.SendTo(Channels::SERVER, &newPacket); -} - -void InWorld::SendShutdownRequest() { - ClientPacket newPacket; - - //send a shutdown request - newPacket.type = SerialPacketType::SHUTDOWN_REQUEST; - newPacket.accountIndex = accountIndex; - - network.SendTo(Channels::SERVER, &newPacket); -} - -void InWorld::HandleLogoutResponse(ClientPacket* const argPacket) { - if (localCharacter) { - characterMap.erase(characterIndex); - localCharacter = nullptr; - } - - accountIndex = -1; - characterIndex = -1; - - //reset the camera - camera.marginX = camera.marginY = 0; - - //because, why not? I guess... - SendDisconnectRequest(); -} - -void InWorld::HandleDisconnectResponse(ClientPacket* const argPacket) { - HandleLogoutResponse(argPacket);//shortcut - SetNextScene(SceneList::DISCONNECTEDSCREEN); - ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out"; -} - -void InWorld::HandleDisconnectForced(ClientPacket* const argPacket) { - HandleDisconnectResponse(argPacket);//shortcut - SetNextScene(SceneList::DISCONNECTEDSCREEN); - ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server"; -} - -void InWorld::CheckHeartBeat() { - //check the connection (heartbeat) - if (Clock::now() - lastBeat > std::chrono::seconds(3)) { - if (attemptedBeats > 2) { - //escape to the disconnect screen - SendDisconnectRequest(); - SetNextScene(SceneList::DISCONNECTEDSCREEN); - ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server"; - } - else { - ServerPacket newPacket; - newPacket.type = SerialPacketType::PING; - network.SendTo(Channels::SERVER, &newPacket); - - attemptedBeats++; - lastBeat = Clock::now(); - } - } -} - -//------------------------- -//map management -//------------------------- - -void InWorld::SendRegionRequest(int roomIndex, int x, int y) { - RegionPacket packet; - - //pack the region's data - packet.type = SerialPacketType::REGION_REQUEST; - packet.roomIndex = roomIndex; - packet.x = x; - packet.y = y; - - network.SendTo(Channels::SERVER, &packet); -} - -void InWorld::HandleRegionContent(RegionPacket* const argPacket) { - //replace existing regions - regionPager.UnloadIf([&](Region const& region) -> bool { - return region.GetX() == argPacket->x && region.GetY() == argPacket->y; - }); - regionPager.PushRegion(argPacket->region); - - //clean up after the serial code - delete argPacket->region; - argPacket->region = nullptr; -} - -void InWorld::UpdateMap() { - if (roomIndex == -1) { - return; - } - - //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 - regionPager.GetContainer()->remove_if([&](Region const& region) -> bool { - return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd; - }); - - //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)) { - SendRegionRequest(roomIndex, i, j); - } - } - } -} - -//------------------------- -//entity management -//------------------------- - -//DOCS: preexisting characters will result in query responses -//DOCS: new characters will result in create messages -//DOCS: this client's character will exist in both (skipped) - -void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) { - //prevent double message - if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { - std::ostringstream msg; - msg << "Double character creation event; "; - msg << "Index: " << argPacket->characterIndex << "; "; - msg << "Handle: " << argPacket->handle; - throw(std::runtime_error(msg.str())); - } - - //implicity create and retrieve the entity - BaseCharacter* character = &characterMap[argPacket->characterIndex]; - - //fill the character's info - character->SetOrigin(argPacket->origin); - character->SetMotion(argPacket->motion); - character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); - character->SetHandle(argPacket->handle); - character->SetAvatar(argPacket->avatar); - character->SetOwner(argPacket->accountIndex); - character->CorrectSprite(); - - //check for this player's character - if (character->GetOwner() == accountIndex) { - localCharacter = static_cast(character); - - //focus the camera on this character - camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); - camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); - - //focus on this character's info - characterIndex = argPacket->characterIndex; - roomIndex = argPacket->roomIndex; - } - - //debug - std::cout << "Create, total: " << characterMap.size() << std::endl; -} - -void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { - //ignore if this character doesn't exist - std::map::iterator characterIt = characterMap.find(argPacket->characterIndex); - if (characterIt == characterMap.end()) { - return; - } - - //check for this player's character - if ((*characterIt).second.GetOwner() == accountIndex) { - localCharacter = nullptr; - - //clear the camera - camera.marginX = 0; - camera.marginY = 0; - - //clear the room - roomIndex = -1; - } - - //remove this character - characterMap.erase(characterIt); - - //debug - std::cout << "Delete, total: " << characterMap.size() << std::endl; -} - -void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) { - //prevent a double message about this player's character - if (argPacket->accountIndex == accountIndex) { - return; - } - - //ignore characters in a different room (sub-optimal) - if (argPacket->roomIndex != roomIndex) { - return; - } - - //implicitly construct the character if it doesn't exist - BaseCharacter* character = &characterMap[argPacket->characterIndex]; - - //set/update the character's info - character->SetOrigin(argPacket->origin); - character->SetMotion(argPacket->motion); - character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); - character->SetHandle(argPacket->handle); - character->SetAvatar(argPacket->avatar); - character->SetOwner(argPacket->accountIndex); - character->CorrectSprite(); - - //debug - std::cout << "Query, total: " << characterMap.size() << std::endl; -} - -void InWorld::HandleCharacterSetRoom(CharacterPacket* const argPacket) { - //someone else's character - if (argPacket->characterIndex != characterIndex) { - characterMap.erase(argPacket->characterIndex); - return; - } - - //this character is moving between rooms - roomIndex = argPacket->roomIndex; - - //set the character's info - localCharacter->SetOrigin(argPacket->origin); - localCharacter->SetMotion(argPacket->motion); - localCharacter->CorrectSprite(); - - //clear the old room's data - regionPager.UnloadAll(); - monsterMap.clear(); - - //use the jenky pattern for std::map to skip this player's character - for (std::map::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) { - if (it->first != characterIndex) { - it = characterMap.erase(it); - } - else { - ++it; - } - } - - //request the info on characters in this room - CharacterPacket newPacket; - newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS; - newPacket.roomIndex = roomIndex; - network.SendTo(Channels::SERVER, &newPacket); -} - -void InWorld::HandleCharacterSetOrigin(CharacterPacket* const argPacket) { - //TODO: Authentication - if (argPacket->characterIndex == characterIndex) { - return; - } - - //check that this character exists - std::map::iterator characterIt = characterMap.find(argPacket->characterIndex); - if (characterIt != characterMap.end()) { - //set the origin and motion - characterIt->second.SetOrigin(argPacket->origin); - characterIt->second.SetMotion(argPacket->motion); - characterIt->second.CorrectSprite(); - } -} - -void InWorld::HandleCharacterSetMotion(CharacterPacket* const argPacket) { - //TODO: Authentication - if (argPacket->characterIndex == characterIndex) { - return; - } - - //check that this character exists - std::map::iterator characterIt = characterMap.find(argPacket->characterIndex); - if (characterIt != characterMap.end()) { - //set the origin and motion - characterIt->second.SetOrigin(argPacket->origin); - characterIt->second.SetMotion(argPacket->motion); - characterIt->second.CorrectSprite(); - } -} - -//------------------------- -//player movement -//------------------------- - -//TODO: add a "movement" packet type -void InWorld::SendLocalCharacterMotion() { - CharacterPacket newPacket; - newPacket.type = SerialPacketType::CHARACTER_SET_MOTION; - - newPacket.accountIndex = accountIndex; - newPacket.characterIndex = characterIndex; - newPacket.roomIndex = roomIndex; - newPacket.origin = localCharacter->GetOrigin(); - newPacket.motion = localCharacter->GetMotion(); - - network.SendTo(Channels::SERVER, &newPacket); -} - -std::list InWorld::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) { - //prepare for collisions - BoundingBox wallBounds = {0, 0, tileWidth, tileHeight}; - std::list boxList; - - //NOTE: for loops were too dense to work with, so I've just used while loops - - //outer loop - wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x); - while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) { - //inner loop - wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y); - while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) { - //check to see if this tile is solid - if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) { - //push onto the box set - boxList.push_front(wallBounds); - } - - //increment - wallBounds.y += wallBounds.h; - } - - //increment - wallBounds.x += wallBounds.w; - } - - return std::move(boxList); -} \ No newline at end of file diff --git a/common/network/packet_types/character_packet.hpp b/common/network/packet_types/character_packet.hpp index 9b7dfde..c7e1040 100644 --- a/common/network/packet_types/character_packet.hpp +++ b/common/network/packet_types/character_packet.hpp @@ -34,14 +34,11 @@ struct CharacterPacket : SerialPacketBase { //the owner int accountIndex; - //TODO: Authentication token? //location int roomIndex; Vector2 origin; Vector2 motion; - - //gameplay components: equipment, items, buffs, debuffs... }; void serializeCharacter(void* buffer, CharacterPacket* packet); diff --git a/common/network/packet_types/client_packet.hpp b/common/network/packet_types/client_packet.hpp index 32efb06..2d684b1 100644 --- a/common/network/packet_types/client_packet.hpp +++ b/common/network/packet_types/client_packet.hpp @@ -28,6 +28,7 @@ struct ClientPacket : SerialPacketBase { int clientIndex; int accountIndex; char username[PACKET_STRING_SIZE]; + //TODO: (9) password, auth token }; void serializeClient(void* buffer, ClientPacket* packet); diff --git a/common/network/packet_types/monster_packet.cpp b/common/network/packet_types/monster_packet.cpp new file mode 100644 index 0000000..c365207 --- /dev/null +++ b/common/network/packet_types/monster_packet.cpp @@ -0,0 +1,70 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "monster_packet.hpp" + +#include "serial_utility.hpp" + +void serializeMonster(void* buffer, MonsterPacket* packet) { + serialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the monster + serialCopy(&buffer, &packet->monsterIndex, sizeof(int)); + serialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + serialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //bounds + serialCopy(&buffer, &packet->bounds.x, sizeof(int)); + serialCopy(&buffer, &packet->bounds.y, sizeof(int)); + serialCopy(&buffer, &packet->bounds.w, sizeof(int)); + serialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + + //location + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + serialCopy(&buffer, &packet->origin.x, sizeof(double)); + serialCopy(&buffer, &packet->origin.y, sizeof(double)); + serialCopy(&buffer, &packet->motion.x, sizeof(double)); + serialCopy(&buffer, &packet->motion.y, sizeof(double)); +} + +void deserializeMonster(void* buffer, MonsterPacket* packet) { + deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the monster + deserialCopy(&buffer, &packet->monsterIndex, sizeof(int)); + deserialCopy(&buffer, packet->handle, PACKET_STRING_SIZE); + deserialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE); + + //bounds + deserialCopy(&buffer, &packet->bounds.x, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.y, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.w, sizeof(int)); + deserialCopy(&buffer, &packet->bounds.h, sizeof(int)); + + + //location + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + deserialCopy(&buffer, &packet->origin.x, sizeof(double)); + deserialCopy(&buffer, &packet->origin.y, sizeof(double)); + deserialCopy(&buffer, &packet->motion.x, sizeof(double)); + deserialCopy(&buffer, &packet->motion.y, sizeof(double)); +} diff --git a/common/network/packet_types/monster_packet.hpp b/common/network/packet_types/monster_packet.hpp new file mode 100644 index 0000000..1dfae0c --- /dev/null +++ b/common/network/packet_types/monster_packet.hpp @@ -0,0 +1,46 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 MONSTERPACKET_HPP_ +#define MONSTERPACKET_HPP_ + +#include "serial_packet_base.hpp" + +#include "bounding_box.hpp" +#include "vector2.hpp" + +struct MonsterPacket : SerialPacketBase { + //identify the monster + int monsterIndex; + char handle[PACKET_STRING_SIZE]; + char avatar[PACKET_STRING_SIZE]; + BoundingBox bounds; + + //location + int roomIndex; + Vector2 origin; + Vector2 motion; +}; + +void serializeMonster(void* buffer, MonsterPacket* packet); +void deserializeMonster(void* buffer, MonsterPacket* packet); + +#endif \ No newline at end of file diff --git a/common/network/packet_types/text_packet.cpp b/common/network/packet_types/text_packet.cpp index 56a9836..2ec8ce2 100644 --- a/common/network/packet_types/text_packet.cpp +++ b/common/network/packet_types/text_packet.cpp @@ -29,6 +29,12 @@ void serializeText(void* buffer, TextPacket* packet) { //content serialCopy(&buffer, packet->name, PACKET_STRING_SIZE); serialCopy(&buffer, packet->text, PACKET_STRING_SIZE); + + //location + serialCopy(&buffer, &packet->roomIndex, sizeof(int)); + serialCopy(&buffer, &packet->origin.x, sizeof(double)); + serialCopy(&buffer, &packet->origin.y, sizeof(double)); + serialCopy(&buffer, &packet->range, sizeof(int)); } void deserializeText(void* buffer, TextPacket* packet) { @@ -37,4 +43,10 @@ void deserializeText(void* buffer, TextPacket* packet) { //content deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE); deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE); + + //location + deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); + deserialCopy(&buffer, &packet->origin.x, sizeof(double)); + deserialCopy(&buffer, &packet->origin.y, sizeof(double)); + deserialCopy(&buffer, &packet->range, sizeof(int)); } \ No newline at end of file diff --git a/common/network/packet_types/text_packet.hpp b/common/network/packet_types/text_packet.hpp index 0e793b6..9b9ae4b 100644 --- a/common/network/packet_types/text_packet.hpp +++ b/common/network/packet_types/text_packet.hpp @@ -24,9 +24,14 @@ #include "serial_packet_base.hpp" +#include "vector2.hpp" + struct TextPacket : SerialPacketBase { char name[PACKET_STRING_SIZE]; char text[PACKET_STRING_SIZE]; + int roomIndex; + Vector2 origin; + int range; }; void serializeText(void* buffer, TextPacket* packet); diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp index 5d609f3..2075c75 100644 --- a/common/network/serial_packet.hpp +++ b/common/network/serial_packet.hpp @@ -25,6 +25,7 @@ #include "serial_packet_base.hpp" #include "character_packet.hpp" #include "client_packet.hpp" +#include "monster_packet.hpp" #include "region_packet.hpp" #include "server_packet.hpp" #include "text_packet.hpp" @@ -33,14 +34,15 @@ typedef SerialPacketBase SerialPacket; //DOCS: NETWORK_VERSION is used to discern compatible servers and clients -constexpr int NETWORK_VERSION = 20141227; +constexpr int NETWORK_VERSION = 20150214; union MaxPacket { CharacterPacket a; ClientPacket b; - RegionPacket c; - ServerPacket d; - TextPacket e; + MonsterPacket c; + RegionPacket d; + ServerPacket e; + TextPacket f; }; constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket); diff --git a/common/network/serial_packet_type.hpp b/common/network/serial_packet_type.hpp index c4e9842..d538c24 100644 --- a/common/network/serial_packet_type.hpp +++ b/common/network/serial_packet_type.hpp @@ -27,10 +27,9 @@ * valid data, but it will still be carried in that packet's format. */ -//TODO: This needs to be smoothed out enum class SerialPacketType { //default: there is something wrong - NONE = 0, + NONE, //------------------------- //ServerPacket @@ -38,12 +37,12 @@ enum class SerialPacketType { //------------------------- //heartbeat - PING = 1, - PONG = 2, + PING, + PONG, //Used for finding available servers - BROADCAST_REQUEST = 3, - BROADCAST_RESPONSE = 4, + BROADCAST_REQUEST, + BROADCAST_RESPONSE, //------------------------- //ClientPacket @@ -51,24 +50,24 @@ enum class SerialPacketType { //------------------------- //Connecting to a server as a client - JOIN_REQUEST = 5, - JOIN_RESPONSE = 6, + JOIN_REQUEST, + JOIN_RESPONSE, //disconnect from the server - DISCONNECT_REQUEST = 7, - DISCONNECT_RESPONSE = 8, - DISCONNECT_FORCED = 9, + DISCONNECT_REQUEST, + DISCONNECT_RESPONSE, + ADMIN_DISCONNECT_FORCED, //load the account - LOGIN_REQUEST = 10, - LOGIN_RESPONSE = 11, + LOGIN_REQUEST, + LOGIN_RESPONSE, //unload the account - LOGOUT_REQUEST = 12, - LOGOUT_RESPONSE = 13, + LOGOUT_REQUEST, + LOGOUT_RESPONSE, //shut down the server - SHUTDOWN_REQUEST = 14, + ADMIN_SHUTDOWN_REQUEST, //------------------------- //RegionPacket @@ -76,35 +75,54 @@ enum class SerialPacketType { //------------------------- //map data - REGION_REQUEST = 15, //NOTE: technically a query - REGION_CONTENT = 16, + REGION_REQUEST, + REGION_CONTENT, //------------------------- //CharacterPacket // character index, // handle, avatar, // account index (owner), - // room index, origin, motion, - // statistics + // room index, origin, motion //------------------------- //character management - CHARACTER_CREATE = 17, - CHARACTER_DELETE = 18, - CHARACTER_LOAD = 19, - CHARACTER_UNLOAD = 20, + CHARACTER_CREATE, + CHARACTER_DELETE, + CHARACTER_LOAD, + CHARACTER_UNLOAD, //find out info from the server - QUERY_CHARACTER_EXISTS = 21, - QUERY_CHARACTER_STATS = 22, - QUERY_CHARACTER_LOCATION = 23, + QUERY_CHARACTER_EXISTS, + QUERY_CHARACTER_STATS, + QUERY_CHARACTER_LOCATION, //set the info in the server - CHARACTER_SET_ROOM = 24, - CHARACTER_SET_ORIGIN = 25, - CHARACTER_SET_MOTION = 26, + CHARACTER_MOVEMENT, + CHARACTER_ATTACK, + CHARACTER_DAMAGE, - //TODO: enemy management + //admin control +// ADMIN_SET_CHARACTER_ORIGIN, + + //------------------------- + //MonsterPacket + // monster index, + // handle, avatar + // bounds + // room index, origin, motion + //------------------------- + + MONSTER_CREATE, + MONSTER_DELETE, + + QUERY_MONSTER_EXISTS, + QUERY_MONSTER_STATS, + QUERY_MONSTER_LOCATION, + + MONSTER_MOVEMENT, + MONSTER_ATTACK, + MONSTER_DAMAGE, //------------------------- //TextPacket @@ -112,20 +130,24 @@ enum class SerialPacketType { //------------------------- //general speech - TEXT_BROADCAST = 27, + TEXT_BROADCAST, + TEXT_SPEECH, + TEXT_WHISPER, //rejection/error messages - JOIN_REJECTION = 28, - LOGIN_REJECTION = 29, - REGION_REJECTION = 30, - CHARACTER_REJECTION = 31, - SHUTDOWN_REJECTION = 32, + JOIN_REJECTION, + LOGIN_REJECTION, + REGION_REJECTION, + CHARACTER_REJECTION, + MONSTER_REJECTION, + SHUTDOWN_REJECTION, + QUERY_REJECTION, //------------------------- //not used //------------------------- - LAST = 33 + LAST }; #endif \ No newline at end of file diff --git a/common/network/serial_utility.cpp b/common/network/serial_utility.cpp index a0d2c61..25a3dfc 100644 --- a/common/network/serial_utility.cpp +++ b/common/network/serial_utility.cpp @@ -24,6 +24,7 @@ //packet types #include "character_packet.hpp" #include "client_packet.hpp" +#include "monster_packet.hpp" #include "region_packet.hpp" #include "server_packet.hpp" #include "text_packet.hpp" @@ -56,12 +57,12 @@ void serializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::JOIN_RESPONSE: case SerialPacketType::DISCONNECT_REQUEST: case SerialPacketType::DISCONNECT_RESPONSE: - case SerialPacketType::DISCONNECT_FORCED: + case SerialPacketType::ADMIN_DISCONNECT_FORCED: case SerialPacketType::LOGIN_REQUEST: case SerialPacketType::LOGIN_RESPONSE: case SerialPacketType::LOGOUT_REQUEST: case SerialPacketType::LOGOUT_RESPONSE: - case SerialPacketType::SHUTDOWN_REQUEST: + case SerialPacketType::ADMIN_SHUTDOWN_REQUEST: serializeClient(buffer, static_cast(packet)); break; case SerialPacketType::REGION_REQUEST: @@ -75,17 +76,31 @@ void serializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::QUERY_CHARACTER_EXISTS: case SerialPacketType::QUERY_CHARACTER_STATS: case SerialPacketType::QUERY_CHARACTER_LOCATION: - case SerialPacketType::CHARACTER_SET_ROOM: - case SerialPacketType::CHARACTER_SET_ORIGIN: - case SerialPacketType::CHARACTER_SET_MOTION: + case SerialPacketType::CHARACTER_MOVEMENT: + case SerialPacketType::CHARACTER_ATTACK: + case SerialPacketType::CHARACTER_DAMAGE: serializeCharacter(buffer, static_cast(packet)); break; + case SerialPacketType::MONSTER_CREATE: + case SerialPacketType::MONSTER_DELETE: + case SerialPacketType::QUERY_MONSTER_EXISTS: + case SerialPacketType::QUERY_MONSTER_STATS: + case SerialPacketType::QUERY_MONSTER_LOCATION: + case SerialPacketType::MONSTER_MOVEMENT: + case SerialPacketType::MONSTER_ATTACK: + case SerialPacketType::MONSTER_DAMAGE: + serializeMonster(buffer, static_cast(packet)); + break; case SerialPacketType::TEXT_BROADCAST: + case SerialPacketType::TEXT_SPEECH: + case SerialPacketType::TEXT_WHISPER: case SerialPacketType::JOIN_REJECTION: case SerialPacketType::LOGIN_REJECTION: case SerialPacketType::REGION_REJECTION: case SerialPacketType::CHARACTER_REJECTION: + case SerialPacketType::MONSTER_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION: + case SerialPacketType::QUERY_REJECTION: serializeText(buffer, static_cast(packet)); break; } @@ -107,12 +122,12 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::JOIN_RESPONSE: case SerialPacketType::DISCONNECT_REQUEST: case SerialPacketType::DISCONNECT_RESPONSE: - case SerialPacketType::DISCONNECT_FORCED: + case SerialPacketType::ADMIN_DISCONNECT_FORCED: case SerialPacketType::LOGIN_REQUEST: case SerialPacketType::LOGIN_RESPONSE: case SerialPacketType::LOGOUT_REQUEST: case SerialPacketType::LOGOUT_RESPONSE: - case SerialPacketType::SHUTDOWN_REQUEST: + case SerialPacketType::ADMIN_SHUTDOWN_REQUEST: deserializeClient(buffer, static_cast(packet)); break; case SerialPacketType::REGION_REQUEST: @@ -126,17 +141,31 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::QUERY_CHARACTER_EXISTS: case SerialPacketType::QUERY_CHARACTER_STATS: case SerialPacketType::QUERY_CHARACTER_LOCATION: - case SerialPacketType::CHARACTER_SET_ROOM: - case SerialPacketType::CHARACTER_SET_ORIGIN: - case SerialPacketType::CHARACTER_SET_MOTION: + case SerialPacketType::CHARACTER_MOVEMENT: + case SerialPacketType::CHARACTER_ATTACK: + case SerialPacketType::CHARACTER_DAMAGE: deserializeCharacter(buffer, static_cast(packet)); break; + case SerialPacketType::MONSTER_CREATE: + case SerialPacketType::MONSTER_DELETE: + case SerialPacketType::QUERY_MONSTER_EXISTS: + case SerialPacketType::QUERY_MONSTER_STATS: + case SerialPacketType::QUERY_MONSTER_LOCATION: + case SerialPacketType::MONSTER_MOVEMENT: + case SerialPacketType::MONSTER_ATTACK: + case SerialPacketType::MONSTER_DAMAGE: + deserializeMonster(buffer, static_cast(packet)); + break; case SerialPacketType::TEXT_BROADCAST: + case SerialPacketType::TEXT_SPEECH: + case SerialPacketType::TEXT_WHISPER: case SerialPacketType::JOIN_REJECTION: case SerialPacketType::LOGIN_REJECTION: case SerialPacketType::REGION_REJECTION: case SerialPacketType::CHARACTER_REJECTION: + case SerialPacketType::MONSTER_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION: + case SerialPacketType::QUERY_REJECTION: deserializeText(buffer, static_cast(packet)); break; } diff --git a/common/network/udp_network_utility.cpp b/common/network/udp_network_utility.cpp index 4dfb044..ec8733f 100644 --- a/common/network/udp_network_utility.cpp +++ b/common/network/udp_network_utility.cpp @@ -140,7 +140,6 @@ int UDPNetworkUtility::SendToAllChannels(void* data, int len) { return sent; } -//TODO: put a void* and int* parameter list here int UDPNetworkUtility::Receive() { memset(packet->data, 0, packet->maxlen); int ret = SDLNet_UDP_Recv(socket, packet); diff --git a/common/utilities/ip_operators.cpp b/common/utilities/ip_operators.cpp new file mode 100644 index 0000000..fe3ba48 --- /dev/null +++ b/common/utilities/ip_operators.cpp @@ -0,0 +1,30 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "ip_operators.hpp" + +bool operator==(IPaddress lhs, IPaddress rhs) { + return lhs.host == rhs.host && lhs.port == rhs.port; +} + +bool operator!=(IPaddress lhs, IPaddress rhs) { + return !(lhs == rhs); +} \ No newline at end of file diff --git a/common/utilities/utility.hpp b/common/utilities/ip_operators.hpp similarity index 80% rename from common/utilities/utility.hpp rename to common/utilities/ip_operators.hpp index 53cb426..cdfff9e 100644 --- a/common/utilities/utility.hpp +++ b/common/utilities/ip_operators.hpp @@ -19,16 +19,13 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef UTILITY_HPP_ -#define UTILITY_HPP_ +#ifndef IPOPERATORS_HPP_ +#define IPOPERATORS_HPP_ -#include +#include "SDL/SDL_net.h" -std::string truncatePath(std::string pathname); +//these should've come standard +bool operator==(IPaddress lhs, IPaddress rhs); +bool operator!=(IPaddress lhs, IPaddress rhs); -//fixing known bugs in g++ -std::string to_string_custom(int i); - -int to_integer_custom(std::string); - -#endif +#endif \ No newline at end of file diff --git a/rsc/scripts/map_saver.lua b/rsc/scripts/map_saver.lua index b9b77ea..0715807 100644 --- a/rsc/scripts/map_saver.lua +++ b/rsc/scripts/map_saver.lua @@ -11,5 +11,5 @@ function mapSaver.Save(r) io.write("map_saver:Save(", Region.GetX(r), ", ", Region.GetY(r), ")\n") end ---TODO: create a flexible saving & loading system +--TODO: (9) create a flexible saving & loading system return mapSaver \ No newline at end of file diff --git a/rsc/scripts/setup_server.sql b/rsc/scripts/setup_server.sql index e7e9c63..ddb1826 100644 --- a/rsc/scripts/setup_server.sql +++ b/rsc/scripts/setup_server.sql @@ -1,10 +1,10 @@ ---TODO: An archive table of all dead characters +--TODO: (9) An archive table of all dead characters CREATE TABLE IF NOT EXISTS Accounts ( uid INTEGER PRIMARY KEY AUTOINCREMENT, - username varchar(100) UNIQUE, + username varchar(100) UNIQUE, --TODO: (9) Swap username for email address - --TODO: server-client security + --server-client security -- passhash varchar(100), -- passsalt varchar(100), @@ -101,5 +101,5 @@ CREATE TABLE IF NOT EXISTS WornEquipment ( --unique information durability INTEGER DEFAULT 0, stats INTEGER REFERENCES StatisticSets(uid) - --TODO: attached script? + --attached script? ); diff --git a/server/accounts/account_data.hpp b/server/accounts/account_data.hpp index c40f281..97df753 100644 --- a/server/accounts/account_data.hpp +++ b/server/accounts/account_data.hpp @@ -47,7 +47,7 @@ private: int clientIndex; std::string username; - //TODO: password + //password/auth token //bit fields? bool blackListed = false; diff --git a/server/monsters/monster_manager.cpp b/server/monsters/monster_manager.cpp index 5717e45..b0f3d11 100644 --- a/server/monsters/monster_manager.cpp +++ b/server/monsters/monster_manager.cpp @@ -30,45 +30,45 @@ MonsterManager::~MonsterManager() { } int MonsterManager::Create(std::string) { - //TODO + //Create } void MonsterManager::Unload(int uid) { - //TODO + //Unload } void MonsterManager::UnloadAll() { - //TODO + //UnloadAll } void MonsterManager::UnloadIf(std::function)> fn) { - //TODO + //UnloadIf } MonsterData* MonsterManager::Get(int uid) { - //TODO + //Get } int MonsterManager::GetLoadedCount() { - //TODO + //GetLoadedCount } std::map* MonsterManager::GetContainer() { - //TODO + //GetContainer } lua_State* MonsterManager::SetLuaState(lua_State* L) { - //TODO + //SetLuaState } lua_State* MonsterManager::GetLuaState() { - //TODO + //GetLuaState } sqlite3* MonsterManager::SetDatabase(sqlite3* db) { - //TODO + //SetDatabase } sqlite3* MonsterManager::GetDatabase() { - //TODO + //GetDatabase } diff --git a/server/rooms/room_api.cpp b/server/rooms/room_api.cpp index 19b3a95..ffb9c8a 100644 --- a/server/rooms/room_api.cpp +++ b/server/rooms/room_api.cpp @@ -66,7 +66,6 @@ static int getWaypointMgr(lua_State* L) { } static int initialize(lua_State* L) { - //TODO: This could fit into the room system's globals RoomData* room = static_cast(lua_touserdata(L, 1)); //set the refs of these parameters (backwards, since it pops from the top of the stack) diff --git a/server/rooms/room_manager_api.cpp b/server/rooms/room_manager_api.cpp index 1eade08..1d4ba15 100644 --- a/server/rooms/room_manager_api.cpp +++ b/server/rooms/room_manager_api.cpp @@ -71,7 +71,7 @@ int unloadRoom(lua_State* L) { } int getRoom(lua_State* L) { - //TODO: integer vs name for getRoom() + //integer vs name for getRoom() RoomManager& roomMgr = RoomManager::GetSingleton(); RoomData* room = nullptr; diff --git a/server/server_application.hpp b/server/server_application.hpp index 8ed4f24..d53ed32 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -34,6 +34,7 @@ #include "udp_network_utility.hpp" //common utilities +#include "ip_operators.hpp" #include "serial_packet.hpp" #include "singleton.hpp" @@ -47,10 +48,6 @@ #include #include -//global utility functions -bool operator==(IPaddress lhs, IPaddress rhs); -bool operator!=(IPaddress lhs, IPaddress rhs); - //The main application class class ServerApplication: public Singleton { public: @@ -68,47 +65,59 @@ private: //handle incoming traffic void HandlePacket(SerialPacket* const); - //heartbeat sustem - void HandlePing(ServerPacket* const); - void HandlePong(ServerPacket* const); + //heartbeat system + void hPing(ServerPacket* const); + void hPong(ServerPacket* const); //basic connections - void HandleBroadcastRequest(ServerPacket* const); - void HandleJoinRequest(ClientPacket* const); - void HandleLoginRequest(ClientPacket* const); + void hBroadcastRequest(ServerPacket* const); + void hJoinRequest(ClientPacket* const); + void hLoginRequest(ClientPacket* const); //client disconnections - void HandleLogoutRequest(ClientPacket* const); - void HandleDisconnectRequest(ClientPacket* const); + void hLogoutRequest(ClientPacket* const); + void hDisconnectRequest(ClientPacket* const); //server commands - void HandleDisconnectForced(ClientPacket* const); - void HandleShutdownRequest(ClientPacket* const); + void hAdminDisconnectForced(ClientPacket* const); + void hAdminShutdownRequest(ClientPacket* const); //data management - void HandleRegionRequest(RegionPacket* const); - void HandleCharacterExists(CharacterPacket* const); - - void SaveServerState(); - void FullClientUnload(int index); - void FullAccountUnload(int index); - void FullCharacterUnload(int index); + void hRegionRequest(RegionPacket* const); + void hQueryCharacterExists(CharacterPacket* const); + void hQueryCharacterStats(CharacterPacket* const); + void hQueryCharacterLocation(CharacterPacket* const); + void hQueryMonsterExists(MonsterPacket* const); + void hQueryMonsterStats(MonsterPacket* const); + void hQueryMonsterLocation(MonsterPacket* const); //character management - void HandleCharacterCreate(CharacterPacket* const); - void HandleCharacterDelete(CharacterPacket* const); - void HandleCharacterLoad(CharacterPacket* const); - void HandleCharacterUnload(CharacterPacket* const); + void hCharacterCreate(CharacterPacket* const); + void hCharacterDelete(CharacterPacket* const); + void hCharacterLoad(CharacterPacket* const); + void hCharacterUnload(CharacterPacket* const); //character movement - void HandleCharacterSetRoom(CharacterPacket* const); - void HandleCharacterSetOrigin(CharacterPacket* const); - void HandleCharacterSetMotion(CharacterPacket* const); + void hCharacterMovement(CharacterPacket* const); + void hCharacterAttack(CharacterPacket* const); + void hCharacterDamage(CharacterPacket* const); + + //character management + void hMonsterDamage(MonsterPacket* const); + + //chat + void hTextBroadcast(TextPacket* const); + void hTextSpeech(TextPacket* const); + void hTextWhisper(TextPacket* const); //utility methods void PumpPacket(SerialPacket* const); void PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance); void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex); + void SaveServerState(); + void FullClientUnload(int index); + void FullAccountUnload(int index); + void FullCharacterUnload(int index); //APIs and utilities sqlite3* database = nullptr; diff --git a/server/server_character_methods.cpp b/server/server_character_methods.cpp index 910a6cc..38127e1 100644 --- a/server/server_character_methods.cpp +++ b/server/server_character_methods.cpp @@ -28,7 +28,7 @@ //Character Management //------------------------- -void ServerApplication::HandleCharacterCreate(CharacterPacket* const argPacket) { +void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) { int characterIndex = characterMgr.Create(argPacket->accountIndex, argPacket->handle, argPacket->avatar); if (characterIndex < 0) { @@ -55,7 +55,7 @@ void ServerApplication::HandleCharacterCreate(CharacterPacket* const argPacket) PumpPacket(&newPacket); } -void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) { +void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) { //get the user's data AccountData* accountData = accountMgr.Get(argPacket->accountIndex); if (!accountData) { @@ -102,7 +102,7 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) PumpPacket(static_cast(&newPacket)); } -void ServerApplication::HandleCharacterLoad(CharacterPacket* const argPacket) { +void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) { int characterIndex = characterMgr.Load(argPacket->accountIndex, argPacket->handle, argPacket->avatar); if (characterIndex < 0) { @@ -135,7 +135,7 @@ void ServerApplication::HandleCharacterLoad(CharacterPacket* const argPacket) { PumpPacket(&newPacket); } -void ServerApplication::HandleCharacterUnload(CharacterPacket* const argPacket) { +void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) { //get the entries CharacterData* characterData = characterMgr.Get(argPacket->characterIndex); if (!characterData) { @@ -144,12 +144,12 @@ void ServerApplication::HandleCharacterUnload(CharacterPacket* const argPacket) AccountData* accountData = accountMgr.Get(characterData->GetOwner()); if (!accountData) { - return; //TODO: logic_error + return; } ClientData* clientData = clientMgr.Get(accountData->GetClientIndex()); if (!clientData) { - return; //TODO: logic_error + return; } //check for fraud @@ -175,105 +175,15 @@ void ServerApplication::HandleCharacterUnload(CharacterPacket* const argPacket) //character movement //------------------------- -//TODO: ? Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments +//TODO: (2) Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments -void ServerApplication::HandleCharacterSetRoom(CharacterPacket* const argPacket) { +void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) { //get the specified objects AccountData* accountData = accountMgr.Get(argPacket->accountIndex); CharacterData* characterData = characterMgr.Get(argPacket->characterIndex); if (!accountData || !characterData) { - throw(std::runtime_error("Failed to set character room, missing data")); - } - - //get this account's client - ClientData* clientData = clientMgr.Get(accountData->GetClientIndex()); - - //check for fraud - if (clientData->GetAddress() != argPacket->srcAddress) { - std::cerr << "Falsified set character origin targeting uid(" << argPacket->characterIndex << ")" << std::endl; - return; - } - - //check if allowed - if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) { - //TODO: send to the client? - std::cerr << "Failed to set character room due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl; - return; - } - - //pop from the old room - roomMgr.PopCharacter(characterData); - - //set the character's room, zero it's origin, zero it's motion - characterData->SetRoomIndex(argPacket->roomIndex); - characterData->SetOrigin({0, 0}); - characterData->SetMotion({0, 0}); - - //push to the new room - roomMgr.PushCharacter(characterData); - - //update the clients - CharacterPacket newPacket; - CopyCharacterToPacket(&newPacket, argPacket->characterIndex); - newPacket.type = SerialPacketType::CHARACTER_SET_ROOM; - PumpPacket(&newPacket); -} - -void ServerApplication::HandleCharacterSetOrigin(CharacterPacket* const argPacket) { - //get the specified objects - AccountData* accountData = accountMgr.Get(argPacket->accountIndex); - CharacterData* characterData = characterMgr.Get(argPacket->characterIndex); - - if (!accountData || !characterData) { - throw(std::runtime_error("Failed to set character origin, missing data")); - } - - //get this account's client - ClientData* clientData = clientMgr.Get(accountData->GetClientIndex()); - - //check for fraud - if (clientData->GetAddress() != argPacket->srcAddress) { - std::cerr << "Falsified set character origin targeting uid(" << argPacket->characterIndex << ")" << std::endl; - return; - } - - //check if allowed - if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) { - //TODO: send to the client? - std::cerr << "Failed to set character origin due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl; - return; - } - - //set the character's origin, zero it's motion - characterData->SetOrigin(argPacket->origin); - characterData->SetMotion({0, 0}); - - //update the clients - CharacterPacket newPacket; - CopyCharacterToPacket(&newPacket, argPacket->characterIndex); - newPacket.type = SerialPacketType::CHARACTER_SET_ORIGIN; - PumpPacket(&newPacket); -} - -void ServerApplication::HandleCharacterSetMotion(CharacterPacket* const argPacket) { - //get the specified objects - AccountData* accountData = accountMgr.Get(argPacket->accountIndex); - - if (!accountData) { - std::ostringstream msg; - msg << "Failed to set character motion, missing account: Index " << argPacket->accountIndex << "; "; - msg << "Number of accounts loaded: " << accountMgr.GetContainer()->size(); - throw(std::runtime_error(msg.str())); - } - - CharacterData* characterData = characterMgr.Get(argPacket->characterIndex); - - if (!characterData) { - std::ostringstream msg; - msg << "Failed to set character motion, missing character: Index " << argPacket->characterIndex << "; "; - msg << "Number of characters loaded: " << characterMgr.GetContainer()->size(); - throw(std::runtime_error(msg.str())); + throw(std::runtime_error("Failed to move a character, missing data")); } //get this account's client @@ -287,18 +197,47 @@ void ServerApplication::HandleCharacterSetMotion(CharacterPacket* const argPacke //check if allowed if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) { - //TODO: send to the client? + //TODO: (2) send to the client? std::cerr << "Failed to set character motion due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl; return; } - //set the character's origin and motion - characterData->SetOrigin(argPacket->origin); - characterData->SetMotion(argPacket->motion); + //check if moving rooms + if (characterData->GetRoomIndex() != argPacket->roomIndex) { + //delete from the old room + CharacterPacket newPacket; + CopyCharacterToPacket(&newPacket, argPacket->characterIndex); + newPacket.type = SerialPacketType::CHARACTER_DELETE; + PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1); - //update the clients - CharacterPacket newPacket; - CopyCharacterToPacket(&newPacket, argPacket->characterIndex); - newPacket.type = SerialPacketType::CHARACTER_SET_MOTION; - PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1); + //move the character between rooms + roomMgr.PopCharacter(characterData); + characterData->SetRoomIndex(argPacket->roomIndex); + roomMgr.PushCharacter(characterData); + + //create in the new room + CopyCharacterToPacket(&newPacket, argPacket->characterIndex); + newPacket.type = SerialPacketType::CHARACTER_CREATE; + PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1); + } + //if not moving between rooms + else { + //set the character's origin and motion + characterData->SetOrigin(argPacket->origin); + characterData->SetMotion(argPacket->motion); + + //update the clients + CharacterPacket newPacket; + CopyCharacterToPacket(&newPacket, argPacket->characterIndex); + newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; + PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1); + } } + +void ServerApplication::hCharacterAttack(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hCharacterDamage(CharacterPacket* const argPacket) { + //TODO: (9) empty +} \ No newline at end of file diff --git a/server/server_chat.cpp b/server/server_chat.cpp new file mode 100644 index 0000000..ed9c4e4 --- /dev/null +++ b/server/server_chat.cpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "server_application.hpp" + +void ServerApplication::hTextBroadcast(TextPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hTextSpeech(TextPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hTextWhisper(TextPacket* const argPacket) { + //TODO: (9) empty +} diff --git a/server/server_connections.cpp b/server/server_connections.cpp index 12ceda0..36c5bf0 100644 --- a/server/server_connections.cpp +++ b/server/server_connections.cpp @@ -28,13 +28,13 @@ //heartbeat system //------------------------- -void ServerApplication::HandlePing(ServerPacket* const argPacket) { +void ServerApplication::hPing(ServerPacket* const argPacket) { ServerPacket newPacket; newPacket.type = SerialPacketType::PONG; network.SendTo(argPacket->srcAddress, &newPacket); } -void ServerApplication::HandlePong(ServerPacket* const argPacket) { +void ServerApplication::hPong(ServerPacket* const argPacket) { clientMgr.HandlePong(argPacket); } @@ -42,7 +42,7 @@ void ServerApplication::HandlePong(ServerPacket* const argPacket) { //basic connections //------------------------- -void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) { +void ServerApplication::hBroadcastRequest(ServerPacket* const argPacket) { //send the server's data ServerPacket newPacket; @@ -54,7 +54,7 @@ void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) { network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); } -void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { +void ServerApplication::hJoinRequest(ClientPacket* const argPacket) { //register the client int clientIndex = clientMgr.Create(argPacket->srcAddress); @@ -69,7 +69,7 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { std::cout << "New join, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; } -void ServerApplication::HandleLoginRequest(ClientPacket* const argPacket) { +void ServerApplication::hLoginRequest(ClientPacket* const argPacket) { //get the client data ClientData* clientData = clientMgr.Get(argPacket->clientIndex); @@ -110,7 +110,7 @@ void ServerApplication::HandleLoginRequest(ClientPacket* const argPacket) { std::cout << "New login, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; } -void ServerApplication::HandleLogoutRequest(ClientPacket* const argPacket) { +void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) { //get the account and client data AccountData* accountData = accountMgr.Get(argPacket->accountIndex); if (!accountData) { @@ -144,7 +144,7 @@ void ServerApplication::HandleLogoutRequest(ClientPacket* const argPacket) { std::cout << "New logout, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; } -void ServerApplication::HandleDisconnectRequest(ClientPacket* const argPacket) { +void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) { //get the client data ClientData* clientData = clientMgr.Get(argPacket->clientIndex); if (!clientData) { @@ -170,7 +170,3 @@ void ServerApplication::HandleDisconnectRequest(ClientPacket* const argPacket) { //finished this routine std::cout << "New disconnection, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; } - -void ServerApplication::HandleDisconnectForced(ClientPacket* const argPacket) { - //TODO: HandleDisconnectForced -} \ No newline at end of file diff --git a/server/server_data.cpp b/server/server_data_queries.cpp similarity index 80% rename from server/server_data.cpp rename to server/server_data_queries.cpp index c8f3c92..1019223 100644 --- a/server/server_data.cpp +++ b/server/server_data_queries.cpp @@ -25,20 +25,10 @@ #include //------------------------- -//General data management +//Queries //------------------------- -//TODO: Queries - -void ServerApplication::SaveServerState() { - //TODO: SaveServerState -} - -//------------------------- -//Map management -//------------------------- - -void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { +void ServerApplication::hRegionRequest(RegionPacket* const argPacket) { //get the region object, send a rejection on error RoomData* room = roomMgr.Get(argPacket->roomIndex); if (!room) { @@ -71,7 +61,7 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); } -void ServerApplication::HandleCharacterExists(CharacterPacket* const argPacket) { +void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket) { //respond with all character data CharacterPacket newPacket; @@ -84,3 +74,23 @@ void ServerApplication::HandleCharacterExists(CharacterPacket* const argPacket) network.SendTo(argPacket->srcAddress, static_cast(&newPacket)); } } + +void ServerApplication::hQueryCharacterStats(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hQueryCharacterLocation(CharacterPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hQueryMonsterExists(MonsterPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hQueryMonsterStats(MonsterPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hQueryMonsterLocation(MonsterPacket* const argPacket) { + //TODO: (9) empty +} diff --git a/server/server_logic.cpp b/server/server_logic.cpp index 802c8c9..78d5114 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -23,7 +23,6 @@ //utility functions #include "sql_tools.hpp" -#include "utility.hpp" //std & STL #include @@ -129,7 +128,6 @@ void ServerApplication::Init(int argc, char* argv[]) { //debug output //------------------------- - //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; @@ -196,7 +194,8 @@ void ServerApplication::Proc() { void ServerApplication::Quit() { std::cout << "Shutting down" << std::endl; - //TODO: save the server state + //save the server state + SaveServerState(); //close the managers accountMgr.UnloadAll(); @@ -215,99 +214,116 @@ void ServerApplication::Quit() { } //------------------------- -//direct incoming traffic +//handle incoming traffic //------------------------- void ServerApplication::HandlePacket(SerialPacket* const argPacket) { switch(argPacket->type) { //heartbeat system case SerialPacketType::PING: - HandlePing(static_cast(argPacket)); + hPing(static_cast(argPacket)); break; case SerialPacketType::PONG: - HandlePong(static_cast(argPacket)); + hPong(static_cast(argPacket)); break; //client connections case SerialPacketType::BROADCAST_REQUEST: - HandleBroadcastRequest(static_cast(argPacket)); + hBroadcastRequest(static_cast(argPacket)); break; case SerialPacketType::JOIN_REQUEST: - HandleJoinRequest(static_cast(argPacket)); + hJoinRequest(static_cast(argPacket)); break; case SerialPacketType::LOGIN_REQUEST: - HandleLoginRequest(static_cast(argPacket)); + hLoginRequest(static_cast(argPacket)); break; //client disconnections case SerialPacketType::LOGOUT_REQUEST: - HandleLogoutRequest(static_cast(argPacket)); + hLogoutRequest(static_cast(argPacket)); break; case SerialPacketType::DISCONNECT_REQUEST: - HandleDisconnectRequest(static_cast(argPacket)); + hDisconnectRequest(static_cast(argPacket)); break; //server commands -// case SerialPacketType::DISCONNECT_FORCED: -// HandleDisconnectForced(static_cast(argPacket)); -// break; - case SerialPacketType::SHUTDOWN_REQUEST: - HandleShutdownRequest(static_cast(argPacket)); + case SerialPacketType::ADMIN_DISCONNECT_FORCED: + hAdminDisconnectForced(static_cast(argPacket)); + break; + case SerialPacketType::ADMIN_SHUTDOWN_REQUEST: + hAdminShutdownRequest(static_cast(argPacket)); break; //data management & queries case SerialPacketType::REGION_REQUEST: - HandleRegionRequest(static_cast(argPacket)); + hRegionRequest(static_cast(argPacket)); break; case SerialPacketType::QUERY_CHARACTER_EXISTS: - HandleCharacterExists(static_cast(argPacket)); + hQueryCharacterExists(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_CHARACTER_STATS: + hQueryCharacterStats(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_CHARACTER_LOCATION: + hQueryCharacterLocation(static_cast(argPacket)); + break; + + case SerialPacketType::QUERY_MONSTER_EXISTS: + hQueryMonsterExists(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_MONSTER_STATS: + hQueryMonsterStats(static_cast(argPacket)); + break; + case SerialPacketType::QUERY_MONSTER_LOCATION: + hQueryMonsterLocation(static_cast(argPacket)); break; //character management case SerialPacketType::CHARACTER_CREATE: - HandleCharacterCreate(static_cast(argPacket)); + hCharacterCreate(static_cast(argPacket)); break; case SerialPacketType::CHARACTER_DELETE: - HandleCharacterDelete(static_cast(argPacket)); + hCharacterDelete(static_cast(argPacket)); break; case SerialPacketType::CHARACTER_LOAD: - HandleCharacterLoad(static_cast(argPacket)); + hCharacterLoad(static_cast(argPacket)); break; case SerialPacketType::CHARACTER_UNLOAD: - HandleCharacterUnload(static_cast(argPacket)); + hCharacterUnload(static_cast(argPacket)); break; //character movement - case SerialPacketType::CHARACTER_SET_ROOM: - HandleCharacterSetRoom(static_cast(argPacket)); + case SerialPacketType::CHARACTER_MOVEMENT: + hCharacterMovement(static_cast(argPacket)); break; - case SerialPacketType::CHARACTER_SET_ORIGIN: - HandleCharacterSetOrigin(static_cast(argPacket)); + case SerialPacketType::CHARACTER_ATTACK: + hCharacterAttack(static_cast(argPacket)); break; - case SerialPacketType::CHARACTER_SET_MOTION: - HandleCharacterSetMotion(static_cast(argPacket)); + case SerialPacketType::CHARACTER_DAMAGE: + hCharacterDamage(static_cast(argPacket)); break; -/* - case SerialPacketType::QUERY_CHARACTER_STATS: -// HandleCharacterStatsRequest(static_cast(argPacket)); - break; - case SerialPacketType::QUERY_CHARACTER_LOCATION: -// HandleCharacterStatsRequest(static_cast(argPacket)); + + //monster management + case SerialPacketType::MONSTER_DAMAGE: + hMonsterDamage(static_cast(argPacket)); break; + + //chat case SerialPacketType::TEXT_BROADCAST: -// HandleCharacterStatsRequest(static_cast(argPacket)); + hTextBroadcast(static_cast(argPacket)); + break; + case SerialPacketType::TEXT_SPEECH: + hTextSpeech(static_cast(argPacket)); + break; + case SerialPacketType::TEXT_WHISPER: + hTextWhisper(static_cast(argPacket)); break; - //enemy management - //TODO: enemy management - - //TODO: text -*/ //handle errors default: { std::ostringstream msg; msg << "Unknown SerialPacketType encountered in the server: "; - msg << to_string_custom(static_cast(argPacket->type)); + msg << static_cast(argPacket->type); throw(std::runtime_error(msg.str())); } break; diff --git a/server/server_methods.cpp b/server/server_methods.cpp index 1d50643..d440153 100644 --- a/server/server_methods.cpp +++ b/server/server_methods.cpp @@ -25,23 +25,15 @@ #include #include -//------------------------- -//these should've come standard -//------------------------- - -bool operator==(IPaddress lhs, IPaddress rhs) { - return lhs.host == rhs.host && lhs.port == rhs.port; -} - -bool operator!=(IPaddress lhs, IPaddress rhs) { - return !(lhs == rhs); -} - //------------------------- //server commands //------------------------- -void ServerApplication::HandleShutdownRequest(ClientPacket* const argPacket) { +void ServerApplication::hAdminDisconnectForced(ClientPacket* const argPacket) { + //TODO: (9) empty +} + +void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) { //get the account and client data AccountData* accountData = accountMgr.Get(argPacket->accountIndex); if (!accountData) { @@ -84,7 +76,7 @@ void ServerApplication::HandleShutdownRequest(ClientPacket* const argPacket) { //disconnect all clients TextPacket newPacket; - newPacket.type = SerialPacketType::DISCONNECT_FORCED; + newPacket.type = SerialPacketType::ADMIN_DISCONNECT_FORCED; strncpy(newPacket.text, "Server shutdown", PACKET_STRING_SIZE); PumpPacket(&newPacket); @@ -92,6 +84,10 @@ void ServerApplication::HandleShutdownRequest(ClientPacket* const argPacket) { std::cout << "Shutdown signal accepted" << std::endl; } +void ServerApplication::SaveServerState() { + //TODO: (9) empty +} + //------------------------- //full unload methods //------------------------- diff --git a/server/server_monster_methods.cpp b/server/server_monster_methods.cpp new file mode 100644 index 0000000..ae8ba43 --- /dev/null +++ b/server/server_monster_methods.cpp @@ -0,0 +1,26 @@ +/* Copyright: (c) Kayne Ruse 2013-2015 + * + * 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 "server_application.hpp" + +void ServerApplication::hMonsterDamage(MonsterPacket* const argPacket) { + //TODO: (9) empty +} \ No newline at end of file diff --git a/server/server_utilities/makefile b/server/server_utilities/makefile index f24e1ba..8d12afe 100644 --- a/server/server_utilities/makefile +++ b/server/server_utilities/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. ../../common/utilities +INCLUDES+=. LIBS+= CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) diff --git a/server/server_utilities/sql_tools.cpp b/server/server_utilities/sql_tools.cpp index d83acba..78e1065 100644 --- a/server/server_utilities/sql_tools.cpp +++ b/server/server_utilities/sql_tools.cpp @@ -21,10 +21,9 @@ */ #include "sql_tools.hpp" -#include "utility.hpp" - #include #include +#include #include int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**), void* argPtr) { @@ -42,9 +41,10 @@ int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char* int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg); if (ret != SQLITE_OK) { //handle any errors received from the SQL - std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg); + std::ostringstream msg; + msg << "SQL Script Error " << ret << ": " << errmsg; free(errmsg); - throw(e); + throw(std::runtime_error( msg.str() )); } return ret; } \ No newline at end of file diff --git a/server/waypoints/waypoint_manager_api.cpp b/server/waypoints/waypoint_manager_api.cpp index 447c666..a88dc48 100644 --- a/server/waypoints/waypoint_manager_api.cpp +++ b/server/waypoints/waypoint_manager_api.cpp @@ -27,12 +27,10 @@ static int create(lua_State* L) { WaypointManager* mgr = static_cast(lua_touserdata(L, 1)); - //TODO } static int unload(lua_State* L) { WaypointManager* mgr = static_cast(lua_touserdata(L, 1)); - //TODO } static int getWaypoint(lua_State* L) { diff --git a/todo.txt b/todo.txt index 119146c..eca1dfc 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,5 @@ TODO: In need of script APIs (list) * Characters - * Monsters - * Waypoints TODO: Account passwords (list) * backbone account server OR @@ -9,15 +7,21 @@ TODO: Account passwords (list) * ... * salts & hashes -TODO: Split config.cfg in two, one for the server and the client -TODO: Add the "home" parameter to the server's config file -TODO: Waypoints, with positions and trigger zones (collision areas) for doors, monster spawns, etc. -TODO: Fix shoddy movement -TODO: Periodic mass server saves -TODO: Remove the big "Shut Down" button (currently broken...) -TODO: Make a way for the server owner to control the server directly -TODO: The TileSheet class should implement the surface itself -TODO: Time delay for requesting region packets -TODO: A proper logging system -TODO: Fix the const-ness of accessors -TODO: Add a screenshot of the game to README.md \ No newline at end of file +TODO: Features + * Make sure login errors are sent to the client + * Split config.cfg in two, one for the server and the client + * Add the "home" parameter to the server's config file + * Waypoints, with positions and trigger zones (collision areas) for doors, monster spawns, etc. + * Fix shoddy movement + * Periodic mass server saves + * Remove the big "Shut Down" button (currently broken...) + * Make a way for the server owner to control the server directly + * The TileSheet class should implement the surface itself + * Time delay for requesting region packets + * A proper logging system + * Fix the const-ness of accessors + * Add a screenshot of the game to README.md + * joystick/gamepad support + * add the tilesheet to the map system + * ping/delay displayed in the lobby + * login screen prompting for username & password \ No newline at end of file