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