diff --git a/client/client_application.cpp b/client/client_application.cpp index 21ad65e..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" //------------------------- @@ -185,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/gameplay_scenes/in_world_networking.cpp b/client/gameplay_scenes/in_world_networking.cpp deleted file mode 100644 index db23ce1..0000000 --- a/client/gameplay_scenes/in_world_networking.cpp +++ /dev/null @@ -1,264 +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 "ip_operators.hpp" -#include "terminal_error.hpp" - -#include -#include -#include - -//------------------------- -//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; - case SerialPacketType::CHARACTER_MOVEMENT: - HandleCharacterMovement(static_cast(argPacket)); - break; - case SerialPacketType::CHARACTER_ATTACK: - HandleCharacterAttack(static_cast(argPacket)); - break; - - //monster management - case SerialPacketType::MONSTER_CREATE: - HandleMonsterCreate(static_cast(argPacket)); - break; - case SerialPacketType::MONSTER_DELETE: - HandleMonsterDelete(static_cast(argPacket)); - break; - case SerialPacketType::QUERY_MONSTER_EXISTS: - HandleMonsterQueryExists(static_cast(argPacket)); - break; - case SerialPacketType::MONSTER_MOVEMENT: - HandleMonsterMovement(static_cast(argPacket)); - break; - case SerialPacketType::MONSTER_ATTACK: - HandleMonsterAttack(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); - } - } - } -} \ No newline at end of file diff --git a/client/gameplay_scenes/in_world.hpp b/client/gameplay_scenes/world.hpp similarity index 68% rename from client/gameplay_scenes/in_world.hpp rename to client/gameplay_scenes/world.hpp index bbf4705..cc2135a 100644 --- a/client/gameplay_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,42 +71,56 @@ 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 HandleCharacterMovement(CharacterPacket* const); - void HandleCharacterAttack(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); //monster management - void HandleMonsterCreate(MonsterPacket* const); - void HandleMonsterDelete(MonsterPacket* const); - void HandleMonsterQueryExists(MonsterPacket* const); - void HandleMonsterMovement(MonsterPacket* const); - void HandleMonsterAttack(MonsterPacket* const); + 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); - //player movement + //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); diff --git a/client/gameplay_scenes/in_world_characters.cpp b/client/gameplay_scenes/world_characters.cpp similarity index 88% rename from client/gameplay_scenes/in_world_characters.cpp rename to client/gameplay_scenes/world_characters.cpp index 328cfd7..8512e76 100644 --- a/client/gameplay_scenes/in_world_characters.cpp +++ b/client/gameplay_scenes/world_characters.cpp @@ -19,7 +19,7 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "in_world.hpp" +#include "world.hpp" #include "channels.hpp" @@ -35,7 +35,7 @@ //DOCS: new characters will result in create messages //DOCS: this client's character will exist in both (skipped) -void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) { +void World::hCharacterCreate(CharacterPacket* const argPacket) { //prevent double message if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { std::ostringstream msg; @@ -74,7 +74,7 @@ void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) { std::cout << "Character Create, total: " << characterMap.size() << std::endl; } -void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { +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()) { @@ -100,7 +100,7 @@ void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { std::cout << "Character Delete, total: " << characterMap.size() << std::endl; } -void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) { +void World::hQueryCharacterExists(CharacterPacket* const argPacket) { //prevent a double message about this player's character if (argPacket->accountIndex == accountIndex) { return; @@ -127,7 +127,15 @@ void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) { std::cout << "Character Query, total: " << characterMap.size() << std::endl; } -void InWorld::HandleCharacterMovement(CharacterPacket* const argPacket) { +void World::hQueryCharacterStats(CharacterPacket* const argPacket) { + //TODO: empty +} + +void World::hQueryCharacterLocation(CharacterPacket* const argPacket) { + //TODO: empty +} + +void World::hCharacterMovement(CharacterPacket* const argPacket) { //TODO: (1) Authentication if (argPacket->characterIndex == characterIndex) { return; @@ -143,15 +151,19 @@ void InWorld::HandleCharacterMovement(CharacterPacket* const argPacket) { } } -void InWorld::HandleCharacterAttack(CharacterPacket* const argPacket) { +void World::hCharacterAttack(CharacterPacket* const argPacket) { + //TODO: (1) attack animation +} + +void World::hCharacterDamage(CharacterPacket* const argPacket) { //TODO: (1) attack animation } //------------------------- -//player movement +//player movement & collision //------------------------- -void InWorld::SendLocalCharacterMovement() { +void World::SendLocalCharacterMovement() { CharacterPacket newPacket; newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; @@ -164,7 +176,7 @@ void InWorld::SendLocalCharacterMovement() { network.SendTo(Channels::SERVER, &newPacket); } -std::list InWorld::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) { +std::list World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) { //prepare for collisions BoundingBox wallBounds = {0, 0, tileWidth, tileHeight}; std::list boxList; diff --git a/client/gameplay_scenes/world_chat.cpp b/client/gameplay_scenes/world_chat.cpp new file mode 100644 index 0000000..9386478 --- /dev/null +++ b/client/gameplay_scenes/world_chat.cpp @@ -0,0 +1,39 @@ +/* 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" + +//------------------------- +//chat +//------------------------- + +void World::hTextBroadcast(TextPacket* const argPacket) { + //TODO: (1) empty +} + +void World::hTextSpeech(TextPacket* const argPacket) { + //TODO: (1) empty +} + +void World::hTextWhisper(TextPacket* const argPacket) { + //TODO: (1) empty +} + diff --git a/client/gameplay_scenes/world_connections.cpp b/client/gameplay_scenes/world_connections.cpp new file mode 100644 index 0000000..c20c101 --- /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: 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/in_world_scene.cpp b/client/gameplay_scenes/world_logic.cpp similarity index 62% rename from client/gameplay_scenes/in_world_scene.cpp rename to client/gameplay_scenes/world_logic.cpp index 44004ea..509d570 100644 --- a/client/gameplay_scenes/in_world_scene.cpp +++ b/client/gameplay_scenes/world_logic.cpp @@ -19,7 +19,7 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "in_world.hpp" +#include "world.hpp" #include "channels.hpp" @@ -34,7 +34,7 @@ //Public access members //------------------------- -InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): +World::World(int* const argClientIndex, int* const argAccountIndex): clientIndex(*argClientIndex), accountIndex(*argAccountIndex) { @@ -75,8 +75,8 @@ InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): 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); + newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS; + network.SendTo(Channels::SERVER, &newPacket); //set the camera's values camera.width = GetScreen()->w; @@ -86,7 +86,7 @@ InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): // } -InWorld::~InWorld() { +World::~World() { //unload the local data characterMap.clear(); monsterMap.clear(); @@ -96,11 +96,11 @@ InWorld::~InWorld() { //Frame loop //------------------------- -void InWorld::FrameStart() { +void World::FrameStart() { // } -void InWorld::Update() { +void World::Update() { //create and zero the buffer SerialPacket* packetBuffer = reinterpret_cast(new char[MAX_PACKET_SIZE]); memset(packetBuffer, 0, MAX_PACKET_SIZE); @@ -154,18 +154,18 @@ void InWorld::Update() { camera.y = localCharacter->GetOrigin().y - camera.marginY; } -void InWorld::FrameEnd() { +void World::FrameEnd() { // } -void InWorld::RenderFrame() { +void World::RenderFrame() { // SDL_FillRect(GetScreen(), 0, 0); Render(GetScreen()); SDL_Flip(GetScreen()); fps.Calculate(); } -void InWorld::Render(SDL_Surface* const screen) { +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); @@ -192,32 +192,32 @@ void InWorld::Render(SDL_Surface* const screen) { //Event handlers //------------------------- -void InWorld::QuitEvent() { +void World::QuitEvent() { //two-step logout SendDisconnectRequest(); SetNextScene(SceneList::QUIT); } -void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) { +void World::MouseMotion(SDL_MouseMotionEvent const& motion) { disconnectButton.MouseMotion(motion); shutDownButton.MouseMotion(motion); } -void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) { +void World::MouseButtonDown(SDL_MouseButtonEvent const& button) { disconnectButton.MouseButtonDown(button); shutDownButton.MouseButtonDown(button); } -void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& 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) { - SendShutdownRequest(); + SendAdminShutdownRequest(); } } -void InWorld::KeyDown(SDL_KeyboardEvent const& key) { +void World::KeyDown(SDL_KeyboardEvent const& key) { //hotkeys switch(key.keysym.sym) { case SDLK_ESCAPE: @@ -258,7 +258,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) { SendLocalCharacterMovement(); } -void InWorld::KeyUp(SDL_KeyboardEvent const& key) { +void World::KeyUp(SDL_KeyboardEvent const& key) { //character movement if (!localCharacter) { return; @@ -302,4 +302,117 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { 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/in_world_monsters.cpp b/client/gameplay_scenes/world_monsters.cpp similarity index 84% rename from client/gameplay_scenes/in_world_monsters.cpp rename to client/gameplay_scenes/world_monsters.cpp index c9f3a45..9b8acda 100644 --- a/client/gameplay_scenes/in_world_monsters.cpp +++ b/client/gameplay_scenes/world_monsters.cpp @@ -19,7 +19,7 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "in_world.hpp" +#include "world.hpp" #include "channels.hpp" @@ -31,7 +31,7 @@ //monster management //------------------------- -void InWorld::HandleMonsterCreate(MonsterPacket* const argPacket) { +void World::hMonsterCreate(MonsterPacket* const argPacket) { //check for logic errors if (monsterMap.find(argPacket->monsterIndex) != monsterMap.end()) { std::ostringstream msg; @@ -64,7 +64,7 @@ void InWorld::HandleMonsterCreate(MonsterPacket* const argPacket) { std::cout << "Monster Create, total: " << monsterMap.size() << std::endl; } -void InWorld::HandleMonsterDelete(MonsterPacket* const argPacket) { +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()) { @@ -78,7 +78,7 @@ void InWorld::HandleMonsterDelete(MonsterPacket* const argPacket) { std::cout << "Monster Delete, total: " << monsterMap.size() << std::endl; } -void InWorld::HandleMonsterQueryExists(MonsterPacket* const argPacket) { +void World::hQueryMonsterExists(MonsterPacket* const argPacket) { //ignore monsters in a different room (sub-optimal) if (argPacket->roomIndex != roomIndex) { return; @@ -98,7 +98,15 @@ void InWorld::HandleMonsterQueryExists(MonsterPacket* const argPacket) { std::cout << "Monster Query, total: " << monsterMap.size() << std::endl; } -void InWorld::HandleMonsterMovement(MonsterPacket* const argPacket) { +void World::hQueryMonsterStats(MonsterPacket* const argPacket) { + //TODO: empty +} + +void World::hQueryMonsterLocation(MonsterPacket* const argPacket) { + //TODO: 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()) { @@ -109,6 +117,10 @@ void InWorld::HandleMonsterMovement(MonsterPacket* const argPacket) { monsterIt->second.SetOrigin(argPacket->motion); } -void InWorld::HandleMonsterAttack(MonsterPacket* const argPacket) { +void World::hMonsterAttack(MonsterPacket* const argPacket) { //TODO: (1) HandleMonsterAttack +} + +void World::hMonsterDamage(MonsterPacket* const argPacket) { + //TODO: (1) empty } \ No newline at end of file diff --git a/client/menu_scenes/lobby_menu.cpp b/client/menu_scenes/lobby_menu.cpp index 95704a0..f9997b7 100644 --- a/client/menu_scenes/lobby_menu.cpp +++ b/client/menu_scenes/lobby_menu.cpp @@ -248,7 +248,7 @@ 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) { diff --git a/client/menu_scenes/main_menu.cpp b/client/menu_scenes/main_menu.cpp index cd62757..53bda74 100644 --- a/client/menu_scenes/main_menu.cpp +++ b/client/menu_scenes/main_menu.cpp @@ -125,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/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/common/network/serial_packet_type.hpp b/common/network/serial_packet_type.hpp index cd798ab..d538c24 100644 --- a/common/network/serial_packet_type.hpp +++ b/common/network/serial_packet_type.hpp @@ -141,6 +141,7 @@ enum class SerialPacketType { CHARACTER_REJECTION, MONSTER_REJECTION, SHUTDOWN_REJECTION, + QUERY_REJECTION, //------------------------- //not used diff --git a/common/network/serial_utility.cpp b/common/network/serial_utility.cpp index 7159b10..25a3dfc 100644 --- a/common/network/serial_utility.cpp +++ b/common/network/serial_utility.cpp @@ -100,6 +100,7 @@ void serializePacket(void* buffer, SerialPacketBase* packet) { case SerialPacketType::CHARACTER_REJECTION: case SerialPacketType::MONSTER_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION: + case SerialPacketType::QUERY_REJECTION: serializeText(buffer, static_cast(packet)); break; } @@ -164,6 +165,7 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) { 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/server/server_logic.cpp b/server/server_logic.cpp index 83ee0b6..c64525f 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -213,7 +213,7 @@ void ServerApplication::Quit() { } //------------------------- -//direct incoming traffic +//handle incoming traffic //------------------------- void ServerApplication::HandlePacket(SerialPacket* const argPacket) {