diff --git a/client/client_application.cpp b/client/client_application.cpp index b9a31bd..d3ce86c 100644 --- a/client/client_application.cpp +++ b/client/client_application.cpp @@ -124,7 +124,7 @@ void ClientApplication::LoadScene(SceneList sceneIndex) { activeScene = new OptionsMenu(&config); break; case SceneList::LOBBYMENU: - activeScene = new LobbyMenu(&config, &network, &clientIndex, &accountIndex, &characterIndex); + activeScene = new LobbyMenu(&config, &network, &clientIndex, &accountIndex); break; case SceneList::INWORLD: activeScene = new InWorld(&config, &network, &clientIndex, &accountIndex, &characterIndex, &combatMap, &characterMap); diff --git a/client/in_combat.cpp b/client/in_combat.cpp index 6be762f..24b85e9 100644 --- a/client/in_combat.cpp +++ b/client/in_combat.cpp @@ -85,12 +85,12 @@ void InCombat::FrameStart() { } void InCombat::Update(double delta) { - SerialPacket packet; - - //suck in all waiting packets - while(network.Receive(&packet)) { - HandlePacket(packet); + //suck in and process all waiting packets + SerialPacket* packetBuffer = static_cast(malloc(MAX_PACKET_SIZE)); + while(network.Receive(packetBuffer)) { + HandlePacket(packetBuffer); } + free(static_cast(packetBuffer)); //TODO: more } @@ -154,19 +154,19 @@ void InCombat::KeyUp(SDL_KeyboardEvent const& key) { //Network handlers //------------------------- -void InCombat::HandlePacket(SerialPacket packet) { - switch(packet.meta.type) { - case SerialPacket::Type::DISCONNECT: - HandleDisconnect(packet); +void InCombat::HandlePacket(SerialPacket* const argPacket) { + switch(argPacket->type) { + case SerialPacketType::DISCONNECT: + HandleDisconnect(argPacket); break; //handle errors default: - throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in InCombat: " + to_string_custom(int(packet.meta.type)))); + throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in InCombat: " + to_string_custom(static_cast(argPacket->type)) )); break; } } -void InCombat::HandleDisconnect(SerialPacket) { +void InCombat::HandleDisconnect(SerialPacket* const) { SetNextScene(SceneList::RESTART); } @@ -177,52 +177,56 @@ void InCombat::HandleDisconnect(SerialPacket) { //------------------------- void InCombat::RequestSynchronize() { - SerialPacket packet; + ClientPacket newPacket; //request a sync - packet.meta.type = SerialPacket::Type::SYNCHRONIZE; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::SYNCHRONIZE; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } void InCombat::SendPlayerUpdate() { - SerialPacket packet; + CharacterPacket newPacket; //pack the packet - packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE; - packet.characterInfo.clientIndex = clientIndex; - packet.characterInfo.accountIndex = accountIndex; - packet.characterInfo.characterIndex = characterIndex; -// packet.characterInfo.position = localCharacter->position; -// packet.characterInfo.motion = localCharacter->motion; - //TODO: stats + newPacket.type = SerialPacketType::CHARACTER_UPDATE; - network.SendTo(Channels::SERVER, &packet); + newPacket.characterIndex = characterIndex; + //handle, avatar + newPacket.accountIndex = accountIndex; +// newPacket.roomIndex = localCharacter->roomIndex; +// newPacket.origin = localCharacter->origin; +// newPacket.motion = localCharacter->motion; +// newPacket.stats = localCharacter->stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + network.SendTo(Channels::SERVER, &newPacket); } void InCombat::RequestDisconnect() { - SerialPacket packet; + ClientPacket newPacket; //send a disconnect request - packet.meta.type = SerialPacket::Type::DISCONNECT; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::DISCONNECT; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } void InCombat::RequestShutdown() { - SerialPacket packet; + ClientPacket newPacket; //send a shutdown request - packet.meta.type = SerialPacket::Type::SHUTDOWN; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::SHUTDOWN; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } diff --git a/client/in_combat.hpp b/client/in_combat.hpp index ea8dad1..d345037 100644 --- a/client/in_combat.hpp +++ b/client/in_combat.hpp @@ -73,8 +73,8 @@ protected: void KeyUp(SDL_KeyboardEvent const&); //Network handlers - void HandlePacket(SerialPacket); - void HandleDisconnect(SerialPacket); + void HandlePacket(SerialPacket* const); + void HandleDisconnect(SerialPacket* const); //TODO: more network handlers //Server control diff --git a/client/in_world.cpp b/client/in_world.cpp index 01a8ed0..abd311e 100644 --- a/client/in_world.cpp +++ b/client/in_world.cpp @@ -22,6 +22,7 @@ #include "in_world.hpp" #include "channels.hpp" +#include "utility.hpp" #include #include @@ -93,12 +94,12 @@ void InWorld::FrameStart() { } void InWorld::Update(double delta) { - SerialPacket packet; - - //suck in all waiting packets - while(network.Receive(&packet)) { - HandlePacket(packet); + //suck in and process all waiting packets + SerialPacket* packetBuffer = static_cast(malloc(MAX_PACKET_SIZE)); + while(network.Receive(packetBuffer)) { + HandlePacket(packetBuffer); } + free(static_cast(packetBuffer)); //update the characters for (auto& it : characterMap) { @@ -128,8 +129,8 @@ void InWorld::RenderFrame() { void InWorld::Render(SDL_Surface* const screen) { //draw the map - for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { - tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y); + for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { + tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y); } //draw characters @@ -184,6 +185,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) { case SDLK_LEFT: if (localCharacter) { localCharacter->motion.x -= CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -191,6 +193,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) { case SDLK_RIGHT: if (localCharacter) { localCharacter->motion.x += CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -198,6 +201,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) { case SDLK_UP: if (localCharacter) { localCharacter->motion.y -= CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -205,6 +209,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) { case SDLK_DOWN: if (localCharacter) { localCharacter->motion.y += CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -217,6 +222,7 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { case SDLK_LEFT: if (localCharacter) { localCharacter->motion.x += CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -224,6 +230,7 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { case SDLK_RIGHT: if (localCharacter) { localCharacter->motion.x -= CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -231,6 +238,7 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { case SDLK_UP: if (localCharacter) { localCharacter->motion.y += CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -238,6 +246,7 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { case SDLK_DOWN: if (localCharacter) { localCharacter->motion.y -= CHARACTER_WALKING_SPEED; + localCharacter->CorrectSprite(); SendPlayerUpdate(); } break; @@ -248,80 +257,59 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) { //Network handlers //------------------------- -void InWorld::HandlePacket(SerialPacket packet) { - switch(packet.meta.type) { - case SerialPacket::Type::DISCONNECT: - HandleDisconnect(packet); +void InWorld::HandlePacket(SerialPacket* const argPacket) { + switch(argPacket->type) { + case SerialPacketType::DISCONNECT: + HandleDisconnect(argPacket); break; - case SerialPacket::Type::REGION_CONTENT: - HandleRegionContent(packet); + case SerialPacketType::CHARACTER_NEW: + HandleCharacterNew(static_cast(argPacket)); break; - case SerialPacket::Type::CHARACTER_UPDATE: - HandleCharacterUpdate(packet); + case SerialPacketType::CHARACTER_DELETE: + HandleCharacterDelete(static_cast(argPacket)); break; - case SerialPacket::Type::CHARACTER_NEW: - HandleCharacterNew(packet); + case SerialPacketType::CHARACTER_UPDATE: + HandleCharacterUpdate(static_cast(argPacket)); break; - case SerialPacket::Type::CHARACTER_DELETE: - HandleCharacterDelete(packet); + case SerialPacketType::REGION_CONTENT: + HandleRegionContent(static_cast(argPacket)); break; //handle errors default: - throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in InWorld: " + to_string_custom(int(packet.meta.type)))); + throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in InWorld: " + to_string_custom(static_cast(argPacket->type)) )); break; } } -void InWorld::HandleDisconnect(SerialPacket packet) { +void InWorld::HandleDisconnect(SerialPacket* const argPacket) { SetNextScene(SceneList::RESTART); } -void InWorld::HandleRegionContent(SerialPacket packet) { - //replace existing regions - regionPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y); - regionPager.PushRegion(packet.regionInfo.region); - packet.regionInfo.region = nullptr; -} - -void InWorld::HandleCharacterUpdate(SerialPacket packet) { - if (characterMap.find(packet.characterInfo.characterIndex) == characterMap.end()) { - HandleCharacterNew(packet); - return; - } - - //update only if the message didn't originate from here - if (packet.characterInfo.clientIndex != clientIndex) { - characterMap[packet.characterInfo.characterIndex].origin = packet.characterInfo.origin; - characterMap[packet.characterInfo.characterIndex].motion = packet.characterInfo.motion; - } - characterMap[packet.characterInfo.characterIndex].CorrectSprite(); -} - -void InWorld::HandleCharacterNew(SerialPacket packet) { - if (characterMap.find(packet.characterInfo.characterIndex) != characterMap.end()) { +void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) { + if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { throw(std::runtime_error("Cannot create duplicate characters")); } //create the character object - CharacterData& character = characterMap[packet.characterInfo.characterIndex]; + CharacterData& character = characterMap[argPacket->characterIndex]; //set the members - character.handle = packet.characterInfo.handle; - character.avatar = packet.characterInfo.avatar; + character.handle = argPacket->handle; + character.avatar = argPacket->avatar; character.sprite.LoadSurface(config["dir.sprites"] + character.avatar, 4, 4); - character.mapIndex = packet.characterInfo.mapIndex; - character.origin = packet.characterInfo.origin; - character.motion = packet.characterInfo.motion; - character.stats = packet.characterInfo.stats; + character.roomIndex = argPacket->roomIndex; + character.origin = argPacket->origin; + character.motion = argPacket->motion; + character.stats = argPacket->stats; character.CorrectSprite(); //catch this client's player object - if (packet.characterInfo.characterIndex == characterIndex && !localCharacter) { + if (argPacket->accountIndex == accountIndex && !localCharacter) { + characterIndex = argPacket->characterIndex; localCharacter = &character; //setup the camera - //TODO: can't change the screen size? camera.width = GetScreen()->w; camera.height = GetScreen()->h; @@ -331,15 +319,42 @@ void InWorld::HandleCharacterNew(SerialPacket packet) { } } -void InWorld::HandleCharacterDelete(SerialPacket packet) { +void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { //TODO: authenticate when own character is being deleted (linked to a TODO in the server) //catch this client's player object - if (packet.characterInfo.characterIndex == characterIndex) { + if (argPacket->characterIndex == characterIndex) { characterIndex = -1; localCharacter = nullptr; } - characterMap.erase(packet.characterInfo.characterIndex); + characterMap.erase(argPacket->characterIndex); +} + +void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) { + if (characterMap.find(argPacket->characterIndex) == characterMap.end()) { + HandleCharacterNew(argPacket); + return; + } + + CharacterData& character = characterMap[argPacket->characterIndex]; + + //other characters moving + if (argPacket->characterIndex != characterIndex) { + character.roomIndex = argPacket->roomIndex; + character.origin = argPacket->origin; + character.motion = argPacket->motion; + character.CorrectSprite(); + } +} + +void InWorld::HandleRegionContent(RegionPacket* const argPacket) { + //replace existing regions + regionPager.UnloadRegion(argPacket->x, argPacket->y); + regionPager.PushRegion(argPacket->region); + + //clean up after the serial code + delete argPacket->region; + argPacket->region = nullptr; } //------------------------- @@ -347,63 +362,68 @@ void InWorld::HandleCharacterDelete(SerialPacket packet) { //------------------------- void InWorld::RequestSynchronize() { - SerialPacket packet; + ClientPacket newPacket; //request a sync - packet.meta.type = SerialPacket::Type::SYNCHRONIZE; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::SYNCHRONIZE; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } void InWorld::SendPlayerUpdate() { - SerialPacket packet; + CharacterPacket newPacket; //pack the packet - packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE; - packet.characterInfo.clientIndex = clientIndex; - packet.characterInfo.accountIndex = accountIndex; - packet.characterInfo.characterIndex = characterIndex; - packet.characterInfo.origin = localCharacter->origin; - packet.characterInfo.motion = localCharacter->motion; + newPacket.type = SerialPacketType::CHARACTER_UPDATE; - network.SendTo(Channels::SERVER, &packet); + newPacket.characterIndex = characterIndex; + //handle, avatar + newPacket.accountIndex = accountIndex; + newPacket.roomIndex = localCharacter->roomIndex; + newPacket.origin = localCharacter->origin; + newPacket.motion = localCharacter->motion; + newPacket.stats = localCharacter->stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + network.SendTo(Channels::SERVER, &newPacket); } void InWorld::RequestDisconnect() { - SerialPacket packet; + ClientPacket newPacket; //send a disconnect request - packet.meta.type = SerialPacket::Type::DISCONNECT; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::DISCONNECT; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } void InWorld::RequestShutDown() { - SerialPacket packet; + ClientPacket newPacket; //send a shutdown request - packet.meta.type = SerialPacket::Type::SHUTDOWN; - packet.clientInfo.clientIndex = clientIndex; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; + newPacket.type = SerialPacketType::SHUTDOWN; + newPacket.clientIndex = clientIndex; + newPacket.accountIndex = accountIndex; - network.SendTo(Channels::SERVER, &packet); + network.SendTo(Channels::SERVER, &newPacket); } -void InWorld::RequestRegion(int mapIndex, int x, int y) { - SerialPacket packet; +void InWorld::RequestRegion(int roomIndex, int x, int y) { + RegionPacket packet; //pack the region's data - packet.meta.type = SerialPacket::Type::REGION_REQUEST; - packet.regionInfo.mapIndex = mapIndex; - packet.regionInfo.x = x; - packet.regionInfo.y = y; + packet.type = SerialPacketType::REGION_REQUEST; + packet.roomIndex = roomIndex; + packet.x = x; + packet.y = y; network.SendTo(Channels::SERVER, &packet); } @@ -422,13 +442,13 @@ void InWorld::UpdateMap() { int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT; //prune distant regions - for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { + for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) { //check if the region is outside off this area - if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) { + if (it->GetX() < xStart || it->GetX() > xEnd || it->GetY() < yStart || it->GetY() > yEnd) { //clunky, but the alternative was time consuming - int tmpX = (*it)->GetX(); - int tmpY = (*it)->GetY(); + int tmpX = it->GetX(); + int tmpY = it->GetY(); ++it; regionPager.UnloadRegion(tmpX, tmpY); diff --git a/client/in_world.hpp b/client/in_world.hpp index 038d22c..156d35e 100644 --- a/client/in_world.hpp +++ b/client/in_world.hpp @@ -23,9 +23,7 @@ #define INWORLD_HPP_ //maps -#include "map_allocator.hpp" -#include "map_file_format.hpp" -#include "region_pager.hpp" +#include "region_pager_base.hpp" //networking #include "udp_network_utility.hpp" @@ -80,19 +78,19 @@ protected: void KeyUp(SDL_KeyboardEvent const&); //Network handlers - void HandlePacket(SerialPacket); - void HandleDisconnect(SerialPacket); - void HandleCharacterNew(SerialPacket); - void HandleCharacterDelete(SerialPacket); - void HandleCharacterUpdate(SerialPacket); - void HandleRegionContent(SerialPacket); + void HandlePacket(SerialPacket* const); + void HandleDisconnect(SerialPacket* const); + void HandleCharacterNew(CharacterPacket* const); + void HandleCharacterDelete(CharacterPacket* const); + void HandleCharacterUpdate(CharacterPacket* const); + void HandleRegionContent(RegionPacket* const); //Server control void RequestSynchronize(); void SendPlayerUpdate(); void RequestDisconnect(); void RequestShutDown(); - void RequestRegion(int mapIndex, int x, int y); + void RequestRegion(int roomIndex, int x, int y); //utilities void UpdateMap(); @@ -112,7 +110,7 @@ protected: TileSheet tileSheet; //map - RegionPager regionPager; + RegionPagerBase regionPager; //UI Button disconnectButton; diff --git a/client/lobby_menu.cpp b/client/lobby_menu.cpp index fa1925e..8cbf55a 100644 --- a/client/lobby_menu.cpp +++ b/client/lobby_menu.cpp @@ -34,14 +34,12 @@ LobbyMenu::LobbyMenu( ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, - int* const argAccountIndex, - int* const argCharacterIndex + int* const argAccountIndex ): config(*argConfig), network(*argNetwork), clientIndex(*argClientIndex), - accountIndex(*argAccountIndex), - characterIndex(*argCharacterIndex) + accountIndex(*argAccountIndex) { //setup the utility objects image.LoadSurface(config["dir.interface"] + "button_menu.bmp"); @@ -87,10 +85,11 @@ void LobbyMenu::FrameStart() { void LobbyMenu::Update(double delta) { //suck in and process all waiting packets - SerialPacket packet; - while(network.Receive(&packet)) { - HandlePacket(packet); + SerialPacket* packetBuffer = static_cast(malloc(MAX_PACKET_SIZE)); + while(network.Receive(packetBuffer)) { + HandlePacket(packetBuffer); } + free(static_cast(packetBuffer)); } void LobbyMenu::FrameEnd() { @@ -149,7 +148,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { if (search.MouseButtonUp(button) == Button::State::HOVER) { //broadcast to the network, or a specific server SerialPacket packet; - packet.meta.type = SerialPacket::Type::BROADCAST_REQUEST; + packet.type = SerialPacketType::BROADCAST_REQUEST; network.SendTo(config["server.host"].c_str(), config.Int("server.port"), &packet); //reset the server list @@ -159,11 +158,9 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) { //pack the packet - SerialPacket packet; - packet.meta.type = SerialPacket::Type::JOIN_REQUEST; - strncpy(packet.clientInfo.username, config["client.username"].c_str(), PACKET_STRING_SIZE); - strncpy(packet.clientInfo.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE); - strncpy(packet.clientInfo.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE); + ClientPacket packet; + packet.type = SerialPacketType::JOIN_REQUEST; + strncpy(packet.username, config["client.username"].c_str(), PACKET_STRING_SIZE); //join the selected server network.SendTo(&selection->address, &packet); @@ -176,6 +173,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { else if ( //has the user selected a server on the list? + //TODO: replace with regular collision checker button.x > listBox.x && button.x < listBox.x + listBox.w && button.y > listBox.y && @@ -204,34 +202,47 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) { //Network handlers //------------------------- -void LobbyMenu::HandlePacket(SerialPacket packet) { - switch(packet.meta.type) { - case SerialPacket::Type::BROADCAST_RESPONSE: { - //extract the data - ServerInformation server; - server.address = packet.meta.srcAddress; - server.networkVersion = packet.serverInfo.networkVersion; - server.name = packet.serverInfo.name; - server.playerCount = packet.serverInfo.playerCount; - - //NOTE: Check compatibility here - server.compatible = server.networkVersion == NETWORK_VERSION; - - //push - serverInfo.push_back(server); - } +void LobbyMenu::HandlePacket(SerialPacket* const argPacket) { + switch(argPacket->type) { + case SerialPacketType::BROADCAST_RESPONSE: + HandleBroadcastResponse(static_cast(argPacket)); break; - case SerialPacket::Type::JOIN_RESPONSE: - clientIndex = packet.clientInfo.clientIndex; - accountIndex = packet.clientInfo.accountIndex; - characterIndex = packet.clientInfo.characterIndex; - network.Bind(&packet.meta.srcAddress, Channels::SERVER); - SetNextScene(SceneList::INWORLD); + case SerialPacketType::JOIN_RESPONSE: + HandleJoinResponse(static_cast(argPacket)); break; - //handle errors default: - throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in LobbyMenu: " + to_string_custom(int(packet.meta.type)))); + throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast(argPacket->type)) )); break; } +} + +void LobbyMenu::HandleBroadcastResponse(ServerPacket* const argPacket) { + //extract the data + ServerInformation server; + server.address = argPacket->srcAddress; + server.name = argPacket->name; + server.playerCount = argPacket->playerCount; + server.version = argPacket->version; + + //NOTE: Check compatibility here + server.compatible = server.version == NETWORK_VERSION; + + //push + serverInfo.push_back(server); +} + +void LobbyMenu::HandleJoinResponse(ClientPacket* const argPacket) { + clientIndex = argPacket->clientIndex; + accountIndex = argPacket->accountIndex; + network.Bind(&argPacket->srcAddress, Channels::SERVER); + SetNextScene(SceneList::INWORLD); + + //send this player's character info + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_NEW; + 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); } \ No newline at end of file diff --git a/client/lobby_menu.hpp b/client/lobby_menu.hpp index 2360705..a27c1a9 100644 --- a/client/lobby_menu.hpp +++ b/client/lobby_menu.hpp @@ -22,13 +22,13 @@ #ifndef LOBBYMENU_HPP_ #define LOBBYMENU_HPP_ -//graphics & utilities +//graphics & ui #include "image.hpp" #include "raster_font.hpp" #include "button.hpp" -#include "config_utility.hpp" -//network +//utilities +#include "config_utility.hpp" #include "udp_network_utility.hpp" //client @@ -44,8 +44,7 @@ public: ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, - int* const argAccountIndex, - int* const argCharacterIndex + int* const argAccountIndex ); ~LobbyMenu(); @@ -64,14 +63,15 @@ protected: void KeyUp(SDL_KeyboardEvent const&); //Network handlers - void HandlePacket(SerialPacket); + void HandlePacket(SerialPacket* const); + void HandleBroadcastResponse(ServerPacket* const); + void HandleJoinResponse(ClientPacket* const); //shared parameters ConfigUtility& config; UDPNetworkUtility& network; int& clientIndex; int& accountIndex; - int& characterIndex; //members Image image; @@ -83,9 +83,9 @@ protected: //server list struct ServerInformation { IPaddress address; - int networkVersion; std::string name; int playerCount; + int version; bool compatible; }; diff --git a/client/main_menu.cpp b/client/main_menu.cpp index b5d633e..457bd12 100644 --- a/client/main_menu.cpp +++ b/client/main_menu.cpp @@ -53,6 +53,9 @@ MainMenu::MainMenu(ConfigUtility* const argConfig): startButton.SetText("Start"); optionsButton.SetText("Options"); quitButton.SetText("Quit"); + + //debug + // } MainMenu::~MainMenu() { diff --git a/client/makefile b/client/makefile index bba3c67..947b822 100644 --- a/client/makefile +++ b/client/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. ../common/gameplay ../common/graphics ../common/map ../common/network ../common/ui ../common/utilities +INCLUDES+=. ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet ../common/network/serial ../common/ui ../common/utilities LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) -DGRAPHICS diff --git a/common/gameplay/character_data.hpp b/common/gameplay/character_data.hpp index ff129b2..361788b 100644 --- a/common/gameplay/character_data.hpp +++ b/common/gameplay/character_data.hpp @@ -45,7 +45,7 @@ struct CharacterData { std::string avatar; //world position - int mapIndex = 0; + int roomIndex = 0; Vector2 origin = {0.0,0.0}; Vector2 motion = {0.0,0.0}; Vector2 bounds = {0.0,0.0}; diff --git a/common/gameplay/combat_data.hpp b/common/gameplay/combat_data.hpp index db87851..b170e5f 100644 --- a/common/gameplay/combat_data.hpp +++ b/common/gameplay/combat_data.hpp @@ -35,24 +35,23 @@ //std namespace #include -#include +#include #include -#define COMBAT_MAX_CHARACTER_COUNT 12 -#define COMBAT_MAX_ENEMY_COUNT 12 +#define COMBAT_MAX_CHARACTERS 12 +#define COMBAT_MAX_ENEMIES 12 struct CombatData { enum class Terrain { - //TODO: types of terrains + //TODO: types of combat terrains NONE = 0, GRASSLANDS, }; typedef std::chrono::steady_clock Clock; - //combatants, point to the std::map's internal pairs - std::list*> characterList; - std::list*> enemyList; + std::array characterArray; + std::array enemyArray; //world interaction int mapIndex = 0; diff --git a/common/gameplay/enemy_data.hpp b/common/gameplay/enemy_data.hpp index 62de98c..9fd96e2 100644 --- a/common/gameplay/enemy_data.hpp +++ b/common/gameplay/enemy_data.hpp @@ -46,6 +46,8 @@ struct EnemyData { //TODO: buffs //TODO: debuffs + //TODO: rewards + //active gameplay members //NOTE: these are lost when unloaded #ifdef GRAPHICS diff --git a/common/gameplay/sanity_check.cpp b/common/gameplay/sanity_check.cpp index 1e20ccf..8669811 100644 --- a/common/gameplay/sanity_check.cpp +++ b/common/gameplay/sanity_check.cpp @@ -19,19 +19,13 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "account_data.hpp" #include "character_data.hpp" -#include "client_data.hpp" #include "combat_data.hpp" #include "enemy_data.hpp" -#include "room_data.hpp" #include "statistics.hpp" /* DOCS: Sanity check, read more * Since most/all of the files in this directory are header files, I've created * this source file as a "sanity check", to ensure that the above header files * are written correctly via make. - * - * Oddly enough, I'm pretty sure this is the first directory compiled in a - * clean build. */ \ No newline at end of file diff --git a/common/makefile b/common/makefile index 0e48688..b670b7d 100644 --- a/common/makefile +++ b/common/makefile @@ -3,7 +3,6 @@ all: $(MAKE) -C graphics $(MAKE) -C map $(MAKE) -C network - $(MAKE) -C script $(MAKE) -C ui $(MAKE) -C utilities diff --git a/common/map/map_allocator.cpp b/common/map/map_allocator.cpp deleted file mode 100644 index d57351c..0000000 --- a/common/map/map_allocator.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "map_allocator.hpp" - -#include - -void BlankAllocator::Create(Region** const ptr, int x, int y) { - (*ptr) = new Region(x, y); -} - -void BlankAllocator::Unload(Region* const ptr) { - delete ptr; -} - -void LuaAllocator::Create(Region** const ptr, int x, int y) { - //something to work on - (*ptr) = new Region(x, y); - - //API hook - lua_getglobal(state, "map"); - lua_getfield(state, -1, "create"); - lua_pushlightuserdata(state, *ptr); - if (lua_pcall(state, 1, 0, 0) != LUA_OK) { - throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); - } - lua_pop(state, 1); -} - -void LuaAllocator::Unload(Region* const ptr) { - //API hook - lua_getglobal(state, "map"); - lua_getfield(state, -1, "unload"); - lua_pushlightuserdata(state, ptr); - if (lua_pcall(state, 1, 0, 0) != LUA_OK) { - throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); - } - lua_pop(state, 1); - - //clean up the memory - delete ptr; -} diff --git a/common/map/map_file_format.cpp b/common/map/map_file_format.cpp deleted file mode 100644 index b4366e4..0000000 --- a/common/map/map_file_format.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "map_file_format.hpp" - -#include - -void DummyFormat::Load(Region** const ptr, int x, int y) { - //EMPTY -} - -void DummyFormat::Save(Region* const ptr) { - //EMPTY -} - -void LuaFormat::Load(Region** const ptr, int x, int y) { - //something to load into - - if (!(*ptr)) { - (*ptr) = new Region(x, y); - } - - //API hook - lua_getglobal(state, "map"); - lua_getfield(state, -1, "load"); - lua_pushlightuserdata(state, *ptr); - lua_pushstring(state, saveDir.c_str()); - if (lua_pcall(state, 2, 1, 0) != LUA_OK) { - throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); - } - if (lua_toboolean(state, -1) == false) { - delete (*ptr); - (*ptr) = nullptr; - } - lua_pop(state, 2); -} - -void LuaFormat::Save(Region* const ptr) { - //API hook - lua_getglobal(state, "map"); - lua_getfield(state, -1, "save"); - lua_pushlightuserdata(state, ptr); - lua_pushstring(state, saveDir.c_str()); - if (lua_pcall(state, 2, 0, 0) != LUA_OK) { - throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); - } - lua_pop(state, 1); -} \ No newline at end of file diff --git a/common/map/pager_api.cpp b/common/map/pager_api.cpp new file mode 100644 index 0000000..8f60e61 --- /dev/null +++ b/common/map/pager_api.cpp @@ -0,0 +1,156 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "pager_api.hpp" + +#include "region_pager_lua.hpp" +#include "region.hpp" + +#include +#include + +static int setTile(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + int ret = pager->SetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5)); + lua_pushinteger(L, ret); + return 1; +} + +static int getTile(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + int ret = pager->GetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4)); + lua_pushinteger(L, ret); + return 1; +} + +static int getRegion(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + lua_pushlightuserdata(L, region); + return 1; +} + +static int setDirectory(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + std::string s = pager->SetDirectory(lua_tostring(L, 2)); + lua_pushstring(L, s.c_str()); + return 1; +} + +static int getDirectory(lua_State* L) { + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + std::string s = pager->GetDirectory(); + lua_pushstring(L, s.c_str()); + return 1; +} + +static int loadRegion(lua_State* L) { + //get the parameters + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + std::string s = pager->GetDirectory(); + + //push the parameters + lua_getglobal(L, "region"); + lua_getfield(L, -1, "load"); + lua_pushlightuserdata(L, region); + lua_pushstring(L, s.c_str()); + + //call the method + if (lua_pcall(L, 2, 1, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(L, -1) )); + } + return 1; +} + +static int saveRegion(lua_State* L) { + //get the parameters + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + std::string s = pager->GetDirectory(); + + //push the parameters + lua_getglobal(L, "region"); + lua_getfield(L, -1, "save"); + lua_pushlightuserdata(L, region); + lua_pushstring(L, s.c_str()); + + //call the method + if (lua_pcall(L, 2, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(L, -1) )); + } + return 0; +} + +static int createRegion(lua_State* L) { + //get the parameters + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + + //push the parameters + lua_getglobal(L, "region"); + lua_getfield(L, -1, "create"); + lua_pushlightuserdata(L, region); + //TODO: parameters + + //call the method + if (lua_pcall(L, 1, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(L, -1) )); + } + return 0; +} + +static int unloadRegion(lua_State* L) { + //get the parameters + RegionPagerLua* pager = reinterpret_cast(lua_touserdata(L, 1)); + Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3)); + std::string s = pager->GetDirectory(); + + //push the parameters + lua_getglobal(L, "region"); + lua_getfield(L, -1, "unload"); + lua_pushlightuserdata(L, region); + lua_pushstring(L, s.c_str()); + + //call the method + if (lua_pcall(L, 2, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(L, -1) )); + } + return 0; +} + +static const luaL_Reg pagerlib[] = { + {"settile", setTile}, + {"gettile", getTile}, + {"getregion", getRegion}, + {"setdirectory", setDirectory}, + {"getdirectory", getDirectory}, + {"loadregion", loadRegion}, + {"saveregion", saveRegion}, + {"createregion", createRegion}, + {"unloadregion", unloadRegion}, + {nullptr, nullptr} +}; + +LUAMOD_API int luaopen_pagerapi(lua_State* L) { + luaL_newlib(L, pagerlib); + return 1; +} \ No newline at end of file diff --git a/common/network/serial.hpp b/common/map/pager_api.hpp similarity index 60% rename from common/network/serial.hpp rename to common/map/pager_api.hpp index 29b9c2d..2531e94 100644 --- a/common/network/serial.hpp +++ b/common/map/pager_api.hpp @@ -19,20 +19,12 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef SERIAL_HPP_ -#define SERIAL_HPP_ +#ifndef PAGERAPI_HPP_ +#define PAGERAPI_HPP_ -#include "serial_packet.hpp" +#include "lua/lua.hpp" -/* NOTE: Keep the PACKET_BUFFER_SIZE up to date - * NOTE: REGION_CONTENT is currently the largest type of packet - * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t) - * map format: sizeof(int) * 3 - * metadata: sizeof(SerialPacket::Type) -*/ -#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacket::Type) - -void serialize(SerialPacket* const, void* dest); -void deserialize(SerialPacket* const, void* src); +#define LUA_PAGERLIBNAME "pager" +LUAMOD_API int luaopen_pagerapi(lua_State* L); #endif diff --git a/common/map/region.cpp b/common/map/region.cpp index ffdbdf1..8de957b 100644 --- a/common/map/region.cpp +++ b/common/map/region.cpp @@ -21,13 +21,20 @@ */ #include "region.hpp" -Region::Region(int argX, int argY): - x(argX), - y(argY) -{ - for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) { - *(reinterpret_cast(tiles) + i) = 0; +#include "utility.hpp" + +#include +#include + +Region::Region(int argX, int argY): x(argX), y(argY) { + if (x != snapToBase(REGION_WIDTH, x) || y != snapToBase(REGION_HEIGHT, y)) { + throw(std::invalid_argument("Region location is off grid")); } + memset(tiles, 0, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t)); +} + +Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) { + memcpy(tiles, rhs.tiles, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t)); } Region::type_t Region::SetTile(int x, int y, int z, type_t v) { diff --git a/common/map/region.hpp b/common/map/region.hpp index 560161b..74fc013 100644 --- a/common/map/region.hpp +++ b/common/map/region.hpp @@ -22,9 +22,9 @@ #ifndef REGION_HPP_ #define REGION_HPP_ -#define REGION_WIDTH 20 -#define REGION_HEIGHT 20 -#define REGION_DEPTH 3 +constexpr int REGION_WIDTH = 20; +constexpr int REGION_HEIGHT = 20; +constexpr int REGION_DEPTH = 3; class Region { public: @@ -32,6 +32,7 @@ public: Region() = delete; Region(int x, int y); + Region(Region const&); ~Region() = default; type_t SetTile(int x, int y, int z, type_t v); diff --git a/common/map/region_api.cpp b/common/map/region_api.cpp new file mode 100644 index 0000000..b30f04f --- /dev/null +++ b/common/map/region_api.cpp @@ -0,0 +1,106 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_api.hpp" + +#include "region.hpp" + +static int setTile(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + int ret = region->SetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1, lua_tointeger(L, 5)); + lua_pushinteger(L, ret); + return 1; +} + +static int getTile(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + int ret = region->GetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1); + lua_pushinteger(L, ret); + return 1; +} + +static int getX(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, region->GetX()); + return 1; +} + +static int getY(lua_State* L) { + Region* region = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, region->GetY()); + return 1; +} + +static int getWidth(lua_State* L) { + lua_pushinteger(L, REGION_WIDTH); + return 1; +} + +static int getHeight(lua_State* L) { + lua_pushinteger(L, REGION_HEIGHT); + return 1; +} + +static int getDepth(lua_State* L) { + lua_pushinteger(L, REGION_DEPTH); + return 1; +} + +static int load(lua_State* L) { + //TODO: fill this + lua_pushboolean(L, false); + return 1; +} + +static int save(lua_State* L) { + //TODO: fill this + return 0; +} + +static int create(lua_State* L) { + //TODO: fill this + return 0; +} + +static int unload(lua_State* L) { + //TODO: fill this + return 0; +} + +static const luaL_Reg regionlib[] = { + {"settile",setTile}, + {"gettile",getTile}, + {"getx",getX}, + {"gety",getY}, + {"getwidth",getWidth}, + {"getheight",getHeight}, + {"getdepth",getDepth}, + {"load",load}, + {"save",save}, + {"create",create}, + {"unload",unload}, + {nullptr, nullptr} +}; + +LUAMOD_API int luaopen_regionapi(lua_State* L) { + luaL_newlib(L, regionlib); + return 1; +} \ No newline at end of file diff --git a/common/map/region_api.hpp b/common/map/region_api.hpp new file mode 100644 index 0000000..310074d --- /dev/null +++ b/common/map/region_api.hpp @@ -0,0 +1,30 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef REGIONAPI_HPP_ +#define REGIONAPI_HPP_ + +#include "lua/lua.hpp" + +#define LUA_REGIONLIBNAME "region" +LUAMOD_API int luaopen_regionapi(lua_State* L); + +#endif diff --git a/common/map/region_pager.hpp b/common/map/region_pager.hpp deleted file mode 100644 index 95864f0..0000000 --- a/common/map/region_pager.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#ifndef REGIONPAGER_HPP_ -#define REGIONPAGER_HPP_ - -#include "region.hpp" -#include "utility.hpp" - -#include - -class RegionPagerBase { -public: - RegionPagerBase() {}; - virtual ~RegionPagerBase() {}; - - //tile manipulation - Region::type_t SetTile(int x, int y, int z, Region::type_t v); - Region::type_t GetTile(int x, int y, int z); - - //region manipulation - Region* GetRegion(int x, int y); - Region* FindRegion(int x, int y); - Region* PushRegion(Region*); - - //interface - virtual Region* LoadRegion(int x, int y) = 0; - virtual Region* SaveRegion(int x, int y) = 0; - virtual Region* CreateRegion(int x, int y) = 0; - virtual void UnloadRegion(int x, int y) = 0; - //TODO: delete existing regions - - //accessors & mutators - std::list* GetContainer() { return ®ionList; } -protected: - std::list regionList; -}; - -template -class RegionPager : public RegionPagerBase { -public: - RegionPager() {}; - ~RegionPager() { - UnloadAll(); - } - - Region* LoadRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - - //load the region if possible - Region* ptr = nullptr; - format.Load(&ptr, x, y); - if (ptr) { - return PushRegion(ptr); - } - return nullptr; - } - - Region* SaveRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - - //find & save the region - Region* ptr = FindRegion(x, y); - if (ptr) { - format.Save(ptr); - } - return ptr; - } - - Region* CreateRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - - //create and push the object - Region* ptr = nullptr; - allocator.Create(&ptr, x, y); - return PushRegion(ptr); - } - - void UnloadRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - - //custom loop - for (std::list::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) { - if ((*it)->GetX() == x && (*it)->GetY() == y) { - allocator.Unload(*it); - it = regionList.erase(it); - continue; - } - ++it; - } - } - void UnloadAll() { - for (auto& it : regionList) { - allocator.Unload(it); - } - regionList.clear(); - } - - //accessors - Allocator* GetAllocator() { return &allocator; } - FileFormat* GetFormat() { return &format; } -protected: - Allocator allocator; - FileFormat format; -}; - -#endif diff --git a/common/map/region_pager.cpp b/common/map/region_pager_base.cpp similarity index 59% rename from common/map/region_pager.cpp rename to common/map/region_pager_base.cpp index 90664dd..a8ad76f 100644 --- a/common/map/region_pager.cpp +++ b/common/map/region_pager_base.cpp @@ -19,10 +19,13 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "region_pager.hpp" +#include "region_pager_base.hpp" #include "utility.hpp" +#include +#include + Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) { Region* ptr = GetRegion(x, y); return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v); @@ -34,10 +37,6 @@ Region::type_t RegionPagerBase::GetTile(int x, int y, int z) { } Region* RegionPagerBase::GetRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - //get the region by various means Region* ptr = nullptr; ptr = FindRegion(x, y); @@ -48,20 +47,41 @@ Region* RegionPagerBase::GetRegion(int x, int y) { } Region* RegionPagerBase::FindRegion(int x, int y) { - //snap the coords - x = snapToBase(REGION_WIDTH, x); - y = snapToBase(REGION_HEIGHT, y); - //find the region - for (std::list::iterator it = regionList.begin(); it != regionList.end(); it++) { - if ((*it)->GetX() == x && (*it)->GetY() == y) { - return *it; - } - } + std::list::iterator it = find_if(regionList.begin(), regionList.end(), [x, y](Region& region) -> bool { + return region.GetX() == x && region.GetY() == y; + }); + return it != regionList.end() ? &(*it) : nullptr; +} + +Region* RegionPagerBase::PushRegion(Region* const ptr) { + regionList.push_front(*ptr); + return ®ionList.front(); +} + +Region* RegionPagerBase::LoadRegion(int x, int y) { + //TODO: load the region if possible return nullptr; } -Region* RegionPagerBase::PushRegion(Region* ptr) { - regionList.push_front(ptr); - return regionList.front(); +Region* RegionPagerBase::SaveRegion(int x, int y) { + //TODO: find & save the region + return nullptr; +} + +Region* RegionPagerBase::CreateRegion(int x, int y) { + if (FindRegion(x, y)) { + throw(std::logic_error("Cannot overwrite an existing region")); + } + regionList.emplace_front(x, y); + return ®ionList.front(); +} + +void RegionPagerBase::UnloadRegion(int x, int y) { + //custom loop, not FindRegion() + regionList.remove_if([x, y](Region& region) -> bool { return region.GetX() == x && region.GetY() == y; }); +} + +void RegionPagerBase::UnloadAll() { + regionList.clear(); } \ No newline at end of file diff --git a/common/map/region_pager_base.hpp b/common/map/region_pager_base.hpp new file mode 100644 index 0000000..004faa4 --- /dev/null +++ b/common/map/region_pager_base.hpp @@ -0,0 +1,56 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef REGIONPAGERBASE_HPP_ +#define REGIONPAGERBASE_HPP_ + +#include "region.hpp" + +#include + +class RegionPagerBase { +public: + RegionPagerBase() = default; + virtual ~RegionPagerBase() { UnloadAll(); }; + + //tile manipulation + virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v); + virtual Region::type_t GetTile(int x, int y, int z); + + //region manipulation + virtual Region* GetRegion(int x, int y); + virtual Region* FindRegion(int x, int y); + virtual Region* PushRegion(Region* const); + + virtual Region* LoadRegion(int x, int y); + virtual Region* SaveRegion(int x, int y); + virtual Region* CreateRegion(int x, int y); + virtual void UnloadRegion(int x, int y); + + virtual void UnloadAll(); + + //accessors & mutators + std::list* GetContainer() { return ®ionList; } +protected: + std::list regionList; +}; + +#endif diff --git a/common/map/region_pager_lua.cpp b/common/map/region_pager_lua.cpp new file mode 100644 index 0000000..a183be8 --- /dev/null +++ b/common/map/region_pager_lua.cpp @@ -0,0 +1,126 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "region_pager_lua.hpp" + +#include "utility.hpp" + +#include + +Region* RegionPagerLua::LoadRegion(int x, int y) { + //load the region if possible + + //something to work on + regionList.emplace_front(x, y); + + //API hook + lua_getglobal(luaState, "region"); + lua_getfield(luaState, -1, "load"); + lua_pushlightuserdata(luaState, ®ionList.front()); + lua_pushstring(luaState, directory.c_str()); + if (lua_pcall(luaState, 2, 1, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) )); + } + //success or failure + if (!lua_toboolean(luaState, -1)) { + lua_pop(luaState, 2); + regionList.pop_front(); + return nullptr; + } + lua_pop(luaState, 2); + return ®ionList.front(); +} + +Region* RegionPagerLua::SaveRegion(int x, int y) { + //find & save the region + Region* ptr = FindRegion(x, y); + if (ptr) { + //API hook + lua_getglobal(luaState, "region"); + lua_getfield(luaState, -1, "save"); + lua_pushlightuserdata(luaState, ptr); + lua_pushstring(luaState, directory.c_str()); + if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) )); + } + lua_pop(luaState, 1); + } + return ptr; +} + +Region* RegionPagerLua::CreateRegion(int x, int y) { + if (FindRegion(x, y)) { + throw(std::logic_error("Cannot overwrite an existing region")); + } + + //something to work on + regionList.emplace_front(x, y); + + //API hook + lua_getglobal(luaState, "region"); + lua_getfield(luaState, -1, "create"); + lua_pushlightuserdata(luaState, ®ionList.front()); + //TODO: parameters + if (lua_pcall(luaState, 1, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) )); + } + lua_pop(luaState, 1); + return ®ionList.front();; +} + +void RegionPagerLua::UnloadRegion(int x, int y) { + lua_getglobal(luaState, "region"); + + regionList.remove_if([&](Region& region) -> bool { + if (region.GetX() == x && region.GetY() == y) { + + //API hook + lua_getfield(luaState, -1, "unload"); + lua_pushlightuserdata(luaState, ®ion); + lua_pushstring(luaState, directory.c_str()); + if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) )); + } + + return true; + } + return false; + }); + + lua_pop(luaState, 1); +} + +void RegionPagerLua::UnloadAll() { + lua_getglobal(luaState, "region"); + + for (auto& it : regionList) { + //API hook + lua_getfield(luaState, -1, "unload"); + lua_pushlightuserdata(luaState, &it); + lua_pushstring(luaState, directory.c_str()); + if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) { + throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) )); + } + } + + lua_pop(luaState, 1); + regionList.clear(); +} \ No newline at end of file diff --git a/common/map/map_file_format.hpp b/common/map/region_pager_lua.hpp similarity index 56% rename from common/map/map_file_format.hpp rename to common/map/region_pager_lua.hpp index 92f0c8d..78aed17 100644 --- a/common/map/map_file_format.hpp +++ b/common/map/region_pager_lua.hpp @@ -19,42 +19,36 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef MAPFILEFORMAT_HPP_ -#define MAPFILEFORMAT_HPP_ +#ifndef REGIONPAGERLUA_HPP_ +#define REGIONPAGERLUA_HPP_ -#include "region.hpp" +#include "region_pager_base.hpp" #include "lua/lua.hpp" #include -class DummyFormat { +class RegionPagerLua : public RegionPagerBase { public: - void Load(Region** const, int x, int y); - void Save(Region* const); + RegionPagerLua() = default; + ~RegionPagerLua() = default; - std::string SetSaveDir(std::string s) { return saveDir = s; } - std::string GetSaveDir() { return saveDir; } -private: - std::string saveDir; -}; + //region manipulation + Region* LoadRegion(int x, int y) override; + Region* SaveRegion(int x, int y) override; + Region* CreateRegion(int x, int y) override; + void UnloadRegion(int x, int y) override; -//TODO: verbose save file format -//TODO: compact save file format + void UnloadAll() override; -class LuaFormat { -public: - void Load(Region** const, int x, int y); - void Save(Region* const); + std::string SetDirectory(std::string s) { return directory = s; } + std::string GetDirectory() { return directory; } - std::string SetSaveDir(std::string s) { return saveDir = s; } - std::string GetSaveDir() { return saveDir; } - - lua_State* SetLuaState(lua_State* L) { return state = L; } - lua_State* GetLuaState() { return state; } -private: - std::string saveDir; - lua_State* state = nullptr; + lua_State* SetLuaState(lua_State* L) { return luaState = L; } + lua_State* GetLuaState() { return luaState; } +protected: + std::string directory; + lua_State* luaState = nullptr; }; #endif diff --git a/common/network/makefile b/common/network/makefile index 7053c0f..618d925 100644 --- a/common/network/makefile +++ b/common/network/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. ../gameplay ../map ../utilities +INCLUDES+=. packet serial ../gameplay ../map ../utilities LIBS+= CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) @@ -17,6 +17,8 @@ OUT=$(addprefix $(OUTDIR)/,libcommon.a) #targets all: $(OBJ) $(OUT) ar -crs $(OUT) $(OBJ) + $(MAKE) -C packet + $(MAKE) -C serial $(OBJ): | $(OBJDIR) diff --git a/common/network/packet/character_packet.hpp b/common/network/packet/character_packet.hpp new file mode 100644 index 0000000..3b44d9b --- /dev/null +++ b/common/network/packet/character_packet.hpp @@ -0,0 +1,53 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef CHARACTERPACKET_HPP_ +#define CHARACTERPACKET_HPP_ + +#include "serial_packet_base.hpp" + +#include "vector2.hpp" +#include "statistics.hpp" + +struct CharacterPacket : SerialPacketBase { + //identify the character + int characterIndex; + char handle[PACKET_STRING_SIZE]; + char avatar[PACKET_STRING_SIZE]; + + //the owner + int accountIndex; + + //location + int roomIndex; + Vector2 origin; + Vector2 motion; + + //gameplay + Statistics stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs +}; + +#endif \ No newline at end of file diff --git a/common/network/packet/client_packet.hpp b/common/network/packet/client_packet.hpp new file mode 100644 index 0000000..f191b11 --- /dev/null +++ b/common/network/packet/client_packet.hpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef CLIENTPACKET_HPP_ +#define CLIENTPACKET_HPP_ + +#include "serial_packet_base.hpp" + +struct ClientPacket : SerialPacketBase { + int clientIndex; + int accountIndex; + char username[PACKET_STRING_SIZE]; +// char password[PACKET_STRING_SIZE]; //hashed, not currently used +}; + +#endif \ No newline at end of file diff --git a/common/network/packet/combat_packet.hpp b/common/network/packet/combat_packet.hpp new file mode 100644 index 0000000..a95ca25 --- /dev/null +++ b/common/network/packet/combat_packet.hpp @@ -0,0 +1,46 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef COMBATPACKET_HPP_ +#define COMBATPACKET_HPP_ + +#include "serial_packet_base.hpp" + +#include "combat_data.hpp" + +struct CombatPacket : SerialPacketBase { + //identify the combat instance + int combatIndex; + int difficulty; + CombatData::Terrain terrainType; + + //combatants + int characterArray[COMBAT_MAX_CHARACTERS]; + int enemyArray[COMBAT_MAX_ENEMIES]; + + //location + int mapIndex; + Vector2 origin; + + //TODO: rewards +}; + +#endif \ No newline at end of file diff --git a/common/network/packet/enemy_packet.hpp b/common/network/packet/enemy_packet.hpp new file mode 100644 index 0000000..4a3d343 --- /dev/null +++ b/common/network/packet/enemy_packet.hpp @@ -0,0 +1,44 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef ENEMYPACKET_HPP_ +#define ENEMYPACKET_HPP_ + +#include "serial_packet_base.hpp" + +struct EnemyPacket : SerialPacketBase { + //identify the enemy + int enemyIndex; + char handle[PACKET_STRING_SIZE]; + char avatar[PACKET_STRING_SIZE]; + + //gameplay + Statistics stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + //TODO: rewards +}; + +#endif \ No newline at end of file diff --git a/common/script/makefile b/common/network/packet/makefile similarity index 87% rename from common/script/makefile rename to common/network/packet/makefile index 7cab524..f993f8b 100644 --- a/common/script/makefile +++ b/common/network/packet/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. ../map ../utilities +INCLUDES+=. ../../gameplay ../../map ../../utilities LIBS+= CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) @@ -11,7 +11,7 @@ OBJDIR=obj OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o)) #output -OUTDIR=../.. +OUTDIR=../../.. OUT=$(addprefix $(OUTDIR)/,libcommon.a) #targets diff --git a/common/network/packet/region_packet.hpp b/common/network/packet/region_packet.hpp new file mode 100644 index 0000000..8a9085e --- /dev/null +++ b/common/network/packet/region_packet.hpp @@ -0,0 +1,38 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef REGIONPACKET_HPP_ +#define REGIONPACKET_HPP_ + +#include "serial_packet_base.hpp" + +#include "region.hpp" + +struct RegionPacket : SerialPacketBase { + //location/identify the region + int roomIndex; + int x, y; + + //the data + Region* region; +}; + +#endif \ No newline at end of file diff --git a/common/network/packet/sanity_check.cpp b/common/network/packet/sanity_check.cpp new file mode 100644 index 0000000..f250d69 --- /dev/null +++ b/common/network/packet/sanity_check.cpp @@ -0,0 +1,28 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial_packet.hpp" + +/* DOCS: Sanity check, read more + * Since most/all of the files in this directory are header files, I've created + * this source file as a "sanity check", to ensure that the above header files + * are written correctly via make. +*/ diff --git a/common/network/packet/serial_packet.hpp b/common/network/packet/serial_packet.hpp new file mode 100644 index 0000000..44198aa --- /dev/null +++ b/common/network/packet/serial_packet.hpp @@ -0,0 +1,44 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERIALPACKET_HPP_ +#define SERIALPACKET_HPP_ + +#include "character_packet.hpp" +#include "client_packet.hpp" +#include "combat_packet.hpp" +#include "enemy_packet.hpp" +#include "region_packet.hpp" +#include "server_packet.hpp" + +//NOTE: SerialPacket is defined in serial_packet_base.hpp + +union MaxPacket { + CharacterPacket a; + ClientPacket b; + CombatPacket c; + EnemyPacket d; + RegionPacket e; + ServerPacket f; +}; +constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket); + +#endif diff --git a/common/network/packet/serial_packet_base.hpp b/common/network/packet/serial_packet_base.hpp new file mode 100644 index 0000000..156d1e5 --- /dev/null +++ b/common/network/packet/serial_packet_base.hpp @@ -0,0 +1,46 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERIALPACKETBASE_HPP_ +#define SERIALPACKETBASE_HPP_ + +#ifndef SERIALPACKET_HPP_ + #error Cannot include this file without 'serial_packet.hpp' +#endif + +#include "serial_packet_type.hpp" + +#include "SDL/SDL_net.h" + +constexpr int NETWORK_VERSION = 20140607; +constexpr int PACKET_STRING_SIZE = 100; + +struct SerialPacketBase { + //members + SerialPacketType type; + IPaddress srcAddress; + + virtual ~SerialPacketBase() {}; +}; + +typedef SerialPacketBase SerialPacket; + +#endif diff --git a/common/network/packet/serial_packet_type.hpp b/common/network/packet/serial_packet_type.hpp new file mode 100644 index 0000000..9142dcc --- /dev/null +++ b/common/network/packet/serial_packet_type.hpp @@ -0,0 +1,113 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERIALPACKETTYPE_HPP_ +#define SERIALPACKETTYPE_HPP_ + +/* Key for the comments: + * request => response +*/ + +enum class SerialPacketType { + //default: there is something wrong + NONE = 0, + + //keep alive + //ping => pong + PING = 1, + PONG = 2, + + //search for the server list + //none => server name, player count, version info (and source address) + BROADCAST_REQUEST = 3, + BROADCAST_RESPONSE = 4, + + //try to join the server + //username, and password => client index, account index + JOIN_REQUEST = 5, + JOIN_RESPONSE = 6, + JOIN_REJECTION = 7, + + //mass update of all surrounding content + //character.x, character.y => packet barrage + SYNCHRONIZE = 8, + + //disconnect from the server + //autentication, account index => disconnect that account + DISCONNECT = 9, + + //shut down the server + //autentication => disconnect, shutdown + SHUTDOWN = 10, + + //map data + //room index, region.x, region.y => room index, region.x, region.y, region content + REGION_REQUEST = 11, + REGION_CONTENT = 12, + + //combat data + //TODO: system incomplete + COMBAT_NEW = 13, + COMBAT_DELETE = 14, + COMBAT_UPDATE = 15, + + COMBAT_ENTER_REQUEST = 16, + COMBAT_ENTER_RESPONSE = 17, + + COMBAT_EXIT_REQUEST = 18, + COMBAT_EXIT_RESPONSE = 19, + + //TODO: COMBAT info + + COMBAT_REJECTION = 20, + + //character data + //character data => etc. + CHARACTER_NEW = 21, + CHARACTER_DELETE = 22, + CHARACTER_UPDATE = 23, + + //authentication, character index => character stats + CHARACTER_STATS_REQUEST= 24, + CHARACTER_STATS_RESPONSE = 25, + + //character new => character rejection, disconnect? + CHARACTER_REJECTION = 26, + + //enemy data + //enemy data => etc. + ENEMY_NEW = 27, + ENEMY_DELETE = 28, + ENEMY_UPDATE = 29, + + ENEMY_STATS_REQUEST = 30, + ENEMY_STATS_RESPONSE = 31, + + //enemy index => enemy doens't exist + ENEMY_REJECTION= 32, + + //NOTE: more packet types go here + + //not used + LAST +}; + +#endif \ No newline at end of file diff --git a/common/network/packet/server_packet.hpp b/common/network/packet/server_packet.hpp new file mode 100644 index 0000000..fcd4a49 --- /dev/null +++ b/common/network/packet/server_packet.hpp @@ -0,0 +1,34 @@ +/* Copyright: (c) Kayne Ruse 2013, 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERVERPACKET_HPP_ +#define SERVERPACKET_HPP_ + +#include "serial_packet_base.hpp" + +struct ServerPacket : SerialPacketBase { + //identify the server + char name[PACKET_STRING_SIZE]; + int playerCount; + int version; +}; + +#endif \ No newline at end of file diff --git a/common/network/serial.cpp b/common/network/serial.cpp deleted file mode 100644 index 961afd4..0000000 --- a/common/network/serial.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "serial.hpp" - -#include "map_allocator.hpp" -#include "statistics.hpp" - -#include - -//------------------------- -//Convenience Macros -//------------------------- - -#define SERIALIZE(buffer, data, size) memcpy(buffer, data, size); buffer += size; -#define DESERIALIZE(buffer, data, size) memcpy(data, buffer, size); buffer += size; - -//------------------------- -//internal serialization functions -//------------------------- - -void serializeType(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); -} - -void serializeServer(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //server info - SERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int)); - SERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE); - SERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int)); -} - -void serializeClient(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //indexes - SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int)); - SERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int)); - SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int)); - - //texts - SERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE); - //TODO: password - SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); -} - -void serializeRegionFormat(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //format - SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int)); - SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int)); - SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int)); -} - -void serializeRegionContent(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //format - SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int)); - SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int)); - SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int)); - - //content - for (register int i = 0; i < REGION_WIDTH; i++) { - for (register int j = 0; j < REGION_HEIGHT; j++) { - for (register int k = 0; k < REGION_DEPTH; k++) { - *reinterpret_cast(buffer) = packet->regionInfo.region->GetTile(i, j, k); - buffer += sizeof(Region::type_t); - } - } - } -} - -void serializeCombat(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //integers - SERIALIZE(buffer, &packet->combatInfo.combatIndex, sizeof(int)); - SERIALIZE(buffer, &packet->combatInfo.difficulty, sizeof(int)); - - SERIALIZE(buffer, &packet->combatInfo.terrainType, sizeof(CombatData::Terrain)); - - //arrays - SERIALIZE(buffer, &packet->combatInfo.characterArray, COMBAT_MAX_CHARACTER_COUNT); - SERIALIZE(buffer, &packet->combatInfo.enemyArray, COMBAT_MAX_ENEMY_COUNT); - - //position - SERIALIZE(buffer, &packet->combatInfo.mapIndex, sizeof(int)); - SERIALIZE(buffer, &packet->combatInfo.origin.x, sizeof(double)); - SERIALIZE(buffer, &packet->combatInfo.origin.y, sizeof(double)); - - //TODO: rewards -} - -void serializeStatistics(Statistics* stats, char* buffer) { - //integers - SERIALIZE(buffer, &stats->level, sizeof(int)); - SERIALIZE(buffer, &stats->exp, sizeof(int)); - SERIALIZE(buffer, &stats->maxHP, sizeof(int)); - SERIALIZE(buffer, &stats->health, sizeof(int)); - SERIALIZE(buffer, &stats->maxMP, sizeof(int)); - SERIALIZE(buffer, &stats->mana, sizeof(int)); - SERIALIZE(buffer, &stats->attack, sizeof(int)); - SERIALIZE(buffer, &stats->defence, sizeof(int)); - SERIALIZE(buffer, &stats->intelligence, sizeof(int)); - SERIALIZE(buffer, &stats->resistance, sizeof(int)); - SERIALIZE(buffer, &stats->speed, sizeof(int)); - - //floats - SERIALIZE(buffer, &stats->accuracy, sizeof(float)); - SERIALIZE(buffer, &stats->evasion, sizeof(float)); - SERIALIZE(buffer, &stats->luck, sizeof(float)); -} - -void serializeCharacter(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //indexes - SERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int)); - SERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int)); - SERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int)); - - //texts - SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); - - //vectors - SERIALIZE(buffer, &packet->characterInfo.origin.x, sizeof(double)); - SERIALIZE(buffer, &packet->characterInfo.origin.y, sizeof(double)); - SERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double)); - SERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double)); - - //stats structure - serializeStatistics(&packet->characterInfo.stats, buffer); - buffer += sizeof(Statistics); -} - -void serializeEnemy(SerialPacket* packet, char* buffer) { - SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //texts - SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); - - //stats structure - serializeStatistics(&packet->characterInfo.stats, buffer); - buffer += sizeof(Statistics); -} - -//------------------------- -//internal deserialization functions -//------------------------- - -void deserializeType(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); -} - -void deserializeServer(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //server info - DESERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int)); - DESERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE); - DESERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int)); -} - -void deserializeClient(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //indexes - DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int)); - - //texts - DESERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE); - //TODO: password - DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); -} - -void deserializeRegionFormat(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //format - DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int)); - DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int)); -} - -void deserializeRegionContent(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //format - DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int)); - DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int)); - - //an object to work on - BlankAllocator().Create( - &packet->regionInfo.region, - packet->regionInfo.x, - packet->regionInfo.y - ); - - //content - for (register int i = 0; i < REGION_WIDTH; i++) { - for (register int j = 0; j < REGION_HEIGHT; j++) { - for (register int k = 0; k < REGION_DEPTH; k++) { - packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast(buffer)); - buffer += sizeof(Region::type_t); - } - } - } -} - - -void deserializeCombat(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //integers - DESERIALIZE(buffer, &packet->combatInfo.combatIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->combatInfo.difficulty, sizeof(int)); - - DESERIALIZE(buffer, &packet->combatInfo.terrainType, sizeof(CombatData::Terrain)); - - //arrays - DESERIALIZE(buffer, &packet->combatInfo.characterArray, COMBAT_MAX_CHARACTER_COUNT); - DESERIALIZE(buffer, &packet->combatInfo.enemyArray, COMBAT_MAX_ENEMY_COUNT); - - //position - DESERIALIZE(buffer, &packet->combatInfo.mapIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->combatInfo.origin.x, sizeof(double)); - DESERIALIZE(buffer, &packet->combatInfo.origin.y, sizeof(double)); - - //TODO: rewards -} - - -void deserializeStatistics(Statistics* stats, char* buffer) { - //integers - DESERIALIZE(buffer, &stats->level, sizeof(int)); - DESERIALIZE(buffer, &stats->exp, sizeof(int)); - DESERIALIZE(buffer, &stats->maxHP, sizeof(int)); - DESERIALIZE(buffer, &stats->health, sizeof(int)); - DESERIALIZE(buffer, &stats->maxMP, sizeof(int)); - DESERIALIZE(buffer, &stats->mana, sizeof(int)); - DESERIALIZE(buffer, &stats->attack, sizeof(int)); - DESERIALIZE(buffer, &stats->defence, sizeof(int)); - DESERIALIZE(buffer, &stats->intelligence, sizeof(int)); - DESERIALIZE(buffer, &stats->resistance, sizeof(int)); - DESERIALIZE(buffer, &stats->speed, sizeof(int)); - - //floats - DESERIALIZE(buffer, &stats->accuracy, sizeof(float)); - DESERIALIZE(buffer, &stats->evasion, sizeof(float)); - DESERIALIZE(buffer, &stats->luck, sizeof(float)); -} - -void deserializeCharacter(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //indexes - DESERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int)); - DESERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int)); - - //texts - DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); - - //vectors - DESERIALIZE(buffer, &packet->characterInfo.origin.x, sizeof(double)); - DESERIALIZE(buffer, &packet->characterInfo.origin.y, sizeof(double)); - DESERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double)); - DESERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double)); - - //stats structure - deserializeStatistics(&packet->characterInfo.stats, buffer); - buffer += sizeof(Statistics); -} - -void deserializeEnemy(SerialPacket* packet, char* buffer) { - DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); - - //texts - DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE); - DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE); - - //stats structure - deserializeStatistics(&packet->characterInfo.stats, buffer); - buffer += sizeof(Statistics); -} - -//------------------------- -//the interface functions -//------------------------- - -void serialize(SerialPacket* packet, void* buffer) { - switch(packet->meta.type) { - //no extra data - case SerialPacket::Type::NONE: - case SerialPacket::Type::PING: - case SerialPacket::Type::PONG: - case SerialPacket::Type::BROADCAST_REQUEST: - - //all rejections - case SerialPacket::Type::BROADCAST_REJECTION: - case SerialPacket::Type::JOIN_REJECTION: - case SerialPacket::Type::REGION_REJECTION: - case SerialPacket::Type::CHARACTER_REJECTION: - case SerialPacket::Type::ENEMY_REJECTION: - case SerialPacket::Type::COMBAT_REJECTION: - - serializeType(packet, reinterpret_cast(buffer)); - break; - - //server info - case SerialPacket::Type::BROADCAST_RESPONSE: - serializeServer(packet, reinterpret_cast(buffer)); - break; - - //client info - case SerialPacket::Type::JOIN_REQUEST: - case SerialPacket::Type::JOIN_RESPONSE: - case SerialPacket::Type::SYNCHRONIZE: - case SerialPacket::Type::DISCONNECT: - case SerialPacket::Type::SHUTDOWN: - serializeClient(packet, reinterpret_cast(buffer)); - break; - - //region info - case SerialPacket::Type::REGION_REQUEST: - serializeRegionFormat(packet, reinterpret_cast(buffer)); - break; - - case SerialPacket::Type::REGION_CONTENT: - serializeRegionContent(packet, reinterpret_cast(buffer)); - break; - - //combat info - case SerialPacket::Type::COMBAT_NEW: - case SerialPacket::Type::COMBAT_DELETE: - case SerialPacket::Type::COMBAT_UPDATE: - - //TODO: is this the best fit? - case SerialPacket::Type::COMBAT_ENTER_REQUEST: - case SerialPacket::Type::COMBAT_ENTER_RESPONSE: - case SerialPacket::Type::COMBAT_EXIT_REQUEST: - case SerialPacket::Type::COMBAT_EXIT_RESPONSE: - - serializeCombat(packet, reinterpret_cast(buffer)); - break; - - //character info - case SerialPacket::Type::CHARACTER_NEW: - case SerialPacket::Type::CHARACTER_DELETE: - case SerialPacket::Type::CHARACTER_UPDATE: - case SerialPacket::Type::CHARACTER_STATS_REQUEST: - case SerialPacket::Type::CHARACTER_STATS_RESPONSE: - serializeCharacter(packet, reinterpret_cast(buffer)); - break; - - //enemy info - case SerialPacket::Type::ENEMY_NEW: - case SerialPacket::Type::ENEMY_DELETE: - case SerialPacket::Type::ENEMY_UPDATE: - case SerialPacket::Type::ENEMY_STATS_REQUEST: - case SerialPacket::Type::ENEMY_STATS_RESPONSE: - serializeEnemy(packet, reinterpret_cast(buffer)); - break; - } -} - -void deserialize(SerialPacket* packet, void* buffer) { - //find the type, so that you can actually deserialize the packet! - deserializeType(packet, reinterpret_cast(buffer)); - switch(packet->meta.type) { - //no extra data - case SerialPacket::Type::NONE: - case SerialPacket::Type::PING: - case SerialPacket::Type::PONG: - case SerialPacket::Type::BROADCAST_REQUEST: - - //all rejections - case SerialPacket::Type::BROADCAST_REJECTION: - case SerialPacket::Type::JOIN_REJECTION: - case SerialPacket::Type::REGION_REJECTION: - case SerialPacket::Type::CHARACTER_REJECTION: - case SerialPacket::Type::ENEMY_REJECTION: - case SerialPacket::Type::COMBAT_REJECTION: - - //NOTHING - break; - - //server info - case SerialPacket::Type::BROADCAST_RESPONSE: - deserializeServer(packet, reinterpret_cast(buffer)); - break; - - //client info - case SerialPacket::Type::JOIN_REQUEST: - case SerialPacket::Type::JOIN_RESPONSE: - case SerialPacket::Type::SYNCHRONIZE: - case SerialPacket::Type::DISCONNECT: - case SerialPacket::Type::SHUTDOWN: - deserializeClient(packet, reinterpret_cast(buffer)); - break; - - //region info - case SerialPacket::Type::REGION_REQUEST: - deserializeRegionFormat(packet, reinterpret_cast(buffer)); - break; - - case SerialPacket::Type::REGION_CONTENT: - deserializeRegionContent(packet, reinterpret_cast(buffer)); - break; - - //combat info - case SerialPacket::Type::COMBAT_NEW: - case SerialPacket::Type::COMBAT_DELETE: - case SerialPacket::Type::COMBAT_UPDATE: - - //TODO: is this the best fit? - case SerialPacket::Type::COMBAT_ENTER_REQUEST: - case SerialPacket::Type::COMBAT_ENTER_RESPONSE: - case SerialPacket::Type::COMBAT_EXIT_REQUEST: - case SerialPacket::Type::COMBAT_EXIT_RESPONSE: - - serializeCombat(packet, reinterpret_cast(buffer)); - break; - - //character info - case SerialPacket::Type::CHARACTER_NEW: - case SerialPacket::Type::CHARACTER_DELETE: - case SerialPacket::Type::CHARACTER_UPDATE: - case SerialPacket::Type::CHARACTER_STATS_REQUEST: - case SerialPacket::Type::CHARACTER_STATS_RESPONSE: - deserializeCharacter(packet, reinterpret_cast(buffer)); - break; - - //enemy info - case SerialPacket::Type::ENEMY_NEW: - case SerialPacket::Type::ENEMY_DELETE: - case SerialPacket::Type::ENEMY_UPDATE: - case SerialPacket::Type::ENEMY_STATS_REQUEST: - case SerialPacket::Type::ENEMY_STATS_RESPONSE: - serializeEnemy(packet, reinterpret_cast(buffer)); - break; - } -} \ No newline at end of file diff --git a/common/network/serial/makefile b/common/network/serial/makefile new file mode 100644 index 0000000..564b228 --- /dev/null +++ b/common/network/serial/makefile @@ -0,0 +1,37 @@ +#config +INCLUDES+=. ../packet ../../gameplay ../../map ../../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)/,libcommon.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/common/network/serial/serial.cpp b/common/network/serial/serial.cpp new file mode 100644 index 0000000..791da27 --- /dev/null +++ b/common/network/serial/serial.cpp @@ -0,0 +1,183 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +//simple type functions +void serializeType(SerialPacketBase* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); +} + +void deserializeType(SerialPacketBase* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); +} + +//main switch functions +void serializePacket(SerialPacketBase* packet, void* buffer) { + switch(packet->type) { + //no extra data + case SerialPacketType::NONE: + case SerialPacketType::PING: + case SerialPacketType::PONG: + case SerialPacketType::BROADCAST_REQUEST: + + //all rejections + case SerialPacketType::JOIN_REJECTION: + case SerialPacketType::CHARACTER_REJECTION: + case SerialPacketType::ENEMY_REJECTION: + case SerialPacketType::COMBAT_REJECTION: + + serializeType(packet, buffer); + break; + + //character info + case SerialPacketType::CHARACTER_NEW: + case SerialPacketType::CHARACTER_DELETE: + case SerialPacketType::CHARACTER_UPDATE: + case SerialPacketType::CHARACTER_STATS_REQUEST: + case SerialPacketType::CHARACTER_STATS_RESPONSE: + serializeCharacter(static_cast(packet), buffer); + break; + + //client info + case SerialPacketType::JOIN_REQUEST: + case SerialPacketType::JOIN_RESPONSE: + case SerialPacketType::SYNCHRONIZE: + case SerialPacketType::DISCONNECT: + case SerialPacketType::SHUTDOWN: + serializeClient(static_cast(packet), buffer); + break; + + //combat info + case SerialPacketType::COMBAT_NEW: + case SerialPacketType::COMBAT_DELETE: + case SerialPacketType::COMBAT_UPDATE: + + case SerialPacketType::COMBAT_ENTER_REQUEST: + case SerialPacketType::COMBAT_ENTER_RESPONSE: + case SerialPacketType::COMBAT_EXIT_REQUEST: + case SerialPacketType::COMBAT_EXIT_RESPONSE: + + serializeCombat(static_cast(packet), buffer); + break; + + //enemy info + case SerialPacketType::ENEMY_NEW: + case SerialPacketType::ENEMY_DELETE: + case SerialPacketType::ENEMY_UPDATE: + case SerialPacketType::ENEMY_STATS_REQUEST: + case SerialPacketType::ENEMY_STATS_RESPONSE: + serializeEnemy(static_cast(packet), buffer); + break; + + //region info + case SerialPacketType::REGION_REQUEST: + serializeRegionFormat(static_cast(packet), buffer); + break; + + case SerialPacketType::REGION_CONTENT: + serializeRegionContent(static_cast(packet), buffer); + break; + + //server info + case SerialPacketType::BROADCAST_RESPONSE: + serializeServer(static_cast(packet), buffer); + break; + } +} + +void deserializePacket(SerialPacketBase* packet, void* buffer) { + //find the type, so that you can actually deserialize the packet! + deserializeType(packet, buffer); + switch(packet->type) { + //no extra data + case SerialPacketType::NONE: + case SerialPacketType::PING: + case SerialPacketType::PONG: + case SerialPacketType::BROADCAST_REQUEST: + + //all rejections + case SerialPacketType::JOIN_REJECTION: + case SerialPacketType::CHARACTER_REJECTION: + case SerialPacketType::ENEMY_REJECTION: + case SerialPacketType::COMBAT_REJECTION: + + //NOTHING + break; + + //character info + case SerialPacketType::CHARACTER_NEW: + case SerialPacketType::CHARACTER_DELETE: + case SerialPacketType::CHARACTER_UPDATE: + case SerialPacketType::CHARACTER_STATS_REQUEST: + case SerialPacketType::CHARACTER_STATS_RESPONSE: + deserializeCharacter(static_cast(packet), buffer); + break; + + //client info + case SerialPacketType::JOIN_REQUEST: + case SerialPacketType::JOIN_RESPONSE: + case SerialPacketType::SYNCHRONIZE: + case SerialPacketType::DISCONNECT: + case SerialPacketType::SHUTDOWN: + deserializeClient(static_cast(packet), buffer); + break; + + //combat info + case SerialPacketType::COMBAT_NEW: + case SerialPacketType::COMBAT_DELETE: + case SerialPacketType::COMBAT_UPDATE: + + //TODO: is this the best fit? + case SerialPacketType::COMBAT_ENTER_REQUEST: + case SerialPacketType::COMBAT_ENTER_RESPONSE: + case SerialPacketType::COMBAT_EXIT_REQUEST: + case SerialPacketType::COMBAT_EXIT_RESPONSE: + + serializeCombat(static_cast(packet), buffer); + break; + + //enemy info + case SerialPacketType::ENEMY_NEW: + case SerialPacketType::ENEMY_DELETE: + case SerialPacketType::ENEMY_UPDATE: + case SerialPacketType::ENEMY_STATS_REQUEST: + case SerialPacketType::ENEMY_STATS_RESPONSE: + serializeEnemy(static_cast(packet), buffer); + break; + + //region info + case SerialPacketType::REGION_REQUEST: + deserializeRegionFormat(static_cast(packet), buffer); + break; + + case SerialPacketType::REGION_CONTENT: + deserializeRegionContent(static_cast(packet), buffer); + break; + + //server info + case SerialPacketType::BROADCAST_RESPONSE: + deserializeServer(static_cast(packet), buffer); + break; + } +} \ No newline at end of file diff --git a/common/network/serial/serial.hpp b/common/network/serial/serial.hpp new file mode 100644 index 0000000..02d5dba --- /dev/null +++ b/common/network/serial/serial.hpp @@ -0,0 +1,65 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERIALIZE_HPP_ +#define SERIALIZE_HPP_ + +#include "serial_packet.hpp" + +#include "region.hpp" +#include "statistics.hpp" + +//Primary interface functions +void serializePacket(SerialPacketBase*, void* dest); +void deserializePacket(SerialPacketBase*, void* src); + +void serializeType(SerialPacketBase*, void*); +void deserializeType(SerialPacketBase*, void*); + +//utility functions, exposed +void serializeCharacter(CharacterPacket*, void*); +void serializeClient(ClientPacket*, void*); +void serializeCombat(CombatPacket*, void*); +void serializeEnemy(EnemyPacket*, void*); +void serializeRegionFormat(RegionPacket*, void*); +void serializeRegionContent(RegionPacket*, void*); +void serializeServer(ServerPacket*, void*); +void serializeStatistics(Statistics*, void*); + +void deserializeCharacter(CharacterPacket*, void*); +void deserializeClient(ClientPacket*, void*); +void deserializeCombat(CombatPacket*, void*); +void deserializeEnemy(EnemyPacket*, void*); +void deserializeRegionFormat(RegionPacket*, void*); +void deserializeRegionContent(RegionPacket*, void*); +void deserializeServer(ServerPacket*, void*); +void deserializeStatistics(Statistics*, void*); + +/* DOCS: Keep the PACKET_BUFFER_SIZE up to date + * DOCS: REGION_CONTENT is currently the largest type of packet, read more + * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t) + * map format: sizeof(int) * 3 + * metadata: sizeof(SerialPacket::Type) +*/ + +constexpr int PACKET_BUFFER_SIZE = REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacketType); + +#endif \ No newline at end of file diff --git a/common/network/serial/serial_character.cpp b/common/network/serial/serial_character.cpp new file mode 100644 index 0000000..3805702 --- /dev/null +++ b/common/network/serial/serial_character.cpp @@ -0,0 +1,80 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeCharacter(CharacterPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the character + SERIALIZE(buffer, &packet->characterIndex, sizeof(int)); + SERIALIZE(buffer, &packet->handle, PACKET_STRING_SIZE); + SERIALIZE(buffer, &packet->avatar, PACKET_STRING_SIZE); + + //the owner + SERIALIZE(buffer, &packet->accountIndex, sizeof(int)); + + //location + SERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + SERIALIZE(buffer, &packet->origin.x, sizeof(double)); + SERIALIZE(buffer, &packet->origin.y, sizeof(double)); + SERIALIZE(buffer, &packet->motion.x, sizeof(double)); + SERIALIZE(buffer, &packet->motion.y, sizeof(double)); + + //stats structure + serializeStatistics(&packet->stats, buffer); + buffer = reinterpret_cast(buffer) + sizeof(Statistics); + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs +} + +void deserializeCharacter(CharacterPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the character + DESERIALIZE(buffer, &packet->characterIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->handle, PACKET_STRING_SIZE); + DESERIALIZE(buffer, &packet->avatar, PACKET_STRING_SIZE); + + //the owner + DESERIALIZE(buffer, &packet->accountIndex, sizeof(int)); + + //location + DESERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->origin.x, sizeof(double)); + DESERIALIZE(buffer, &packet->origin.y, sizeof(double)); + DESERIALIZE(buffer, &packet->motion.x, sizeof(double)); + DESERIALIZE(buffer, &packet->motion.y, sizeof(double)); + + //stats structure + deserializeStatistics(&packet->stats, buffer); + buffer = reinterpret_cast(buffer) + sizeof(Statistics); + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs +} diff --git a/common/network/serial/serial_client.cpp b/common/network/serial/serial_client.cpp new file mode 100644 index 0000000..96bc881 --- /dev/null +++ b/common/network/serial/serial_client.cpp @@ -0,0 +1,42 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeClient(ClientPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + SERIALIZE(buffer, &packet->clientIndex, sizeof(int)); + SERIALIZE(buffer, &packet->accountIndex, sizeof(int)); + SERIALIZE(buffer, &packet->username, PACKET_STRING_SIZE); +// SERIALIZE(buffer, &packet->password, PACKET_STRING_SIZE); +} + +void deserializeClient(ClientPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + DESERIALIZE(buffer, &packet->clientIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->accountIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->username, PACKET_STRING_SIZE); +// DESERIALIZE(buffer, &packet->password, PACKET_STRING_SIZE); +} diff --git a/common/network/serial/serial_combat.cpp b/common/network/serial/serial_combat.cpp new file mode 100644 index 0000000..881db97 --- /dev/null +++ b/common/network/serial/serial_combat.cpp @@ -0,0 +1,64 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeCombat(CombatPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the combat instance + SERIALIZE(buffer, &packet->combatIndex, sizeof(int)); + SERIALIZE(buffer, &packet->difficulty, sizeof(int)); + SERIALIZE(buffer, &packet->terrainType, sizeof(CombatData::Terrain)); + + //combatants + SERIALIZE(buffer, &packet->characterArray, sizeof(int) * COMBAT_MAX_CHARACTERS); + SERIALIZE(buffer, &packet->enemyArray, sizeof(int) * COMBAT_MAX_ENEMIES); + + //location + SERIALIZE(buffer, &packet->mapIndex, sizeof(int)); + SERIALIZE(buffer, &packet->origin.x, sizeof(double)); + SERIALIZE(buffer, &packet->origin.y, sizeof(double)); + + //TODO: rewards +} + +void deserializeCombat(CombatPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the combat instance + DESERIALIZE(buffer, &packet->combatIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->difficulty, sizeof(int)); + DESERIALIZE(buffer, &packet->terrainType, sizeof(CombatData::Terrain)); + + //combatants + DESERIALIZE(buffer, &packet->characterArray, sizeof(int) * COMBAT_MAX_CHARACTERS); + DESERIALIZE(buffer, &packet->enemyArray, sizeof(int) * COMBAT_MAX_ENEMIES); + + //location + DESERIALIZE(buffer, &packet->mapIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->origin.x, sizeof(double)); + DESERIALIZE(buffer, &packet->origin.y, sizeof(double)); + + //TODO: rewards +} diff --git a/common/network/serial/serial_enemy.cpp b/common/network/serial/serial_enemy.cpp new file mode 100644 index 0000000..363ca1f --- /dev/null +++ b/common/network/serial/serial_enemy.cpp @@ -0,0 +1,66 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeEnemy(EnemyPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the enemy + SERIALIZE(buffer, &packet->enemyIndex, sizeof(int)); + SERIALIZE(buffer, &packet->handle, PACKET_STRING_SIZE); + SERIALIZE(buffer, &packet->avatar, PACKET_STRING_SIZE); + + //gameplay + + //stats structure + serializeStatistics(&packet->stats, buffer); + buffer = reinterpret_cast(buffer) + sizeof(Statistics); + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + //TODO: rewards +} + +void deserializeEnemy(EnemyPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the enemy + DESERIALIZE(buffer, &packet->enemyIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->handle, PACKET_STRING_SIZE); + DESERIALIZE(buffer, &packet->avatar, PACKET_STRING_SIZE); + + //stats structure + deserializeStatistics(&packet->stats, buffer); + buffer = reinterpret_cast(buffer) + sizeof(Statistics); + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + //TODO: rewards +} diff --git a/common/network/serial/serial_region.cpp b/common/network/serial/serial_region.cpp new file mode 100644 index 0000000..31145bd --- /dev/null +++ b/common/network/serial/serial_region.cpp @@ -0,0 +1,83 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeRegionFormat(RegionPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //format + SERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + SERIALIZE(buffer, &packet->x, sizeof(int)); + SERIALIZE(buffer, &packet->y, sizeof(int)); +} + +void serializeRegionContent(RegionPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //format + SERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + SERIALIZE(buffer, &packet->x, sizeof(int)); + SERIALIZE(buffer, &packet->y, sizeof(int)); + + //content + for (register int i = 0; i < REGION_WIDTH; i++) { + for (register int j = 0; j < REGION_HEIGHT; j++) { + for (register int k = 0; k < REGION_DEPTH; k++) { + *reinterpret_cast(buffer) = packet->region->GetTile(i, j, k); + buffer = reinterpret_cast(buffer) + sizeof(Region::type_t); + } + } + } +} + +void deserializeRegionFormat(RegionPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //format + DESERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->x, sizeof(int)); + DESERIALIZE(buffer, &packet->y, sizeof(int)); +} + +void deserializeRegionContent(RegionPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //format + DESERIALIZE(buffer, &packet->roomIndex, sizeof(int)); + DESERIALIZE(buffer, &packet->x, sizeof(int)); + DESERIALIZE(buffer, &packet->y, sizeof(int)); + + //an object to work on + packet->region = new Region(packet->x, packet->y); + + //content + for (register int i = 0; i < REGION_WIDTH; i++) { + for (register int j = 0; j < REGION_HEIGHT; j++) { + for (register int k = 0; k < REGION_DEPTH; k++) { + packet->region->SetTile(i, j, k, *reinterpret_cast(buffer)); + buffer = reinterpret_cast(buffer) + sizeof(Region::type_t); + } + } + } +} \ No newline at end of file diff --git a/common/network/serial/serial_server.cpp b/common/network/serial/serial_server.cpp new file mode 100644 index 0000000..12a2f34 --- /dev/null +++ b/common/network/serial/serial_server.cpp @@ -0,0 +1,42 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeServer(ServerPacket* packet, void* buffer) { + SERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the server + SERIALIZE(buffer, &packet->name, PACKET_STRING_SIZE); + SERIALIZE(buffer, &packet->playerCount, sizeof(int)); + SERIALIZE(buffer, &packet->version, sizeof(int)); +} + +void deserializeServer(ServerPacket* packet, void* buffer) { + DESERIALIZE(buffer, &packet->type, sizeof(SerialPacketType)); + + //identify the server + DESERIALIZE(buffer, &packet->name, PACKET_STRING_SIZE); + DESERIALIZE(buffer, &packet->playerCount, sizeof(int)); + DESERIALIZE(buffer, &packet->version, sizeof(int)); +} diff --git a/common/network/serial/serial_statistics.cpp b/common/network/serial/serial_statistics.cpp new file mode 100644 index 0000000..6a594a8 --- /dev/null +++ b/common/network/serial/serial_statistics.cpp @@ -0,0 +1,65 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "serial.hpp" + +#include "serial_util.hpp" + +void serializeStatistics(Statistics* stats, void* buffer) { + //integers + SERIALIZE(buffer, &stats->level, sizeof(int)); + SERIALIZE(buffer, &stats->exp, sizeof(int)); + SERIALIZE(buffer, &stats->maxHP, sizeof(int)); + SERIALIZE(buffer, &stats->health, sizeof(int)); + SERIALIZE(buffer, &stats->maxMP, sizeof(int)); + SERIALIZE(buffer, &stats->mana, sizeof(int)); + SERIALIZE(buffer, &stats->attack, sizeof(int)); + SERIALIZE(buffer, &stats->defence, sizeof(int)); + SERIALIZE(buffer, &stats->intelligence, sizeof(int)); + SERIALIZE(buffer, &stats->resistance, sizeof(int)); + SERIALIZE(buffer, &stats->speed, sizeof(int)); + + //floats + SERIALIZE(buffer, &stats->accuracy, sizeof(float)); + SERIALIZE(buffer, &stats->evasion, sizeof(float)); + SERIALIZE(buffer, &stats->luck, sizeof(float)); +} + + +void deserializeStatistics(Statistics* stats, void* buffer) { + //integers + DESERIALIZE(buffer, &stats->level, sizeof(int)); + DESERIALIZE(buffer, &stats->exp, sizeof(int)); + DESERIALIZE(buffer, &stats->maxHP, sizeof(int)); + DESERIALIZE(buffer, &stats->health, sizeof(int)); + DESERIALIZE(buffer, &stats->maxMP, sizeof(int)); + DESERIALIZE(buffer, &stats->mana, sizeof(int)); + DESERIALIZE(buffer, &stats->attack, sizeof(int)); + DESERIALIZE(buffer, &stats->defence, sizeof(int)); + DESERIALIZE(buffer, &stats->intelligence, sizeof(int)); + DESERIALIZE(buffer, &stats->resistance, sizeof(int)); + DESERIALIZE(buffer, &stats->speed, sizeof(int)); + + //floats + DESERIALIZE(buffer, &stats->accuracy, sizeof(float)); + DESERIALIZE(buffer, &stats->evasion, sizeof(float)); + DESERIALIZE(buffer, &stats->luck, sizeof(float)); +} diff --git a/common/network/serial/serial_util.hpp b/common/network/serial/serial_util.hpp new file mode 100644 index 0000000..a0910b8 --- /dev/null +++ b/common/network/serial/serial_util.hpp @@ -0,0 +1,31 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SERIALIZEUTIL_HPP_ +#define SERIALIZEUTIL_HPP_ + +#include + +//NOTE: The strange assignments here used in order to move the void* parameter +#define SERIALIZE(buffer, data, size) memcpy(buffer, data, size); buffer = reinterpret_cast(buffer) + size; +#define DESERIALIZE(buffer, data, size) memcpy(data, buffer, size); buffer = reinterpret_cast(buffer) + size; + +#endif diff --git a/common/network/serial_packet.hpp b/common/network/serial_packet.hpp deleted file mode 100644 index d378fde..0000000 --- a/common/network/serial_packet.hpp +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2013, 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#ifndef SERIALPACKET_HPP_ -#define SERIALPACKET_HPP_ - -#include "vector2.hpp" -#include "region.hpp" -#include "statistics.hpp" -#include "combat_data.hpp" - -#include "SDL/SDL_net.h" - -#define NETWORK_VERSION 20140601 -#define PACKET_STRING_SIZE 100 - -//TODO: would it be possible to serialize structures directly? -union SerialPacket { - //types of packets - enum class Type { - //default: there is something wrong - NONE = 0, - - //keep alive - PING, - PONG, - - //searching for a server to join - BROADCAST_REQUEST, - BROADCAST_RESPONSE, - BROADCAST_REJECTION, - - //try to join the server - JOIN_REQUEST, - JOIN_RESPONSE, - JOIN_REJECTION, - - //mass update - SYNCHRONIZE, - - //disconnect from the server - DISCONNECT, - - //shut down the server - SHUTDOWN, - - //map data - REGION_REQUEST, - REGION_CONTENT, - REGION_REJECTION, - - //combat data - COMBAT_NEW, - COMBAT_DELETE, - COMBAT_UPDATE, - - COMBAT_ENTER_REQUEST, - COMBAT_ENTER_RESPONSE, - - COMBAT_EXIT_REQUEST, - COMBAT_EXIT_RESPONSE, - - //TODO: COMBAT info - - COMBAT_REJECTION, - - //character data - CHARACTER_NEW, - CHARACTER_DELETE, - CHARACTER_UPDATE, - - CHARACTER_STATS_REQUEST, - CHARACTER_STATS_RESPONSE, - - CHARACTER_REJECTION, - - //enemy data - ENEMY_NEW, - ENEMY_DELETE, - ENEMY_UPDATE, - - ENEMY_STATS_REQUEST, - ENEMY_STATS_RESPONSE, - - ENEMY_REJECTION, - - //more packet types go here - - //not used - LAST, - }; - - //metadata on the packet itself - struct Metadata { - Type type; - IPaddress srcAddress; - }meta; - - //info about the server - struct ServerInformation { - Metadata meta; - int networkVersion; - char name[PACKET_STRING_SIZE]; - int playerCount; - }serverInfo; - - //info about the client - struct ClientInformation { - Metadata meta; - int clientIndex; - int accountIndex; - int characterIndex; - char username[PACKET_STRING_SIZE]; - //TODO: password - char handle[PACKET_STRING_SIZE]; - char avatar[PACKET_STRING_SIZE]; - }clientInfo; - - //info about a region - struct RegionInformation { - Metadata meta; - int mapIndex; - int x, y; - Region* region; - }regionInfo; - - //info about a combat scenario - struct CombatInformation { - Metadata meta; - int combatIndex; - int difficulty; - CombatData::Terrain terrainType; - int characterArray[COMBAT_MAX_CHARACTER_COUNT]; - int enemyArray[COMBAT_MAX_ENEMY_COUNT]; - int mapIndex; - Vector2 origin; - //TODO: rewards - }combatInfo; - - //info about a character - struct CharacterInformation { - Metadata meta; - int clientIndex; - int accountIndex; - int characterIndex; - char handle[PACKET_STRING_SIZE]; - char avatar[PACKET_STRING_SIZE]; - int mapIndex; - Vector2 origin; - Vector2 motion; - Statistics stats; - }characterInfo; - - //info about an enemy - struct EnemyInformation { - Metadata meta; - char handle[PACKET_STRING_SIZE]; - char avatar[PACKET_STRING_SIZE]; - Statistics stats; - //TODO: rewards - }enemyInfo; - - //defaults - SerialPacket() { - meta.type = Type::NONE; - meta.srcAddress = {0,0}; - } -}; - -#endif diff --git a/common/network/udp_network_utility.cpp b/common/network/udp_network_utility.cpp index 5fb669e..275c1c8 100644 --- a/common/network/udp_network_utility.cpp +++ b/common/network/udp_network_utility.cpp @@ -166,7 +166,7 @@ int UDPNetworkUtility::SendTo(const char* ip, int port, SerialPacket* serialPack int UDPNetworkUtility::SendTo(IPaddress* add, SerialPacket* serialPacket) { memset(packet->data, 0, packet->maxlen); - serialize(serialPacket, packet->data); + serializePacket(serialPacket, packet->data); packet->len = PACKET_BUFFER_SIZE; packet->address = *add; @@ -181,7 +181,7 @@ int UDPNetworkUtility::SendTo(IPaddress* add, SerialPacket* serialPacket) { int UDPNetworkUtility::SendTo(int channel, SerialPacket* serialPacket) { memset(packet->data, 0, packet->maxlen); - serialize(serialPacket, packet->data); + serializePacket(serialPacket, packet->data); packet->len = PACKET_BUFFER_SIZE; int ret = SDLNet_UDP_Send(socket, channel, packet); @@ -195,7 +195,7 @@ int UDPNetworkUtility::SendTo(int channel, SerialPacket* serialPacket) { int UDPNetworkUtility::SendToAllChannels(SerialPacket* serialPacket) { memset(packet->data, 0, packet->maxlen); - serialize(serialPacket, packet->data); + serializePacket(serialPacket, packet->data); packet->len = PACKET_BUFFER_SIZE; int sent = 0; @@ -213,8 +213,8 @@ int UDPNetworkUtility::SendToAllChannels(SerialPacket* serialPacket) { int UDPNetworkUtility::Receive(SerialPacket* serialPacket) { memset(packet->data, 0, packet->maxlen); int ret = SDLNet_UDP_Recv(socket, packet); - deserialize(serialPacket, packet->data); - serialPacket->meta.srcAddress = packet->address; + deserializePacket(serialPacket, packet->data); + serialPacket->srcAddress = packet->address; if (ret < 0) { throw(std::runtime_error("Unknown network error occured")); diff --git a/common/script/linit.cpp b/common/script/linit.cpp deleted file mode 100644 index 4f9eb81..0000000 --- a/common/script/linit.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $ -** Initialization of libraries for lua.c and other clients -** See Copyright Notice in lua.h -*/ - -/* Modified for use in Tortuga, renamed to linit.cpp -*/ - - -/* -** If you embed Lua in your program and need to open the standard -** libraries, call luaL_openlibs in your program. If you need a -** different set of libraries, copy this file to your project and edit -** it to suit your needs. -*/ - - -#define linit_c -#define LUA_LIB - -#include "lua/lua.hpp" -#include "map_api.hpp" - - -/* -** these libs are loaded by lua.c and are readily available to any Lua -** program -*/ -static const luaL_Reg loadedlibs[] = { - /* Standard libs */ - {"_G", luaopen_base}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_COLIBNAME, luaopen_coroutine}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_OSLIBNAME, luaopen_os}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_BITLIBNAME, luaopen_bit32}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_DBLIBNAME, luaopen_debug}, - - /* custom libs */ - {LUA_MAPLIBNAME, luaopen_mapapi}, - - {NULL, NULL} -}; - - -/* -** these libs are preloaded and must be required before used -*/ -static const luaL_Reg preloadedlibs[] = { - {NULL, NULL} -}; - - -LUALIB_API void luaL_openlibs (lua_State *L) { - const luaL_Reg *lib; - /* call open functions from 'loadedlibs' and set results to global table */ - for (lib = loadedlibs; lib->func; lib++) { - luaL_requiref(L, lib->name, lib->func, 1); - lua_pop(L, 1); /* remove lib */ - } - /* add open functions from 'preloadedlibs' into 'package.preload' table */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); - for (lib = preloadedlibs; lib->func; lib++) { - lua_pushcfunction(L, lib->func); - lua_setfield(L, -2, lib->name); - } - lua_pop(L, 1); /* remove _PRELOAD table */ -} \ No newline at end of file diff --git a/common/script/map_api.cpp b/common/script/map_api.cpp deleted file mode 100644 index 9ecfea4..0000000 --- a/common/script/map_api.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "map_api.hpp" - -//map headers -#include "map_allocator.hpp" -#include "map_file_format.hpp" -#include "region_pager.hpp" - -//NOTE: When operating on a region, setTile() & getTile() *are not* zero indexed, but when operating on the entire map they *are* zero indexed. - -static int setTile(lua_State* L) { - if (lua_gettop(L) == 5) { - //operating on a region - Region* ptr = (Region*)lua_touserdata(L, 1); - ptr->SetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1, lua_tointeger(L, 5)); - } - else { - //operating on the whole map - lua_pushstring(L, "pager"); - lua_gettable(L, LUA_REGISTRYINDEX); - - //assume the pager is using lua - RegionPager* pager = reinterpret_cast*>(lua_touserdata(L, -1)); - - //balance the stack - lua_pop(L, 1); - - pager->SetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4)); - } - return 0; -} - -static int getTile(lua_State* L) { - if (lua_gettop(L) == 4) { - //operating on a region - Region* ptr = (Region*)lua_touserdata(L, 1); - int ret = ptr->GetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1); - lua_pushnumber(L, ret); - } - else { - //operating on the whole map - lua_pushstring(L, "pager"); - lua_gettable(L, LUA_REGISTRYINDEX); - - //assume the pager is using lua - RegionPager* pager = reinterpret_cast*>(lua_touserdata(L, -1)); - - //balance the stack - lua_pop(L, 1); - - int ret = pager->GetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3)); - lua_pushnumber(L, ret); - } - return 1; -} - -static int getX(lua_State* L) { - Region* ptr = (Region*)lua_touserdata(L, 1); - lua_pushinteger(L, ptr->GetX()); - return 1; -} - -static int getY(lua_State* L) { - Region* ptr = (Region*)lua_touserdata(L, 1); - lua_pushinteger(L, ptr->GetY()); - return 1; -} - -static int getRegionWidth(lua_State* L) { - lua_pushinteger(L, REGION_WIDTH); - return 1; -} - -static int getRegionHeight(lua_State* L) { - lua_pushinteger(L, REGION_HEIGHT); - return 1; -} - -static int getRegionDepth(lua_State* L) { - lua_pushinteger(L, REGION_DEPTH); - return 1; -} - -static int dummy(lua_State* L) { - return 0; -} - -static const luaL_Reg regionlib[] = { - {"create", dummy}, - {"unload", dummy}, - {"load", dummy}, - {"save", dummy}, - {"settile",setTile}, - {"gettile",getTile}, - {"getx",getX}, - {"gety",getY}, - {"getregionwidth",getRegionWidth}, - {"getregionheight",getRegionHeight}, - {"getregiondepth",getRegionDepth}, - {nullptr, nullptr} -}; - -LUAMOD_API int luaopen_mapapi(lua_State* L) { - luaL_newlib(L, regionlib); - return 1; -} \ No newline at end of file diff --git a/makefile b/makefile index 27fd80e..080a22d 100644 --- a/makefile +++ b/makefile @@ -4,7 +4,6 @@ #RM=del /y CXXFLAGS+=-static-libgcc -static-libstdc++ -CFLAGS+=-static-libgcc export diff --git a/rsc/scripts/setup_server.lua b/rsc/scripts/setup_server.lua index 8629320..bae4a74 100644 --- a/rsc/scripts/setup_server.lua +++ b/rsc/scripts/setup_server.lua @@ -4,33 +4,17 @@ print("Lua script check (./rsc)") --Map API overrides ------------------------- -function map.create(region) - for i = 1, map.getregionwidth() do - for j = 1, map.getregionheight() do - if math.abs(map.getx(region) + i -1) == math.abs(map.gety(region) + j -1) then - map.settile(region, i, j, 1, 50) +function region.create(r) + for i = 1, region.getwidth() do + for j = 1, region.getheight() do + if math.abs(region.getx(r) + i -1) == math.abs(region.gety(r) + j -1) then + region.settile(r, i, j, 1, 50) else - map.settile(region, i, j, 1, 14) + region.settile(r, i, j, 1, 14) end end end + + --signal + region.settile(r, 4, 5, 2, 86) end - -function map.unload(region) - -- -end - -function map.load(region, dir) - --return true if file loaded, otherwise return false - return false -end - -function map.save(region, dir) - -- -end - -------------------------- ---Enemy API -------------------------- - ---TODO \ No newline at end of file diff --git a/rsc/scripts/setup_server.sql b/rsc/scripts/setup_server.sql index 04a6aab..88d0a82 100644 --- a/rsc/scripts/setup_server.sql +++ b/rsc/scripts/setup_server.sql @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS Characters ( birth timestamp NOT NULL DEFAULT (datetime()), --position - mapIndex INTEGER DEFAULT 0, + roomIndex INTEGER DEFAULT 0, originX INTEGER DEFAULT 0, originY INTEGER DEFAULT 0, diff --git a/common/gameplay/account_data.hpp b/server/account_data.hpp similarity index 100% rename from common/gameplay/account_data.hpp rename to server/account_data.hpp diff --git a/server/account_management.cpp b/server/account_manager.cpp similarity index 85% rename from server/account_management.cpp rename to server/account_manager.cpp index eb298d8..c29bd29 100644 --- a/server/account_management.cpp +++ b/server/account_manager.cpp @@ -19,9 +19,7 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "server_application.hpp" - -#include "sqlite3/sqlite3.h" +#include "account_manager.hpp" #include @@ -35,10 +33,10 @@ static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;"; //------------------------- -//Define the methods +//Define the public methods //------------------------- -int ServerApplication::CreateUserAccount(std::string username, int clientIndex) { +int AccountManager::CreateAccount(std::string username, int clientIndex) { //create this user account, failing if it exists, leave this account in memory sqlite3_stmt* statement = nullptr; @@ -62,10 +60,10 @@ int ServerApplication::CreateUserAccount(std::string username, int clientIndex) sqlite3_finalize(statement); //load this account into memory - return LoadUserAccount(username, clientIndex); + return LoadAccount(username, clientIndex); } -int ServerApplication::LoadUserAccount(std::string username, int clientIndex) { +int AccountManager::LoadAccount(std::string username, int clientIndex) { //load this user account, failing if it is in memory, creating it if it doesn't exist sqlite3_stmt* statement = nullptr; @@ -111,13 +109,13 @@ int ServerApplication::LoadUserAccount(std::string username, int clientIndex) { if (ret == SQLITE_DONE) { //create the non-existant account instead - return CreateUserAccount(username, clientIndex); + return CreateAccount(username, clientIndex); } - throw(std::runtime_error(std::string() + "Unknown SQL error in LoadUserAccount: " + sqlite3_errmsg(database) )); + throw(std::runtime_error(std::string() + "Unknown SQL error in LoadAccount: " + sqlite3_errmsg(database) )); } -int ServerApplication::SaveUserAccount(int uid) { +int AccountManager::SaveAccount(int uid) { //save this user account from memory, replacing it if it exists in the database //DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID. @@ -160,14 +158,14 @@ int ServerApplication::SaveUserAccount(int uid) { return 0; } -void ServerApplication::UnloadUserAccount(int uid) { +void AccountManager::UnloadAccount(int uid) { //save this user account, and then unload it //NOTE: the associated characters are unloaded externally - SaveUserAccount(uid); + SaveAccount(uid); accountMap.erase(uid); } -void ServerApplication::DeleteUserAccount(int uid) { +void AccountManager::DeleteAccount(int uid) { //delete a user account from the database, and remove it from memory //NOTE: the associated characters should be deleted externally sqlite3_stmt* statement = nullptr; @@ -193,3 +191,36 @@ void ServerApplication::DeleteUserAccount(int uid) { sqlite3_finalize(statement); accountMap.erase(uid); } + +void AccountManager::UnloadAll() { + for (auto& it : accountMap) { + SaveAccount(it.first); + } + accountMap.clear(); +} + +//------------------------- +//Define the accessors and mutators +//------------------------- + +AccountData* AccountManager::GetAccount(int uid) { + std::map::iterator it = accountMap.find(uid); + + if (it == accountMap.end()) { + return nullptr; + } + + return &it->second; +} + +std::map* AccountManager::GetContainer() { + return &accountMap; +} + +sqlite3* AccountManager::SetDatabase(sqlite3* db) { + return database = db; +} + +sqlite3* AccountManager::GetDatabase() { + return database; +} diff --git a/server/account_manager.hpp b/server/account_manager.hpp new file mode 100644 index 0000000..7c6cc1f --- /dev/null +++ b/server/account_manager.hpp @@ -0,0 +1,57 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef ACCOUNTMANAGER_HPP_ +#define ACCOUNTMANAGER_HPP_ + +#include "account_data.hpp" + +#include "sqlite3/sqlite3.h" + +#include + +class AccountManager { +public: + AccountManager() = default; + ~AccountManager() { UnloadAll(); }; + + //public access methods + int CreateAccount(std::string username, int clientIndex); + int LoadAccount(std::string username, int clientIndex); + int SaveAccount(int uid); + void UnloadAccount(int uid); + void DeleteAccount(int uid); + + void UnloadAll(); + + //accessors and mutators + AccountData* GetAccount(int uid); + std::map* GetContainer(); + + sqlite3* SetDatabase(sqlite3* db); + sqlite3* GetDatabase(); + +private: + std::map accountMap; + sqlite3* database = nullptr; +}; + +#endif diff --git a/server/character_management.cpp b/server/character_manager.cpp similarity index 85% rename from server/character_management.cpp rename to server/character_manager.cpp index 3991305..21eb99a 100644 --- a/server/character_management.cpp +++ b/server/character_manager.cpp @@ -19,7 +19,7 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#include "server_application.hpp" +#include "character_manager.hpp" #include "sqlite3/sqlite3.h" @@ -33,7 +33,7 @@ static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, av static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;"; static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET " - "mapIndex = ?2," + "roomIndex = ?2," "originX = ?3," "originY = ?4," "level = ?5," @@ -58,9 +58,8 @@ static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;"; //Define the methods //------------------------- -//TODO: should statistics be stored separately? //TODO: default stats as a parameter? This would be good for differing beggining states or multiple classes -int ServerApplication::CreateCharacter(int owner, std::string handle, std::string avatar) { +int CharacterManager::CreateCharacter(int owner, std::string handle, std::string avatar) { //Create the character, failing if it exists sqlite3_stmt* statement = nullptr; @@ -93,7 +92,7 @@ int ServerApplication::CreateCharacter(int owner, std::string handle, std::strin return LoadCharacter(owner, handle, avatar); } -int ServerApplication::LoadCharacter(int owner, std::string handle, std::string avatar) { +int CharacterManager::LoadCharacter(int owner, std::string handle, std::string avatar) { //load the specified character, creating it if it doesn't exist //fail if it is already loaded, or does not belong to this account sqlite3_stmt* statement = nullptr; @@ -138,7 +137,7 @@ int ServerApplication::LoadCharacter(int owner, std::string handle, std::string //Don't cache the birth //world origin - newChar.mapIndex = sqlite3_column_int(statement, 5); + newChar.roomIndex = sqlite3_column_int(statement, 5); newChar.origin.x = (double)sqlite3_column_int(statement, 6); newChar.origin.y = (double)sqlite3_column_int(statement, 7); @@ -178,7 +177,7 @@ int ServerApplication::LoadCharacter(int owner, std::string handle, std::string throw(std::runtime_error(std::string() + "Unknown SQL error in LoadCharacter: " + sqlite3_errmsg(database) )); } -int ServerApplication::SaveCharacter(int uid) { +int CharacterManager::SaveCharacter(int uid) { //save this character from memory, replacing it if it exists in the database //DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID. @@ -198,7 +197,7 @@ int ServerApplication::SaveCharacter(int uid) { //parameters bool ret = false; ret |= sqlite3_bind_int(statement, 1, uid) != SQLITE_OK; - ret |= sqlite3_bind_int(statement, 2, character.mapIndex) != SQLITE_OK; + ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK; @@ -241,13 +240,13 @@ int ServerApplication::SaveCharacter(int uid) { return 0; } -void ServerApplication::UnloadCharacter(int uid) { +void CharacterManager::UnloadCharacter(int uid) { //save this character, then unload it SaveCharacter(uid); characterMap.erase(uid); } -void ServerApplication::DeleteCharacter(int uid) { +void CharacterManager::DeleteCharacter(int uid) { //delete this character from the database, then remove it from memory sqlite3_stmt* statement = nullptr; @@ -272,3 +271,48 @@ void ServerApplication::DeleteCharacter(int uid) { sqlite3_finalize(statement); characterMap.erase(uid); } + +void CharacterManager::UnloadCharacterIf(std::function::iterator)> f) { + //save this character, then unload it if the parameter returns true + for (std::map::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) { + if (f(it)) { + SaveCharacter(it->first); + it = characterMap.erase(it); + continue; + } + it++; + } +} + +void CharacterManager::UnloadAll() { + for (auto& it : characterMap) { + SaveCharacter(it.first); + } + characterMap.clear(); +} + +//------------------------- +//Define the accessors and mutators +//------------------------- + +CharacterData* CharacterManager::GetCharacter(int uid) { + std::map::iterator it = characterMap.find(uid); + + if (it == characterMap.end()) { + return nullptr; + } + + return &it->second; +} + +std::map* CharacterManager::GetContainer() { + return &characterMap; +} + +sqlite3* CharacterManager::SetDatabase(sqlite3* db) { + return database = db; +} + +sqlite3* CharacterManager::GetDatabase() { + return database; +} \ No newline at end of file diff --git a/server/character_manager.hpp b/server/character_manager.hpp new file mode 100644 index 0000000..191fd4c --- /dev/null +++ b/server/character_manager.hpp @@ -0,0 +1,60 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef CHARACTERMANAGER_HPP_ +#define CHARACTERMANAGER_HPP_ + +#include "character_data.hpp" + +#include "sqlite3/sqlite3.h" + +#include +#include + +class CharacterManager { +public: + CharacterManager() = default; + ~CharacterManager() { UnloadAll(); }; + + //public access methods + int CreateCharacter(int owner, std::string handle, std::string avatar); + int LoadCharacter(int owner, std::string handle, std::string avatar); + int SaveCharacter(int uid); + void UnloadCharacter(int uid); + void DeleteCharacter(int uid); + + void UnloadCharacterIf(std::function::iterator)> f); + + void UnloadAll(); + + //accessors and mutators + CharacterData* GetCharacter(int uid); + std::map* GetContainer(); + + sqlite3* SetDatabase(sqlite3* db); + sqlite3* GetDatabase(); + +private: + std::map characterMap; + sqlite3* database = nullptr; +}; + +#endif diff --git a/common/gameplay/client_data.hpp b/server/client_data.hpp similarity index 100% rename from common/gameplay/client_data.hpp rename to server/client_data.hpp diff --git a/server/combat_manager.cpp b/server/combat_manager.cpp new file mode 100644 index 0000000..be4f9ac --- /dev/null +++ b/server/combat_manager.cpp @@ -0,0 +1,54 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "combat_manager.hpp" + +//------------------------- +//public access methods +//------------------------- + +//TODO + +//------------------------- +//accessors and mutators +//------------------------- + +CombatData* CombatManager::GetCombat(int uid) { + std::map::iterator it = combatMap.find(uid); + + if (it == combatMap.end()) { + return nullptr; + } + + return &it->second; +} + +std::map* CombatManager::GetContainer() { + return &combatMap; +} + +lua_State* CombatManager::SetLuaState(lua_State* L) { + return luaState = L; +} + +lua_State* CombatManager::GetLuaState() { + return luaState; +} diff --git a/server/combat_manager.hpp b/server/combat_manager.hpp new file mode 100644 index 0000000..77573ab --- /dev/null +++ b/server/combat_manager.hpp @@ -0,0 +1,51 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef COMBATMANAGER_HPP_ +#define COMBATMANAGER_HPP_ + +#include "combat_data.hpp" + +#include "lua/lua.hpp" + +#include + +class CombatManager { +public: + CombatManager() = default; + ~CombatManager() = default; + + //public access methods + //TODO + + //accessors and mutators + CombatData* GetCombat(int uid); + std::map* GetContainer(); + + lua_State* SetLuaState(lua_State*); + lua_State* GetLuaState(); + +private: + std::map combatMap; + lua_State* luaState = nullptr; +}; + +#endif \ No newline at end of file diff --git a/server/enemy_manager.cpp b/server/enemy_manager.cpp new file mode 100644 index 0000000..2b49d3d --- /dev/null +++ b/server/enemy_manager.cpp @@ -0,0 +1,54 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "enemy_manager.hpp" + +//------------------------- +//public access methods +//------------------------- + +//TODO + +//------------------------- +//accessors and mutators +//------------------------- + +EnemyData* EnemyManager::GetEnemy(int uid) { + std::map::iterator it = enemyMap.find(uid); + + if (it == enemyMap.end()) { + return nullptr; + } + + return &it->second; +} + +std::map* EnemyManager::GetContainer() { + return &enemyMap; +} + +lua_State* EnemyManager::SetLuaState(lua_State* L) { + return luaState = L; +} + +lua_State* EnemyManager::GetLuaState() { + return luaState; +} diff --git a/common/map/map_allocator.hpp b/server/enemy_manager.hpp similarity index 68% rename from common/map/map_allocator.hpp rename to server/enemy_manager.hpp index 1efeaf8..dae86ad 100644 --- a/common/map/map_allocator.hpp +++ b/server/enemy_manager.hpp @@ -19,30 +19,33 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef MAPALLOCATOR_HPP_ -#define MAPALLOCATOR_HPP_ +#ifndef ENEMYMANAGER_HPP_ +#define ENEMYMANAGER_HPP_ -#include "region.hpp" +#include "enemy_data.hpp" #include "lua/lua.hpp" -class BlankAllocator { +#include + +class EnemyManager { public: - void Create(Region** const, int x, int y); - void Unload(Region* const); + EnemyManager() = default; + ~EnemyManager() = default; + + //public access methods + //TODO + + //accessors and mutators + EnemyData* GetEnemy(int uid); + std::map* GetContainer(); + + lua_State* SetLuaState(lua_State*); + lua_State* GetLuaState(); + private: - // + std::map enemyMap; + lua_State* luaState = nullptr; }; -class LuaAllocator { -public: - void Create(Region** const, int x, int y); - void Unload(Region* const); - - lua_State* SetLuaState(lua_State* L) { return state = L; } - lua_State* GetLuaState() { return state; } -private: - lua_State* state = nullptr; -}; - -#endif +#endif \ No newline at end of file diff --git a/server/linit.cpp b/server/linit.cpp new file mode 100644 index 0000000..13541f2 --- /dev/null +++ b/server/linit.cpp @@ -0,0 +1,83 @@ +/* $Id: linit.c,v 1.32, modified + * Initialization of libraries for lua.c and other clients + * See Copyright Notice in lua.h + * + * If you embed Lua in your program and need to open the standard + * libraries, call luaL_openlibs in your program. If you need a + * different set of libraries, copy this file to your project and edit + * it to suit your needs. + * + * Modified for use in Tortuga, renamed to linit.cpp + * Modifications are released under the zlib license: + * + * Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#define linit_c +#define LUA_LIB + +#include "lua/lua.hpp" + +#include "region_api.hpp" +#include "pager_api.hpp" + +//these libs are loaded by lua.c and are readily available to any Lua program +static const luaL_Reg loadedlibs[] = { + //Standard libs + {"_G", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_COLIBNAME, luaopen_coroutine}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_BITLIBNAME, luaopen_bit32}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + + //custom libs + {LUA_REGIONLIBNAME, luaopen_regionapi}, + {LUA_PAGERLIBNAME, luaopen_pagerapi}, + + {NULL, NULL} +}; + + +//these libs are preloaded and must be required before used +static const luaL_Reg preloadedlibs[] = { + {NULL, NULL} +}; + +LUALIB_API void luaL_openlibs (lua_State *L) { + const luaL_Reg *lib; + //call open functions from 'loadedlibs' and set results to global table + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); //remove lib + } + //add open functions from 'preloadedlibs' into 'package.preload' table + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); + for (lib = preloadedlibs; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_setfield(L, -2, lib->name); + } + lua_pop(L, 1); //remove _PRELOAD table +} \ No newline at end of file diff --git a/server/makefile b/server/makefile index 901f8a6..1d8df31 100644 --- a/server/makefile +++ b/server/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. ../common/gameplay ../common/map ../common/network ../common/script ../common/utilities +INCLUDES+=. ../common/gameplay ../common/map ../common/network ../common/network/packet ../common/network/serial ../common/utilities LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3 CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) diff --git a/server/room_api.cpp b/server/room_api.cpp new file mode 100644 index 0000000..ea7ea52 --- /dev/null +++ b/server/room_api.cpp @@ -0,0 +1,63 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "room_api.hpp" + +#include "room_manager.hpp" +#include "room_data.hpp" + +static int getType(lua_State* L) { + RoomData* room = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushinteger(L, static_cast(room->type)); + return 1; +} + +//TODO: parameters + +static int getRegionPager(lua_State* L) { + RoomData* room = reinterpret_cast(lua_touserdata(L, 1)); + lua_pushlightuserdata(L, reinterpret_cast(&room->pager)); + return 1; +} + +//RoomManager only +static int getRoom(lua_State* L) { + //get the room manager + lua_pushstring(L, ROOM_MANAGER_PSEUDOINDEX); + lua_gettable(L, LUA_REGISTRYINDEX); + RoomManager* roomMgr = reinterpret_cast(lua_touserdata(L, -1)); + + //push the room and return it + lua_pushlightuserdata(L, reinterpret_cast( roomMgr->GetRoom(lua_tointeger(L, -2)) )); + return 1; +} + +static const luaL_Reg roomlib[] = { + {"gettype",getType}, + {"getregionpager",getRegionPager}, + {"getroom",getRoom}, + {nullptr, nullptr} +}; + +LUAMOD_API int luaopen_roomapi(lua_State* L) { + luaL_newlib(L, roomlib); + return 1; +} \ No newline at end of file diff --git a/common/script/map_api.hpp b/server/room_api.hpp similarity index 88% rename from common/script/map_api.hpp rename to server/room_api.hpp index efa2abd..a9c31a8 100644 --- a/common/script/map_api.hpp +++ b/server/room_api.hpp @@ -19,12 +19,12 @@ * 3. This notice may not be removed or altered from any source * distribution. */ -#ifndef MAPAPI_HPP_ -#define MAPAPI_HPP_ +#ifndef ROOMAPI_HPP_ +#define ROOMAPI_HPP_ #include "lua/lua.hpp" -#define LUA_MAPLIBNAME "map" -LUAMOD_API int luaopen_mapapi(lua_State* L); +#define LUA_ROOMLIBNAME "room" +LUAMOD_API int luaopen_roomapi(lua_State* L); #endif diff --git a/common/gameplay/room_data.hpp b/server/room_data.hpp similarity index 82% rename from common/gameplay/room_data.hpp rename to server/room_data.hpp index ae49465..cf1b6cb 100644 --- a/common/gameplay/room_data.hpp +++ b/server/room_data.hpp @@ -22,14 +22,24 @@ #ifndef ROOMDATA_HPP_ #define ROOMDATA_HPP_ +//map system +#include "region_pager_lua.hpp" + struct RoomData { enum class RoomType { - OVERWORLD, - RUINS, - TOWERS, - FORESTS, - CAVES, + OVERWORLD = 0, + RUINS = 1, + TOWERS = 2, + FORESTS = 3, + CAVE = 4, }; + + //members + RegionPagerLua pager; + RoomType type; + + //TODO: collision map + //TODO: NPCs? }; #endif diff --git a/server/room_manager.cpp b/server/room_manager.cpp new file mode 100644 index 0000000..8f60ba4 --- /dev/null +++ b/server/room_manager.cpp @@ -0,0 +1,72 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "room_manager.hpp" + +#include + +//------------------------- +//public access methods +//------------------------- + +RoomData* RoomManager::CreateRoom(int uid) { + //don't overwrite existing rooms + std::map::iterator it = roomMap.find(uid); + if (it != roomMap.end()) { + throw(std::runtime_error("Cannot overwrite an existing room")); + } + roomMap[uid] = new RoomData(); + //TODO: create room in the API + if (luaState) { + roomMap[uid]->pager.SetLuaState(luaState); + } + return roomMap[uid]; +} + +RoomData* RoomManager::UnloadRoom(int uid) { + //TODO: unload room in the API + delete roomMap[uid]; + roomMap.erase(uid); +} + +RoomData* RoomManager::GetRoom(int uid) { + RoomData* ptr = FindRoom(uid); + if (ptr) return ptr; + ptr = CreateRoom(uid); + return ptr; +} + +RoomData* RoomManager::FindRoom(int uid) { + std::map::iterator it = roomMap.find(uid); + if (it == roomMap.end()) { + return nullptr; + } + return it->second; +} + +RoomData* RoomManager::PushRoom(int uid, RoomData* room) { + //unload existing rooms with this index + std::map::iterator it = roomMap.find(uid); + if (it != roomMap.end()) { + UnloadRoom(uid); + } + roomMap[uid] = room; +} diff --git a/server/room_manager.hpp b/server/room_manager.hpp new file mode 100644 index 0000000..80480f7 --- /dev/null +++ b/server/room_manager.hpp @@ -0,0 +1,57 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef ROOMMANAGER_HPP_ +#define ROOMMANAGER_HPP_ + +#include "room_data.hpp" + +#include "lua/lua.hpp" + +#include + +#define ROOM_MANAGER_PSEUDOINDEX "RoomManager" + +class RoomManager { +public: + RoomManager() = default; + ~RoomManager() = default; + + //public access methods + RoomData* CreateRoom(int uid); + RoomData* UnloadRoom(int uid); + + RoomData* GetRoom(int uid); + RoomData* FindRoom(int uid); + RoomData* PushRoom(int uid, RoomData*); + + //accessors and mutators + std::map* GetContainer() { return &roomMap; } + + lua_State* SetLuaState(lua_State* L) { return luaState = L; } + lua_State* GetLuaState() { return luaState; } + +private: + std::map roomMap; + lua_State* luaState = nullptr; +}; + +#endif \ No newline at end of file diff --git a/server/server_application.cpp b/server/server_application.cpp new file mode 100644 index 0000000..4bc1644 --- /dev/null +++ b/server/server_application.cpp @@ -0,0 +1,489 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "server_application.hpp" + +#include "sql_utility.hpp" +#include "serial.hpp" +#include "utility.hpp" + +#include +#include +#include + +//------------------------- +//public methods +//------------------------- + +void ServerApplication::Init(int argc, char** argv) { + //NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed. + std::cout << "Beginning startup" << std::endl; + + //initial setup + config.Load("rsc\\config.cfg"); + + //------------------------- + //Initialize the APIs + //------------------------- + + //Init SDL + if (SDL_Init(0)) { + throw(std::runtime_error("Failed to initialize SDL")); + } + std::cout << "Initialized SDL" << std::endl; + + //Init SDL_net + if (SDLNet_Init()) { + throw(std::runtime_error("Failed to initialize SDL_net")); + } + network.Open(config.Int("server.port")); + std::cout << "Initialized SDL_net" << std::endl; + + //Init SQL + int ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr); + if (ret != SQLITE_OK || !database) { + throw(std::runtime_error(std::string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) )); + } + std::cout << "Initialized SQL" << std::endl; + + //Init lua + luaState = luaL_newstate(); + if (!luaState) { + throw(std::runtime_error("Failed to initialize lua")); + } + luaL_openlibs(luaState); + std::cout << "Initialized lua" << std::endl; + + //------------------------- + //Setup the objects + //------------------------- + + //set the hooks + accountMgr.SetDatabase(database); + characterMgr.SetDatabase(database); + + combatMgr.SetLuaState(luaState); + roomMgr.SetLuaState(luaState); + enemyMgr.SetLuaState(luaState); + + std::cout << "Internal managers set" << std::endl; + + //register the "globals" + lua_pushstring(luaState, ROOM_MANAGER_PSEUDOINDEX); + lua_pushlightuserdata(luaState, &roomMgr); + lua_settable(luaState, LUA_REGISTRYINDEX); + + std::cout << "Internal managers registered with lua" << std::endl; + + //------------------------- + //Run the startup scripts + //------------------------- + + //setup the database + if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) { + throw(std::runtime_error("Failed to initialize SQL's setup script")); + } + std::cout << "Completed SQL's setup script" << std::endl; + + //run lua's startup script + if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) { + throw(std::runtime_error(std::string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) )); + } + std::cout << "Completed lua's setup script" << std::endl; + + //------------------------- + //debug output + //------------------------- + + std::cout << "Internal sizes:" << std::endl; + std::cout << "\tTile Size: " << sizeof(Region::type_t) << std::endl; + std::cout << "\tRegion Format: " << REGION_WIDTH << ", " << REGION_HEIGHT << ", " << REGION_DEPTH << std::endl; + std::cout << "\tRegion Content Footprint: " << REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) << std::endl; + std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl; + std::cout << "\tMAX_PACKET_SIZE: " << MAX_PACKET_SIZE << std::endl; + + //------------------------- + //finalize the startup + //------------------------- + + std::cout << "Startup completed successfully" << std::endl; + + //------------------------- + //debugging + //------------------------- + + //... +} + +void ServerApplication::Proc() { + SerialPacket* packetBuffer = static_cast(malloc(MAX_PACKET_SIZE)); + while(running) { + //suck in the waiting packets & process them + while(network.Receive(packetBuffer)) { + HandlePacket(packetBuffer); + } + //update the internals + //TODO: update the internals i.e. player positions + //give the computer a break + SDL_Delay(10); + } + free(static_cast(packetBuffer)); +} + +void ServerApplication::Quit() { + std::cout << "Shutting down" << std::endl; + + //close the managers + clientMap.clear(); + accountMgr.UnloadAll(); + characterMgr.UnloadAll(); + //TODO: unload combats + //TODO: unload enemies + //TODO: unload rooms + + //APIs + lua_close(luaState); + sqlite3_close_v2(database); + network.Close(); + SDLNet_Quit(); + SDL_Quit(); + + std::cout << "Shutdown finished" << std::endl; +} + +//------------------------- +//handle incoming traffic +//------------------------- + +void ServerApplication::HandlePacket(SerialPacket* const argPacket) { + switch(argPacket->type) { + //basic connections + case SerialPacketType::BROADCAST_REQUEST: + HandleBroadcastRequest(static_cast(argPacket)); + break; + case SerialPacketType::JOIN_REQUEST: + HandleJoinRequest(static_cast(argPacket)); + break; + case SerialPacketType::DISCONNECT: + HandleDisconnect(static_cast(argPacket)); + break; + case SerialPacketType::SHUTDOWN: + HandleShutdown(static_cast(argPacket)); + break; + + //map management + case SerialPacketType::REGION_REQUEST: + HandleRegionRequest(static_cast(argPacket)); + break; + + //combat management + //TODO: combat management + + //character management + case SerialPacketType::CHARACTER_NEW: + HandleCharacterNew(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_DELETE: + HandleCharacterDelete(static_cast(argPacket)); + break; + case SerialPacketType::CHARACTER_UPDATE: + case SerialPacketType::CHARACTER_STATS_REQUEST: + HandleCharacterUpdate(static_cast(argPacket)); + break; + + //enemy management + //TODO: enemy management + + //mismanagement + case SerialPacketType::SYNCHRONIZE: + HandleSynchronize(static_cast(argPacket)); + break; + + //handle errors + default: + throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in the server: " + to_string_custom(static_cast(argPacket->type)) )); + break; + } +} + +//------------------------- +//basic connections +//------------------------- + +void ServerApplication::HandleBroadcastRequest(SerialPacket* const argPacket) { + //send the server's data + ServerPacket newPacket; + + newPacket.type = SerialPacketType::BROADCAST_RESPONSE; + strncpy(newPacket.name, config["server.name"].c_str(), PACKET_STRING_SIZE); + newPacket.playerCount = characterMgr.GetContainer()->size(); + newPacket.version = NETWORK_VERSION; + + network.SendTo(&argPacket->srcAddress, static_cast(&newPacket)); +} + +void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) { + //create the new client + ClientData newClient; + newClient.address = argPacket->srcAddress; + + //load the user account + //TODO: handle passwords + int accountIndex = accountMgr.LoadAccount(argPacket->username, clientUID); + if (accountIndex < 0) { + //TODO: send rejection packet + std::cerr << "Error: Account already loaded: " << accountIndex << std::endl; + return; + } + + //send the client their info + ClientPacket newPacket; + newPacket.type = SerialPacketType::JOIN_RESPONSE; + newPacket.clientIndex = clientUID; + newPacket.accountIndex = accountIndex; + + network.SendTo(&newClient.address, static_cast(&newPacket)); + + //finished this routine + clientMap[clientUID++] = newClient; + std::cout << "New connection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl; +} + +void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) { + //TODO: authenticate who is disconnecting/kicking + + //forward to the specified client + network.SendTo( + &clientMap[ accountMgr.GetAccount(argPacket->accountIndex)->clientIndex ].address, + static_cast(argPacket) + ); + + //save and unload this account's characters + //pump the unload message to all remaining clients + characterMgr.UnloadCharacterIf([&](std::map::iterator it) -> bool { + if (argPacket->accountIndex == it->second.owner) { + PumpCharacterUnload(it->first); + return true; + } + return false; + }); + + //erase the in-memory stuff + clientMap.erase(accountMgr.GetAccount(argPacket->accountIndex)->clientIndex); + accountMgr.UnloadAccount(argPacket->accountIndex); + + //finished this routine + std::cout << "Disconnection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl; +} + +void ServerApplication::HandleShutdown(SerialPacket* const argPacket) { + //TODO: authenticate who is shutting the server down + + //end the server + running = false; + + //disconnect all clients + SerialPacket newPacket; + newPacket.type = SerialPacketType::DISCONNECT; + PumpPacket(&newPacket); + + //finished this routine + std::cout << "Shutdown signal accepted" << std::endl; +} + +//------------------------- +//map management +//------------------------- + +void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) { + RegionPacket newPacket; + + newPacket.type = SerialPacketType::REGION_CONTENT; + newPacket.roomIndex = argPacket->roomIndex; + newPacket.x = argPacket->x; + newPacket.y = argPacket->y; + + newPacket.region = roomMgr.GetRoom(argPacket->roomIndex)->pager.GetRegion(argPacket->x, argPacket->y); + + //send the content + network.SendTo(&argPacket->srcAddress, static_cast(&newPacket)); +} + +//------------------------- +//combat management +//------------------------- + +//TODO: combat management + +//------------------------- +//Character Management +//------------------------- + +void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) { + //NOTE: misnomer, try to load the character first + int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar); + + if (characterIndex == -1) { + //TODO: rejection packet + std::cerr << "Warning: Character already loaded" << std::endl; + return; + } + + if (characterIndex == -2) { + //TODO: rejection packet + std::cerr << "Warning: Character already exists" << std::endl; + return; + } + + //send this new character to all clients + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_NEW; + CopyCharacterToPacket(&newPacket, characterIndex); + PumpPacket(&newPacket); +} + +void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) { + //NOTE: Disconnecting only unloads a character, this explicitly deletes it + + //Authenticate the owner is doing this + int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar); + + //if this is not your character + if (characterIndex == -2) { + //TODO: rejection packet + std::cerr << "Warning: Character cannot be deleted" << std::endl; + + //unload an unneeded character + if (characterIndex != -1) { + characterMgr.UnloadCharacter(characterIndex); + } + return; + } + + //delete it + characterMgr.DeleteCharacter(characterIndex); + + //TODO: success packet + + //Unload this character from all clients + PumpCharacterUnload(characterIndex); +} + +void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) { + CharacterData* character = characterMgr.GetCharacter(argPacket->characterIndex); + + //make a new character if this one doesn't exist + if (!character) { + //this isn't normal + std::cerr << "Warning: HandleCharacterUpdate() is passing to HandleCharacterNew()" << std::endl; + HandleCharacterNew(argPacket); + return; + } + + /* TODO: rewrite this design flaw, read more + * Slaving the client to the server here is a terrible idea, instead there + * needs to be a utility function to update and send the server-side character + * to the clients. + * + * Other things to consider include functionality to reequip the character, + * apply status effects and to change the stats as well. These should all be + * handled server-side. + */ + character->roomIndex = argPacket->roomIndex; + character->origin = argPacket->origin; + character->motion = argPacket->motion; + + character->stats = argPacket->stats; + + //TODO: equipment + //TODO: items + //TODO: buffs + //TODO: debuffs + + PumpPacket(argPacket); +} + +//------------------------- +//enemy management +//------------------------- + +//TODO: enemy management + +//------------------------- +//mismanagement +//------------------------- + +void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) { + //TODO: compensate for large distances + //NOTE: I quite dislike this function + + //send all of the server's data to this client + ClientData& client = clientMap[argPacket->clientIndex]; + + //send all characters + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_UPDATE; + + for (auto& it : *characterMgr.GetContainer()) { + newPacket.characterIndex = it.first; + CopyCharacterToPacket(&newPacket, it.first); + network.SendTo(&client.address, static_cast(&newPacket)); + } + + //TODO: more in HandleSynchronize() +} + +//------------------------- +//utility methods +//------------------------- + +//TODO: a function that only sends to characters in a certain proximity + +void ServerApplication::PumpPacket(SerialPacket* const argPacket) { + for (auto& it : clientMap) { + network.SendTo(&it.second.address, argPacket); + } +} + +void ServerApplication::PumpCharacterUnload(int uid) { + //delete the client-side character(s) + CharacterPacket newPacket; + newPacket.type = SerialPacketType::CHARACTER_DELETE; + newPacket.characterIndex = uid; + PumpPacket(static_cast(&newPacket)); +} + +void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) { + CharacterData* character = characterMgr.GetCharacter(characterIndex); + if (!character) { + throw(std::runtime_error("Failed to copy a character to a packet")); + } + + //TODO: keep this up to date when the character changes + packet->characterIndex = characterIndex; + strncpy(packet->handle, character->handle.c_str(), PACKET_STRING_SIZE); + strncpy(packet->avatar, character->avatar.c_str(), PACKET_STRING_SIZE); + packet->accountIndex = character->owner; + packet->roomIndex = character->roomIndex; + packet->origin = character->origin; + packet->motion = character->motion; + packet->stats = character->stats; +} \ No newline at end of file diff --git a/server/server_application.hpp b/server/server_application.hpp index cbc7511..ca2129b 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -23,23 +23,16 @@ #define SERVERAPPLICATION_HPP_ //server specific stuff +#include "account_manager.hpp" +#include "character_manager.hpp" #include "client_data.hpp" -#include "account_data.hpp" -#include "character_data.hpp" -#include "combat_data.hpp" -#include "enemy_factory_generic.hpp" +#include "combat_manager.hpp" +#include "enemy_manager.hpp" +#include "room_manager.hpp" -//maps -#include "map_allocator.hpp" -#include "map_file_format.hpp" -#include "region_pager.hpp" - -//networking +//common utilities #include "udp_network_utility.hpp" - -//common #include "config_utility.hpp" -#include "vector2.hpp" //APIs #include "lua/lua.hpp" @@ -51,10 +44,9 @@ #include //The main application class -//TODO: modulate this god class class ServerApplication { public: - //standard functions + //public methods ServerApplication() = default; ~ServerApplication() = default; @@ -63,61 +55,57 @@ public: void Quit(); private: - void HandlePacket(SerialPacket); - //handle incoming traffic - void HandleBroadcastRequest(SerialPacket); - void HandleJoinRequest(SerialPacket); - void HandleSynchronize(SerialPacket); - void HandleDisconnect(SerialPacket); - void HandleShutdown(SerialPacket); - void HandleCharacterUpdate(SerialPacket); - void HandleRegionRequest(SerialPacket); + void HandlePacket(SerialPacket* const); - //TODO: a function that only sends to characters in a certain proximity - void PumpPacket(SerialPacket); - void PumpCharacterUnload(int uid); + //basic connections + void HandleBroadcastRequest(SerialPacket* const); + void HandleJoinRequest(ClientPacket* const); + void HandleDisconnect(ClientPacket* const); + void HandleShutdown(SerialPacket* const); - //Account management - int CreateUserAccount(std::string username, int clientIndex); - int LoadUserAccount(std::string username, int clientIndex); - int SaveUserAccount(int uid); - void UnloadUserAccount(int uid); - void DeleteUserAccount(int uid); - - //character management - int CreateCharacter(int owner, std::string handle, std::string avatar); - int LoadCharacter(int owner, std::string handle, std::string avatar); - int SaveCharacter(int uid); - void UnloadCharacter(int uid); - void DeleteCharacter(int uid); + //map management + void HandleRegionRequest(RegionPacket* const); + //combat management //TODO: combat management - //APIs - UDPNetworkUtility network; + //character management + void HandleCharacterNew(CharacterPacket* const); + void HandleCharacterDelete(CharacterPacket* const); + void HandleCharacterUpdate(CharacterPacket* const); + + //enemy management + //TODO: enemy management + + //mismanagement + void HandleSynchronize(ClientPacket* const); + + //utility methods + //TODO: a function that only sends to characters in a certain proximity + void PumpPacket(SerialPacket* const); + void PumpCharacterUnload(int uid); + void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex); + + //APIs and utilities sqlite3* database = nullptr; lua_State* luaState = nullptr; + UDPNetworkUtility network; + ConfigUtility config; - //server tables + //simple tables std::map clientMap; - std::map accountMap; - std::map characterMap; - std::map combatMap; - std::map enemyMap; - //maps - //TODO: I need to handle multiple map objects - //TODO: Unload regions that are distant from any characters - RegionPager regionPager; - EnemyFactoryGeneric enemyFactory; + //managers + AccountManager accountMgr; + CharacterManager characterMgr; + CombatManager combatMgr; + EnemyManager enemyMgr; + RoomManager roomMgr; //misc bool running = true; - ConfigUtility config; int clientUID = 0; - int combatUID = 0; - int enemyUID = 0; }; #endif diff --git a/server/server_connections.cpp b/server/server_connections.cpp deleted file mode 100644 index 047462f..0000000 --- a/server/server_connections.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2013, 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "server_application.hpp" - -#include -#include - -//------------------------- -//Handle various network input -//------------------------- - -void ServerApplication::HandleBroadcastRequest(SerialPacket packet) { - //pack the server's data - packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE; - packet.serverInfo.networkVersion = NETWORK_VERSION; - snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str()); - packet.serverInfo.playerCount = characterMap.size(); - - //bounce this packet - network.SendTo(&packet.meta.srcAddress, &packet); -} - -void ServerApplication::HandleJoinRequest(SerialPacket packet) { - //create the new client - ClientData newClient; - newClient.address = packet.meta.srcAddress; - - //load the user account - int accountIndex = LoadUserAccount(packet.clientInfo.username, clientUID); - if (accountIndex < 0) { - //TODO: send rejection packet - std::cerr << "Error: Account already loaded: " << accountIndex << std::endl; - return; - } - - //load the new character - int characterIndex = LoadCharacter(accountIndex, packet.clientInfo.handle, packet.clientInfo.avatar); - if (characterIndex < 0) { - //TODO: send rejection packet - std::cerr << "Error: Character already loaded: " << characterIndex << std::endl; - UnloadUserAccount(accountIndex); - return; - } - - //send the client their info - packet.meta.type = SerialPacket::Type::JOIN_RESPONSE; - packet.clientInfo.clientIndex = clientUID; - packet.clientInfo.accountIndex = accountIndex; - packet.clientInfo.characterIndex = characterIndex; - - //bounce this packet - network.SendTo(&newClient.address, &packet); - - //reference to prevent multiple lookups - //TODO: I need a way to pack structures unto packets more easily - //NOTE: this chunk of code is similar to HandleSynchronize - CharacterData& character = characterMap[characterIndex]; - - //send the new character to all clients - packet.meta.type = SerialPacket::Type::CHARACTER_NEW; - packet.characterInfo.characterIndex = characterIndex; - strncpy(packet.characterInfo.handle, character.handle.c_str(), PACKET_STRING_SIZE); - strncpy(packet.characterInfo.avatar, character.avatar.c_str(), PACKET_STRING_SIZE); - packet.characterInfo.mapIndex = character.mapIndex; - packet.characterInfo.origin = character.origin; - packet.characterInfo.motion = character.motion; - packet.characterInfo.stats = character.stats; - - PumpPacket(packet); - - //TODO: don't send anything to a certain client until they send the OK (the sync packet? or ignore client side?) - //finished this routine - clientMap[clientUID++] = newClient; - std::cout << "Connect, total: " << clientMap.size() << std::endl; -} - -void ServerApplication::HandleSynchronize(SerialPacket packet) { - //TODO: compensate for large distances - - //send all the server's data to this client - SerialPacket newPacket; - - //characters - newPacket.meta.type = SerialPacket::Type::CHARACTER_UPDATE; - for (auto& it : characterMap) { - //TODO: update this for the expanded CharacterData structure - newPacket.characterInfo.characterIndex = it.first; - snprintf(newPacket.characterInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); - snprintf(newPacket.characterInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); - newPacket.characterInfo.mapIndex = it.second.mapIndex; - newPacket.characterInfo.origin = it.second.origin; - newPacket.characterInfo.motion = it.second.motion; - newPacket.characterInfo.stats = it.second.stats; - - network.SendTo(&clientMap[packet.clientInfo.clientIndex].address, &newPacket); - } -} - -void ServerApplication::HandleDisconnect(SerialPacket packet) { - //TODO: authenticate who is disconnecting/kicking - - //forward to the specified client - network.SendTo(&clientMap[accountMap[packet.clientInfo.accountIndex].clientIndex].address, &packet); - - //unload client and server-side characters - for (std::map::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) { - if (it->second.owner == packet.clientInfo.accountIndex) { - PumpCharacterUnload(it->first); - SaveCharacter(it->first); - it = characterMap.erase(it); //efficient - continue; - } - else { - ++it; - } - } - - //erase the in-memory stuff - clientMap.erase(accountMap[packet.clientInfo.accountIndex].clientIndex); - UnloadUserAccount(packet.clientInfo.accountIndex); - - //finished this routine - std::cout << "Disconnect, total: " << clientMap.size() << std::endl; -} - -void ServerApplication::HandleShutdown(SerialPacket packet) { - //TODO: authenticate who is shutting the server down - - //end the server - running = false; - - //disconnect all clients - packet.meta.type = SerialPacket::Type::DISCONNECT; - PumpPacket(packet); - - //finished this routine - std::cout << "Shutdown signal accepted" << std::endl; -} - -void ServerApplication::HandleCharacterUpdate(SerialPacket packet) { - //TODO: this should be moved elsewhere - if (characterMap.find(packet.characterInfo.characterIndex) == characterMap.end()) { - throw(std::runtime_error("Cannot update a non-existant character")); - } - - //TODO: the server needs it's own movement system too - characterMap[packet.characterInfo.characterIndex].origin = packet.characterInfo.origin; - characterMap[packet.characterInfo.characterIndex].motion = packet.characterInfo.motion; - - PumpPacket(packet); -} - -void ServerApplication::HandleRegionRequest(SerialPacket packet) { - //TODO: this should be moved elsewhere - packet.meta.type = SerialPacket::Type::REGION_CONTENT; - packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y); - - //send the content - network.SendTo(&packet.meta.srcAddress, &packet); -} - -void ServerApplication::PumpPacket(SerialPacket packet) { - //NOTE: I don't really like this, but it'll do for now - for (auto& it : clientMap) { - network.SendTo(&it.second.address, &packet); - } -} - -void ServerApplication::PumpCharacterUnload(int uid) { - //delete the client-side character(s) - SerialPacket delPacket; - delPacket.meta.type = SerialPacket::Type::CHARACTER_DELETE; - delPacket.characterInfo.characterIndex = uid; - PumpPacket(delPacket); -} \ No newline at end of file diff --git a/server/server_internals.cpp b/server/server_internals.cpp deleted file mode 100644 index 4ee835f..0000000 --- a/server/server_internals.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright: (c) Kayne Ruse 2014 - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. -*/ -#include "server_application.hpp" - -#include "sql_utility.hpp" -#include "serial.hpp" - -#include -#include -#include - -//------------------------- -//Define the public members -//------------------------- - -void ServerApplication::Init(int argc, char** argv) { - //NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed. - std::cout << "Beginning startup" << std::endl; - - //initial setup - config.Load("rsc\\config.cfg"); - - //------------------------- - //Initialize the APIs - //------------------------- - - //Init SDL - if (SDL_Init(0)) { - throw(std::runtime_error("Failed to initialize SDL")); - } - std::cout << "Initialized SDL" << std::endl; - - //Init SDL_net - if (SDLNet_Init()) { - throw(std::runtime_error("Failed to initialize SDL_net")); - } - network.Open(config.Int("server.port")); - std::cout << "Initialized SDL_net" << std::endl; - - //Init SQL - int ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr); - if (ret != SQLITE_OK || !database) { - throw(std::runtime_error(std::string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) )); - } - std::cout << "Initialized SQL" << std::endl; - - //Init lua - luaState = luaL_newstate(); - if (!luaState) { - throw(std::runtime_error("Failed to initialize lua")); - } - luaL_openlibs(luaState); - std::cout << "Initialized lua" << std::endl; - - //------------------------- - //Setup the objects - //------------------------- - - //setup the map object - regionPager.GetAllocator()->SetLuaState(luaState); - regionPager.GetFormat()->SetLuaState(luaState); - regionPager.GetFormat()->SetSaveDir(config["dir.maps"] + config["map.savename"]); - std::cout << "Prepared the map system" << std::endl; - - //push the pager onto the lua registry - lua_pushstring(luaState, "pager"); - lua_pushlightuserdata(luaState, reinterpret_cast(®ionPager)); - lua_settable(luaState, LUA_REGISTRYINDEX); - std::cout << "Registered the map system in lua" << std::endl; - - //------------------------- - //Run the startup scripts - //------------------------- - - //setup the database - if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) { - throw(std::runtime_error("Failed to initialize SQL's setup script")); - } - std::cout << "Completed SQL's setup script" << std::endl; - - //run lua's startup script - if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) { - throw(std::runtime_error(std::string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) )); - } - std::cout << "Completed lua's setup script" << std::endl; - - //debug output - std::cout << "Internal sizes:" << std::endl; - std::cout << "\tsizeof(SerialPacket): " << sizeof(SerialPacket) << std::endl; - std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl; - - //finalize the startup - std::cout << "Startup completed successfully" << std::endl; - - //debugging - // -} - -void ServerApplication::Proc() { - SerialPacket packet; - while(running) { - //suck in the waiting packets & process them - while(network.Receive(&packet)) { - HandlePacket(packet); - } - //update the internals - //TODO: update the internals i.e. player positions - //give the computer a break - SDL_Delay(10); - } -} - -void ServerApplication::Quit() { - std::cout << "Shutting down" << std::endl; - - //save the server state - for (auto& it : accountMap) { - SaveUserAccount(it.first); - } - for (auto& it : characterMap) { - SaveCharacter(it.first); - } - - //empty the members - accountMap.clear(); - characterMap.clear(); - regionPager.UnloadAll(); - - //APIs - lua_close(luaState); - sqlite3_close_v2(database); - network.Close(); - SDLNet_Quit(); - SDL_Quit(); - - std::cout << "Shutdown finished" << std::endl; -} - -//------------------------- -//Define the uber switch -//------------------------- - -void ServerApplication::HandlePacket(SerialPacket packet) { - switch(packet.meta.type) { - case SerialPacket::Type::BROADCAST_REQUEST: - HandleBroadcastRequest(packet); - break; - case SerialPacket::Type::JOIN_REQUEST: - HandleJoinRequest(packet); - break; - case SerialPacket::Type::SYNCHRONIZE: - HandleSynchronize(packet); - break; - case SerialPacket::Type::DISCONNECT: - HandleDisconnect(packet); - break; - case SerialPacket::Type::SHUTDOWN: - HandleShutdown(packet); - break; - case SerialPacket::Type::CHARACTER_UPDATE: - HandleCharacterUpdate(packet); - break; - case SerialPacket::Type::REGION_REQUEST: - HandleRegionRequest(packet); - break; - //handle errors - default: - throw(std::runtime_error("Unknown SerialPacket::Type encountered")); - break; - } -} diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..d9279d1 --- /dev/null +++ b/todo.txt @@ -0,0 +1,47 @@ +TODO: rename restart scene to cleanup scene +TODO: encapsulate the data structures +TODO: Get the rooms working + +TODO: Rejection packets +TODO: Authentication +TODO: server is slaved to the client + +TODO: I need to keep the documentation up to date. Namely, the GDD is getting out of date. +TODO: I completely forgot about status ailments +TODO: Time delay for requesting region packets +TODO: command line parameters overriding config.cfg settings + +--Battle System-- + +TODO + +--Requirements-- + +The enemies need AI scripts +The scripts need to be able to generate other enemies (frog king). +The characters need a flag to show if they're in a combat instance or not, to signify of they should be unloaded client-side +On each game loop, the server should envoke each combat instance's update function + Each combat instance invokes each enemy's and character's update functions + These update functions increase the ATB guagues + if an ATB guage is full + than the stored command is executed + the players issue their commands during the build up + if there isn't a command ready, then the player is still choosing + for the enemies, the stored commands are driven by scripts, so when the enemies need to attack, their attached scripts are called. + after the commands are called, the ATB is reset to 0. + etc... + +--Enemy API-- + +enemyTables -- The global store of enemy tables. Only accessed by C++ code (unless you want to break something). + +enemy.new(parameters) -- return a new enemy object + +table.logic: the AI logic. If null, do nothing +table.ref: reference to the enemy itself, for use by API functions, set by constructor? + +combat -- the combat API +combat.new(mapIndex, x, y) -- return combat instance's index +combat.pushenemy(c, enemy) -- return the enemy's position +combat.popenemy(c, position) -- +