Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a5757748cf | |||
| f4e4728ce3 |
@@ -1,6 +1,6 @@
|
||||
## Outline
|
||||
|
||||
Tortuga is a 2D MMORPG featuring permadeath, with an emphasis on multiplayer cooperation, exploration and customization. The game runs on customizable public and private servers.
|
||||
Tortuga is a 2D multiplayer JRPG featuring permadeath, with an emphasis on multiplayer cooperation, exploration and customization. The game runs on customizable public and private servers.
|
||||
|
||||
This game is inspired by classic 2D RPGs (Final Fantasy, The Legend of Zelda), as well as more modern sandboxes amd MMOs (Minecraft, EVE Online). This project is currently independently created and funded, with the goal of creating a game that will engage the players and inspire a large community.
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ void BaseScene::HandleEvents() {
|
||||
break;
|
||||
|
||||
#ifdef USE_EVENT_JOYSTICK
|
||||
//EMPTY
|
||||
//TODO: joystick/gamepad support
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT_UNKNOWN
|
||||
|
||||
@@ -59,7 +59,7 @@ protected:
|
||||
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
||||
|
||||
#ifdef USE_EVENT_JOYSTICK
|
||||
//EMPTY
|
||||
//TODO: joystick/gamepad support
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT_UNKNOWN
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "main_menu.hpp"
|
||||
#include "options_menu.hpp"
|
||||
#include "lobby_menu.hpp"
|
||||
#include "world.hpp"
|
||||
#include "in_world.hpp"
|
||||
#include "disconnected_screen.hpp"
|
||||
|
||||
//-------------------------
|
||||
@@ -83,6 +83,7 @@ void ClientApplication::Init(int argc, char* argv[]) {
|
||||
//debug output
|
||||
//-------------------------
|
||||
|
||||
//TODO: enable/disable these with a switch
|
||||
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
||||
|
||||
std::cout << "Internal sizes:" << std::endl;
|
||||
@@ -169,7 +170,6 @@ void ClientApplication::Quit() {
|
||||
//-------------------------
|
||||
|
||||
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
||||
//BUG: #16 Resources are being reloaded between scenes
|
||||
UnloadScene();
|
||||
switch(sceneIndex) {
|
||||
//add scene creation calls here
|
||||
@@ -186,8 +186,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
|
||||
case SceneList::LOBBYMENU:
|
||||
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
|
||||
break;
|
||||
case SceneList::WORLD:
|
||||
activeScene = new World(&clientIndex, &accountIndex);
|
||||
case SceneList::INWORLD:
|
||||
activeScene = new InWorld(&clientIndex, &accountIndex);
|
||||
break;
|
||||
case SceneList::DISCONNECTEDSCREEN:
|
||||
activeScene = new DisconnectedScreen();
|
||||
|
||||
@@ -21,26 +21,3 @@
|
||||
*/
|
||||
#include "base_monster.hpp"
|
||||
|
||||
#include "config_utility.hpp"
|
||||
|
||||
void BaseMonster::CorrectSprite() {
|
||||
//TODO: (9) BaseMonster::CorrectSprite()
|
||||
}
|
||||
|
||||
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,17 +29,8 @@ public:
|
||||
BaseMonster() = default;
|
||||
virtual ~BaseMonster() = default;
|
||||
|
||||
void CorrectSprite();
|
||||
|
||||
std::string SetHandle(std::string s);
|
||||
std::string GetHandle() const;
|
||||
std::string SetAvatar(std::string s);
|
||||
std::string GetAvatar() const;
|
||||
|
||||
protected:
|
||||
//metadata
|
||||
std::string handle;
|
||||
std::string avatar;
|
||||
//
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -23,13 +23,54 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList) {
|
||||
bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList, Uint8* keyState) {
|
||||
//skip this if there's no movement
|
||||
if (motion == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//determine the simple movement based on input
|
||||
Vector2 newMotion = {0, 0};
|
||||
if (keyState[SDLK_w]) {
|
||||
newMotion.y -= CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_a]) {
|
||||
newMotion.x -= CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_s]) {
|
||||
newMotion.y += CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_d]) {
|
||||
newMotion.x += CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
for(auto& box : boxList) {
|
||||
if (box.CheckOverlap(origin + bounds)) {
|
||||
origin -= motion;
|
||||
motion = {0, 0};
|
||||
return true;
|
||||
if (box.CheckCollision(origin + bounds)) {
|
||||
//push the character to the closest non-contact position
|
||||
Vector2 shift = box.CalcShift(origin + bounds);
|
||||
origin += shift;
|
||||
|
||||
//set any motion in that direction to zero
|
||||
if (shift.x != 0) {
|
||||
newMotion.x = 0;
|
||||
}
|
||||
if (shift.y != 0) {
|
||||
newMotion.y = 0;
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
//handle diagonals
|
||||
if (newMotion.x != 0 && newMotion.y != 0) {
|
||||
newMotion *= CHARACTER_WALKING_MOD;
|
||||
}
|
||||
|
||||
//set the new motion
|
||||
motion = newMotion;
|
||||
|
||||
//signal for updates
|
||||
return ret;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
LocalCharacter() = default;
|
||||
virtual ~LocalCharacter() = default;
|
||||
|
||||
bool ProcessCollisionGrid(std::list<BoundingBox>);
|
||||
bool ProcessCollisionGrid(std::list<BoundingBox>, Uint8* keyState);
|
||||
|
||||
private:
|
||||
//NOTE: NO MEMBERS
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
class World: public BaseScene {
|
||||
class InWorld : public BaseScene {
|
||||
public:
|
||||
//Public access members
|
||||
World(int* const argClientIndex, int* const argAccountIndex);
|
||||
~World();
|
||||
InWorld(int* const argClientIndex, int* const argAccountIndex);
|
||||
~InWorld();
|
||||
|
||||
protected:
|
||||
//Frame loop
|
||||
@@ -71,57 +71,43 @@ protected:
|
||||
void KeyDown(SDL_KeyboardEvent const&);
|
||||
void KeyUp(SDL_KeyboardEvent const&);
|
||||
|
||||
//handle incoming traffic
|
||||
//Basic connections
|
||||
void HandlePacket(SerialPacket* const);
|
||||
void HandlePing(ServerPacket* const);
|
||||
void HandlePong(ServerPacket* const);
|
||||
|
||||
//heartbeat system
|
||||
void hPing(ServerPacket* const);
|
||||
void hPong(ServerPacket* const);
|
||||
//Connection control
|
||||
void SendLogoutRequest();
|
||||
void SendDisconnectRequest();
|
||||
void SendShutdownRequest();
|
||||
|
||||
void HandleLogoutResponse(ClientPacket* const);
|
||||
void HandleDisconnectResponse(ClientPacket* const);
|
||||
void HandleDisconnectForced(ClientPacket* const);
|
||||
|
||||
void CheckHeartBeat();
|
||||
|
||||
//basic connections
|
||||
void SendLogoutRequest();
|
||||
void SendDisconnectRequest();
|
||||
void SendAdminDisconnectForced();
|
||||
void SendAdminShutdownRequest();
|
||||
|
||||
void hLogoutResponse(ClientPacket* const);
|
||||
void hDisconnectResponse(ClientPacket* const);
|
||||
void hAdminDisconnectForced(ClientPacket* const);
|
||||
|
||||
//map management
|
||||
void SendRegionRequest(int roomIndex, int x, int y);
|
||||
void hRegionContent(RegionPacket* const);
|
||||
void HandleRegionContent(RegionPacket* const);
|
||||
void UpdateMap();
|
||||
|
||||
//character management
|
||||
void hCharacterUpdate(CharacterPacket* const);
|
||||
void hCharacterCreate(CharacterPacket* const);
|
||||
void hCharacterDelete(CharacterPacket* const);
|
||||
void hQueryCharacterExists(CharacterPacket* const);
|
||||
void hQueryCharacterStats(CharacterPacket* const);
|
||||
void hQueryCharacterLocation(CharacterPacket* const);
|
||||
void hCharacterMovement(CharacterPacket* const);
|
||||
void hCharacterAttack(CharacterPacket* const);
|
||||
void hCharacterDamage(CharacterPacket* const);
|
||||
void HandleCharacterCreate(CharacterPacket* const);
|
||||
void HandleCharacterDelete(CharacterPacket* const);
|
||||
void HandleCharacterQueryExists(CharacterPacket* const);
|
||||
void HandleCharacterMovement(CharacterPacket* const);
|
||||
void HandleCharacterAttack(CharacterPacket* const);
|
||||
|
||||
//monster management
|
||||
void hMonsterCreate(MonsterPacket* const);
|
||||
void hMonsterDelete(MonsterPacket* const);
|
||||
void hQueryMonsterExists(MonsterPacket* const);
|
||||
void hQueryMonsterStats(MonsterPacket* const);
|
||||
void hQueryMonsterLocation(MonsterPacket* const);
|
||||
void hMonsterMovement(MonsterPacket* const);
|
||||
void hMonsterAttack(MonsterPacket* const);
|
||||
void hMonsterDamage(MonsterPacket* const);
|
||||
void HandleMonsterCreate(MonsterPacket* const);
|
||||
void HandleMonsterDelete(MonsterPacket* const);
|
||||
void HandleMonsterQueryExists(MonsterPacket* const);
|
||||
void HandleMonsterMovement(MonsterPacket* const);
|
||||
void HandleMonsterAttack(MonsterPacket* const);
|
||||
|
||||
//chat
|
||||
void hTextBroadcast(TextPacket* const);
|
||||
void hTextSpeech(TextPacket* const);
|
||||
void hTextWhisper(TextPacket* const);
|
||||
|
||||
//general gameplay
|
||||
//player movement
|
||||
void ProcessLocalCharacterMovement();
|
||||
void SendLocalCharacterMovement();
|
||||
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
|
||||
|
||||
@@ -157,7 +143,7 @@ protected:
|
||||
LocalCharacter* localCharacter = nullptr;
|
||||
|
||||
//heartbeat
|
||||
//TODO: (2) Heartbeat needs it's own utility
|
||||
//TODO: Heartbeat needs it's own utility
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
Clock::time_point lastBeat = Clock::now();
|
||||
int attemptedBeats = 0;
|
||||
@@ -165,6 +151,7 @@ protected:
|
||||
//ugly references; I hate this
|
||||
ConfigUtility& config = ConfigUtility::GetSingleton();
|
||||
UDPNetworkUtility& network = UDPNetworkUtility::GetSingleton();
|
||||
Uint8* keyState = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
+81
-68
@@ -19,7 +19,7 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "world.hpp"
|
||||
#include "in_world.hpp"
|
||||
|
||||
#include "channels.hpp"
|
||||
|
||||
@@ -35,25 +35,7 @@
|
||||
//DOCS: new characters will result in create messages
|
||||
//DOCS: this client's character will exist in both (skipped)
|
||||
|
||||
void World::hCharacterUpdate(CharacterPacket* const argPacket) {
|
||||
//TODO: (1) Authentication
|
||||
//NOTE: applies to the local character too
|
||||
|
||||
//check that this character exists
|
||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||
if (characterIt != characterMap.end()) {
|
||||
//update the origin and motion, if there's a difference
|
||||
if (characterIt->second.GetOrigin() != argPacket->origin) {
|
||||
characterIt->second.SetOrigin(argPacket->origin);
|
||||
}
|
||||
if (characterIt->second.GetMotion() != argPacket->motion) {
|
||||
characterIt->second.SetMotion(argPacket->motion);
|
||||
characterIt->second.CorrectSprite(); //only correct the sprite if the motion changes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::hCharacterCreate(CharacterPacket* const argPacket) {
|
||||
void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) {
|
||||
//prevent double message
|
||||
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
|
||||
std::ostringstream msg;
|
||||
@@ -67,42 +49,32 @@ void World::hCharacterCreate(CharacterPacket* const argPacket) {
|
||||
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->SetOrigin(argPacket->origin);
|
||||
character->SetMotion(argPacket->motion);
|
||||
character->SetBounds(argPacket->bounds);
|
||||
|
||||
character->CorrectSprite();
|
||||
|
||||
//check for this player's character
|
||||
if (character->GetOwner() == accountIndex) {
|
||||
localCharacter = static_cast<LocalCharacter*>(character);
|
||||
|
||||
//focus the camera on this character's sprite
|
||||
//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;
|
||||
|
||||
//query the world state (room)
|
||||
CharacterPacket newPacket;
|
||||
memset(&newPacket, 0, MAX_PACKET_SIZE);
|
||||
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
||||
newPacket.roomIndex = roomIndex;
|
||||
network.SendTo(Channels::SERVER, &newPacket);
|
||||
newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
|
||||
network.SendTo(Channels::SERVER, &newPacket);
|
||||
}
|
||||
|
||||
//debug
|
||||
std::cout << "Character Create, total: " << characterMap.size() << std::endl;
|
||||
std::cout << "Create, total: " << characterMap.size() << std::endl;
|
||||
}
|
||||
|
||||
void World::hCharacterDelete(CharacterPacket* const argPacket) {
|
||||
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()) {
|
||||
@@ -119,24 +91,20 @@ void World::hCharacterDelete(CharacterPacket* const argPacket) {
|
||||
|
||||
//clear the room
|
||||
roomIndex = -1;
|
||||
regionPager.UnloadAll();
|
||||
characterMap.clear();
|
||||
monsterMap.clear();
|
||||
}
|
||||
else {
|
||||
//remove this character
|
||||
characterMap.erase(characterIt);
|
||||
}
|
||||
|
||||
//remove this character
|
||||
characterMap.erase(characterIt);
|
||||
|
||||
//debug
|
||||
std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
|
||||
std::cout << "Delete, total: " << characterMap.size() << std::endl;
|
||||
}
|
||||
|
||||
void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
|
||||
void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) {
|
||||
//prevent a double message about this player's character
|
||||
// if (argPacket->accountIndex == accountIndex) {
|
||||
// return;
|
||||
// }
|
||||
if (argPacket->accountIndex == accountIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
//ignore characters in a different room (sub-optimal)
|
||||
if (argPacket->roomIndex != roomIndex) {
|
||||
@@ -156,19 +124,11 @@ void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
|
||||
character->CorrectSprite();
|
||||
|
||||
//debug
|
||||
std::cout << "Character Query, total: " << characterMap.size() << std::endl;
|
||||
std::cout << "Query, total: " << characterMap.size() << std::endl;
|
||||
}
|
||||
|
||||
void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) World::hQueryCharacterStats()
|
||||
}
|
||||
|
||||
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) World::hQueryCharacterLocation()
|
||||
}
|
||||
|
||||
void World::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||
//TODO: (1) Authentication
|
||||
void InWorld::HandleCharacterMovement(CharacterPacket* const argPacket) {
|
||||
//TODO: Authentication
|
||||
if (argPacket->characterIndex == characterIndex) {
|
||||
return;
|
||||
}
|
||||
@@ -183,19 +143,72 @@ void World::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||
}
|
||||
}
|
||||
|
||||
void World::hCharacterAttack(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) World::hCharacterAttack()
|
||||
}
|
||||
|
||||
void World::hCharacterDamage(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) World::hCharacterDamage()
|
||||
void InWorld::HandleCharacterAttack(CharacterPacket* const argPacket) {
|
||||
//TODO: attack animation
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//player movement & collision
|
||||
//monster management
|
||||
//-------------------------
|
||||
|
||||
void World::SendLocalCharacterMovement() {
|
||||
void InWorld::HandleMonsterCreate(MonsterPacket* const argPacket) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
void InWorld::HandleMonsterDelete(MonsterPacket* const argPacket) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
void InWorld::HandleMonsterQueryExists(MonsterPacket* const argPacket) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
void InWorld::HandleMonsterMovement(MonsterPacket* const argPacket) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
void InWorld::HandleMonsterAttack(MonsterPacket* const argPacket) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//player movement
|
||||
//-------------------------
|
||||
|
||||
void InWorld::ProcessLocalCharacterMovement() {
|
||||
//character movement
|
||||
if (!localCharacter) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 newMotion = {0, 0};
|
||||
if (keyState[SDLK_w]) {
|
||||
newMotion.y -= CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_a]) {
|
||||
newMotion.x -= CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_s]) {
|
||||
newMotion.y += CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
if (keyState[SDLK_d]) {
|
||||
newMotion.x += CHARACTER_WALKING_SPEED;
|
||||
}
|
||||
|
||||
//handle diagonals
|
||||
if (newMotion.x != 0 && newMotion.y != 0) {
|
||||
newMotion *= CHARACTER_WALKING_MOD;
|
||||
}
|
||||
|
||||
//set the info
|
||||
if (localCharacter->GetMotion() != newMotion) {
|
||||
localCharacter->SetMotion(newMotion);
|
||||
localCharacter->CorrectSprite();
|
||||
SendLocalCharacterMovement();
|
||||
}
|
||||
}
|
||||
|
||||
void InWorld::SendLocalCharacterMovement() {
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
|
||||
|
||||
@@ -208,7 +221,7 @@ void World::SendLocalCharacterMovement() {
|
||||
network.SendTo(Channels::SERVER, &newPacket);
|
||||
}
|
||||
|
||||
std::list<BoundingBox> World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
|
||||
std::list<BoundingBox> InWorld::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
|
||||
//prepare for collisions
|
||||
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
|
||||
std::list<BoundingBox> boxList;
|
||||
@@ -0,0 +1,264 @@
|
||||
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "in_world.hpp"
|
||||
|
||||
#include "channels.hpp"
|
||||
#include "ip_operators.hpp"
|
||||
#include "terminal_error.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
//-------------------------
|
||||
//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;
|
||||
case SerialPacketType::CHARACTER_MOVEMENT:
|
||||
HandleCharacterMovement(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_ATTACK:
|
||||
HandleCharacterAttack(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//monster management
|
||||
case SerialPacketType::MONSTER_CREATE:
|
||||
HandleMonsterCreate(static_cast<MonsterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::MONSTER_DELETE:
|
||||
HandleMonsterDelete(static_cast<MonsterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::QUERY_MONSTER_EXISTS:
|
||||
HandleMonsterQueryExists(static_cast<MonsterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::MONSTER_MOVEMENT:
|
||||
HandleMonsterMovement(static_cast<MonsterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::MONSTER_ATTACK:
|
||||
HandleMonsterAttack(static_cast<MonsterPacket*>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/* 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 "terminal_error.hpp"
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
//-------------------------
|
||||
//Public access members
|
||||
//-------------------------
|
||||
|
||||
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
|
||||
clientIndex(*argClientIndex),
|
||||
accountIndex(*argAccountIndex),
|
||||
keyState(SDL_GetKeyState(nullptr))
|
||||
{
|
||||
//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, keyState)) {
|
||||
localCharacter->CorrectSprite();
|
||||
SendLocalCharacterMovement();
|
||||
}
|
||||
|
||||
//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);
|
||||
std::ostringstream msg;
|
||||
msg << fps.GetFrameRate();
|
||||
font.DrawStringTo(msg.str(), 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 & player input
|
||||
switch(key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
//TODO: the escape key should actually control menus and stuff
|
||||
SendLogoutRequest();
|
||||
return;
|
||||
case SDLK_w:
|
||||
case SDLK_a:
|
||||
case SDLK_s:
|
||||
case SDLK_d:
|
||||
ProcessLocalCharacterMovement();
|
||||
break;
|
||||
default:
|
||||
//DOCS: prevents wrong keys screwing with character movement
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
|
||||
switch(key.keysym.sym) {
|
||||
case SDLK_w:
|
||||
case SDLK_a:
|
||||
case SDLK_s:
|
||||
case SDLK_d:
|
||||
ProcessLocalCharacterMovement();
|
||||
break;
|
||||
default:
|
||||
//DOCS: prevents wrong keys screwing with character movement
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,134 +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 "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) World::SendAdminDisconnectForced()
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -1,427 +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 "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: (2) 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);
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
try {
|
||||
//update the map
|
||||
UpdateMap();
|
||||
}
|
||||
catch(terminal_error& e) {
|
||||
throw(e);
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
std::cerr << "UpdateMap Error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
//debugging
|
||||
// std::ostringstream msg;
|
||||
// msg << it->GetX() << ", " << it->GetY();
|
||||
// font.DrawStringTo(msg.str(), screen, it->GetX() * tileSheet.GetImage()->GetClipW() - camera.x, it->GetY() * tileSheet.GetImage()->GetClipH() - camera.y);
|
||||
}
|
||||
|
||||
//draw the entities
|
||||
for (auto& it : characterMap) {
|
||||
//BUG: #29 Characters (and other entities) are drawn out of order
|
||||
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: (3) 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_UPDATE:
|
||||
hCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,118 +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 "world.hpp"
|
||||
|
||||
#include "channels.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
//-------------------------
|
||||
//static functions
|
||||
//-------------------------
|
||||
|
||||
static int regionChecksum(Region* const region) {
|
||||
int sum = 0;
|
||||
for(int i = 0; i < REGION_WIDTH; i++) {
|
||||
for (int j = 0; j < REGION_HEIGHT; j++) {
|
||||
for (int k = 0; k < REGION_DEPTH; k++) {
|
||||
sum += region->GetTile(i, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//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) {
|
||||
//checksum
|
||||
if (regionChecksum(argPacket->region) == 0) {
|
||||
std::ostringstream msg;
|
||||
msg << "Received region checksum failed: " << argPacket->x << ", " << argPacket->y;
|
||||
throw(std::runtime_error(msg.str()));
|
||||
}
|
||||
|
||||
//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) {
|
||||
Region* region = regionPager.FindRegion(i, j);
|
||||
if (!region) {
|
||||
//request absent region
|
||||
SendRegionRequest(roomIndex, i, j);
|
||||
}
|
||||
else if (regionChecksum(region) == 0) {
|
||||
//checksum failed
|
||||
//NOTE: this patches bug #45, but does not resolve it
|
||||
regionPager.UnloadIf([region](Region const& ref) -> bool {
|
||||
//remove the erroneous region
|
||||
return region == &ref;
|
||||
});
|
||||
SendRegionRequest(roomIndex, i, j);
|
||||
std::ostringstream msg;
|
||||
msg << "Existing region checksum failed: " << roomIndex << ", " << i << ", " << j;
|
||||
throw(std::runtime_error(msg.str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +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 "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) World::hQueryMonsterStats()
|
||||
}
|
||||
|
||||
void World::hQueryMonsterLocation(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) World::hQueryMonsterLocation()
|
||||
}
|
||||
|
||||
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) World::hMonsterAttack()
|
||||
}
|
||||
|
||||
void World::hMonsterDamage(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) World::hMonsterDamage()
|
||||
}
|
||||
@@ -100,15 +100,14 @@ void LobbyMenu::FrameEnd() {
|
||||
}
|
||||
|
||||
void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||
//TODO: (2) I need a proper UI system for the entire client and the editor
|
||||
//TODO: I need a proper UI system for the entire client and the editor
|
||||
|
||||
//UI
|
||||
search.DrawTo(screen);
|
||||
join.DrawTo(screen);
|
||||
back.DrawTo(screen);
|
||||
|
||||
//TODO: (3) draw headers for the server list
|
||||
//TODO: (3) ping/delay displayed in the server list
|
||||
//TODO: draw headers for the server list
|
||||
for (int i = 0; i < serverInfo.size(); i++) {
|
||||
//draw the selected server's highlight
|
||||
if (selection == &serverInfo[i]) {
|
||||
@@ -132,6 +131,8 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||
if (!serverInfo[i].compatible) {
|
||||
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
||||
}
|
||||
|
||||
//TODO: ping/delay?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +166,7 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||
//has the user selected a server on the list?
|
||||
BoundingBox tmpBox = listBox;
|
||||
tmpBox.h *= serverInfo.size();
|
||||
if (tmpBox.CheckOverlap({button.x, button.y})) {
|
||||
if (tmpBox.CheckCollision({button.x, button.y, 0, 0})) {
|
||||
selection = &serverInfo[(button.y - listBox.y)/listBox.h];
|
||||
}
|
||||
else {
|
||||
@@ -249,15 +250,15 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
|
||||
throw(std::runtime_error("Client index invalid during login"));
|
||||
}
|
||||
accountIndex = argPacket->accountIndex;
|
||||
SetNextScene(SceneList::WORLD);
|
||||
SetNextScene(SceneList::INWORLD);
|
||||
}
|
||||
|
||||
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
||||
//TODO: (9) LobbyMenu::HandleJoinRejection()
|
||||
//TODO: Better output for join rejection
|
||||
}
|
||||
|
||||
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
|
||||
//TODO: (9) LobbyMenu::HandleLoginRejection
|
||||
//TODO: Better output for login rejection
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
|
||||
@@ -88,7 +88,8 @@ void MainMenu::Render(SDL_Surface* const screen) {
|
||||
//text
|
||||
font.DrawStringTo("Thanks for playing!", screen, 50, screen->h - 50 - image.GetClipH() * 2);
|
||||
font.DrawStringTo("You can get the latest version at: ", screen, 50, screen->h - 50 - image.GetClipH() * 1);
|
||||
font.DrawStringTo("krgamestudios.com", screen, 50, screen->h - 50 - image.GetClipH() * 0);
|
||||
font.DrawStringTo("https://github.com/Ratstail91/Tortuga", screen, 50, screen->h - 50 - image.GetClipH() * 0);
|
||||
//TODO: replace this with a website address
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
@@ -108,7 +109,7 @@ void MainMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
||||
}
|
||||
|
||||
void MainMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||
//TODO: (2) Buttons should only register as "selected" when the left button is used
|
||||
//TODO: Buttons should only register as "selected" when the left button is used
|
||||
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
|
||||
SetNextScene(SceneList::LOBBYMENU);
|
||||
}
|
||||
@@ -125,9 +126,5 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
|
||||
}
|
||||
|
||||
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
||||
switch(key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
QuitEvent();
|
||||
break;
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "raster_font.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
//NOTE: The options screen needs to be USED
|
||||
//TODO: The options screen needs to be USED
|
||||
class OptionsMenu : public BaseScene {
|
||||
public:
|
||||
//Public access members
|
||||
|
||||
@@ -33,7 +33,7 @@ enum class SceneList {
|
||||
MAINMENU,
|
||||
OPTIONSMENU,
|
||||
LOBBYMENU,
|
||||
WORLD,
|
||||
INWORLD,
|
||||
DISCONNECTEDSCREEN,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* 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 "map_system_api.hpp"
|
||||
|
||||
//all map API headers
|
||||
#include "region_api.hpp"
|
||||
#include "region_pager_api.hpp"
|
||||
|
||||
//useful "globals"
|
||||
//...
|
||||
|
||||
//This mimics linit.c to create a nested collection of all map modules.
|
||||
static const luaL_Reg funcs[] = {
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const luaL_Reg libs[] = {
|
||||
{"Region", openRegionAPI},
|
||||
{"RegionPager", openRegionPagerAPI},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
int openMapSystemAPI(lua_State* L) {
|
||||
//create the table
|
||||
luaL_newlibtable(L, libs);
|
||||
|
||||
//push the "global" functions
|
||||
luaL_setfuncs(L, funcs, 0);
|
||||
|
||||
//push the substable
|
||||
for (const luaL_Reg* lib = libs; lib->func; lib++) {
|
||||
lib->func(L);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef TRIGGERAPI_HPP_
|
||||
#define TRIGGERAPI_HPP_
|
||||
#ifndef MAPSYSTEMAPI_HPP_
|
||||
#define MAPSYSTEMAPI_APP_
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_TRIGGER_API "trigger"
|
||||
LUAMOD_API int openTriggerAPI(lua_State* L);
|
||||
#define TORTUGA_MAP_SYSTEM_API "map_system"
|
||||
LUAMOD_API int openMapSystemAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_REGION_API "region"
|
||||
#define TORTUGA_REGION_NAME "region"
|
||||
LUAMOD_API int openRegionAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "region.hpp"
|
||||
|
||||
//DOCS: These glue functions simply wrap RegionPagerLua's methods
|
||||
//NOTE: zero indexing is used here, but not in the region API
|
||||
|
||||
static int setTile(lua_State* L) {
|
||||
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_REGION_PAGER_API "region_pager"
|
||||
#define TORTUGA_REGION_PAGER_NAME "region_pager"
|
||||
LUAMOD_API int openRegionPagerAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,6 @@ Region* RegionPagerBase::FindRegion(int x, int y) {
|
||||
}
|
||||
|
||||
Region* RegionPagerBase::PushRegion(Region* const ptr) {
|
||||
//BUG: #45 Some regions are occasionally losing their tile data
|
||||
regionList.push_front(*ptr);
|
||||
return ®ionList.front();
|
||||
}
|
||||
|
||||
@@ -36,18 +36,11 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) {
|
||||
|
||||
//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));
|
||||
|
||||
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));
|
||||
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
}
|
||||
|
||||
@@ -64,17 +57,10 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) {
|
||||
|
||||
//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));
|
||||
|
||||
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));
|
||||
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "serial_packet_base.hpp"
|
||||
|
||||
#include "bounding_box.hpp"
|
||||
#include "vector2.hpp"
|
||||
|
||||
struct CharacterPacket : SerialPacketBase {
|
||||
@@ -35,12 +34,14 @@ struct CharacterPacket : SerialPacketBase {
|
||||
|
||||
//the owner
|
||||
int accountIndex;
|
||||
//TODO: Authentication token?
|
||||
|
||||
//location
|
||||
int roomIndex;
|
||||
Vector2 origin;
|
||||
Vector2 motion;
|
||||
BoundingBox bounds;
|
||||
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
};
|
||||
|
||||
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
||||
|
||||
@@ -28,7 +28,6 @@ struct ClientPacket : SerialPacketBase {
|
||||
int clientIndex;
|
||||
int accountIndex;
|
||||
char username[PACKET_STRING_SIZE];
|
||||
//TODO: (3) password, auth token
|
||||
};
|
||||
|
||||
void serializeClient(void* buffer, ClientPacket* packet);
|
||||
|
||||
@@ -44,6 +44,9 @@ void serializeMonster(void* buffer, MonsterPacket* packet) {
|
||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||
serialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||
|
||||
//attack data
|
||||
//TODO
|
||||
}
|
||||
|
||||
void deserializeMonster(void* buffer, MonsterPacket* packet) {
|
||||
@@ -67,4 +70,7 @@ void deserializeMonster(void* buffer, MonsterPacket* packet) {
|
||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||
deserialCopy(&buffer, &packet->motion.y, sizeof(double));
|
||||
|
||||
//attack data
|
||||
//TODO
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ struct MonsterPacket : SerialPacketBase {
|
||||
int roomIndex;
|
||||
Vector2 origin;
|
||||
Vector2 motion;
|
||||
|
||||
//TODO: attack data
|
||||
};
|
||||
|
||||
void serializeMonster(void* buffer, MonsterPacket* packet);
|
||||
|
||||
@@ -29,12 +29,6 @@ void serializeText(void* buffer, TextPacket* packet) {
|
||||
//content
|
||||
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||
|
||||
//location
|
||||
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||
serialCopy(&buffer, &packet->range, sizeof(int));
|
||||
}
|
||||
|
||||
void deserializeText(void* buffer, TextPacket* packet) {
|
||||
@@ -43,10 +37,4 @@ void deserializeText(void* buffer, TextPacket* packet) {
|
||||
//content
|
||||
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||
|
||||
//location
|
||||
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||
deserialCopy(&buffer, &packet->range, sizeof(int));
|
||||
}
|
||||
@@ -24,14 +24,9 @@
|
||||
|
||||
#include "serial_packet_base.hpp"
|
||||
|
||||
#include "vector2.hpp"
|
||||
|
||||
struct TextPacket : SerialPacketBase {
|
||||
char name[PACKET_STRING_SIZE];
|
||||
char text[PACKET_STRING_SIZE];
|
||||
int roomIndex;
|
||||
Vector2 origin;
|
||||
int range;
|
||||
};
|
||||
|
||||
void serializeText(void* buffer, TextPacket* packet);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
typedef SerialPacketBase SerialPacket;
|
||||
|
||||
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
||||
constexpr int NETWORK_VERSION = 20150304;
|
||||
constexpr int NETWORK_VERSION = -1;
|
||||
|
||||
union MaxPacket {
|
||||
CharacterPacket a;
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
/* DOCS: The headers indicate what packet type is used for each message
|
||||
* different messages under the same header will carry different amounts of
|
||||
* valid data, but it will still be carried in that packet's format.
|
||||
* FORMAT_* is for internal use, deviding the different format bounds.
|
||||
*/
|
||||
|
||||
//TODO: This needs to be smoothed out
|
||||
enum class SerialPacketType {
|
||||
//default: there is something wrong
|
||||
NONE,
|
||||
@@ -37,8 +37,6 @@ enum class SerialPacketType {
|
||||
// name, player count, version
|
||||
//-------------------------
|
||||
|
||||
FORMAT_SERVER,
|
||||
|
||||
//heartbeat
|
||||
PING,
|
||||
PONG,
|
||||
@@ -47,15 +45,11 @@ enum class SerialPacketType {
|
||||
BROADCAST_REQUEST,
|
||||
BROADCAST_RESPONSE,
|
||||
|
||||
FORMAT_END_SERVER,
|
||||
|
||||
//-------------------------
|
||||
//ClientPacket
|
||||
// client index, account index, username
|
||||
//-------------------------
|
||||
|
||||
FORMAT_CLIENT,
|
||||
|
||||
//Connecting to a server as a client
|
||||
JOIN_REQUEST,
|
||||
JOIN_RESPONSE,
|
||||
@@ -63,7 +57,7 @@ enum class SerialPacketType {
|
||||
//disconnect from the server
|
||||
DISCONNECT_REQUEST,
|
||||
DISCONNECT_RESPONSE,
|
||||
ADMIN_DISCONNECT_FORCED,
|
||||
DISCONNECT_FORCED,
|
||||
|
||||
//load the account
|
||||
LOGIN_REQUEST,
|
||||
@@ -74,36 +68,26 @@ enum class SerialPacketType {
|
||||
LOGOUT_RESPONSE,
|
||||
|
||||
//shut down the server
|
||||
ADMIN_SHUTDOWN_REQUEST,
|
||||
|
||||
FORMAT_END_CLIENT,
|
||||
SHUTDOWN_REQUEST,
|
||||
|
||||
//-------------------------
|
||||
//RegionPacket
|
||||
// room index, x, y, raw data
|
||||
//-------------------------
|
||||
|
||||
FORMAT_REGION,
|
||||
|
||||
//map data
|
||||
REGION_REQUEST,
|
||||
REGION_REQUEST, //NOTE: technically a query
|
||||
REGION_CONTENT,
|
||||
|
||||
FORMAT_END_REGION,
|
||||
|
||||
//-------------------------
|
||||
//CharacterPacket
|
||||
// character index,
|
||||
// handle, avatar,
|
||||
// account index (owner),
|
||||
// room index, origin, motion
|
||||
// room index, origin, motion,
|
||||
// statistics
|
||||
//-------------------------
|
||||
|
||||
FORMAT_CHARACTER,
|
||||
|
||||
//full data update
|
||||
CHARACTER_UPDATE,
|
||||
|
||||
//character management
|
||||
CHARACTER_CREATE,
|
||||
CHARACTER_DELETE,
|
||||
@@ -115,56 +99,38 @@ enum class SerialPacketType {
|
||||
QUERY_CHARACTER_STATS,
|
||||
QUERY_CHARACTER_LOCATION,
|
||||
|
||||
//actions taken
|
||||
//set the info in the server
|
||||
CHARACTER_MOVEMENT,
|
||||
CHARACTER_ATTACK,
|
||||
CHARACTER_DAMAGE,
|
||||
|
||||
//admin control
|
||||
// ADMIN_SET_CHARACTER_ORIGIN,
|
||||
|
||||
FORMAT_END_CHARACTER,
|
||||
|
||||
//-------------------------
|
||||
//MonsterPacket
|
||||
// monster index,
|
||||
// handle, avatar
|
||||
// bounds
|
||||
// handle, avatar, hitbox
|
||||
// room index, origin, motion
|
||||
// TODO: attack data
|
||||
//-------------------------
|
||||
|
||||
FORMAT_MONSTER,
|
||||
|
||||
//full data update
|
||||
MONSTER_UPDATE,
|
||||
|
||||
//character management
|
||||
MONSTER_CREATE,
|
||||
MONSTER_DELETE,
|
||||
|
||||
//find out info from the server
|
||||
QUERY_MONSTER_EXISTS,
|
||||
QUERY_MONSTER_STATS,
|
||||
QUERY_MONSTER_LOCATION,
|
||||
QUERY_MONSTER_EXISTS, //a list of monsters in a room
|
||||
QUERY_MONSTER_STATS, //statistics of a specific monster type or instance
|
||||
QUERY_MONSTER_LOCATION, //umm...
|
||||
|
||||
//actions taken
|
||||
MONSTER_MOVEMENT,
|
||||
MONSTER_MOVEMENT, //monster movement
|
||||
MONSTER_ATTACK,
|
||||
MONSTER_DAMAGE,
|
||||
|
||||
FORMAT_END_MONSTER,
|
||||
|
||||
//-------------------------
|
||||
//TextPacket
|
||||
// name, text
|
||||
//-------------------------
|
||||
|
||||
FORMAT_TEXT,
|
||||
|
||||
//general speech
|
||||
TEXT_BROADCAST,
|
||||
TEXT_SPEECH,
|
||||
TEXT_WHISPER,
|
||||
|
||||
//rejection/error messages
|
||||
JOIN_REJECTION,
|
||||
@@ -173,9 +139,6 @@ enum class SerialPacketType {
|
||||
CHARACTER_REJECTION,
|
||||
MONSTER_REJECTION,
|
||||
SHUTDOWN_REJECTION,
|
||||
QUERY_REJECTION,
|
||||
|
||||
FORMAT_END_TEXT,
|
||||
|
||||
//-------------------------
|
||||
//not used
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
//macros
|
||||
#define BOUNDS(type, lower, upper) ((type) > (lower) && (type) < (upper))
|
||||
|
||||
//raw memory copy
|
||||
void serialCopy(void** buffer, void* data, int size) {
|
||||
memcpy(*buffer, data, size);
|
||||
@@ -49,28 +46,58 @@ void deserialCopy(void** buffer, void* data, int size) {
|
||||
|
||||
//main switch functions
|
||||
void serializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
||||
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
||||
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
||||
serializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
||||
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
||||
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
||||
serializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
switch(packet->type) {
|
||||
case SerialPacketType::PING:
|
||||
case SerialPacketType::PONG:
|
||||
case SerialPacketType::BROADCAST_REQUEST:
|
||||
case SerialPacketType::BROADCAST_RESPONSE:
|
||||
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::JOIN_REQUEST:
|
||||
case SerialPacketType::JOIN_RESPONSE:
|
||||
case SerialPacketType::DISCONNECT_REQUEST:
|
||||
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||
case SerialPacketType::DISCONNECT_FORCED:
|
||||
case SerialPacketType::LOGIN_REQUEST:
|
||||
case SerialPacketType::LOGIN_RESPONSE:
|
||||
case SerialPacketType::LOGOUT_REQUEST:
|
||||
case SerialPacketType::LOGOUT_RESPONSE:
|
||||
case SerialPacketType::SHUTDOWN_REQUEST:
|
||||
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::REGION_REQUEST:
|
||||
case SerialPacketType::REGION_CONTENT:
|
||||
serializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_CREATE:
|
||||
case SerialPacketType::CHARACTER_DELETE:
|
||||
case SerialPacketType::CHARACTER_LOAD:
|
||||
case SerialPacketType::CHARACTER_UNLOAD:
|
||||
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
||||
case SerialPacketType::QUERY_CHARACTER_STATS:
|
||||
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
||||
case SerialPacketType::CHARACTER_MOVEMENT:
|
||||
case SerialPacketType::CHARACTER_ATTACK:
|
||||
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::MONSTER_CREATE:
|
||||
case SerialPacketType::MONSTER_DELETE:
|
||||
case SerialPacketType::QUERY_MONSTER_EXISTS:
|
||||
case SerialPacketType::QUERY_MONSTER_STATS:
|
||||
case SerialPacketType::QUERY_MONSTER_LOCATION:
|
||||
case SerialPacketType::MONSTER_MOVEMENT:
|
||||
case SerialPacketType::MONSTER_ATTACK:
|
||||
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::TEXT_BROADCAST:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::LOGIN_REJECTION:
|
||||
case SerialPacketType::REGION_REJECTION:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
case SerialPacketType::MONSTER_REJECTION:
|
||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||
serializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,27 +106,57 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
SerialPacketType type;
|
||||
memcpy(&type, buffer, sizeof(SerialPacketType));
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
||||
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
||||
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
||||
deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
||||
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
||||
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||
}
|
||||
|
||||
if (BOUNDS(type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
||||
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
switch(type) {
|
||||
case SerialPacketType::PING:
|
||||
case SerialPacketType::PONG:
|
||||
case SerialPacketType::BROADCAST_REQUEST:
|
||||
case SerialPacketType::BROADCAST_RESPONSE:
|
||||
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::JOIN_REQUEST:
|
||||
case SerialPacketType::JOIN_RESPONSE:
|
||||
case SerialPacketType::DISCONNECT_REQUEST:
|
||||
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||
case SerialPacketType::DISCONNECT_FORCED:
|
||||
case SerialPacketType::LOGIN_REQUEST:
|
||||
case SerialPacketType::LOGIN_RESPONSE:
|
||||
case SerialPacketType::LOGOUT_REQUEST:
|
||||
case SerialPacketType::LOGOUT_RESPONSE:
|
||||
case SerialPacketType::SHUTDOWN_REQUEST:
|
||||
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::REGION_REQUEST:
|
||||
case SerialPacketType::REGION_CONTENT:
|
||||
deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_CREATE:
|
||||
case SerialPacketType::CHARACTER_DELETE:
|
||||
case SerialPacketType::CHARACTER_LOAD:
|
||||
case SerialPacketType::CHARACTER_UNLOAD:
|
||||
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
||||
case SerialPacketType::QUERY_CHARACTER_STATS:
|
||||
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
||||
case SerialPacketType::CHARACTER_MOVEMENT:
|
||||
case SerialPacketType::CHARACTER_ATTACK:
|
||||
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::MONSTER_CREATE:
|
||||
case SerialPacketType::MONSTER_DELETE:
|
||||
case SerialPacketType::QUERY_MONSTER_EXISTS:
|
||||
case SerialPacketType::QUERY_MONSTER_STATS:
|
||||
case SerialPacketType::QUERY_MONSTER_LOCATION:
|
||||
case SerialPacketType::MONSTER_MOVEMENT:
|
||||
case SerialPacketType::MONSTER_ATTACK:
|
||||
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::TEXT_BROADCAST:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::LOGIN_REJECTION:
|
||||
case SerialPacketType::REGION_REJECTION:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
case SerialPacketType::MONSTER_REJECTION:
|
||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -140,6 +140,7 @@ int UDPNetworkUtility::SendToAllChannels(void* data, int len) {
|
||||
return sent;
|
||||
}
|
||||
|
||||
//TODO: put a void* and int* parameter list here
|
||||
int UDPNetworkUtility::Receive() {
|
||||
memset(packet->data, 0, packet->maxlen);
|
||||
int ret = SDLNet_UDP_Recv(socket, packet);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#ifndef BOUNDINGBOX_HPP_
|
||||
#define BOUNDINGBOX_HPP_
|
||||
|
||||
#include "vector2.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -32,16 +34,15 @@ public:
|
||||
int w, h;
|
||||
|
||||
BoundingBox() = default;
|
||||
BoundingBox(int i, int j): x(i), y(j), w(0), h(0) {};
|
||||
BoundingBox(int i, int j, int k, int l): x(i), y(j), w(k), h(l) {};
|
||||
~BoundingBox() = default;
|
||||
BoundingBox& operator=(BoundingBox const&) = default;
|
||||
|
||||
int Size() {
|
||||
return std::max(w*h,0);
|
||||
return (w-x) * (h-y);
|
||||
}
|
||||
|
||||
bool CheckOverlap(BoundingBox rhs) {
|
||||
bool CheckCollision(BoundingBox rhs) {
|
||||
return !(
|
||||
x >= rhs.x + rhs.w ||
|
||||
y >= rhs.y + rhs.h ||
|
||||
@@ -49,24 +50,25 @@ public:
|
||||
rhs.y >= y + h);
|
||||
}
|
||||
|
||||
BoundingBox CalcOverlap(BoundingBox rhs) {
|
||||
if (!CheckOverlap(rhs)) {
|
||||
return {0, 0, 0, 0};
|
||||
Vector2 CalcShift(BoundingBox rhs) {
|
||||
if (!CheckCollision(rhs)) {
|
||||
return {0, 0};
|
||||
}
|
||||
BoundingBox ret;
|
||||
ret.x = std::max(x, rhs.x);
|
||||
ret.y = std::max(y, rhs.y);
|
||||
ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x;
|
||||
ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y;
|
||||
return ret;
|
||||
|
||||
//DOCS: Given two BoundingBox objects, how does the other have to move so that they are no longer colliding?
|
||||
Vector2 horizontal = {0, 0};
|
||||
Vector2 vertical = {0, 0};
|
||||
|
||||
horizontal.x = std::abs(x + w - rhs.x) < std::abs(rhs.x + rhs.w - x) ? x + w - rhs.x -1 : -(rhs.x + rhs.w - x -1);
|
||||
vertical.y = std::abs(y + h - rhs.x) < std::abs(rhs.y + rhs.h - y) ? y + h - rhs.y -1 : -(rhs.y + rhs.h - y -1);
|
||||
|
||||
return std::abs(vertical.y) < std::abs(horizontal.x) ? vertical : horizontal;
|
||||
}
|
||||
};
|
||||
|
||||
//This is explicitly a POD
|
||||
static_assert(std::is_pod<BoundingBox>::value, "BoundingBox is not a POD");
|
||||
|
||||
#include "vector2.hpp"
|
||||
|
||||
//operators
|
||||
inline BoundingBox operator+(BoundingBox b, Vector2 v) {
|
||||
return {b.x + (int)v.x, b.y + (int)v.y, b.w, b.h};
|
||||
|
||||
@@ -20,7 +20,7 @@ release: clean all package
|
||||
#For use on my machine ONLY
|
||||
package:
|
||||
rar a -r -ep Tortuga.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll
|
||||
rar a -r Tortuga.rar rsc/* copyright.txt instructions.txt
|
||||
rar a -r Tortuga.rar rsc/* copyright.txt README.txt
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir $(OUTDIR)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
local doorUtility = {}
|
||||
|
||||
roomAPI = require("room")
|
||||
regionPagerAPI = require("region_pager")
|
||||
|
||||
triggerAPI = require("trigger")
|
||||
triggerManagerAPI = require("trigger_manager")
|
||||
|
||||
entityAPI = require("entity")
|
||||
characterAPI = require("character")
|
||||
|
||||
networkAPI = require("network")
|
||||
|
||||
function doorUtility.createTrigger(handle, room, x, y, script)
|
||||
local pager = roomAPI.GetPager(room)
|
||||
|
||||
--place the indicator tile
|
||||
regionPagerAPI.SetTile(pager, x / 32, y / 32, 0, mapMaker.dirt)
|
||||
regionPagerAPI.SetTile(pager, x / 32, y / 32, 1, mapMaker.blank)
|
||||
regionPagerAPI.SetTile(pager, x / 32, y / 32, 2, mapMaker.blank)
|
||||
|
||||
--create the trigger object
|
||||
triggerManagerAPI.Create(
|
||||
roomAPI.GetTriggerMgr(room), handle, x, y,
|
||||
0, 0, 32, 32, --size of the tiles
|
||||
script
|
||||
)
|
||||
end
|
||||
|
||||
function doorUtility.createDoorPair(handle, roomOne, Xone, Yone, roomTwo, Xtwo, Ytwo)
|
||||
--create the scripts
|
||||
local function scriptOne(entity)
|
||||
if entityAPI.GetType(entity) ~= "character" then return end
|
||||
|
||||
--move the character
|
||||
characterAPI.SetRoom(entity, roomTwo)
|
||||
characterAPI.SetOrigin(entity, Xtwo, Ytwo-16)
|
||||
networkAPI.PumpCharacterUpdate(entity)
|
||||
|
||||
--disable the other trigger
|
||||
local triggerTwo = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomTwo), handle)
|
||||
triggerAPI.PushExclusionEntity(triggerTwo, entity)
|
||||
end
|
||||
|
||||
local function scriptTwo(entity)
|
||||
if entityAPI.GetType(entity) ~= "character" then return end
|
||||
|
||||
--move the character
|
||||
characterAPI.SetRoom(entity, roomOne)
|
||||
characterAPI.SetOrigin(entity, Xone, Yone-16) --NOTE: the 16 pixel margin for presentation
|
||||
networkAPI.PumpCharacterUpdate(entity)
|
||||
|
||||
--disable the other trigger
|
||||
local triggerOne = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomOne), handle)
|
||||
triggerAPI.PushExclusionEntity(triggerOne, entity)
|
||||
end
|
||||
|
||||
--create the triggers proper
|
||||
doorUtility.createTrigger(handle, roomOne, Xone, Yone, scriptOne)
|
||||
doorUtility.createTrigger(handle, roomTwo, Xtwo, Ytwo, scriptTwo)
|
||||
end
|
||||
|
||||
return doorUtility
|
||||
+25
-45
@@ -1,4 +1,4 @@
|
||||
local regionAPI = require("region")
|
||||
local Region = require("map_system").Region
|
||||
|
||||
local mapMaker = {}
|
||||
|
||||
@@ -7,7 +7,6 @@ function mapMaker.Sqr(x) return x*x end
|
||||
function mapMaker.Dist(x, y, i, j) return math.sqrt(mapMaker.Sqr(x - i) + mapMaker.Sqr(y - j)) end
|
||||
|
||||
--tile macros, mapped to the tilesheet "overworld.bmp"
|
||||
mapMaker.blank = 0
|
||||
mapMaker.water = 18 + 3 * 0
|
||||
mapMaker.sand = 18 + 3 * 1
|
||||
mapMaker.plains = 18 + 3 * 2
|
||||
@@ -21,43 +20,42 @@ mapMaker.edges.south = 16
|
||||
mapMaker.edges.east = 1
|
||||
mapMaker.edges.west = -1
|
||||
|
||||
--TODO: (1) path system
|
||||
--use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges
|
||||
function mapMaker.SmoothEdgesSimple(r)
|
||||
--make and pad an array to use
|
||||
local shiftArray = {}
|
||||
for i = 1, regionAPI.GetWidth(r) do
|
||||
for i = 1, Region.GetWidth(r) do
|
||||
shiftArray[i] = {}
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
for j = 1, Region.GetHeight(r) do
|
||||
shiftArray[i][j] = 0
|
||||
end
|
||||
end
|
||||
|
||||
--build the array
|
||||
for i = 1, regionAPI.GetWidth(r) do
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
--if (not regionAPI edge) and (west tile < this tile), etc.
|
||||
if i > 1 and regionAPI.GetTile(r, i - 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||
for i = 1, Region.GetWidth(r) do
|
||||
for j = 1, Region.GetHeight(r) do
|
||||
--if (not region edge) and (west tile < this tile), etc.
|
||||
if i > 1 and Region.GetTile(r, i - 1, j, 1) < Region.GetTile(r, i, j, 1) then
|
||||
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.west
|
||||
end
|
||||
if j > 1 and regionAPI.GetTile(r, i, j - 1, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||
if j > 1 and Region.GetTile(r, i, j - 1, 1) < Region.GetTile(r, i, j, 1) then
|
||||
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.north
|
||||
end
|
||||
if i < regionAPI.GetWidth(r) and regionAPI.GetTile(r, i + 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||
if i < Region.GetWidth(r) and Region.GetTile(r, i + 1, j, 1) < Region.GetTile(r, i, j, 1) then
|
||||
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.east
|
||||
end
|
||||
if j < regionAPI.GetHeight(r) and regionAPI.GetTile(r, i, j + 1, 1) < regionAPI.GetTile(r, i, j, 1) then
|
||||
if j < Region.GetHeight(r) and Region.GetTile(r, i, j + 1, 1) < Region.GetTile(r, i, j, 1) then
|
||||
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.south
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--finally apply this
|
||||
for i = 1, regionAPI.GetWidth(r) do
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
for i = 1, Region.GetWidth(r) do
|
||||
for j = 1, Region.GetHeight(r) do
|
||||
if shiftArray[i][j] ~= 0 then
|
||||
regionAPI.SetTile(r, i, j, 2, regionAPI.GetTile(r, i, j, 1) + shiftArray[i][j])
|
||||
regionAPI.SetTile(r, i, j, 1, regionAPI.GetTile(r, i, j, 1) - 3)
|
||||
Region.SetTile(r, i, j, 2, Region.GetTile(r, i, j, 1) + shiftArray[i][j])
|
||||
Region.SetTile(r, i, j, 1, Region.GetTile(r, i, j, 1) - 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -65,31 +63,28 @@ end
|
||||
|
||||
--custom generation systems here
|
||||
function mapMaker.DebugIsland(r)
|
||||
--debug
|
||||
io.write("map_maker:DebugIsland(", regionAPI.GetX(r), ", ", regionAPI.GetY(r), ")\n")
|
||||
|
||||
--basic distance check for each tile, placing an island around the world origin
|
||||
for i = 1, regionAPI.GetWidth(r) do
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
local dist = mapMaker.Dist(0, 0, i + regionAPI.GetX(r) -1, j + regionAPI.GetY(r) -1)
|
||||
for i = 1, Region.GetWidth(r) do
|
||||
for j = 1, Region.GetHeight(r) do
|
||||
local dist = mapMaker.Dist(0, 0, i + Region.GetX(r) -1, j + Region.GetY(r) -1)
|
||||
if dist < 10 then
|
||||
regionAPI.SetTile(r, i, j, 1, mapMaker.plains)
|
||||
Region.SetTile(r, i, j, 1, mapMaker.plains)
|
||||
elseif dist < 12 then
|
||||
regionAPI.SetTile(r, i, j, 1, mapMaker.sand)
|
||||
Region.SetTile(r, i, j, 1, mapMaker.sand)
|
||||
else
|
||||
regionAPI.SetTile(r, i, j, 1, mapMaker.water)
|
||||
regionAPI.SetSolid(r, i, j, true)
|
||||
Region.SetTile(r, i, j, 1, mapMaker.water)
|
||||
Region.SetSolid(r, i, j, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--examples of the smoothing function NOT working correctly
|
||||
--[[
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
regionAPI.SetTile(r, 3, j, 1, mapMaker.dirt)
|
||||
regionAPI.SetTile(r, 4, j, 1, mapMaker.dirt)
|
||||
for j = 1, Region.GetHeight(r) do
|
||||
Region.SetTile(r, 3, j, 1, mapMaker.dirt)
|
||||
Region.SetTile(r, 4, j, 1, mapMaker.dirt)
|
||||
|
||||
regionAPI.SetTile(r, 10, j, 1, mapMaker.dirt)
|
||||
Region.SetTile(r, 10, j, 1, mapMaker.dirt)
|
||||
end
|
||||
--]]
|
||||
|
||||
@@ -97,19 +92,4 @@ function mapMaker.DebugIsland(r)
|
||||
mapMaker.SmoothEdgesSimple(r)
|
||||
end
|
||||
|
||||
function mapMaker.DebugGrassland(r)
|
||||
--debug
|
||||
io.write("map_maker:DebugGrassland(", regionAPI.GetX(r), ", ", regionAPI.GetY(r), ")\n")
|
||||
|
||||
--all dirt
|
||||
for i = 1, regionAPI.GetWidth(r) do
|
||||
for j = 1, regionAPI.GetHeight(r) do
|
||||
regionAPI.SetTile(r, i, j, 1, mapMaker.grass)
|
||||
end
|
||||
end
|
||||
|
||||
--A generic edge system
|
||||
-- mapMaker.SmoothEdgesSimple(r)
|
||||
end
|
||||
|
||||
return mapMaker
|
||||
@@ -1,15 +1,15 @@
|
||||
local region = require("region")
|
||||
local Region = require("map_system").Region
|
||||
|
||||
local mapSaver = {}
|
||||
|
||||
function mapSaver.Load(r)
|
||||
--empty
|
||||
-- io.write("map_saver:Load(", region.GetX(r), ", ", region.GetY(r), ")\n")
|
||||
io.write("map_saver:Load(", Region.GetX(r), ", ", Region.GetY(r), ")\n")
|
||||
end
|
||||
function mapSaver.Save(r)
|
||||
--empty
|
||||
-- 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
|
||||
|
||||
--TODO: (3) create a flexible saving & loading system
|
||||
--TODO: create a flexible saving & loading system
|
||||
return mapSaver
|
||||
@@ -1,36 +1,18 @@
|
||||
print("Lua script check")
|
||||
|
||||
--requirements
|
||||
roomManagerAPI = require("room_manager")
|
||||
roomAPI = require("room")
|
||||
|
||||
mapMaker = require("map_maker")
|
||||
mapSaver = require("map_saver")
|
||||
roomSystem = require("room_system")
|
||||
|
||||
doorUtility = require("door_utility")
|
||||
|
||||
--test the room hooks
|
||||
roomManagerAPI.SetOnCreate(function(room, index)
|
||||
print("", "Creating room: ", roomAPI.GetName(room), index)
|
||||
|
||||
roomAPI.SetOnTick(room, function(room)
|
||||
roomAPI.ForEachCharacter(room, function(character)
|
||||
--
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
roomManagerAPI.SetOnUnload(function(room, index)
|
||||
print("", "Unloading room: ", roomAPI.GetName(room), index)
|
||||
end)
|
||||
local function dumpTable(t)
|
||||
print(t)
|
||||
for k, v in pairs(t) do
|
||||
print("",k,v)
|
||||
end
|
||||
end
|
||||
|
||||
--NOTE: room 0 is the first that the client asks for, therefore it must exist
|
||||
local overworld, uidOne = roomManagerAPI.CreateRoom("overworld", "overworld.bmp")
|
||||
roomAPI.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
|
||||
local underworld, uidTwo = roomManagerAPI.CreateRoom("underworld", "overworld.bmp")
|
||||
roomAPI.Initialize(underworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugGrassland, mapSaver.Save)
|
||||
|
||||
--call the monstrosity
|
||||
doorUtility.createDoorPair("pair 1", overworld, -64, -64, underworld, 64, 64)
|
||||
local overworld, uid = roomSystem.RoomManager.CreateRoom("overworld", "overworld.bmp")
|
||||
roomSystem.Room.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
|
||||
|
||||
print("Finished the lua script")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
--TODO: (3) An archive table of all dead characters
|
||||
--TODO: An archive table of all dead characters
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Accounts (
|
||||
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username varchar(100) UNIQUE, --TODO: (3) Swap username for email address
|
||||
username varchar(100) UNIQUE,
|
||||
|
||||
--server-client security
|
||||
--TODO: server-client security
|
||||
-- passhash varchar(100),
|
||||
-- passsalt varchar(100),
|
||||
|
||||
@@ -24,14 +24,10 @@ CREATE TABLE IF NOT EXISTS Characters (
|
||||
avatar varchar(100),
|
||||
birth timestamp NOT NULL DEFAULT (datetime()),
|
||||
|
||||
--physically exists in the world
|
||||
--position in the world
|
||||
roomIndex INTEGER DEFAULT 0,
|
||||
originX INTEGER DEFAULT 0,
|
||||
originY INTEGER DEFAULT 0,
|
||||
boundsX INTEGER DEFAULT 0,
|
||||
boundsY INTEGER DEFAULT 0,
|
||||
boundsW INTEGER DEFAULT 0,
|
||||
boundsH INTEGER DEFAULT 0,
|
||||
|
||||
--statistics
|
||||
baseStats INTEGER REFERENCES StatisticSets(uid),
|
||||
@@ -105,5 +101,5 @@ CREATE TABLE IF NOT EXISTS WornEquipment (
|
||||
--unique information
|
||||
durability INTEGER DEFAULT 0,
|
||||
stats INTEGER REFERENCES StatisticSets(uid)
|
||||
--attached script?
|
||||
--TODO: attached script?
|
||||
);
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
|
||||
int clientIndex;
|
||||
std::string username;
|
||||
//password/auth token
|
||||
//TODO: password
|
||||
|
||||
//bit fields?
|
||||
bool blackListed = false;
|
||||
|
||||
@@ -28,31 +28,15 @@
|
||||
//-------------------------
|
||||
|
||||
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);";
|
||||
|
||||
static const char* LOAD_USER_ACCOUNT = "SELECT "
|
||||
"uid, "
|
||||
"blacklisted, "
|
||||
"whitelisted, "
|
||||
"mod, "
|
||||
"admin "
|
||||
" FROM Accounts WHERE username = ?;";
|
||||
|
||||
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET "
|
||||
"blacklisted = ?2, "
|
||||
"whitelisted = ?3, "
|
||||
"mod = ?4, "
|
||||
"admin = ?5 "
|
||||
"WHERE uid = ?1;";
|
||||
|
||||
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM Accounts WHERE username = ?;";
|
||||
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted = ?2, whitelisted = ?3, mod = ?4, admin = ?5 WHERE uid = ?1;";
|
||||
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
|
||||
|
||||
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
|
||||
|
||||
//-------------------------
|
||||
//Define the public methods
|
||||
//-------------------------
|
||||
|
||||
//TODO: (1) block blacklisted accounts
|
||||
int AccountManager::Create(std::string username, int clientIndex) {
|
||||
//create this user account, failing if it exists, leave this account in memory
|
||||
sqlite3_stmt* statement = nullptr;
|
||||
@@ -110,11 +94,11 @@ int AccountManager::Load(std::string username, int clientIndex) {
|
||||
|
||||
//extract the data into memory
|
||||
AccountData& newAccount = elementMap[uid];
|
||||
newAccount.username = username;
|
||||
newAccount.blackListed = sqlite3_column_int(statement, 1);
|
||||
newAccount.whiteListed = sqlite3_column_int(statement, 2);
|
||||
newAccount.mod = sqlite3_column_int(statement, 3);
|
||||
newAccount.admin = sqlite3_column_int(statement, 4);
|
||||
newAccount.username = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
||||
newAccount.blackListed = sqlite3_column_int(statement, 2);
|
||||
newAccount.whiteListed = sqlite3_column_int(statement, 3);
|
||||
newAccount.mod = sqlite3_column_int(statement, 4);
|
||||
newAccount.admin = sqlite3_column_int(statement, 5);
|
||||
newAccount.clientIndex = clientIndex;
|
||||
|
||||
//finish the routine
|
||||
|
||||
@@ -22,108 +22,12 @@
|
||||
#include "character_api.hpp"
|
||||
|
||||
#include "character_data.hpp"
|
||||
#include "character_manager.hpp"
|
||||
#include "entity_api.hpp"
|
||||
#include "room_manager.hpp"
|
||||
#include "server_utilities.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
static int setRoom(lua_State* L) {
|
||||
//reverse engineer the character index
|
||||
int characterIndex = -1;
|
||||
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||
|
||||
for (auto& it : *characterMgr.GetContainer()) {
|
||||
if (character == &it.second) {
|
||||
characterIndex = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//error checking
|
||||
if (characterIndex == -1) {
|
||||
throw(std::runtime_error("Lua Error: Failed to find character index by reference"));
|
||||
}
|
||||
|
||||
//get the room index, depending on the parameter type
|
||||
int roomIndex = -1;
|
||||
RoomManager& roomMgr = RoomManager::GetSingleton();
|
||||
switch(lua_type(L, 2)) {
|
||||
case LUA_TNUMBER:
|
||||
roomIndex = lua_tointeger(L, 2);
|
||||
break;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
//reverse engineer the room index
|
||||
for (auto& it : *roomMgr.GetContainer()) {
|
||||
if (lua_touserdata(L, 2) == &it.second) {
|
||||
roomIndex = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//error checking
|
||||
if (roomIndex == -1) {
|
||||
throw(std::runtime_error("Lua Error: Failed to find room index by reference"));
|
||||
}
|
||||
|
||||
//send the delete & create messages
|
||||
pumpAndChangeRooms(character, roomIndex, characterIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getOwner(lua_State* L) {
|
||||
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, character->GetOwner());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getHandle(lua_State* L) {
|
||||
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||
lua_pushstring(L, character->GetHandle().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getAvatar(lua_State* L) {
|
||||
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||
lua_pushstring(L, character->GetAvatar().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg characterLib[] = {
|
||||
{"SetRoom", setRoom},
|
||||
// {"GetOwner", getOwner}, //unusable without account API
|
||||
{"GetHandle", getHandle},
|
||||
{"GetAvatar", getAvatar},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openCharacterAPI(lua_State* L) {
|
||||
//get the parent table
|
||||
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
|
||||
|
||||
//the local table
|
||||
luaL_newlib(L, characterLib);
|
||||
|
||||
//merge the local table into the parent table
|
||||
lua_pushnil(L); //first key
|
||||
while(lua_next(L, -2)) {
|
||||
//copy the key-value pair
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
//push the copy to the parent table
|
||||
lua_settable(L, -6);
|
||||
|
||||
//pop the original value before continuing
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
//remove the local table, leaving the expanded parent table
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -21,10 +21,6 @@
|
||||
*/
|
||||
#include "character_data.hpp"
|
||||
|
||||
CharacterData::CharacterData(): Entity("character") {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
int CharacterData::GetOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,12 @@
|
||||
|
||||
class CharacterData: public Entity {
|
||||
public:
|
||||
CharacterData();
|
||||
CharacterData() = default;
|
||||
~CharacterData() = default;
|
||||
|
||||
//accessors and mutators
|
||||
//...
|
||||
|
||||
//database stuff
|
||||
int GetOwner();
|
||||
std::string GetHandle();
|
||||
@@ -43,7 +46,7 @@ public:
|
||||
private:
|
||||
friend class CharacterManager;
|
||||
|
||||
int owner = -1;
|
||||
int owner;
|
||||
std::string handle;
|
||||
std::string avatar;
|
||||
};
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include "character_defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -32,45 +30,10 @@
|
||||
//Define the queries
|
||||
//-------------------------
|
||||
|
||||
//NOTE: Programmer set variables are NOT zero-indexed
|
||||
//NOTE: SQLite3 returned variables (i.e. loading) ARE zero-indexed
|
||||
|
||||
static const char* CREATE_CHARACTER = "INSERT INTO Characters ("
|
||||
"owner, "
|
||||
"handle, "
|
||||
"avatar, "
|
||||
"boundsX, "
|
||||
"boundsY, "
|
||||
"boundsW, "
|
||||
"boundsH"
|
||||
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
|
||||
|
||||
static const char* LOAD_CHARACTER = "SELECT "
|
||||
"uid, "
|
||||
"owner, "
|
||||
"handle, "
|
||||
"avatar, "
|
||||
"roomIndex, "
|
||||
"originX, "
|
||||
"originY, "
|
||||
"boundsX, "
|
||||
"boundsY, "
|
||||
"boundsW, "
|
||||
"boundsH "
|
||||
"FROM Characters WHERE handle = ?;";
|
||||
|
||||
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET "
|
||||
"roomIndex = ?2, "
|
||||
"originX = ?3, "
|
||||
"originY = ?4, "
|
||||
"boundsX = ?5, "
|
||||
"boundsY = ?6, "
|
||||
"boundsW = ?7, "
|
||||
"boundsH = ?8 "
|
||||
"WHERE uid = ?1;";
|
||||
|
||||
static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, avatar) VALUES (?, ?, ?);";
|
||||
static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;";
|
||||
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET roomIndex = ?2, originX = ?3, originY = ?4 WHERE uid = ?1;";
|
||||
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
|
||||
|
||||
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
|
||||
|
||||
//-------------------------
|
||||
@@ -92,10 +55,6 @@ int CharacterManager::Create(int owner, std::string handle, std::string avatar)
|
||||
ret |= sqlite3_bind_int(statement, 1, owner);
|
||||
ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC);
|
||||
ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC);
|
||||
ret |= sqlite3_bind_int(statement, 4, CHARACTER_BOUNDS_X);
|
||||
ret |= sqlite3_bind_int(statement, 5, CHARACTER_BOUNDS_Y);
|
||||
ret |= sqlite3_bind_int(statement, 6, CHARACTER_BOUNDS_WIDTH);
|
||||
ret |= sqlite3_bind_int(statement, 7, CHARACTER_BOUNDS_HEIGHT);
|
||||
|
||||
//check for binding errors
|
||||
if (ret) {
|
||||
@@ -162,14 +121,9 @@ int CharacterManager::Load(int owner, std::string handle, std::string avatar) {
|
||||
//Don't cache the birth
|
||||
|
||||
//world origin
|
||||
newChar.roomIndex = sqlite3_column_int(statement, 4);
|
||||
newChar.origin.x = (double)sqlite3_column_int(statement, 5);
|
||||
newChar.origin.y = (double)sqlite3_column_int(statement, 6);
|
||||
//bounds
|
||||
newChar.bounds.x = (int)sqlite3_column_int(statement, 7);
|
||||
newChar.bounds.y = (int)sqlite3_column_int(statement, 8);
|
||||
newChar.bounds.w = (int)sqlite3_column_int(statement, 9);
|
||||
newChar.bounds.h = (int)sqlite3_column_int(statement, 10);
|
||||
newChar.roomIndex = sqlite3_column_int(statement, 5);
|
||||
newChar.origin.x = (double)sqlite3_column_int(statement, 6);
|
||||
newChar.origin.y = (double)sqlite3_column_int(statement, 7);
|
||||
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
|
||||
@@ -211,10 +165,6 @@ int CharacterManager::Save(int uid) {
|
||||
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 5, character.bounds.x) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 6, character.bounds.y) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 7, character.bounds.w) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_int(statement, 8, character.bounds.h) != SQLITE_OK;
|
||||
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
|
||||
@@ -243,7 +193,6 @@ void CharacterManager::Unload(int uid) {
|
||||
}
|
||||
|
||||
void CharacterManager::Delete(int uid) {
|
||||
//TODO: when deleting a character, move it to an archive table
|
||||
//delete this character from the database, then remove it from memory
|
||||
sqlite3_stmt* statement = nullptr;
|
||||
|
||||
@@ -303,15 +252,6 @@ CharacterData* CharacterManager::Get(int uid) {
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
CharacterData* CharacterManager::Get(std::string handle) {
|
||||
for (std::map<int, CharacterData>::iterator it = elementMap.begin(); it != elementMap.end(); ++it) {
|
||||
if (it->second.GetHandle() == handle) {
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int CharacterManager::GetLoadedCount() {
|
||||
return elementMap.size();
|
||||
}
|
||||
|
||||
@@ -44,18 +44,13 @@ public:
|
||||
|
||||
//accessors and mutators
|
||||
CharacterData* Get(int uid);
|
||||
CharacterData* Get(std::string handle);
|
||||
int GetLoadedCount();
|
||||
int GetTotalCount();
|
||||
std::map<int, CharacterData>* GetContainer();
|
||||
|
||||
//API interface
|
||||
sqlite3* SetDatabase(sqlite3* db);
|
||||
sqlite3* GetDatabase();
|
||||
|
||||
//hooks
|
||||
//TODO: character hooks
|
||||
|
||||
private:
|
||||
friend Singleton<CharacterManager>;
|
||||
|
||||
|
||||
@@ -23,88 +23,7 @@
|
||||
|
||||
#include "character_manager.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
//TODO: (1) character hooks?
|
||||
|
||||
static int setOnCreate(lua_State* L) {
|
||||
//TODO: (9) setOnCreate()
|
||||
}
|
||||
|
||||
static int setOnLoad(lua_State* L) {
|
||||
//TODO: (9) setOnLoad()
|
||||
}
|
||||
|
||||
static int setOnSave(lua_State* L) {
|
||||
//TODO: (9) setOnSave()
|
||||
}
|
||||
|
||||
static int setOnUnload(lua_State* L) {
|
||||
//TODO: (9) setOnUnload()
|
||||
}
|
||||
|
||||
static int setOnDelete(lua_State* L) {
|
||||
//TODO: (9) setOnDelete()
|
||||
}
|
||||
|
||||
static int getCharacter(lua_State* L) {
|
||||
//integer vs name
|
||||
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||
CharacterData* characterData = nullptr;
|
||||
|
||||
switch(lua_type(L, 1)) {
|
||||
case LUA_TNUMBER:
|
||||
characterData = characterMgr.Get(lua_tointeger(L, 1));
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
//access characters via their handles
|
||||
characterData = characterMgr.Get(lua_tostring(L, 1));
|
||||
break;
|
||||
}
|
||||
|
||||
if (characterData) {
|
||||
lua_pushlightuserdata(L, static_cast<void*>(characterData));
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getLoadedCount(lua_State* L) {
|
||||
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||
lua_pushinteger(L, characterMgr.GetLoadedCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int forEach(lua_State* L) {
|
||||
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||
//pass each character to the given function
|
||||
for (auto& it : *characterMgr.GetContainer()) {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_pushlightuserdata(L, static_cast<void*>(&it.second));
|
||||
//call each iteration, throwing an exception if something happened
|
||||
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
||||
std::ostringstream os;
|
||||
os << "Lua error: ";
|
||||
os << lua_tostring(L, -1);
|
||||
throw(std::runtime_error(os.str()));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg characterManagerLib[] = {
|
||||
// {"SetOnCreate", setOnCreate},
|
||||
// {"SetOnLoad", setOnLoad},
|
||||
// {"SetOnSave", setOnSave},
|
||||
// {"SetOnUnload", setOnUnload},
|
||||
// {"SetOnDelete", setOnDelete},
|
||||
{"GetCharacter", getCharacter},
|
||||
{"GetLoadedCount", getLoadedCount},
|
||||
{"ForEach", forEach},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#config
|
||||
INCLUDES+=. ../entities ../monsters ../rooms ../server_utilities ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
|
||||
INCLUDES+=. ../entities ../server_utilities ../../common/gameplay ../../common/utilities
|
||||
LIBS+=
|
||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||
|
||||
|
||||
@@ -21,15 +21,11 @@
|
||||
*/
|
||||
#include "client_manager.hpp"
|
||||
|
||||
#include "ip_operators.hpp"
|
||||
#include "udp_network_utility.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
std::list<int> ClientManager::CheckConnections() {
|
||||
//list of clients to disconnect
|
||||
std::list<int> returnList;
|
||||
|
||||
int ClientManager::CheckConnections() {
|
||||
for (auto& it : elementMap) {
|
||||
//3 seconds between beats
|
||||
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
||||
@@ -42,17 +38,21 @@ std::list<int> ClientManager::CheckConnections() {
|
||||
|
||||
for (auto& it : elementMap) {
|
||||
if (it.second.GetAttempts() > 2) {
|
||||
returnList.push_back(it.first);
|
||||
int ret = it.first;
|
||||
// elementMap.erase(it.first);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return returnList;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ClientManager::HandlePong(ServerPacket* const argPacket) {
|
||||
//find and update the specified client
|
||||
for (auto& it : elementMap) {
|
||||
if (it.second.GetAddress() == argPacket->srcAddress) {
|
||||
if (it.second.GetAddress().host == argPacket->srcAddress.host &&
|
||||
it.second.GetAddress().port == argPacket->srcAddress.port
|
||||
) {
|
||||
it.second.ResetAttempts();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
#include "SDL/SDL_net.h"
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
class ClientManager: public Singleton<ClientManager> {
|
||||
public:
|
||||
//methods
|
||||
std::list<int> CheckConnections();
|
||||
int CheckConnections();
|
||||
void HandlePong(ServerPacket* const argPacket);
|
||||
|
||||
//common public methods
|
||||
|
||||
@@ -21,14 +21,6 @@
|
||||
*/
|
||||
#include "entity.hpp"
|
||||
|
||||
Entity::Entity(const char* _type): type(_type) {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
void Entity::Update() {
|
||||
origin += motion;
|
||||
}
|
||||
|
||||
int Entity::SetRoomIndex(int i) {
|
||||
return roomIndex = i;
|
||||
}
|
||||
@@ -41,10 +33,6 @@ Vector2 Entity::SetMotion(Vector2 v) {
|
||||
return motion = v;
|
||||
}
|
||||
|
||||
BoundingBox Entity::SetBounds(BoundingBox b) {
|
||||
return bounds = b;
|
||||
}
|
||||
|
||||
int Entity::GetRoomIndex() const {
|
||||
return roomIndex;
|
||||
}
|
||||
@@ -55,12 +43,4 @@ Vector2 Entity::GetOrigin() const {
|
||||
|
||||
Vector2 Entity::GetMotion() const {
|
||||
return motion;
|
||||
}
|
||||
|
||||
BoundingBox Entity::GetBounds() const {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
const char* Entity::GetType() const {
|
||||
return type;
|
||||
}
|
||||
@@ -22,38 +22,27 @@
|
||||
#ifndef ENTITY_HPP_
|
||||
#define ENTITY_HPP_
|
||||
|
||||
#include "bounding_box.hpp"
|
||||
#include "vector2.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
//The base class for all objects in the world
|
||||
class Entity {
|
||||
public:
|
||||
virtual void Update();
|
||||
|
||||
//accessors & mutators
|
||||
int SetRoomIndex(int i);
|
||||
Vector2 SetOrigin(Vector2 v);
|
||||
Vector2 SetMotion(Vector2 v);
|
||||
BoundingBox SetBounds(BoundingBox b);
|
||||
|
||||
int GetRoomIndex() const;
|
||||
Vector2 GetOrigin() const;
|
||||
Vector2 GetMotion() const;
|
||||
BoundingBox GetBounds() const;
|
||||
|
||||
const char* GetType() const;
|
||||
|
||||
protected:
|
||||
Entity(const char*);
|
||||
Entity() = default;
|
||||
virtual ~Entity() = default;
|
||||
|
||||
int roomIndex = -1;
|
||||
Vector2 origin = {0, 0};
|
||||
Vector2 motion = {0, 0};
|
||||
BoundingBox bounds = {0, 0, 0, 0};
|
||||
const char* type;
|
||||
Vector2 origin;
|
||||
Vector2 motion;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -41,17 +41,6 @@ static int setMotion(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setBounds(lua_State* L) {
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||
entity->SetBounds({
|
||||
lua_tointeger(L, 2),
|
||||
lua_tointeger(L, 3),
|
||||
lua_tointeger(L, 4),
|
||||
lua_tointeger(L, 5)
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getRoomIndex(lua_State* L) {
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, entity->GetRoomIndex());
|
||||
@@ -67,36 +56,18 @@ static int getOrigin(lua_State* L) {
|
||||
|
||||
static int getMotion(lua_State* L) {
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||
lua_pushnumber(L, entity->GetMotion().x);
|
||||
lua_pushnumber(L, entity->GetMotion().y);
|
||||
lua_pushnumber(L, entity->GetOrigin().x);
|
||||
lua_pushnumber(L, entity->GetOrigin().y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int getBounds(lua_State* L) {
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, entity->GetBounds().x);
|
||||
lua_pushinteger(L, entity->GetBounds().y);
|
||||
lua_pushinteger(L, entity->GetBounds().w);
|
||||
lua_pushinteger(L, entity->GetBounds().h);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int getType(lua_State* L) {
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
||||
lua_pushstring(L, entity->GetType());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg entityLib[] = {
|
||||
{"SetRoomIndex", setRoomIndex},
|
||||
{"SetOrigin", setOrigin},
|
||||
{"SetMotion", setMotion},
|
||||
{"SetBounds", setBounds},
|
||||
{"GetRoomIndex", getRoomIndex},
|
||||
{"GetOrigin", getOrigin},
|
||||
{"GetMotion", getMotion},
|
||||
{"GetBounds", getBounds},
|
||||
{"GetType", getType},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
||||
+10
-23
@@ -37,17 +37,10 @@
|
||||
#include "lua.hpp"
|
||||
|
||||
#include "entity_api.hpp"
|
||||
#include "character_api.hpp"
|
||||
#include "character_manager_api.hpp"
|
||||
#include "region_api.hpp"
|
||||
#include "region_pager_api.hpp"
|
||||
#include "monster_api.hpp"
|
||||
#include "monster_manager_api.hpp"
|
||||
#include "network_api.hpp"
|
||||
#include "room_api.hpp"
|
||||
#include "room_manager_api.hpp"
|
||||
#include "trigger_api.hpp"
|
||||
#include "trigger_manager_api.hpp"
|
||||
#include "map_system_api.hpp"
|
||||
#include "monster_system_api.hpp"
|
||||
#include "room_system_api.hpp"
|
||||
#include "waypoint_system_api.hpp"
|
||||
|
||||
//these libs are loaded by lua.c and are readily available to any Lua program
|
||||
static const luaL_Reg loadedlibs[] = {
|
||||
@@ -65,20 +58,14 @@ static const luaL_Reg loadedlibs[] = {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
//these libs are preloaded and must be required before used
|
||||
static const luaL_Reg preloadedlibs[] = {
|
||||
{TORTUGA_ENTITY_API, openEntityAPI}, //required by derived classes
|
||||
{TORTUGA_CHARACTER_API, openCharacterAPI},
|
||||
{TORTUGA_CHARACTER_MANAGER_API, openCharacterManagerAPI},
|
||||
{TORTUGA_MONSTER_API, openMonsterAPI},
|
||||
{TORTUGA_MONSTER_MANAGER_API, openMonsterManagerAPI},
|
||||
{TORTUGA_NETWORK_API, openNetworkAPI},
|
||||
{TORTUGA_REGION_API, openRegionAPI},
|
||||
{TORTUGA_REGION_PAGER_API, openRegionPagerAPI},
|
||||
{TORTUGA_ROOM_API, openRoomAPI},
|
||||
{TORTUGA_ROOM_MANAGER_API, openRoomManagerAPI},
|
||||
{TORTUGA_TRIGGER_API, openTriggerAPI},
|
||||
{TORTUGA_TRIGGER_MANAGER_API, openTriggerManagerAPI},
|
||||
{TORTUGA_ENTITY_API, openEntityAPI},
|
||||
{TORTUGA_MAP_SYSTEM_API, openMapSystemAPI},
|
||||
{TORTUGA_MONSTER_SYSTEM_API, openMonsterSystemAPI},
|
||||
{TORTUGA_ROOM_SYSTEM_API, openRoomSystemAPI},
|
||||
{TORTUGA_WAYPOINT_SYSTEM_API, openWaypointSystemAPI},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "config_utility.hpp"
|
||||
#include "room_manager.hpp"
|
||||
#include "udp_network_utility.hpp"
|
||||
#include "waypoint_manager.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#include directories
|
||||
INCLUDES+=. accounts characters clients entities monsters rooms server_utilities triggers ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
|
||||
INCLUDES+=. accounts characters clients entities monsters rooms server_utilities waypoints ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
|
||||
|
||||
#libraries
|
||||
#the order of the $(LIBS) is important, at least for MinGW
|
||||
@@ -32,7 +32,7 @@ all: $(OBJ) $(OUT)
|
||||
$(MAKE) -C monsters
|
||||
$(MAKE) -C rooms
|
||||
$(MAKE) -C server_utilities
|
||||
$(MAKE) -C triggers
|
||||
$(MAKE) -C waypoints
|
||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||
|
||||
$(OBJ): | $(OBJDIR)
|
||||
|
||||
@@ -61,27 +61,27 @@ static const luaL_Reg monsterLib[] = {
|
||||
};
|
||||
|
||||
LUAMOD_API int openMonsterAPI(lua_State* L) {
|
||||
//get the parent table
|
||||
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
|
||||
|
||||
//the local table
|
||||
luaL_newlib(L, monsterLib);
|
||||
|
||||
//merge the local table into the parent table
|
||||
//get the parent table
|
||||
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
|
||||
|
||||
//clone the parent table into the local table
|
||||
lua_pushnil(L); //first key
|
||||
while(lua_next(L, -2)) {
|
||||
//copy the key-value pair
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
//push the copy to the parent table
|
||||
//push the copy to the local table
|
||||
lua_settable(L, -6);
|
||||
|
||||
//pop the original value before continuing
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
//remove the local table, leaving the expanded parent table
|
||||
//remove the parent table, leaving the expanded child table
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
*/
|
||||
#include "monster_data.hpp"
|
||||
|
||||
MonsterData::MonsterData(): Entity("monster") {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
std::string MonsterData::SetAvatar(std::string s) {
|
||||
return avatar = s;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@
|
||||
|
||||
#include "entity.hpp"
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class MonsterData: public Entity {
|
||||
public:
|
||||
MonsterData();
|
||||
MonsterData() = default;
|
||||
~MonsterData() = default;
|
||||
|
||||
std::string SetAvatar(std::string);
|
||||
@@ -43,7 +41,7 @@ private:
|
||||
friend class MonsterManager;
|
||||
|
||||
std::string avatar;
|
||||
int scriptRef = LUA_NOREF;
|
||||
int scriptRef;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -30,45 +30,45 @@ MonsterManager::~MonsterManager() {
|
||||
}
|
||||
|
||||
int MonsterManager::Create(std::string) {
|
||||
//TODO: (9) MonsterManager::Create()
|
||||
//TODO
|
||||
}
|
||||
|
||||
void MonsterManager::Unload(int uid) {
|
||||
//TODO: (9) MonsterManager::Unload()
|
||||
//TODO
|
||||
}
|
||||
|
||||
void MonsterManager::UnloadAll() {
|
||||
//TODO: (9) MonsterManager::UnloadAll()
|
||||
//TODO
|
||||
}
|
||||
|
||||
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) {
|
||||
//TODO: (9) MonsterManager::UnloadIf()
|
||||
//TODO
|
||||
}
|
||||
|
||||
MonsterData* MonsterManager::Get(int uid) {
|
||||
//TODO: (9) MonsterManager::Get()
|
||||
//TODO
|
||||
}
|
||||
|
||||
int MonsterManager::GetLoadedCount() {
|
||||
//TODO: (9) MonsterManager::GetLoadedCount()
|
||||
//TODO
|
||||
}
|
||||
|
||||
std::map<int, MonsterData>* MonsterManager::GetContainer() {
|
||||
//TODO: (9) MonsterManager::GetContainer()
|
||||
//TODO
|
||||
}
|
||||
|
||||
lua_State* MonsterManager::SetLuaState(lua_State* L) {
|
||||
//TODO: (9) MonsterManager::SetLuaState()
|
||||
//TODO
|
||||
}
|
||||
|
||||
lua_State* MonsterManager::GetLuaState() {
|
||||
//TODO: (9) MonsterManager::GetLuaState()
|
||||
//TODO
|
||||
}
|
||||
|
||||
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
|
||||
//TODO: (9) MonsterManager::SetDatabase()
|
||||
//TODO
|
||||
}
|
||||
|
||||
sqlite3* MonsterManager::GetDatabase() {
|
||||
//TODO: (9) MonsterManager::GetDatabase()
|
||||
//TODO
|
||||
}
|
||||
|
||||
@@ -19,16 +19,37 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "server_application.hpp"
|
||||
#include "monster_system_api.hpp"
|
||||
|
||||
void ServerApplication::hTextBroadcast(TextPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hTextBroadcast()
|
||||
}
|
||||
//all monster API headers
|
||||
#include "monster_api.hpp"
|
||||
#include "monster_manager_api.hpp"
|
||||
|
||||
void ServerApplication::hTextSpeech(TextPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hTextSpeech()
|
||||
}
|
||||
//useful "globals"
|
||||
//...
|
||||
|
||||
void ServerApplication::hTextWhisper(TextPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hTextWhisper()
|
||||
//This mimics linit.c to create a nested collection of all monster modules.
|
||||
static const luaL_Reg funcs[] = {
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const luaL_Reg libs[] = {
|
||||
{"Monster", openMonsterAPI},
|
||||
{"MonsterManager", openMonsterManagerAPI},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
int openMonsterSystemAPI(lua_State* L) {
|
||||
//create the table
|
||||
luaL_newlibtable(L, libs);
|
||||
|
||||
//push the "global" functions
|
||||
luaL_setfuncs(L, funcs, 0);
|
||||
|
||||
//push the substable
|
||||
for (const luaL_Reg* lib = libs; lib->func; lib++) {
|
||||
lib->func(L);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef TRIGGERMANAGERAPI_HPP_
|
||||
#define TRIGGERMANAGERAPI_HPP_
|
||||
#ifndef MONSTERSYSTEMAPI_HPP_
|
||||
#define MONSTERSYSTEMAPI_HPP_
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_TRIGGER_MANAGER_API "trigger_manager"
|
||||
LUAMOD_API int openTriggerManagerAPI(lua_State* L);
|
||||
#define TORTUGA_MONSTER_SYSTEM_API "monster_system"
|
||||
LUAMOD_API int openMonsterSystemAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
@@ -1,73 +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 "network_api.hpp"
|
||||
|
||||
#include "character_data.hpp"
|
||||
#include "character_manager.hpp"
|
||||
#include "server_utilities.hpp"
|
||||
|
||||
static int pumpCharacterUpdate(lua_State* L) {
|
||||
CharacterData* characterData = static_cast<CharacterData*>(lua_touserdata(L, 1));
|
||||
|
||||
//determine the character's index
|
||||
int index = -1;
|
||||
for (auto const& it : *CharacterManager::GetSingleton().GetContainer()) {
|
||||
if(characterData == &it.second) {
|
||||
index = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//signal an error
|
||||
if (index == -1) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//fill the packet with all of this character's data
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_UPDATE;
|
||||
newPacket.characterIndex = index;
|
||||
strncpy(newPacket.handle, characterData->GetHandle().c_str(), PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.avatar, characterData->GetAvatar().c_str(), PACKET_STRING_SIZE);
|
||||
newPacket.accountIndex = characterData->GetOwner();
|
||||
newPacket.roomIndex = characterData->GetRoomIndex();
|
||||
newPacket.origin = characterData->GetOrigin();
|
||||
newPacket.motion = characterData->GetMotion();
|
||||
|
||||
//pump to the room
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
|
||||
//signal success
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg networkLib[] = {
|
||||
{"PumpCharacterUpdate", pumpCharacterUpdate},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openNetworkAPI(lua_State* L) {
|
||||
luaL_newlib(L, networkLib);
|
||||
return 1;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#config
|
||||
INCLUDES+=. ../characters ../entities ../monsters ../server_utilities ../triggers ../../common/gameplay ../../common/map ../../common/utilities
|
||||
INCLUDES+=. ../characters ../entities ../monsters ../server_utilities ../waypoints ../../common/gameplay ../../common/map ../../common/utilities
|
||||
LIBS+=
|
||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
#include "room_data.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
static int setRoomName(lua_State* L) {
|
||||
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
|
||||
room->SetName(lua_tostring(L, 2));
|
||||
@@ -62,45 +59,14 @@ static int getMonsterMgr(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getTriggerMgr(lua_State* L) {
|
||||
static int getWaypointMgr(lua_State* L) {
|
||||
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
|
||||
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetTriggerMgr()) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
//TODO: character list
|
||||
|
||||
static int forEachCharacter(lua_State* L) {
|
||||
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
|
||||
//pass each character to the given function
|
||||
for (auto& it : *room->GetCharacterList()) {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_pushlightuserdata(L, static_cast<void*>(it));
|
||||
//call each iteration, throwing an exception if something happened
|
||||
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
||||
std::ostringstream os;
|
||||
os << "Lua error: ";
|
||||
os << lua_tostring(L, -1);
|
||||
throw(std::runtime_error(os.str()));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setOnTick(lua_State* L) {
|
||||
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, room->GetTickReference());
|
||||
room->SetTickReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getOnTick(lua_State* L) {
|
||||
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, room->GetTickReference());
|
||||
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetWaypointMgr()) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
//set the refs of these parameters (backwards, since it pops from the top of the stack)
|
||||
@@ -121,12 +87,7 @@ static const luaL_Reg roomLib[] = {
|
||||
|
||||
{"GetPager",getPager},
|
||||
{"GetMonsterMgr",getMonsterMgr},
|
||||
{"GetTriggerMgr",getTriggerMgr},
|
||||
|
||||
{"ForEachCharacter", forEachCharacter},
|
||||
|
||||
{"SetOnTick", setOnTick},
|
||||
{"GetOnTick", getOnTick},
|
||||
{"GetWaypointMgr",getWaypointMgr},
|
||||
|
||||
{"Initialize", initialize},
|
||||
{nullptr, nullptr}
|
||||
|
||||
+2
-113
@@ -21,87 +21,6 @@
|
||||
*/
|
||||
#include "room_data.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
|
||||
//TODO: (9) character collisions should be preformed client-side
|
||||
void RoomData::RunFrame() {
|
||||
//get the hook
|
||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, tickRef);
|
||||
|
||||
if (!lua_isnil(lua, -1)) {
|
||||
//call the tick function, with this as a parameter
|
||||
lua_pushlightuserdata(lua, this);
|
||||
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
||||
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
|
||||
}
|
||||
}
|
||||
else {
|
||||
lua_pop(lua, 1);
|
||||
}
|
||||
|
||||
//update the entities in the room
|
||||
for (auto& it : characterList) {
|
||||
it->Update();
|
||||
}
|
||||
//TODO: (3) iterate through the monster map
|
||||
//TODO: (3) trigger script for monsters
|
||||
|
||||
//build a list of game entities
|
||||
std::stack<Entity*> entityStack;
|
||||
for (auto& it : characterList) {
|
||||
entityStack.push(it);
|
||||
}
|
||||
//TODO: (3) push the monster entities
|
||||
|
||||
//compare the triggers to the entities, using their real hitboxes
|
||||
//NOTE: this stack solution should prevent problems when modifying the various lists
|
||||
while(entityStack.size()) {
|
||||
//get the entity & hitbox
|
||||
Entity* entity = entityStack.top();
|
||||
BoundingBox entityBox = entity->GetBounds() + entity->GetOrigin();
|
||||
|
||||
//get the trigger pair & hitbox
|
||||
for (auto& triggerPair : *triggerMgr.GetContainer()) {
|
||||
BoundingBox triggerBox = triggerPair.second.GetBoundingBox() + triggerPair.second.GetOrigin();
|
||||
|
||||
//find all collisions
|
||||
if (entityBox.CheckOverlap(triggerBox)) {
|
||||
//skip members of the exclusion list
|
||||
if (std::any_of(triggerPair.second.GetExclusionList()->begin(), triggerPair.second.GetExclusionList()->end(), [entity](Entity* ptr) -> bool {
|
||||
return entity == ptr;
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//run the trigger script
|
||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, triggerPair.second.GetScriptReference());
|
||||
lua_pushlightuserdata(lua, entity);
|
||||
|
||||
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
||||
//error
|
||||
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
|
||||
}
|
||||
|
||||
//push to the exclusion list
|
||||
triggerPair.second.GetExclusionList()->push_back(entity);
|
||||
}
|
||||
else {
|
||||
//remove members of the exclusion list
|
||||
//NOTE: characters in different rooms won't be removed, but that shouldn't be a problem
|
||||
triggerPair.second.GetExclusionList()->remove_if([entity](Entity* ptr) -> bool {
|
||||
return entity == ptr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//next
|
||||
entityStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
std::string RoomData::SetName(std::string s) {
|
||||
return roomName = s;
|
||||
}
|
||||
@@ -126,40 +45,10 @@ MonsterManager* RoomData::GetMonsterMgr() {
|
||||
return &monsterMgr;
|
||||
}
|
||||
|
||||
TriggerManager* RoomData::GetTriggerMgr() {
|
||||
return &triggerMgr;
|
||||
WaypointManager* RoomData::GetWaypointMgr() {
|
||||
return &waypointMgr;
|
||||
}
|
||||
|
||||
std::list<CharacterData*>* RoomData::GetCharacterList() {
|
||||
return &characterList;
|
||||
}
|
||||
|
||||
lua_State* RoomData::SetLuaState(lua_State* L) {
|
||||
lua = L;
|
||||
pager.SetLuaState(lua);
|
||||
monsterMgr.SetLuaState(lua);
|
||||
triggerMgr.SetLuaState(lua);
|
||||
return lua;
|
||||
}
|
||||
|
||||
lua_State* RoomData::GetLuaState() {
|
||||
return lua;
|
||||
}
|
||||
|
||||
sqlite3* RoomData::SetDatabase(sqlite3* db) {
|
||||
database = db;
|
||||
monsterMgr.SetDatabase(database);
|
||||
return database;
|
||||
}
|
||||
|
||||
sqlite3* RoomData::GetDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
int RoomData::SetTickReference(int i) {
|
||||
return tickRef = i;
|
||||
}
|
||||
|
||||
int RoomData::GetTickReference() {
|
||||
return tickRef;
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "character_data.hpp"
|
||||
#include "monster_manager.hpp"
|
||||
#include "region_pager_lua.hpp"
|
||||
#include "trigger_manager.hpp"
|
||||
#include "waypoint_manager.hpp"
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
@@ -37,8 +37,6 @@ public:
|
||||
RoomData() = default;
|
||||
~RoomData() = default;
|
||||
|
||||
void RunFrame();
|
||||
|
||||
//accessors and mutators
|
||||
std::string SetName(std::string);
|
||||
std::string GetName();
|
||||
@@ -48,37 +46,22 @@ public:
|
||||
|
||||
RegionPagerLua* GetPager();
|
||||
MonsterManager* GetMonsterMgr();
|
||||
TriggerManager* GetTriggerMgr();
|
||||
WaypointManager* GetWaypointMgr();
|
||||
std::list<CharacterData*>* GetCharacterList();
|
||||
|
||||
//API interfaces
|
||||
lua_State* SetLuaState(lua_State* L);
|
||||
lua_State* GetLuaState();
|
||||
sqlite3* SetDatabase(sqlite3* db);
|
||||
sqlite3* GetDatabase();
|
||||
|
||||
//hooks
|
||||
int SetTickReference(int i);
|
||||
int GetTickReference();
|
||||
//TODO: other triggers like player entry & exit, etc.
|
||||
//TODO: triggers for unload, save, per-second, player enter, player exit, etc.
|
||||
|
||||
private:
|
||||
//metadata
|
||||
friend class RoomManager;
|
||||
|
||||
//members
|
||||
std::string roomName;
|
||||
std::string tilesetName;
|
||||
|
||||
//members
|
||||
RegionPagerLua pager;
|
||||
MonsterManager monsterMgr;
|
||||
TriggerManager triggerMgr;
|
||||
WaypointManager waypointMgr;
|
||||
std::list<CharacterData*> characterList;
|
||||
|
||||
//API
|
||||
lua_State* lua = nullptr;
|
||||
sqlite3* database = nullptr;
|
||||
|
||||
//hooks
|
||||
int tickRef = LUA_NOREF;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,79 +35,29 @@ int RoomManager::Create(std::string roomName, std::string tileset) {
|
||||
newRoom->SetName(roomName);
|
||||
newRoom->SetTileset(tileset);
|
||||
|
||||
newRoom->SetLuaState(lua);
|
||||
newRoom->SetDatabase(database);
|
||||
|
||||
//get the hook
|
||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, createRef);
|
||||
|
||||
if(!lua_isnil(lua, -1)) {
|
||||
lua_pushlightuserdata(lua, newRoom);
|
||||
lua_pushinteger(lua, counter);
|
||||
//call the function, 2 arg, 0 return
|
||||
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
|
||||
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
|
||||
}
|
||||
}
|
||||
newRoom->pager.SetLuaState(lua);
|
||||
newRoom->monsterMgr.SetLuaState(lua);
|
||||
newRoom->monsterMgr.SetDatabase(database);
|
||||
newRoom->waypointMgr.SetLuaState(lua);
|
||||
|
||||
//finish the routine
|
||||
return counter++;
|
||||
}
|
||||
|
||||
void RoomManager::UnloadAll() {
|
||||
//get the hook
|
||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
||||
|
||||
if(!lua_isnil(lua, -1)) {
|
||||
//pass each room to the hook
|
||||
for (auto& it : elementMap) {
|
||||
lua_pushvalue(lua, -1); //copy the hook
|
||||
lua_pushlightuserdata(lua, &it.second);
|
||||
lua_pushinteger(lua, it.first);
|
||||
//call the function, 2 arg, 0 return
|
||||
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
|
||||
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pop the hook or nil
|
||||
lua_pop(lua, 1);
|
||||
|
||||
elementMap.clear();
|
||||
}
|
||||
|
||||
void RoomManager::UnloadIf(std::function<bool(std::pair<const int, RoomData const&>)> fn) {
|
||||
//get the hook
|
||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
||||
|
||||
//get the element
|
||||
std::map<int, RoomData>::iterator it = elementMap.begin();
|
||||
|
||||
//jenky pattern
|
||||
while (it != elementMap.end()) {
|
||||
if (fn(*it)) {
|
||||
|
||||
if(!lua_isnil(lua, -1)) {
|
||||
lua_pushvalue(lua, -1); //copy the hook
|
||||
lua_pushlightuserdata(lua, &it->second);
|
||||
lua_pushinteger(lua, it->first);
|
||||
|
||||
//call the function, 2 arg, 0 return
|
||||
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
|
||||
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
|
||||
}
|
||||
}
|
||||
|
||||
it = elementMap.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
//pop the hook or nil
|
||||
lua_pop(lua, 1);
|
||||
}
|
||||
|
||||
void RoomManager::PushCharacter(CharacterData* character) {
|
||||
@@ -121,7 +71,7 @@ void RoomManager::PushCharacter(CharacterData* character) {
|
||||
throw(std::runtime_error("Failed to push an character to a non-existant room"));
|
||||
}
|
||||
|
||||
room->GetCharacterList()->push_back(character);
|
||||
room->characterList.push_back(character);
|
||||
}
|
||||
|
||||
void RoomManager::PopCharacter(CharacterData const* character) {
|
||||
@@ -136,7 +86,7 @@ void RoomManager::PopCharacter(CharacterData const* character) {
|
||||
throw(std::runtime_error("Failed to pop an character to a non-existant room"));
|
||||
}
|
||||
|
||||
room->GetCharacterList()->remove_if([character](CharacterData* ptr) {
|
||||
room->characterList.remove_if([character](CharacterData* ptr) {
|
||||
return character == ptr;
|
||||
});
|
||||
}
|
||||
@@ -169,11 +119,7 @@ std::map<int, RoomData>* RoomManager::GetContainer() {
|
||||
}
|
||||
|
||||
lua_State* RoomManager::SetLuaState(lua_State* L) {
|
||||
lua = L;
|
||||
for (auto& it : elementMap) {
|
||||
it.second.SetLuaState(lua);
|
||||
}
|
||||
return lua;
|
||||
return lua = L;
|
||||
}
|
||||
|
||||
lua_State* RoomManager::GetLuaState() {
|
||||
@@ -181,29 +127,9 @@ lua_State* RoomManager::GetLuaState() {
|
||||
}
|
||||
|
||||
sqlite3* RoomManager::SetDatabase(sqlite3* db) {
|
||||
database = db;
|
||||
for (auto& it : elementMap) {
|
||||
it.second.SetDatabase(database);
|
||||
}
|
||||
return database;
|
||||
return database = db;
|
||||
}
|
||||
|
||||
sqlite3* RoomManager::GetDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
int RoomManager::SetCreateReference(int i) {
|
||||
return createRef = i;
|
||||
}
|
||||
|
||||
int RoomManager::SetUnloadReference(int i) {
|
||||
return unloadRef = i;
|
||||
}
|
||||
|
||||
int RoomManager::GetCreateReference() {
|
||||
return createRef;
|
||||
}
|
||||
|
||||
int RoomManager::GetUnloadReference() {
|
||||
return unloadRef;
|
||||
}
|
||||
|
||||
@@ -49,19 +49,12 @@ public:
|
||||
int GetLoadedCount();
|
||||
std::map<int, RoomData>* GetContainer();
|
||||
|
||||
//API interfaces
|
||||
//hooks
|
||||
lua_State* SetLuaState(lua_State* L);
|
||||
lua_State* GetLuaState();
|
||||
sqlite3* SetDatabase(sqlite3* db);
|
||||
sqlite3* GetDatabase();
|
||||
|
||||
//hooks
|
||||
int SetCreateReference(int i);
|
||||
int SetUnloadReference(int i);
|
||||
|
||||
int GetCreateReference();
|
||||
int GetUnloadReference();
|
||||
|
||||
private:
|
||||
friend Singleton<RoomManager>;
|
||||
|
||||
@@ -70,15 +63,9 @@ private:
|
||||
|
||||
//members
|
||||
std::map<int, RoomData> elementMap;
|
||||
int counter = 0;
|
||||
|
||||
//API
|
||||
lua_State* lua = nullptr;
|
||||
sqlite3* database = nullptr;
|
||||
|
||||
//hooks
|
||||
int createRef = LUA_NOREF;
|
||||
int unloadRef = LUA_NOREF;
|
||||
int counter = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -71,7 +71,7 @@ int unloadRoom(lua_State* L) {
|
||||
}
|
||||
|
||||
int getRoom(lua_State* L) {
|
||||
//integer vs name for getRoom()
|
||||
//TODO: integer vs name for getRoom()
|
||||
RoomManager& roomMgr = RoomManager::GetSingleton();
|
||||
RoomData* room = nullptr;
|
||||
|
||||
@@ -96,26 +96,10 @@ int getRoom(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int setOnCreate(lua_State* L) {
|
||||
RoomManager& roomMgr = RoomManager::GetSingleton();
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, roomMgr.GetCreateReference());
|
||||
roomMgr.SetCreateReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setOnUnload(lua_State* L) {
|
||||
RoomManager& roomMgr = RoomManager::GetSingleton();
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, roomMgr.GetUnloadReference());
|
||||
roomMgr.SetUnloadReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg roomManagerLib[] = {
|
||||
{"CreateRoom", createRoom},
|
||||
{"UnloadRoom", unloadRoom},
|
||||
{"GetRoom", getRoom},
|
||||
{"SetOnCreate", setOnCreate},
|
||||
{"SetOnUnload", setOnUnload},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,40 +19,37 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "trigger_data.hpp"
|
||||
#include "room_system_api.hpp"
|
||||
|
||||
std::string TriggerData::SetHandle(std::string s) {
|
||||
return handle = s;
|
||||
//all room API headers
|
||||
#include "room_api.hpp"
|
||||
#include "room_manager_api.hpp"
|
||||
|
||||
//useful "globals"
|
||||
//...
|
||||
|
||||
//This mimics linit.c to create a nested collection of all room modules.
|
||||
static const luaL_Reg funcs[] = {
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const luaL_Reg libs[] = {
|
||||
{"Room", openRoomAPI},
|
||||
{"RoomManager", openRoomManagerAPI},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
int openRoomSystemAPI(lua_State* L) {
|
||||
//create the table
|
||||
luaL_newlibtable(L, libs);
|
||||
|
||||
//push the "global" functions
|
||||
luaL_setfuncs(L, funcs, 0);
|
||||
|
||||
//push the substable
|
||||
for (const luaL_Reg* lib = libs; lib->func; lib++) {
|
||||
lib->func(L);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string TriggerData::GetHandle() const {
|
||||
return handle;
|
||||
}
|
||||
|
||||
Vector2 TriggerData::SetOrigin(Vector2 v) {
|
||||
return origin = v;
|
||||
}
|
||||
|
||||
Vector2 TriggerData::GetOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
BoundingBox TriggerData::SetBoundingBox(BoundingBox b) {
|
||||
return bounds = b;
|
||||
}
|
||||
|
||||
BoundingBox TriggerData::GetBoundingBox() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
int TriggerData::SetScriptReference(int i) {
|
||||
return scriptRef = i;
|
||||
}
|
||||
|
||||
int TriggerData::GetScriptReference() {
|
||||
return scriptRef;
|
||||
}
|
||||
|
||||
std::list<Entity*>* TriggerData::GetExclusionList() {
|
||||
return &exclusionList;
|
||||
}
|
||||
@@ -19,8 +19,12 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "server_application.hpp"
|
||||
#ifndef ROOMSYSTEMAPI_HPP_
|
||||
#define ROOMSYSTEMAPI_HPP_
|
||||
|
||||
void ServerApplication::hMonsterDamage(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hMonsterDamage()
|
||||
}
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_ROOM_SYSTEM_API "room_system"
|
||||
LUAMOD_API int openRoomSystemAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
@@ -34,13 +34,9 @@
|
||||
#include "udp_network_utility.hpp"
|
||||
|
||||
//common utilities
|
||||
#include "ip_operators.hpp"
|
||||
#include "serial_packet.hpp"
|
||||
#include "singleton.hpp"
|
||||
|
||||
//server utilities
|
||||
#include "server_utilities.hpp"
|
||||
|
||||
//APIs
|
||||
#include "lua.hpp"
|
||||
#include "sqlite3.h"
|
||||
@@ -51,6 +47,10 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
//global utility functions
|
||||
bool operator==(IPaddress lhs, IPaddress rhs);
|
||||
bool operator!=(IPaddress lhs, IPaddress rhs);
|
||||
|
||||
//The main application class
|
||||
class ServerApplication: public Singleton<ServerApplication> {
|
||||
public:
|
||||
@@ -68,53 +68,46 @@ private:
|
||||
//handle incoming traffic
|
||||
void HandlePacket(SerialPacket* const);
|
||||
|
||||
//heartbeat system
|
||||
void hPing(ServerPacket* const);
|
||||
void hPong(ServerPacket* const);
|
||||
//heartbeat sustem
|
||||
void HandlePing(ServerPacket* const);
|
||||
void HandlePong(ServerPacket* const);
|
||||
|
||||
//basic connections
|
||||
void hBroadcastRequest(ServerPacket* const);
|
||||
void hJoinRequest(ClientPacket* const);
|
||||
void hLoginRequest(ClientPacket* const);
|
||||
void HandleBroadcastRequest(ServerPacket* const);
|
||||
void HandleJoinRequest(ClientPacket* const);
|
||||
void HandleLoginRequest(ClientPacket* const);
|
||||
|
||||
//client disconnections
|
||||
void hLogoutRequest(ClientPacket* const);
|
||||
void hDisconnectRequest(ClientPacket* const);
|
||||
void HandleLogoutRequest(ClientPacket* const);
|
||||
void HandleDisconnectRequest(ClientPacket* const);
|
||||
|
||||
//server commands
|
||||
void hAdminDisconnectForced(ClientPacket* const);
|
||||
void hAdminShutdownRequest(ClientPacket* const);
|
||||
void HandleDisconnectForced(ClientPacket* const);
|
||||
void HandleShutdownRequest(ClientPacket* const);
|
||||
|
||||
//data management
|
||||
void hRegionRequest(RegionPacket* const);
|
||||
void hQueryCharacterExists(CharacterPacket* const);
|
||||
void hQueryCharacterStats(CharacterPacket* const);
|
||||
void hQueryCharacterLocation(CharacterPacket* const);
|
||||
void hQueryMonsterExists(MonsterPacket* const);
|
||||
void hQueryMonsterStats(MonsterPacket* const);
|
||||
void hQueryMonsterLocation(MonsterPacket* const);
|
||||
void HandleRegionRequest(RegionPacket* const);
|
||||
void HandleCharacterExists(CharacterPacket* const);
|
||||
|
||||
void SaveServerState();
|
||||
void FullClientUnload(int index);
|
||||
void FullAccountUnload(int index);
|
||||
void FullCharacterUnload(int index);
|
||||
|
||||
//character management
|
||||
void hCharacterCreate(CharacterPacket* const);
|
||||
void hCharacterDelete(CharacterPacket* const);
|
||||
void hCharacterLoad(CharacterPacket* const);
|
||||
void hCharacterUnload(CharacterPacket* const);
|
||||
void HandleCharacterCreate(CharacterPacket* const);
|
||||
void HandleCharacterDelete(CharacterPacket* const);
|
||||
void HandleCharacterLoad(CharacterPacket* const);
|
||||
void HandleCharacterUnload(CharacterPacket* const);
|
||||
|
||||
//character movement
|
||||
void hCharacterMovement(CharacterPacket* const);
|
||||
void hCharacterAttack(CharacterPacket* const);
|
||||
void hCharacterDamage(CharacterPacket* const);
|
||||
|
||||
//character management
|
||||
void hMonsterDamage(MonsterPacket* const);
|
||||
|
||||
//chat
|
||||
void hTextBroadcast(TextPacket* const);
|
||||
void hTextSpeech(TextPacket* const);
|
||||
void hTextWhisper(TextPacket* const);
|
||||
void HandleCharacterMovement(CharacterPacket* const);
|
||||
void HandleCharacterAttack(CharacterPacket* const);
|
||||
|
||||
//utility methods
|
||||
void SaveServerState();
|
||||
void PumpPacket(SerialPacket* const);
|
||||
void PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance);
|
||||
void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
|
||||
|
||||
//APIs and utilities
|
||||
sqlite3* database = nullptr;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
//Character Management
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterCreate(CharacterPacket* const argPacket) {
|
||||
int characterIndex = characterMgr.Create(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
|
||||
|
||||
if (characterIndex < 0) {
|
||||
@@ -46,17 +46,16 @@ void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
|
||||
}
|
||||
|
||||
//push to the rooms
|
||||
CharacterData* characterData = characterMgr.Get(characterIndex);
|
||||
roomMgr.PushCharacter(characterData);
|
||||
roomMgr.PushCharacter(characterMgr.Get(characterIndex));
|
||||
|
||||
//pump this character to all clients
|
||||
CharacterPacket newPacket;
|
||||
copyCharacterToPacket(&newPacket, characterIndex);
|
||||
CopyCharacterToPacket(&newPacket, characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_CREATE;
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
PumpPacket(&newPacket);
|
||||
}
|
||||
|
||||
void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) {
|
||||
//get the user's data
|
||||
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
|
||||
if (!accountData) {
|
||||
@@ -91,20 +90,19 @@ void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
|
||||
}
|
||||
|
||||
//pop from the rooms
|
||||
CharacterData* characterData = characterMgr.Get(characterIndex);
|
||||
roomMgr.PopCharacter(characterData);
|
||||
roomMgr.PopCharacter(characterMgr.Get(characterIndex));
|
||||
|
||||
//delete the character
|
||||
characterMgr.Delete(characterIndex);
|
||||
|
||||
//pump character delete
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
newPacket.characterIndex = characterIndex;
|
||||
pumpPacketProximity(static_cast<SerialPacket*>(&newPacket), characterData->GetRoomIndex());
|
||||
|
||||
//delete the character
|
||||
characterMgr.Delete(characterIndex);
|
||||
PumpPacket(static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
|
||||
void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterLoad(CharacterPacket* const argPacket) {
|
||||
int characterIndex = characterMgr.Load(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
|
||||
|
||||
if (characterIndex < 0) {
|
||||
@@ -128,17 +126,16 @@ void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
|
||||
}
|
||||
|
||||
//push to the rooms
|
||||
CharacterData* characterData = characterMgr.Get(characterIndex);
|
||||
roomMgr.PushCharacter(characterData);
|
||||
roomMgr.PushCharacter(characterMgr.Get(characterIndex));
|
||||
|
||||
//pump this character to all clients
|
||||
CharacterPacket newPacket;
|
||||
copyCharacterToPacket(&newPacket, characterIndex);
|
||||
CopyCharacterToPacket(&newPacket, characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_CREATE;
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
PumpPacket(&newPacket);
|
||||
}
|
||||
|
||||
void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterUnload(CharacterPacket* const argPacket) {
|
||||
//get the entries
|
||||
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
|
||||
if (!characterData) {
|
||||
@@ -147,12 +144,12 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
|
||||
|
||||
AccountData* accountData = accountMgr.Get(characterData->GetOwner());
|
||||
if (!accountData) {
|
||||
return;
|
||||
return; //TODO: logic_error
|
||||
}
|
||||
|
||||
ClientData* clientData = clientMgr.Get(accountData->GetClientIndex());
|
||||
if (!clientData) {
|
||||
return;
|
||||
return; //TODO: logic_error
|
||||
}
|
||||
|
||||
//check for fraud
|
||||
@@ -164,34 +161,29 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
|
||||
//pop from the rooms
|
||||
roomMgr.PopCharacter(characterData);
|
||||
|
||||
//unload the character
|
||||
characterMgr.Unload(argPacket->characterIndex);
|
||||
|
||||
//pump character delete
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
newPacket.characterIndex = argPacket->characterIndex;
|
||||
pumpPacketProximity(static_cast<SerialPacket*>(&newPacket), characterData->GetRoomIndex());
|
||||
|
||||
//unload the character
|
||||
characterMgr.Unload(argPacket->characterIndex);
|
||||
PumpPacket(static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//character movement
|
||||
//-------------------------
|
||||
|
||||
//TODO: (2) Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments
|
||||
//TODO: Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments
|
||||
|
||||
void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterMovement(CharacterPacket* const argPacket) {
|
||||
//get the specified objects
|
||||
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
|
||||
|
||||
if (!accountData) {
|
||||
throw(std::runtime_error("Failed to move a character, missing account"));
|
||||
}
|
||||
|
||||
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
|
||||
|
||||
if (!characterData) {
|
||||
throw(std::runtime_error("Failed to move a character, missing character"));
|
||||
if (!accountData || !characterData) {
|
||||
throw(std::runtime_error("Failed to move a character, missing data"));
|
||||
}
|
||||
|
||||
//get this account's client
|
||||
@@ -205,19 +197,28 @@ void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||
|
||||
//check if allowed
|
||||
if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) {
|
||||
//TODO: (3) send to the client?
|
||||
//TODO: send to the client?
|
||||
std::cerr << "Failed to set character motion due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//check if moving rooms
|
||||
if (characterData->GetRoomIndex() != argPacket->roomIndex) {
|
||||
//set the character's origin and motion
|
||||
characterData->SetOrigin(argPacket->origin);
|
||||
characterData->SetMotion(argPacket->motion);
|
||||
//delete from the old room
|
||||
CharacterPacket newPacket;
|
||||
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
|
||||
|
||||
//send the delete & create messages
|
||||
pumpAndChangeRooms(characterData, argPacket->roomIndex, argPacket->characterIndex);
|
||||
//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 {
|
||||
@@ -227,16 +228,12 @@ void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
|
||||
|
||||
//update the clients
|
||||
CharacterPacket newPacket;
|
||||
copyCharacterToPacket(&newPacket, argPacket->characterIndex);
|
||||
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerApplication::hCharacterAttack(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hCharacterAttack()
|
||||
}
|
||||
|
||||
void ServerApplication::hCharacterDamage(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hCharacterDamage()
|
||||
void ServerApplication::HandleCharacterAttack(CharacterPacket* const) {
|
||||
//TODO: bounce graphical attack data
|
||||
}
|
||||
@@ -28,13 +28,13 @@
|
||||
//heartbeat system
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::hPing(ServerPacket* const argPacket) {
|
||||
void ServerApplication::HandlePing(ServerPacket* const argPacket) {
|
||||
ServerPacket newPacket;
|
||||
newPacket.type = SerialPacketType::PONG;
|
||||
network.SendTo(argPacket->srcAddress, &newPacket);
|
||||
}
|
||||
|
||||
void ServerApplication::hPong(ServerPacket* const argPacket) {
|
||||
void ServerApplication::HandlePong(ServerPacket* const argPacket) {
|
||||
clientMgr.HandlePong(argPacket);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ void ServerApplication::hPong(ServerPacket* const argPacket) {
|
||||
//basic connections
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::hBroadcastRequest(ServerPacket* const argPacket) {
|
||||
void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) {
|
||||
//send the server's data
|
||||
ServerPacket newPacket;
|
||||
|
||||
@@ -54,7 +54,7 @@ void ServerApplication::hBroadcastRequest(ServerPacket* const argPacket) {
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
|
||||
void ServerApplication::hJoinRequest(ClientPacket* const argPacket) {
|
||||
void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
|
||||
//register the client
|
||||
int clientIndex = clientMgr.Create(argPacket->srcAddress);
|
||||
|
||||
@@ -69,7 +69,7 @@ void ServerApplication::hJoinRequest(ClientPacket* const argPacket) {
|
||||
std::cout << "New join, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
|
||||
}
|
||||
|
||||
void ServerApplication::hLoginRequest(ClientPacket* const argPacket) {
|
||||
void ServerApplication::HandleLoginRequest(ClientPacket* const argPacket) {
|
||||
//get the client data
|
||||
ClientData* clientData = clientMgr.Get(argPacket->clientIndex);
|
||||
|
||||
@@ -110,7 +110,7 @@ void ServerApplication::hLoginRequest(ClientPacket* const argPacket) {
|
||||
std::cout << "New login, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
|
||||
}
|
||||
|
||||
void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) {
|
||||
void ServerApplication::HandleLogoutRequest(ClientPacket* const argPacket) {
|
||||
//get the account and client data
|
||||
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
|
||||
if (!accountData) {
|
||||
@@ -138,13 +138,13 @@ void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) {
|
||||
network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket));
|
||||
|
||||
//save and unload this account and it's characters
|
||||
fullAccountUnload(argPacket->accountIndex);
|
||||
FullAccountUnload(argPacket->accountIndex);
|
||||
|
||||
//finished this routine
|
||||
std::cout << "New logout, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
|
||||
}
|
||||
|
||||
void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) {
|
||||
void ServerApplication::HandleDisconnectRequest(ClientPacket* const argPacket) {
|
||||
//get the client data
|
||||
ClientData* clientData = clientMgr.Get(argPacket->clientIndex);
|
||||
if (!clientData) {
|
||||
@@ -165,8 +165,12 @@ void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) {
|
||||
network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket));
|
||||
|
||||
//unload the client, it's accounts, and their characters
|
||||
fullClientUnload(argPacket->clientIndex);
|
||||
FullClientUnload(argPacket->clientIndex);
|
||||
|
||||
//finished this routine
|
||||
std::cout << "New disconnection, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
|
||||
}
|
||||
|
||||
void ServerApplication::HandleDisconnectForced(ClientPacket* const argPacket) {
|
||||
//TODO: HandleDisconnectForced
|
||||
}
|
||||
@@ -25,10 +25,20 @@
|
||||
#include <sstream>
|
||||
|
||||
//-------------------------
|
||||
//Queries
|
||||
//General data management
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::hRegionRequest(RegionPacket* const argPacket) {
|
||||
//TODO: Queries
|
||||
|
||||
void ServerApplication::SaveServerState() {
|
||||
//TODO: SaveServerState
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//Map management
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) {
|
||||
//get the region object, send a rejection on error
|
||||
RoomData* room = roomMgr.Get(argPacket->roomIndex);
|
||||
if (!room) {
|
||||
@@ -61,7 +71,7 @@ void ServerApplication::hRegionRequest(RegionPacket* const argPacket) {
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket) {
|
||||
void ServerApplication::HandleCharacterExists(CharacterPacket* const argPacket) {
|
||||
//respond with all character data
|
||||
CharacterPacket newPacket;
|
||||
|
||||
@@ -69,28 +79,8 @@ void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket)
|
||||
if (argPacket->roomIndex != -1 && it.second.GetRoomIndex() != argPacket->roomIndex) {
|
||||
continue;
|
||||
}
|
||||
copyCharacterToPacket(&newPacket, it.first);
|
||||
CopyCharacterToPacket(&newPacket, it.first);
|
||||
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryCharacterStats(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hQueryCharacterStats()
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryCharacterLocation(CharacterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hQueryCharacterLocation()
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryMonsterExists(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hQueryMonsterExists()
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryMonsterStats(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hQueryMonsterStats()
|
||||
}
|
||||
|
||||
void ServerApplication::hQueryMonsterLocation(MonsterPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hQueryMonsterLocation()
|
||||
}
|
||||
+50
-91
@@ -28,7 +28,6 @@
|
||||
#include <stdexcept>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -129,6 +128,7 @@ void ServerApplication::Init(int argc, char* argv[]) {
|
||||
//debug output
|
||||
//-------------------------
|
||||
|
||||
//TODO: enable/disable these with a switch
|
||||
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
||||
|
||||
std::cout << "Internal sizes:" << std::endl;
|
||||
@@ -162,16 +162,9 @@ void ServerApplication::Init(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
void ServerApplication::Proc() {
|
||||
//network buffer
|
||||
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
|
||||
memset(packetBuffer, 0, MAX_PACKET_SIZE); //zero the buffer
|
||||
|
||||
//time system
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
|
||||
Clock::time_point simTime = Clock::now();
|
||||
Clock::time_point realTime;
|
||||
|
||||
while(running) {
|
||||
//suck in the waiting packets & process them
|
||||
while(network.Receive(packetBuffer)) {
|
||||
@@ -181,33 +174,20 @@ void ServerApplication::Proc() {
|
||||
catch(std::exception& e) {
|
||||
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
|
||||
}
|
||||
//reset the buffer
|
||||
memset(packetBuffer, 0, MAX_PACKET_SIZE);
|
||||
memset(packetBuffer, 0, MAX_PACKET_SIZE); //reset the buffer
|
||||
}
|
||||
//update the internals
|
||||
//...
|
||||
|
||||
//Check connections
|
||||
int disconnected = clientMgr.CheckConnections();
|
||||
if (disconnected != -1) {
|
||||
FullClientUnload(disconnected);
|
||||
std::cerr << "Client dropped: " << disconnected << std::endl;
|
||||
}
|
||||
|
||||
//Check client connections
|
||||
std::list<int> disconnections = clientMgr.CheckConnections();
|
||||
for(auto const& it : disconnections) {
|
||||
fullClientUnload(it);
|
||||
std::cerr << "Client dropped: " << it << std::endl;
|
||||
}
|
||||
|
||||
//"tick" the internals
|
||||
realTime = Clock::now();
|
||||
|
||||
if (simTime < realTime) {
|
||||
while(simTime < realTime) {
|
||||
for (auto& it : *roomMgr.GetContainer()) {
|
||||
it.second.RunFrame();
|
||||
}
|
||||
//~60 FPS
|
||||
simTime += std::chrono::duration<int, std::milli>(16);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//give the machine a break
|
||||
SDL_Delay(10);
|
||||
}
|
||||
//give the machine a break
|
||||
SDL_Delay(10);
|
||||
}
|
||||
delete reinterpret_cast<char*>(packetBuffer);
|
||||
}
|
||||
@@ -215,8 +195,7 @@ void ServerApplication::Proc() {
|
||||
void ServerApplication::Quit() {
|
||||
std::cout << "Shutting down" << std::endl;
|
||||
|
||||
//save the server state
|
||||
SaveServerState();
|
||||
//TODO: save the server state
|
||||
|
||||
//close the managers
|
||||
accountMgr.UnloadAll();
|
||||
@@ -235,111 +214,91 @@ void ServerApplication::Quit() {
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//handle incoming traffic
|
||||
//direct incoming traffic
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
|
||||
switch(argPacket->type) {
|
||||
//heartbeat system
|
||||
case SerialPacketType::PING:
|
||||
hPing(static_cast<ServerPacket*>(argPacket));
|
||||
HandlePing(static_cast<ServerPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::PONG:
|
||||
hPong(static_cast<ServerPacket*>(argPacket));
|
||||
HandlePong(static_cast<ServerPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//client connections
|
||||
case SerialPacketType::BROADCAST_REQUEST:
|
||||
hBroadcastRequest(static_cast<ServerPacket*>(argPacket));
|
||||
HandleBroadcastRequest(static_cast<ServerPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::JOIN_REQUEST:
|
||||
hJoinRequest(static_cast<ClientPacket*>(argPacket));
|
||||
HandleJoinRequest(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::LOGIN_REQUEST:
|
||||
hLoginRequest(static_cast<ClientPacket*>(argPacket));
|
||||
HandleLoginRequest(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//client disconnections
|
||||
case SerialPacketType::LOGOUT_REQUEST:
|
||||
hLogoutRequest(static_cast<ClientPacket*>(argPacket));
|
||||
HandleLogoutRequest(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::DISCONNECT_REQUEST:
|
||||
hDisconnectRequest(static_cast<ClientPacket*>(argPacket));
|
||||
HandleDisconnectRequest(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//server commands
|
||||
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
|
||||
hAdminDisconnectForced(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST:
|
||||
hAdminShutdownRequest(static_cast<ClientPacket*>(argPacket));
|
||||
// case SerialPacketType::DISCONNECT_FORCED:
|
||||
// HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
|
||||
// break;
|
||||
case SerialPacketType::SHUTDOWN_REQUEST:
|
||||
HandleShutdownRequest(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//data management & queries
|
||||
case SerialPacketType::REGION_REQUEST:
|
||||
hRegionRequest(static_cast<RegionPacket*>(argPacket));
|
||||
HandleRegionRequest(static_cast<RegionPacket*>(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::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));
|
||||
HandleCharacterExists(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
//character management
|
||||
case SerialPacketType::CHARACTER_CREATE:
|
||||
hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
|
||||
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_DELETE:
|
||||
hCharacterDelete(static_cast<CharacterPacket*>(argPacket));
|
||||
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_LOAD:
|
||||
hCharacterLoad(static_cast<CharacterPacket*>(argPacket));
|
||||
HandleCharacterLoad(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_UNLOAD:
|
||||
hCharacterUnload(static_cast<CharacterPacket*>(argPacket));
|
||||
HandleCharacterUnload(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
|
||||
/* case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
||||
//
|
||||
break;
|
||||
case SerialPacketType::QUERY_CHARACTER_STATS:
|
||||
//
|
||||
break;
|
||||
case SerialPacketType::QUERY_CHARACTER_LOCATION:
|
||||
//
|
||||
break;
|
||||
*/
|
||||
//character movement
|
||||
case SerialPacketType::CHARACTER_MOVEMENT:
|
||||
hCharacterMovement(static_cast<CharacterPacket*>(argPacket));
|
||||
HandleCharacterMovement(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_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));
|
||||
HandleCharacterAttack(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
/*
|
||||
//enemy management
|
||||
//TODO: enemy management
|
||||
|
||||
//TODO: text
|
||||
*/
|
||||
//handle errors
|
||||
default: {
|
||||
std::ostringstream msg;
|
||||
|
||||
+128
-9
@@ -25,15 +25,23 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//server commands
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::hAdminDisconnectForced(ClientPacket* const argPacket) {
|
||||
//TODO: (9) ServerApplication::hAdminDisconnectForced()
|
||||
}
|
||||
|
||||
void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
|
||||
void ServerApplication::HandleShutdownRequest(ClientPacket* const argPacket) {
|
||||
//get the account and client data
|
||||
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
|
||||
if (!accountData) {
|
||||
@@ -76,14 +84,125 @@ void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
|
||||
|
||||
//disconnect all clients
|
||||
TextPacket newPacket;
|
||||
newPacket.type = SerialPacketType::ADMIN_DISCONNECT_FORCED;
|
||||
newPacket.type = SerialPacketType::DISCONNECT_FORCED;
|
||||
strncpy(newPacket.text, "Server shutdown", PACKET_STRING_SIZE);
|
||||
pumpPacket(&newPacket);
|
||||
PumpPacket(&newPacket);
|
||||
|
||||
//finished this routine
|
||||
std::cout << "Shutdown signal accepted" << std::endl;
|
||||
}
|
||||
|
||||
void ServerApplication::SaveServerState() {
|
||||
//TODO: (3) Periodic mass server saves
|
||||
//-------------------------
|
||||
//full unload methods
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::FullClientUnload(int index) {
|
||||
clientMgr.UnloadIf([&](std::pair<const int, ClientData const&> client) -> bool {
|
||||
//skip the wrong clients
|
||||
if (client.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//unload associated accounts
|
||||
for (std::map<int, AccountData>::iterator it = accountMgr.GetContainer()->begin(); it != accountMgr.GetContainer()->end(); /* EMPTY */) {
|
||||
if (it->second.GetClientIndex() == index) {
|
||||
FullAccountUnload(it->first);
|
||||
it = accountMgr.GetContainer()->begin();
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
//unload this client
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void ServerApplication::FullAccountUnload(int index) {
|
||||
accountMgr.UnloadIf([&](std::pair<const int, AccountData const&> account) -> bool {
|
||||
//skip the wrong accounts
|
||||
if (account.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//unload associated characters
|
||||
for (std::map<int, CharacterData>::iterator it = characterMgr.GetContainer()->begin(); it != characterMgr.GetContainer()->end(); /* EMPTY */) {
|
||||
if (it->second.GetOwner() == index) {
|
||||
FullCharacterUnload(it->first);
|
||||
it = characterMgr.GetContainer()->begin();
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
//unload this account
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void ServerApplication::FullCharacterUnload(int index) {
|
||||
characterMgr.UnloadIf([&](std::pair<const int, CharacterData const&> character) -> bool {
|
||||
//skip the wrong characters
|
||||
if (character.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//pop from the rooms
|
||||
roomMgr.PopCharacter(&character.second);
|
||||
|
||||
//pump character unload
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
newPacket.characterIndex = character.first;
|
||||
//NOTE: more character info as needed
|
||||
|
||||
PumpPacket(&newPacket);
|
||||
|
||||
//unload this character
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//utility methods
|
||||
//-------------------------
|
||||
|
||||
void ServerApplication::PumpPacket(SerialPacket* const argPacket) {
|
||||
for (auto& it : *clientMgr.GetContainer()) {
|
||||
network.SendTo(it.second.GetAddress(), argPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerApplication::PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance) {
|
||||
RoomData* room = roomMgr.Get(roomIndex);
|
||||
|
||||
if (!room) {
|
||||
throw(std::runtime_error("Failed to pump to a non-existant room"));
|
||||
}
|
||||
|
||||
for (auto& character : *room->GetCharacterList()) {
|
||||
if (distance == -1 || (character->GetOrigin() - position).Length() <= distance) {
|
||||
AccountData* account = accountMgr.Get(character->GetOwner());
|
||||
ClientData* client = clientMgr.Get(account->GetClientIndex());
|
||||
network.SendTo(client->GetAddress(), argPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
|
||||
CharacterData* character = characterMgr.Get(characterIndex);
|
||||
if (!character) {
|
||||
throw(std::runtime_error("Failed to copy a character to a packet"));
|
||||
}
|
||||
|
||||
//NOTE: keep this up to date when the character changes
|
||||
packet->characterIndex = characterIndex;
|
||||
strncpy(packet->handle, character->GetHandle().c_str(), PACKET_STRING_SIZE);
|
||||
strncpy(packet->avatar, character->GetAvatar().c_str(), PACKET_STRING_SIZE);
|
||||
packet->accountIndex = character->GetOwner();
|
||||
packet->roomIndex = character->GetRoomIndex();
|
||||
packet->origin = character->GetOrigin();
|
||||
packet->motion = character->GetMotion();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#config
|
||||
INCLUDES+=. ../accounts ../characters ../clients ../entities ../monsters ../rooms ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
|
||||
INCLUDES+=.
|
||||
LIBS+=
|
||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||
|
||||
|
||||
@@ -1,182 +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 "server_utilities.hpp"
|
||||
|
||||
#include "account_manager.hpp"
|
||||
#include "character_manager.hpp"
|
||||
#include "client_manager.hpp"
|
||||
#include "room_manager.hpp"
|
||||
#include "udp_network_utility.hpp"
|
||||
|
||||
//-------------------------
|
||||
//manager unload functions
|
||||
//-------------------------
|
||||
|
||||
void fullClientUnload(int index) {
|
||||
ClientManager::GetSingleton().UnloadIf([index](std::pair<const int, ClientData const&> clientPair) -> bool {
|
||||
//skip the wrong clients
|
||||
if (clientPair.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountManager& accountMgr = AccountManager::GetSingleton();
|
||||
|
||||
//unload associated accounts
|
||||
for (std::map<int, AccountData>::iterator it = accountMgr.GetContainer()->begin(); it != accountMgr.GetContainer()->end(); /* EMPTY */) {
|
||||
if (it->second.GetClientIndex() == index) {
|
||||
fullAccountUnload(it->first);
|
||||
it = accountMgr.GetContainer()->begin();
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
//unload this client
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void fullAccountUnload(int index) {
|
||||
AccountManager::GetSingleton().UnloadIf([index](std::pair<const int, AccountData const&> accountPair) -> bool {
|
||||
//skip the wrong accounts
|
||||
if (accountPair.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CharacterManager& characterMgr = CharacterManager::GetSingleton();
|
||||
|
||||
//unload associated characters
|
||||
for (std::map<int, CharacterData>::iterator it = characterMgr.GetContainer()->begin(); it != characterMgr.GetContainer()->end(); /* EMPTY */) {
|
||||
if (it->second.GetOwner() == index) {
|
||||
fullCharacterUnload(it->first);
|
||||
it = characterMgr.GetContainer()->begin();
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
//unload this account
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void fullCharacterUnload(int index) {
|
||||
CharacterManager::GetSingleton().UnloadIf([index](std::pair<const int, CharacterData const&> characterPair) -> bool {
|
||||
//skip the wrong characters
|
||||
if (characterPair.first != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//pop from the rooms
|
||||
RoomManager::GetSingleton().PopCharacter(&characterPair.second);
|
||||
|
||||
//pump character unload
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
newPacket.characterIndex = characterPair.first;
|
||||
//NOTE: more character info as needed
|
||||
|
||||
//TODO: proximity?
|
||||
pumpPacketProximity(&newPacket, characterPair.second.GetRoomIndex());
|
||||
|
||||
//unload this character
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
//utility functions
|
||||
//-------------------------
|
||||
|
||||
void pumpPacket(SerialPacket* const argPacket) {
|
||||
for (auto& it : *ClientManager::GetSingleton().GetContainer()) {
|
||||
UDPNetworkUtility::GetSingleton().SendTo(it.second.GetAddress(), argPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void pumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance) {
|
||||
RoomData* roomData = RoomManager::GetSingleton().Get(roomIndex);
|
||||
|
||||
if (!roomData) {
|
||||
throw(std::runtime_error("Failed to pump to a non-existant room"));
|
||||
}
|
||||
|
||||
AccountData* accountData = nullptr;
|
||||
ClientData* clientData = nullptr;
|
||||
|
||||
for (auto& characterIt : *roomData->GetCharacterList()) {
|
||||
if (distance == -1 || (characterIt->GetOrigin() - position).Length() <= distance) {
|
||||
accountData = AccountManager::GetSingleton().Get(characterIt->GetOwner());
|
||||
clientData = ClientManager::GetSingleton().Get(accountData->GetClientIndex());
|
||||
UDPNetworkUtility::GetSingleton().SendTo(clientData->GetAddress(), argPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void copyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
|
||||
CharacterData* characterData = CharacterManager::GetSingleton().Get(characterIndex);
|
||||
if (!characterData) {
|
||||
throw(std::runtime_error("Failed to copy a character to a packet"));
|
||||
}
|
||||
|
||||
copyCharacterToPacket(packet, characterData, characterIndex);
|
||||
}
|
||||
|
||||
void copyCharacterToPacket(CharacterPacket* const packet, CharacterData* const characterData, int characterIndex) {
|
||||
//NOTE: keep this up to date when the character changes
|
||||
packet->characterIndex = characterIndex;
|
||||
strncpy(packet->handle, characterData->GetHandle().c_str(), PACKET_STRING_SIZE);
|
||||
strncpy(packet->avatar, characterData->GetAvatar().c_str(), PACKET_STRING_SIZE);
|
||||
packet->accountIndex = characterData->GetOwner();
|
||||
packet->roomIndex = characterData->GetRoomIndex();
|
||||
packet->origin = characterData->GetOrigin();
|
||||
packet->motion = characterData->GetMotion();
|
||||
packet->bounds = characterData->GetBounds();
|
||||
}
|
||||
|
||||
void pumpAndChangeRooms(int characterIndex, int newRoomIndex) {
|
||||
//get the character object
|
||||
CharacterData* character = CharacterManager::GetSingleton().Get(characterIndex);
|
||||
|
||||
//pass ownwards
|
||||
pumpAndChangeRooms(character, newRoomIndex, characterIndex);
|
||||
}
|
||||
|
||||
void pumpAndChangeRooms(CharacterData* const characterData, int newRoomIndex, int characterIndex) {
|
||||
//delete from the old room
|
||||
CharacterPacket newPacket;
|
||||
copyCharacterToPacket(&newPacket, characterData, characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
|
||||
//move the character between rooms
|
||||
RoomManager::GetSingleton().PopCharacter(characterData);
|
||||
characterData->SetRoomIndex(newRoomIndex);
|
||||
RoomManager::GetSingleton().PushCharacter(characterData);
|
||||
|
||||
//create in the new room
|
||||
copyCharacterToPacket(&newPacket, characterData, characterIndex);
|
||||
newPacket.type = SerialPacketType::CHARACTER_CREATE;
|
||||
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
|
||||
}
|
||||
@@ -1,41 +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.
|
||||
*/
|
||||
#ifndef SERVERUTILITIES_HPP_
|
||||
#define SERVERUTILITIES_HPP_
|
||||
|
||||
#include "character_data.hpp"
|
||||
#include "serial_packet.hpp"
|
||||
#include "vector2.hpp"
|
||||
|
||||
void fullClientUnload(int index);
|
||||
void fullAccountUnload(int index);
|
||||
void fullCharacterUnload(int index);
|
||||
|
||||
void pumpPacket(SerialPacket* const argPacket);
|
||||
void pumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position = {0, 0}, int distance = -1);
|
||||
|
||||
void copyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
|
||||
void copyCharacterToPacket(CharacterPacket* const packet, CharacterData* const characterData, int characterIndex);
|
||||
void pumpAndChangeRooms(int characterIndex, int newRoomIndex);
|
||||
void pumpAndChangeRooms(CharacterData* const characterData, int newRoomIndex, int characterIndex);
|
||||
|
||||
#endif
|
||||
@@ -1,126 +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 "trigger_api.hpp"
|
||||
|
||||
#include "trigger_data.hpp"
|
||||
|
||||
//hamdle
|
||||
static int setHandle(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
trigger->SetHandle(lua_tostring(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getHandle(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
lua_pushstring(L, trigger->GetHandle().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//origin
|
||||
static int setOrigin(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
trigger->SetOrigin(Vector2(lua_tonumber(L, 2), lua_tonumber(L, 3)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getOrigin(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
lua_pushnumber(L, trigger->GetOrigin().x);
|
||||
lua_pushnumber(L, trigger->GetOrigin().y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
//bounds
|
||||
static int setBoundingBox(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
trigger->SetBoundingBox(BoundingBox(
|
||||
lua_tonumber(L, 2),
|
||||
lua_tonumber(L, 3),
|
||||
lua_tonumber(L, 4),
|
||||
lua_tonumber(L, 5)
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getBoundingBox(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, trigger->GetBoundingBox().x);
|
||||
lua_pushinteger(L, trigger->GetBoundingBox().y);
|
||||
lua_pushinteger(L, trigger->GetBoundingBox().w);
|
||||
lua_pushinteger(L, trigger->GetBoundingBox().h);
|
||||
return 4;
|
||||
}
|
||||
|
||||
//triggers
|
||||
static int setReference(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, trigger->GetScriptReference());
|
||||
trigger->SetScriptReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getReference(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, trigger->GetScriptReference());
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pushExclusionEntity(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
trigger->GetExclusionList()->push_back(static_cast<Entity*>(lua_touserdata(L, 2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int removeExclusionEntity(lua_State* L) {
|
||||
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
|
||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 2));
|
||||
trigger->GetExclusionList()->remove_if([entity](Entity* ptr){
|
||||
return entity == ptr;
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg triggerLib[] = {
|
||||
{"SetHandle", setHandle},
|
||||
{"GetHandle", getHandle},
|
||||
|
||||
{"SetOrigin",setOrigin},
|
||||
{"GetOrigin",getOrigin},
|
||||
|
||||
{"SetBounds",setBoundingBox},
|
||||
{"GetBounds",getBoundingBox},
|
||||
|
||||
{"SetScript",setReference},
|
||||
{"GetScript",getReference},
|
||||
|
||||
{"PushExclusionEntity", pushExclusionEntity},
|
||||
{"RemoveExclusionEntity", removeExclusionEntity},
|
||||
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openTriggerAPI(lua_State* L) {
|
||||
luaL_newlib(L, triggerLib);
|
||||
return 1;
|
||||
}
|
||||
@@ -1,148 +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 "trigger_manager_api.hpp"
|
||||
|
||||
#include "trigger_manager.hpp"
|
||||
|
||||
static int create(lua_State* L) {
|
||||
//DOCS: params: create(triggerMgr, name[, originX, originY[, boundsX, boundsY, boundsW, boundsH]][, script])
|
||||
|
||||
//get the trigger manager
|
||||
TriggerManager* mgr = static_cast<TriggerManager*>(lua_touserdata(L, 1));
|
||||
|
||||
//create the trigger
|
||||
int index = mgr->Create(lua_tostring(L, 2));
|
||||
TriggerData* triggerData = mgr->Get(index);
|
||||
|
||||
//origin
|
||||
if (lua_gettop(L) >= 4) {
|
||||
triggerData->SetOrigin({lua_tonumber(L, 3), lua_tonumber(L, 4)}); //vectorX, vectorY
|
||||
}
|
||||
|
||||
//bounds
|
||||
if (lua_gettop(L) >= 8) {
|
||||
triggerData->SetBoundingBox({
|
||||
lua_tointeger(L, 5), //boundsX
|
||||
lua_tointeger(L, 6), //boundsY
|
||||
lua_tointeger(L, 7), //boundsW
|
||||
lua_tointeger(L, 8) //boundsH
|
||||
});
|
||||
}
|
||||
|
||||
//if the parameter list isn't capped with a script, append a nil instead
|
||||
if (lua_type(L, -1) != LUA_TFUNCTION) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
//set the script reference (may be nil)
|
||||
triggerData->SetScriptReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
|
||||
//push to the scipts
|
||||
lua_pushlightuserdata(L, static_cast<void*>(triggerData));
|
||||
lua_pushinteger(L, index);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int unload(lua_State* L) {
|
||||
TriggerManager* mgr = static_cast<TriggerManager*>(lua_touserdata(L, 1));
|
||||
int count = 0; //the number removed
|
||||
|
||||
//based on the type
|
||||
switch(lua_type(L, 2)) {
|
||||
//unload this index
|
||||
case LUA_TNUMBER:
|
||||
mgr->UnloadIf([L, &count](std::pair<int, TriggerData const&> it) -> bool {
|
||||
if (it.first == lua_tointeger(L, 2)) {
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
//unload this name
|
||||
case LUA_TSTRING:
|
||||
mgr->UnloadIf([L, &count](std::pair<int, TriggerData const&> it) -> bool {
|
||||
if (it.second.GetHandle() == lua_tostring(L, 2)) {
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
//return the number removed
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getTrigger(lua_State* L) {
|
||||
TriggerManager* mgr = static_cast<TriggerManager*>(lua_touserdata(L, 1));
|
||||
TriggerData* triggerData = nullptr;
|
||||
|
||||
switch(lua_type(L, 2)) {
|
||||
case LUA_TNUMBER:
|
||||
triggerData = mgr->Get(lua_tointeger(L, 2));
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
triggerData = mgr->Get(lua_tostring(L, 2));
|
||||
break;
|
||||
}
|
||||
|
||||
if (triggerData) {
|
||||
lua_pushlightuserdata(L, static_cast<void*>(triggerData));
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int forEach(lua_State* L) {
|
||||
//TODO: (9) forEach()
|
||||
}
|
||||
|
||||
static int getLoadedCount(lua_State* L) {
|
||||
TriggerManager* mgr = static_cast<TriggerManager*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, mgr->GetLoadedCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg triggerManagerLib[] = {
|
||||
{"Create",create},
|
||||
{"Unload",unload},
|
||||
{"GetTrigger",getTrigger},
|
||||
{"GetCount",getLoadedCount},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openTriggerManagerAPI(lua_State* L) {
|
||||
luaL_newlib(L, triggerManagerLib);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* 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 "waypoint_api.hpp"
|
||||
|
||||
#include "waypoint_data.hpp"
|
||||
|
||||
//origin
|
||||
static int setOrigin(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
waypoint->SetOrigin(Vector2(lua_tonumber(L, 2), lua_tonumber(L, 3)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getOrigin(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
lua_pushnumber(L, waypoint->GetOrigin().x);
|
||||
lua_pushnumber(L, waypoint->GetOrigin().y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
//bounds
|
||||
static int setBoundingBox(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
waypoint->SetBoundingBox(BoundingBox(
|
||||
lua_tonumber(L, 2),
|
||||
lua_tonumber(L, 3),
|
||||
lua_tonumber(L, 4),
|
||||
lua_tonumber(L, 5)
|
||||
));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getBoundingBox(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
lua_pushnumber(L, waypoint->GetBoundingBox().x);
|
||||
lua_pushnumber(L, waypoint->GetBoundingBox().y);
|
||||
lua_pushnumber(L, waypoint->GetBoundingBox().w);
|
||||
lua_pushnumber(L, waypoint->GetBoundingBox().h);
|
||||
return 4;
|
||||
}
|
||||
|
||||
//triggers
|
||||
static int setTriggerReference(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, waypoint->GetTriggerReference());
|
||||
waypoint->SetTriggerReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getTriggerReference(lua_State* L) {
|
||||
WaypointData* waypoint = static_cast<WaypointData*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, waypoint->GetTriggerReference());
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg waypointLib[] = {
|
||||
{"SetOrigin",setOrigin},
|
||||
{"GetOrigin",getOrigin},
|
||||
|
||||
{"SetBounds",setBoundingBox},
|
||||
{"GetBounds",getBoundingBox},
|
||||
|
||||
{"SetTrigger",setTriggerReference},
|
||||
{"GetTrigger",getTriggerReference},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openWaypointAPI(lua_State* L) {
|
||||
luaL_newlib(L, waypointLib);
|
||||
return 1;
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef NETWORKAPI_HPP_
|
||||
#define NETWORKAPI_HPP_
|
||||
#ifndef WAYPOINTAPI_HPP_
|
||||
#define WAYPOINTAPI_HPP_
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_NETWORK_API "network"
|
||||
LUAMOD_API int openNetworkAPI(lua_State* L);
|
||||
#define TORTUGA_WAYPOINT_API "waypoint"
|
||||
LUAMOD_API int openWaypointAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
@@ -19,21 +19,28 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "world.hpp"
|
||||
#include "waypoint_data.hpp"
|
||||
|
||||
//-------------------------
|
||||
//chat
|
||||
//-------------------------
|
||||
|
||||
void World::hTextBroadcast(TextPacket* const argPacket) {
|
||||
//TODO: (9) World::hTextBroadcast()
|
||||
int WaypointData::SetTriggerReference(int i) {
|
||||
return triggerRef = i;
|
||||
}
|
||||
|
||||
void World::hTextSpeech(TextPacket* const argPacket) {
|
||||
//TODO: (9) World::hTextSpeech()
|
||||
int WaypointData::GetTriggerReference() {
|
||||
return triggerRef;
|
||||
}
|
||||
|
||||
void World::hTextWhisper(TextPacket* const argPacket) {
|
||||
//TODO: (9) World::hTextWhisper()
|
||||
BoundingBox WaypointData::SetBoundingBox(BoundingBox b) {
|
||||
return bounds = b;
|
||||
}
|
||||
|
||||
BoundingBox WaypointData::GetBoundingBox() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
Vector2 WaypointData::SetOrigin(Vector2 v) {
|
||||
return origin = v;
|
||||
}
|
||||
|
||||
Vector2 WaypointData::GetOrigin() {
|
||||
return origin;
|
||||
}
|
||||
@@ -19,25 +19,20 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef TRIGGERDATA_HPP_
|
||||
#define TRIGGERDATA_HPP_
|
||||
#ifndef WAYPOINTDATA_HPP_
|
||||
#define WAYPOINTDATA_HPP_
|
||||
|
||||
#include "bounding_box.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "vector2.hpp"
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
class TriggerData {
|
||||
class WaypointData {
|
||||
public:
|
||||
TriggerData() = default;
|
||||
~TriggerData() = default;
|
||||
|
||||
std::string SetHandle(std::string);
|
||||
std::string GetHandle() const;
|
||||
WaypointData() = default;
|
||||
~WaypointData() = default;
|
||||
|
||||
Vector2 SetOrigin(Vector2 v);
|
||||
Vector2 GetOrigin();
|
||||
@@ -45,17 +40,15 @@ public:
|
||||
BoundingBox SetBoundingBox(BoundingBox b);
|
||||
BoundingBox GetBoundingBox();
|
||||
|
||||
int SetScriptReference(int i);
|
||||
int GetScriptReference();
|
||||
|
||||
std::list<Entity*>* GetExclusionList();
|
||||
int SetTriggerReference(int i);
|
||||
int GetTriggerReference();
|
||||
|
||||
private:
|
||||
std::string handle;
|
||||
friend class WaypointManager;
|
||||
|
||||
Vector2 origin;
|
||||
BoundingBox bounds;
|
||||
int scriptRef = LUA_NOREF;
|
||||
std::list<Entity*> exclusionList;
|
||||
int triggerRef = LUA_NOREF;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -19,36 +19,47 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#include "trigger_manager.hpp"
|
||||
#include "waypoint_manager.hpp"
|
||||
|
||||
TriggerManager::TriggerManager() {
|
||||
WaypointManager::WaypointManager() {
|
||||
//EMPTY
|
||||
}
|
||||
|
||||
TriggerManager::~TriggerManager() {
|
||||
WaypointManager::~WaypointManager() {
|
||||
UnloadAll();
|
||||
}
|
||||
|
||||
int TriggerManager::Create(std::string handle) {
|
||||
int WaypointManager::Create() {
|
||||
//implicitly creates the element
|
||||
TriggerData& triggerData = elementMap[counter];
|
||||
WaypointData& waypointData = elementMap[counter];
|
||||
|
||||
triggerData.SetHandle(handle);
|
||||
//no real values set
|
||||
waypointData.origin = {0, 0};
|
||||
waypointData.bounds = {0, 0, 0, 0};
|
||||
|
||||
return counter++;
|
||||
}
|
||||
|
||||
void TriggerManager::Unload(int uid) {
|
||||
int WaypointManager::Create(Vector2 origin, BoundingBox bounds) {
|
||||
//implicitly creates the element
|
||||
WaypointData& waypointData = elementMap[counter];
|
||||
|
||||
waypointData.origin = origin;
|
||||
waypointData.bounds = bounds;
|
||||
|
||||
return counter++;
|
||||
}
|
||||
|
||||
void WaypointManager::Unload(int uid) {
|
||||
elementMap.erase(uid);
|
||||
}
|
||||
|
||||
void TriggerManager::UnloadAll() {
|
||||
//TODO: save?
|
||||
void WaypointManager::UnloadAll() {
|
||||
elementMap.clear();
|
||||
}
|
||||
|
||||
void TriggerManager::UnloadIf(std::function<bool(std::pair<const int, TriggerData const&>)> fn) {
|
||||
std::map<int, TriggerData>::iterator it = elementMap.begin();
|
||||
void WaypointManager::UnloadIf(std::function<bool(std::pair<const int, WaypointData const&>)> fn) {
|
||||
std::map<int, WaypointData>::iterator it = elementMap.begin();
|
||||
while (it != elementMap.end()) {
|
||||
if (fn(*it)) {
|
||||
it = elementMap.erase(it);
|
||||
@@ -59,8 +70,8 @@ void TriggerManager::UnloadIf(std::function<bool(std::pair<const int, TriggerDat
|
||||
}
|
||||
}
|
||||
|
||||
TriggerData* TriggerManager::Get(int uid) {
|
||||
std::map<int, TriggerData>::iterator it = elementMap.find(uid);
|
||||
WaypointData* WaypointManager::Get(int uid) {
|
||||
std::map<int, WaypointData>::iterator it = elementMap.find(uid);
|
||||
|
||||
if (it == elementMap.end()) {
|
||||
return nullptr;
|
||||
@@ -69,28 +80,19 @@ TriggerData* TriggerManager::Get(int uid) {
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
TriggerData* TriggerManager::Get(std::string handle) {
|
||||
for (std::map<int, TriggerData>::iterator it = elementMap.begin(); it != elementMap.end(); ++it) {
|
||||
if (it->second.GetHandle() == handle) {
|
||||
return &it->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int TriggerManager::GetLoadedCount() {
|
||||
int WaypointManager::GetLoadedCount() {
|
||||
return elementMap.size();
|
||||
}
|
||||
|
||||
std::map<int, TriggerData>* TriggerManager::GetContainer() {
|
||||
std::map<int, WaypointData>* WaypointManager::GetContainer() {
|
||||
return &elementMap;
|
||||
}
|
||||
|
||||
//hooks
|
||||
lua_State* TriggerManager::SetLuaState(lua_State* L) {
|
||||
lua_State* WaypointManager::SetLuaState(lua_State* L) {
|
||||
return lua = L;
|
||||
}
|
||||
|
||||
lua_State* TriggerManager::GetLuaState() {
|
||||
lua_State* WaypointManager::GetLuaState() {
|
||||
return lua;
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef TRIGGERMANAGER_HPP_
|
||||
#define TRIGGERMANAGER_HPP_
|
||||
#ifndef WAYPOINTMANAGER_HPP_
|
||||
#define WAYPOINTMANAGER_HPP_
|
||||
|
||||
#include "bounding_box.hpp"
|
||||
#include "vector2.hpp"
|
||||
#include "trigger_data.hpp"
|
||||
#include "waypoint_data.hpp"
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
@@ -32,23 +32,23 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class TriggerManager {
|
||||
class WaypointManager {
|
||||
public:
|
||||
TriggerManager();
|
||||
~TriggerManager();
|
||||
WaypointManager();
|
||||
~WaypointManager();
|
||||
|
||||
//common public methods
|
||||
int Create(std::string handle);
|
||||
int Create();
|
||||
int Create(Vector2 origin, BoundingBox bounds);
|
||||
void Unload(int uid);
|
||||
|
||||
void UnloadAll();
|
||||
void UnloadIf(std::function<bool(std::pair<const int, TriggerData const&>)> fn);
|
||||
void UnloadIf(std::function<bool(std::pair<const int, WaypointData const&>)> fn);
|
||||
|
||||
//accessors & mutators
|
||||
TriggerData* Get(int uid);
|
||||
TriggerData* Get(std::string handle);
|
||||
WaypointData* Get(int uid);
|
||||
int GetLoadedCount();
|
||||
std::map<int, TriggerData>* GetContainer();
|
||||
std::map<int, WaypointData>* GetContainer();
|
||||
|
||||
//hooks
|
||||
lua_State* SetLuaState(lua_State* L);
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
private:
|
||||
//members
|
||||
std::map<int, TriggerData> elementMap;
|
||||
std::map<int, WaypointData> elementMap;
|
||||
lua_State* lua = nullptr;
|
||||
int counter = 0;
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
/* 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 "waypoint_manager_api.hpp"
|
||||
|
||||
#include "waypoint_manager.hpp"
|
||||
|
||||
//TODO: figure out a way to iterate through elements of managers from lua
|
||||
|
||||
static int create(lua_State* L) {
|
||||
WaypointManager* mgr = static_cast<WaypointManager*>(lua_touserdata(L, 1));
|
||||
//TODO
|
||||
}
|
||||
|
||||
static int unload(lua_State* L) {
|
||||
WaypointManager* mgr = static_cast<WaypointManager*>(lua_touserdata(L, 1));
|
||||
//TODO
|
||||
}
|
||||
|
||||
static int getWaypoint(lua_State* L) {
|
||||
WaypointManager* mgr = static_cast<WaypointManager*>(lua_touserdata(L, 1));
|
||||
lua_pushlightuserdata(L, mgr->Get(lua_tointeger(L, 2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getLoadedCount(lua_State* L) {
|
||||
WaypointManager* mgr = static_cast<WaypointManager*>(lua_touserdata(L, 1));
|
||||
lua_pushinteger(L, mgr->GetLoadedCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg waypointManagerLib[] = {
|
||||
{"Create",create},
|
||||
{"Unload",unload},
|
||||
{"GetWaypoint",getWaypoint},
|
||||
{"GetCount",getLoadedCount},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
LUAMOD_API int openWaypointManagerAPI(lua_State* L) {
|
||||
luaL_newlib(L, waypointManagerLib);
|
||||
return 1;
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
#ifndef WAYPOINTMANAGERAPI_HPP_
|
||||
#define WAYPOINTMANAGERAPI_HPP_
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
#define TORTUGA_WAYPOINT_MANAGER_API "waypoint_manager"
|
||||
LUAMOD_API int openWaypointManagerAPI(lua_State* L);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user