Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c51f820d5 | |||
| 8bf45bc8e4 | |||
| 5c1ea1988e |
@@ -1,6 +1,6 @@
|
|||||||
## Outline
|
## 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.
|
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.
|
||||||
|
|
||||||
@@ -20,17 +20,13 @@ The most recent stable build for Windows can be found [here](https://dl.dropboxu
|
|||||||
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
||||||
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
||||||
|
|
||||||
## Tools
|
|
||||||
|
|
||||||
* [WinRAR](http://www.rarlab.com/) - The best compression tool available IMO; only needed for distribution
|
|
||||||
|
|
||||||
## Copyright
|
## Copyright
|
||||||
|
|
||||||
(Future versions (to be determined) may be released under a modified version of the [Uplink Developer's License](http://www.introversion.co.uk/uplink/developer/license.html).)
|
(Future versions (to be determined) may be released under a modified version of the [Uplink Developer's License](http://www.introversion.co.uk/uplink/developer/license.html).)
|
||||||
|
|
||||||
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
||||||
|
|
||||||
Copyright (c) 2013-2015 Kayne Ruse
|
Copyright (c) 2013, 2014 Kayne Ruse
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ Both a game server and game client are included in this package.
|
|||||||
Instructions For Setup
|
Instructions For Setup
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
1. To create a server, simply run server.exe
|
1. To create a server, simply run server.exe.
|
||||||
(a public server is provided by default)
|
2. To join that server, run client.exe with config settings not already in use.
|
||||||
2. To join a server, your player information must be input into rsc/config.cfg
|
(Note: This process will be streamlined later).
|
||||||
(NOTE: This process will be streamlined later)
|
|
||||||
3. To change the config settings, open rsc/config.cfg
|
3. To change the config settings, open rsc/config.cfg
|
||||||
4. These settings must be unique for each player:
|
4. These settings must be unique for each player:
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ Instructions For Setup
|
|||||||
* client.avatar = elliot2.bmp #male
|
* client.avatar = elliot2.bmp #male
|
||||||
* client.avatar = coa2.bmp #female
|
* client.avatar = coa2.bmp #female
|
||||||
|
|
||||||
6. When you've correctly set these values, run client.exe, and select 'Start'
|
6. When you've correctly set these values (good luck), select 'Start' from the
|
||||||
from the main menu; this displays the list of available servers.
|
main menu; this displays the list of available servers.
|
||||||
7. Select the name of a server (default is 'Public') and select 'Join'.
|
7. Select the name of your server (default is 'local') and select 'Join'.
|
||||||
8. Welcome to Tortuga, enjoy your stay.
|
8. Welcome to Tortuga, enjoy your stay.
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "main_menu.hpp"
|
#include "main_menu.hpp"
|
||||||
#include "options_menu.hpp"
|
#include "options_menu.hpp"
|
||||||
#include "lobby_menu.hpp"
|
#include "lobby_menu.hpp"
|
||||||
#include "world.hpp"
|
#include "in_world.hpp"
|
||||||
#include "disconnected_screen.hpp"
|
#include "disconnected_screen.hpp"
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -83,6 +83,7 @@ void ClientApplication::Init(int argc, char* argv[]) {
|
|||||||
//debug output
|
//debug output
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
|
//TODO: enable/disable these with a switch
|
||||||
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
|
||||||
|
|
||||||
std::cout << "Internal sizes:" << std::endl;
|
std::cout << "Internal sizes:" << std::endl;
|
||||||
@@ -136,17 +137,11 @@ void ClientApplication::Proc() {
|
|||||||
realTime = Clock::now();
|
realTime = Clock::now();
|
||||||
|
|
||||||
//simulate game time
|
//simulate game time
|
||||||
if (simTime < realTime) {
|
while (simTime < realTime) {
|
||||||
while (simTime < realTime) {
|
//call each user defined function
|
||||||
//call each user defined function
|
activeScene->RunFrame();
|
||||||
activeScene->RunFrame();
|
//~60 FPS
|
||||||
//~60 FPS
|
simTime += std::chrono::duration<int, std::milli>(16);
|
||||||
simTime += std::chrono::duration<int, std::milli>(16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//give the machine a break
|
|
||||||
SDL_Delay(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw the game to the screen
|
//draw the game to the screen
|
||||||
@@ -169,7 +164,6 @@ void ClientApplication::Quit() {
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
||||||
//BUG: #16 Resources are being reloaded between scenes
|
|
||||||
UnloadScene();
|
UnloadScene();
|
||||||
switch(sceneIndex) {
|
switch(sceneIndex) {
|
||||||
//add scene creation calls here
|
//add scene creation calls here
|
||||||
@@ -186,8 +180,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
|
|||||||
case SceneList::LOBBYMENU:
|
case SceneList::LOBBYMENU:
|
||||||
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
|
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::WORLD:
|
case SceneList::INWORLD:
|
||||||
activeScene = new World(&clientIndex, &accountIndex);
|
activeScene = new InWorld(&clientIndex, &accountIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::DISCONNECTEDSCREEN:
|
case SceneList::DISCONNECTEDSCREEN:
|
||||||
activeScene = new DisconnectedScreen();
|
activeScene = new DisconnectedScreen();
|
||||||
|
|||||||
@@ -21,26 +21,3 @@
|
|||||||
*/
|
*/
|
||||||
#include "base_monster.hpp"
|
#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;
|
BaseMonster() = default;
|
||||||
virtual ~BaseMonster() = default;
|
virtual ~BaseMonster() = default;
|
||||||
|
|
||||||
void CorrectSprite();
|
|
||||||
|
|
||||||
std::string SetHandle(std::string s);
|
|
||||||
std::string GetHandle() const;
|
|
||||||
std::string SetAvatar(std::string s);
|
|
||||||
std::string GetAvatar() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//metadata
|
//
|
||||||
std::string handle;
|
|
||||||
std::string avatar;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,15 +21,59 @@
|
|||||||
*/
|
*/
|
||||||
#include "local_character.hpp"
|
#include "local_character.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
bool LocalCharacter::ProcessCollisions(std::list<BoundingBox>& boxList) {
|
||||||
|
if (CheckCollisionSimple(boxList, origin + motion)) {
|
||||||
|
Vector2 velocity;
|
||||||
|
velocity.x = CorrectVelocityX(boxList, motion.x);
|
||||||
|
velocity.y = CorrectVelocityY(boxList, motion.y);
|
||||||
|
origin += velocity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
origin += motion;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool LocalCharacter::ProcessCollisionGrid(std::list<BoundingBox> boxList) {
|
bool LocalCharacter::CheckCollisionSimple(std::list<BoundingBox>& boxList, Vector2 newPos) {
|
||||||
for(auto& box : boxList) {
|
for (auto& it : boxList) {
|
||||||
if (box.CheckOverlap(origin + bounds)) {
|
if (it.CheckOverlap(bounds + newPos)) {
|
||||||
origin -= motion;
|
|
||||||
motion = {0, 0};
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double LocalCharacter::CorrectVelocityX(std::list<BoundingBox>& boxList, double velocityX) {
|
||||||
|
double ret = velocityX;
|
||||||
|
for (auto& it : boxList) {
|
||||||
|
if (it.CheckOverlap(bounds + origin + Vector2(velocityX, 0) )) {
|
||||||
|
if (velocityX > 0) {
|
||||||
|
ret = std::min(ret, it.x - (origin.x + bounds.x + bounds.w -1));
|
||||||
|
ret = std::min(ret, 0.0);
|
||||||
|
}
|
||||||
|
else if (velocityX < 0) {
|
||||||
|
ret = std::max(ret, (it.x + it.w) - (origin.x + bounds.x));
|
||||||
|
ret = std::max(ret, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
double LocalCharacter::CorrectVelocityY(std::list<BoundingBox>& boxList, double velocityY) {
|
||||||
|
double ret = velocityY;
|
||||||
|
for (auto& it : boxList) {
|
||||||
|
if (it.CheckOverlap(bounds + origin + Vector2(0, velocityY) )) {
|
||||||
|
if (velocityY > 0) {
|
||||||
|
ret = std::min(ret, it.y - (origin.y + bounds.y + bounds.h -1));
|
||||||
|
ret = std::min(ret, 0.0);
|
||||||
|
}
|
||||||
|
else if (velocityY < 0) {
|
||||||
|
ret = std::max(ret, (it.y + it.h) - (origin.y + bounds.y));
|
||||||
|
ret = std::max(ret, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,10 +33,12 @@ public:
|
|||||||
LocalCharacter() = default;
|
LocalCharacter() = default;
|
||||||
virtual ~LocalCharacter() = default;
|
virtual ~LocalCharacter() = default;
|
||||||
|
|
||||||
bool ProcessCollisionGrid(std::list<BoundingBox>);
|
bool ProcessCollisions(std::list<BoundingBox>& boxList);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
//NOTE: NO MEMBERS
|
bool CheckCollisionSimple(std::list<BoundingBox>& boxList, Vector2 newPos);
|
||||||
|
double CorrectVelocityX(std::list<BoundingBox>& boxList, double velocityX);
|
||||||
|
double CorrectVelocityY(std::list<BoundingBox>& boxList, double velocityY);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,239 +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>
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//character management
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
//DOCS: preexisting characters will result in query responses
|
|
||||||
//DOCS: new characters will result in create messages
|
|
||||||
//DOCS: this client's character will exist in both (skipped)
|
|
||||||
|
|
||||||
void World::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) {
|
|
||||||
//prevent double message
|
|
||||||
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
|
|
||||||
std::ostringstream msg;
|
|
||||||
msg << "Double character creation event; ";
|
|
||||||
msg << "Index: " << argPacket->characterIndex << "; ";
|
|
||||||
msg << "Handle: " << argPacket->handle;
|
|
||||||
throw(std::runtime_error(msg.str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//implicity create and retrieve the entity
|
|
||||||
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
|
||||||
|
|
||||||
//fill the character's info
|
|
||||||
character->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
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hCharacterDelete(CharacterPacket* const argPacket) {
|
|
||||||
//ignore if this character doesn't exist
|
|
||||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
|
||||||
if (characterIt == characterMap.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check for this player's character
|
|
||||||
if ((*characterIt).second.GetOwner() == accountIndex) {
|
|
||||||
localCharacter = nullptr;
|
|
||||||
|
|
||||||
//clear the camera
|
|
||||||
camera.marginX = 0;
|
|
||||||
camera.marginY = 0;
|
|
||||||
|
|
||||||
//clear the room
|
|
||||||
roomIndex = -1;
|
|
||||||
regionPager.UnloadAll();
|
|
||||||
characterMap.clear();
|
|
||||||
monsterMap.clear();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//remove this character
|
|
||||||
characterMap.erase(characterIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
|
|
||||||
//prevent a double message about this player's character
|
|
||||||
// if (argPacket->accountIndex == accountIndex) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//ignore characters in a different room (sub-optimal)
|
|
||||||
if (argPacket->roomIndex != roomIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//implicitly construct the character if it doesn't exist
|
|
||||||
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
|
||||||
|
|
||||||
//set/update the character's info
|
|
||||||
character->SetOrigin(argPacket->origin);
|
|
||||||
character->SetMotion(argPacket->motion);
|
|
||||||
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
|
||||||
character->SetHandle(argPacket->handle);
|
|
||||||
character->SetAvatar(argPacket->avatar);
|
|
||||||
character->SetOwner(argPacket->accountIndex);
|
|
||||||
character->CorrectSprite();
|
|
||||||
|
|
||||||
//debug
|
|
||||||
std::cout << "Character Query, total: " << characterMap.size() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
|
|
||||||
//TODO: (9) World::hQueryCharacterStats()
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
|
|
||||||
//TODO: (9) World::hQueryCharacterLocation()
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hCharacterMovement(CharacterPacket* const argPacket) {
|
|
||||||
//TODO: (1) Authentication
|
|
||||||
if (argPacket->characterIndex == characterIndex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check that this character exists
|
|
||||||
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
|
||||||
if (characterIt != characterMap.end()) {
|
|
||||||
//set the origin and motion
|
|
||||||
characterIt->second.SetOrigin(argPacket->origin);
|
|
||||||
characterIt->second.SetMotion(argPacket->motion);
|
|
||||||
characterIt->second.CorrectSprite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hCharacterAttack(CharacterPacket* const argPacket) {
|
|
||||||
//TODO: (9) World::hCharacterAttack()
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::hCharacterDamage(CharacterPacket* const argPacket) {
|
|
||||||
//TODO: (9) World::hCharacterDamage()
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//player movement & collision
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void World::SendLocalCharacterMovement() {
|
|
||||||
CharacterPacket newPacket;
|
|
||||||
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
|
|
||||||
|
|
||||||
newPacket.accountIndex = accountIndex;
|
|
||||||
newPacket.characterIndex = characterIndex;
|
|
||||||
newPacket.roomIndex = roomIndex;
|
|
||||||
newPacket.origin = localCharacter->GetOrigin();
|
|
||||||
newPacket.motion = localCharacter->GetMotion();
|
|
||||||
|
|
||||||
network.SendTo(Channels::SERVER, &newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<BoundingBox> World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
|
|
||||||
//prepare for collisions
|
|
||||||
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
|
|
||||||
std::list<BoundingBox> boxList;
|
|
||||||
|
|
||||||
//NOTE: for loops were too dense to work with, so I've just used while loops
|
|
||||||
|
|
||||||
//outer loop
|
|
||||||
wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x);
|
|
||||||
while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) {
|
|
||||||
//inner loop
|
|
||||||
wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y);
|
|
||||||
while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) {
|
|
||||||
//check to see if this tile is solid
|
|
||||||
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
|
|
||||||
//push onto the box set
|
|
||||||
boxList.push_front(wallBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
//increment
|
|
||||||
wallBounds.y += wallBounds.h;
|
|
||||||
}
|
|
||||||
|
|
||||||
//increment
|
|
||||||
wallBounds.x += wallBounds.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::move(boxList);
|
|
||||||
}
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
+2
-3
@@ -1,5 +1,5 @@
|
|||||||
#include directories
|
#include directories
|
||||||
INCLUDES+=. client_utilities entities gameplay_scenes menu_scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities
|
INCLUDES+=. client_utilities entities scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities
|
||||||
|
|
||||||
#libraries
|
#libraries
|
||||||
#the order of the $(LIBS) is important, at least for MinGW
|
#the order of the $(LIBS) is important, at least for MinGW
|
||||||
@@ -27,8 +27,7 @@ OUT=$(addprefix $(OUTDIR)/,client)
|
|||||||
all: $(OBJ) $(OUT)
|
all: $(OBJ) $(OUT)
|
||||||
$(MAKE) -C client_utilities
|
$(MAKE) -C client_utilities
|
||||||
$(MAKE) -C entities
|
$(MAKE) -C entities
|
||||||
$(MAKE) -C gameplay_scenes
|
$(MAKE) -C scenes
|
||||||
$(MAKE) -C menu_scenes
|
|
||||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
#config
|
|
||||||
INCLUDES+=. .. ../../common/graphics ../../common/map ../../common/network ../../common/network/packet_types ../../common/ui ../../common/utilities
|
|
||||||
LIBS+=
|
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
|
||||||
|
|
||||||
#source
|
|
||||||
CXXSRC=$(wildcard *.cpp)
|
|
||||||
|
|
||||||
#objects
|
|
||||||
OBJDIR=obj
|
|
||||||
OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o))
|
|
||||||
|
|
||||||
#output
|
|
||||||
OUTDIR=..
|
|
||||||
OUT=$(addprefix $(OUTDIR)/,client.a)
|
|
||||||
|
|
||||||
#targets
|
|
||||||
all: $(OBJ) $(OUT)
|
|
||||||
ar -crs $(OUT) $(OBJ)
|
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
|
||||||
|
|
||||||
$(OUT): | $(OUTDIR)
|
|
||||||
|
|
||||||
$(OBJDIR):
|
|
||||||
mkdir $(OBJDIR)
|
|
||||||
|
|
||||||
$(OUTDIR):
|
|
||||||
mkdir $(OUTDIR)
|
|
||||||
|
|
||||||
$(OBJDIR)/%.o: %.cpp
|
|
||||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) *.o *.a *.exe
|
|
||||||
|
|
||||||
rebuild: clean all
|
|
||||||
@@ -33,7 +33,7 @@ enum class SceneList {
|
|||||||
MAINMENU,
|
MAINMENU,
|
||||||
OPTIONSMENU,
|
OPTIONSMENU,
|
||||||
LOBBYMENU,
|
LOBBYMENU,
|
||||||
WORLD,
|
INWORLD,
|
||||||
DISCONNECTEDSCREEN,
|
DISCONNECTEDSCREEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void BaseScene::HandleEvents() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
#ifdef USE_EVENT_JOYSTICK
|
||||||
//EMPTY
|
//TODO: joystick/gamepad support
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
#ifdef USE_EVENT_UNKNOWN
|
||||||
@@ -59,7 +59,7 @@ protected:
|
|||||||
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
#ifdef USE_EVENT_JOYSTICK
|
||||||
//EMPTY
|
//TODO: joystick/gamepad support
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
#ifdef USE_EVENT_UNKNOWN
|
||||||
@@ -0,0 +1,731 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013-2015
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "in_world.hpp"
|
||||||
|
|
||||||
|
#include "channels.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
|
#include "terminal_error.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//these should've come standard
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
bool operator==(IPaddress lhs, IPaddress rhs) {
|
||||||
|
return lhs.host == rhs.host && lhs.port == rhs.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(IPaddress lhs, IPaddress rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Public access members
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
|
||||||
|
clientIndex(*argClientIndex),
|
||||||
|
accountIndex(*argAccountIndex)
|
||||||
|
{
|
||||||
|
//setup the utility objects
|
||||||
|
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
||||||
|
buttonImage.SetClipH(buttonImage.GetClipH()/3);
|
||||||
|
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
||||||
|
|
||||||
|
//pass the utility objects
|
||||||
|
disconnectButton.SetImage(&buttonImage);
|
||||||
|
disconnectButton.SetFont(&font);
|
||||||
|
shutDownButton.SetImage(&buttonImage);
|
||||||
|
shutDownButton.SetFont(&font);
|
||||||
|
|
||||||
|
//set the button positions
|
||||||
|
disconnectButton.SetX(50);
|
||||||
|
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
|
||||||
|
shutDownButton.SetX(50);
|
||||||
|
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
|
||||||
|
|
||||||
|
//set the button texts
|
||||||
|
disconnectButton.SetText("Disconnect");
|
||||||
|
shutDownButton.SetText("Shut Down");
|
||||||
|
|
||||||
|
//load the tilesheet
|
||||||
|
//TODO: add the tilesheet to the map system
|
||||||
|
//TODO: Tile size and tile sheet should be loaded elsewhere
|
||||||
|
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
|
||||||
|
|
||||||
|
//Send the character data
|
||||||
|
//TODO: login scene, prompt, etc.
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::CHARACTER_LOAD;
|
||||||
|
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
|
||||||
|
//query the world state
|
||||||
|
memset(&newPacket, 0, MAX_PACKET_SIZE);
|
||||||
|
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
|
||||||
|
//set the camera's values
|
||||||
|
camera.width = GetScreen()->w;
|
||||||
|
camera.height = GetScreen()->h;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
InWorld::~InWorld() {
|
||||||
|
//unload the local data
|
||||||
|
characterMap.clear();
|
||||||
|
monsterMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Frame loop
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::FrameStart() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::Update() {
|
||||||
|
//create and zero the buffer
|
||||||
|
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
|
||||||
|
memset(packetBuffer, 0, MAX_PACKET_SIZE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
//suck in and process all waiting packets
|
||||||
|
while(network.Receive(packetBuffer)) {
|
||||||
|
HandlePacket(packetBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(terminal_error& e) {
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
catch(std::exception& e) {
|
||||||
|
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free the buffer
|
||||||
|
delete reinterpret_cast<char*>(packetBuffer);
|
||||||
|
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//prepare for collisions
|
||||||
|
BoundingBox wallBounds = {0, 0, tileSheet.GetTileW(), tileSheet.GetTileH()};
|
||||||
|
std::list<BoundingBox> boxList;
|
||||||
|
|
||||||
|
//NOTE: for loops were too dense to work with, so I've just used while loops
|
||||||
|
//NOTE: this code is complex, and can be replaced with hard-coded relative positions, at the cost of variable-sized sprites/bounding boxes
|
||||||
|
|
||||||
|
//outer loop
|
||||||
|
wallBounds.x = snapToBase((double)wallBounds.w, localCharacter->GetOrigin().x) - wallBounds.w;
|
||||||
|
while(wallBounds.x < (localCharacter->GetOrigin() + localCharacter->GetBounds()).x + localCharacter->GetBounds().w) {
|
||||||
|
//inner loop
|
||||||
|
wallBounds.y = snapToBase((double)wallBounds.h, localCharacter->GetOrigin().y) - wallBounds.h;
|
||||||
|
while(wallBounds.y < (localCharacter->GetOrigin() + localCharacter->GetBounds()).y + localCharacter->GetBounds().h) {
|
||||||
|
//check to see if this tile is solid
|
||||||
|
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
|
||||||
|
//push onto the box set
|
||||||
|
boxList.push_front(wallBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
//increment
|
||||||
|
wallBounds.y += wallBounds.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
//increment
|
||||||
|
wallBounds.x += wallBounds.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
//process the collisions
|
||||||
|
localCharacter->ProcessCollisions(boxList);
|
||||||
|
|
||||||
|
//update the camera
|
||||||
|
camera.x = localCharacter->GetOrigin().x - camera.marginX;
|
||||||
|
camera.y = localCharacter->GetOrigin().y - camera.marginY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::FrameEnd() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::RenderFrame() {
|
||||||
|
SDL_FillRect(GetScreen(), 0, 0);
|
||||||
|
Render(GetScreen());
|
||||||
|
SDL_Flip(GetScreen());
|
||||||
|
fps.Calculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::Render(SDL_Surface* const screen) {
|
||||||
|
//draw the map
|
||||||
|
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
|
||||||
|
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw the entities
|
||||||
|
for (auto& it : characterMap) {
|
||||||
|
//TODO: depth ordering
|
||||||
|
it.second.DrawTo(screen, camera.x, camera.y);
|
||||||
|
}
|
||||||
|
for (auto& it : monsterMap) {
|
||||||
|
//TODO: depth ordering
|
||||||
|
it.second.DrawTo(screen, camera.x, camera.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw UI
|
||||||
|
disconnectButton.DrawTo(screen);
|
||||||
|
shutDownButton.DrawTo(screen);
|
||||||
|
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Event handlers
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::QuitEvent() {
|
||||||
|
//two-step logout
|
||||||
|
SendDisconnectRequest();
|
||||||
|
SetNextScene(SceneList::QUIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) {
|
||||||
|
disconnectButton.MouseMotion(motion);
|
||||||
|
shutDownButton.MouseMotion(motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
||||||
|
disconnectButton.MouseButtonDown(button);
|
||||||
|
shutDownButton.MouseButtonDown(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||||
|
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
||||||
|
SendLogoutRequest();
|
||||||
|
}
|
||||||
|
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
|
||||||
|
SendShutdownRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
|
||||||
|
//hotkeys
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
//TODO: the escape key should actually control menus and stuff
|
||||||
|
SendLogoutRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//character movement
|
||||||
|
if (!localCharacter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 motion = localCharacter->GetMotion();
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_w:
|
||||||
|
motion.y -= CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_a:
|
||||||
|
motion.x -= CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
motion.y += CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
case SDLK_d:
|
||||||
|
motion.x += CHARACTER_WALKING_SPEED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//DOCS: prevents wrong keys screwing with character movement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//handle diagonals
|
||||||
|
if (motion.x != 0 && motion.y != 0) {
|
||||||
|
motion *= CHARACTER_WALKING_MOD;
|
||||||
|
}
|
||||||
|
//set the info
|
||||||
|
localCharacter->SetMotion(motion);
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
SendLocalCharacterMotion();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
|
||||||
|
//character movement
|
||||||
|
if (!localCharacter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 motion = localCharacter->GetMotion();
|
||||||
|
switch(key.keysym.sym) {
|
||||||
|
case SDLK_w:
|
||||||
|
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_a:
|
||||||
|
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
case SDLK_d:
|
||||||
|
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//DOCS: prevents wrong keys screwing with character movement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//BUGFIX: reset cardinal direction speed on key release
|
||||||
|
if (motion.x > 0) {
|
||||||
|
motion.x = CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
else if (motion.x < 0) {
|
||||||
|
motion.x = -CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
if (motion.y > 0) {
|
||||||
|
motion.y = CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
else if (motion.y < 0) {
|
||||||
|
motion.y = -CHARACTER_WALKING_SPEED;
|
||||||
|
}
|
||||||
|
//handle diagonals
|
||||||
|
if (motion.x != 0 && motion.y != 0) {
|
||||||
|
motion *= CHARACTER_WALKING_MOD;
|
||||||
|
}
|
||||||
|
//set the info
|
||||||
|
localCharacter->SetMotion(motion);
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
SendLocalCharacterMotion();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Basic connections
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::HandlePacket(SerialPacket* const argPacket) {
|
||||||
|
switch(argPacket->type) {
|
||||||
|
//heartbeat system
|
||||||
|
case SerialPacketType::PING:
|
||||||
|
HandlePing(static_cast<ServerPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::PONG:
|
||||||
|
HandlePong(static_cast<ServerPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//game server connections
|
||||||
|
case SerialPacketType::LOGOUT_RESPONSE:
|
||||||
|
HandleLogoutResponse(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||||
|
HandleDisconnectResponse(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::DISCONNECT_FORCED:
|
||||||
|
HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//map management
|
||||||
|
case SerialPacketType::REGION_CONTENT:
|
||||||
|
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//character management
|
||||||
|
case SerialPacketType::CHARACTER_CREATE:
|
||||||
|
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_DELETE:
|
||||||
|
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::QUERY_CHARACTER_EXISTS:
|
||||||
|
HandleCharacterQueryExists(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//character movement
|
||||||
|
case SerialPacketType::CHARACTER_SET_ROOM:
|
||||||
|
HandleCharacterSetRoom(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
||||||
|
HandleCharacterSetOrigin(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::CHARACTER_SET_MOTION:
|
||||||
|
HandleCharacterSetMotion(static_cast<CharacterPacket*>(argPacket));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//rejection messages
|
||||||
|
case SerialPacketType::REGION_REJECTION:
|
||||||
|
case SerialPacketType::CHARACTER_REJECTION:
|
||||||
|
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||||
|
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//errors
|
||||||
|
default: {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Unknown SerialPacketType encountered in InWorld: " << static_cast<int>(argPacket->type);
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandlePing(ServerPacket* const argPacket) {
|
||||||
|
ServerPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::PONG;
|
||||||
|
network.SendTo(argPacket->srcAddress, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandlePong(ServerPacket* const argPacket) {
|
||||||
|
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
|
||||||
|
throw(std::runtime_error("Heartbeat message received from an unknown source"));
|
||||||
|
}
|
||||||
|
attemptedBeats = 0;
|
||||||
|
lastBeat = Clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Connection control
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::SendLogoutRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a logout request
|
||||||
|
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::SendDisconnectRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a disconnect request
|
||||||
|
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
|
||||||
|
newPacket.clientIndex = clientIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::SendShutdownRequest() {
|
||||||
|
ClientPacket newPacket;
|
||||||
|
|
||||||
|
//send a shutdown request
|
||||||
|
newPacket.type = SerialPacketType::SHUTDOWN_REQUEST;
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleLogoutResponse(ClientPacket* const argPacket) {
|
||||||
|
if (localCharacter) {
|
||||||
|
characterMap.erase(characterIndex);
|
||||||
|
localCharacter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountIndex = -1;
|
||||||
|
characterIndex = -1;
|
||||||
|
|
||||||
|
//reset the camera
|
||||||
|
camera.marginX = camera.marginY = 0;
|
||||||
|
|
||||||
|
//because, why not? I guess...
|
||||||
|
SendDisconnectRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleDisconnectResponse(ClientPacket* const argPacket) {
|
||||||
|
HandleLogoutResponse(argPacket);//shortcut
|
||||||
|
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
||||||
|
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleDisconnectForced(ClientPacket* const argPacket) {
|
||||||
|
HandleDisconnectResponse(argPacket);//shortcut
|
||||||
|
SetNextScene(SceneList::DISCONNECTEDSCREEN);
|
||||||
|
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//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.UnloadRegion(argPacket->x, argPacket->y);
|
||||||
|
regionPager.PushRegion(argPacket->region);
|
||||||
|
|
||||||
|
//clean up after the serial code
|
||||||
|
delete argPacket->region;
|
||||||
|
argPacket->region = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::UpdateMap() {
|
||||||
|
if (roomIndex == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
|
||||||
|
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
|
||||||
|
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
|
||||||
|
|
||||||
|
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
|
||||||
|
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
|
||||||
|
|
||||||
|
//prune distant regions
|
||||||
|
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
|
||||||
|
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
|
||||||
|
});
|
||||||
|
|
||||||
|
//request empty regions within this zone
|
||||||
|
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
|
||||||
|
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
|
||||||
|
if (!regionPager.FindRegion(i, j)) {
|
||||||
|
SendRegionRequest(roomIndex, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//entity management
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//NOTE: preexisting characters will result in query responses
|
||||||
|
//NOTE: new characters will result in create messages
|
||||||
|
//NOTE: this client's character will exist in both (skipped)
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) {
|
||||||
|
//prevent double message
|
||||||
|
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "Double character creation event; ";
|
||||||
|
msg << "Index: " << argPacket->characterIndex << "; ";
|
||||||
|
msg << "Handle: " << argPacket->handle;
|
||||||
|
throw(std::runtime_error(msg.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicity create and retrieve the entity
|
||||||
|
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
||||||
|
|
||||||
|
//fill the character's info
|
||||||
|
character->SetOrigin(argPacket->origin);
|
||||||
|
character->SetMotion(argPacket->motion);
|
||||||
|
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
||||||
|
character->SetHandle(argPacket->handle);
|
||||||
|
character->SetAvatar(argPacket->avatar);
|
||||||
|
character->SetOwner(argPacket->accountIndex);
|
||||||
|
character->CorrectSprite();
|
||||||
|
|
||||||
|
//check for this player's character
|
||||||
|
if (character->GetOwner() == accountIndex) {
|
||||||
|
localCharacter = static_cast<LocalCharacter*>(character);
|
||||||
|
|
||||||
|
//focus the camera on this character
|
||||||
|
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
|
||||||
|
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
|
||||||
|
|
||||||
|
//focus on this character's info
|
||||||
|
characterIndex = argPacket->characterIndex;
|
||||||
|
roomIndex = argPacket->roomIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Create, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) {
|
||||||
|
//ignore if this character doesn't exist
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt == characterMap.end()) {
|
||||||
|
//debug
|
||||||
|
std::cout << "Ignoring character deletion" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for this player's character
|
||||||
|
if ((*characterIt).second.GetOwner() == accountIndex) {
|
||||||
|
localCharacter = nullptr;
|
||||||
|
|
||||||
|
//clear the camera
|
||||||
|
camera.marginX = 0;
|
||||||
|
camera.marginY = 0;
|
||||||
|
|
||||||
|
//clear the room
|
||||||
|
roomIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove this character
|
||||||
|
characterMap.erase(characterIt);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Delete, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) {
|
||||||
|
//prevent a double message about this player's character
|
||||||
|
if (argPacket->accountIndex == accountIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ignore characters in a different room (sub-optimal)
|
||||||
|
if (argPacket->roomIndex != roomIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//implicitly construct the character if it doesn't exist
|
||||||
|
BaseCharacter* character = &characterMap[argPacket->characterIndex];
|
||||||
|
|
||||||
|
//set/update the character's info
|
||||||
|
character->SetOrigin(argPacket->origin);
|
||||||
|
character->SetMotion(argPacket->motion);
|
||||||
|
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
|
||||||
|
character->SetHandle(argPacket->handle);
|
||||||
|
character->SetAvatar(argPacket->avatar);
|
||||||
|
character->SetOwner(argPacket->accountIndex);
|
||||||
|
character->CorrectSprite();
|
||||||
|
|
||||||
|
//debug
|
||||||
|
std::cout << "Query, total: " << characterMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterSetRoom(CharacterPacket* const argPacket) {
|
||||||
|
//someone else's character
|
||||||
|
if (argPacket->characterIndex != characterIndex) {
|
||||||
|
characterMap.erase(argPacket->characterIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this character is moving between rooms
|
||||||
|
roomIndex = argPacket->roomIndex;
|
||||||
|
|
||||||
|
//set the character's info
|
||||||
|
localCharacter->SetOrigin(argPacket->origin);
|
||||||
|
localCharacter->SetMotion(argPacket->motion);
|
||||||
|
localCharacter->CorrectSprite();
|
||||||
|
|
||||||
|
//clear the old room's data
|
||||||
|
regionPager.UnloadAll();
|
||||||
|
monsterMap.clear();
|
||||||
|
|
||||||
|
//use the jenky pattern for std::map to skip this player's character
|
||||||
|
for (std::map<int, BaseCharacter>::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) {
|
||||||
|
if (it->first != characterIndex) {
|
||||||
|
it = characterMap.erase(it);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//request the info on characters in this room
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
|
||||||
|
newPacket.roomIndex = roomIndex;
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterSetOrigin(CharacterPacket* const argPacket) {
|
||||||
|
//check that this character exists
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt != characterMap.end()) {
|
||||||
|
//set the origin and motion
|
||||||
|
characterIt->second.SetOrigin(argPacket->origin);
|
||||||
|
characterIt->second.SetMotion(argPacket->motion);
|
||||||
|
characterIt->second.CorrectSprite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterSetMotion(CharacterPacket* const argPacket) {
|
||||||
|
//check that this character exists
|
||||||
|
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
|
||||||
|
if (characterIt != characterMap.end()) {
|
||||||
|
//set the origin and motion
|
||||||
|
characterIt->second.SetOrigin(argPacket->origin);
|
||||||
|
characterIt->second.SetMotion(argPacket->motion);
|
||||||
|
characterIt->second.CorrectSprite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//player movement
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//TODO: add a "movement" packet type
|
||||||
|
void InWorld::SendLocalCharacterMotion() {
|
||||||
|
CharacterPacket newPacket;
|
||||||
|
newPacket.type = SerialPacketType::CHARACTER_SET_MOTION;
|
||||||
|
|
||||||
|
newPacket.accountIndex = accountIndex;
|
||||||
|
newPacket.characterIndex = characterIndex;
|
||||||
|
newPacket.roomIndex = roomIndex;
|
||||||
|
newPacket.origin = localCharacter->GetOrigin();
|
||||||
|
newPacket.motion = localCharacter->GetMotion();
|
||||||
|
|
||||||
|
network.SendTo(Channels::SERVER, &newPacket);
|
||||||
|
}
|
||||||
@@ -49,11 +49,11 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class World: public BaseScene {
|
class InWorld : public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
World(int* const argClientIndex, int* const argAccountIndex);
|
InWorld(int* const argClientIndex, int* const argAccountIndex);
|
||||||
~World();
|
~InWorld();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//Frame loop
|
//Frame loop
|
||||||
@@ -71,59 +71,35 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
//handle incoming traffic
|
//Basic connections
|
||||||
void HandlePacket(SerialPacket* const);
|
void HandlePacket(SerialPacket* const);
|
||||||
|
void HandlePing(ServerPacket* const);
|
||||||
|
void HandlePong(ServerPacket* const);
|
||||||
|
|
||||||
//heartbeat system
|
//Connection control
|
||||||
void hPing(ServerPacket* const);
|
|
||||||
void hPong(ServerPacket* const);
|
|
||||||
|
|
||||||
void CheckHeartBeat();
|
|
||||||
|
|
||||||
//basic connections
|
|
||||||
void SendLogoutRequest();
|
void SendLogoutRequest();
|
||||||
void SendDisconnectRequest();
|
void SendDisconnectRequest();
|
||||||
void SendAdminDisconnectForced();
|
void SendShutdownRequest();
|
||||||
void SendAdminShutdownRequest();
|
|
||||||
|
|
||||||
void hLogoutResponse(ClientPacket* const);
|
void HandleLogoutResponse(ClientPacket* const);
|
||||||
void hDisconnectResponse(ClientPacket* const);
|
void HandleDisconnectResponse(ClientPacket* const);
|
||||||
void hAdminDisconnectForced(ClientPacket* const);
|
void HandleDisconnectForced(ClientPacket* const);
|
||||||
|
|
||||||
//map management
|
//map management
|
||||||
void SendRegionRequest(int roomIndex, int x, int y);
|
void SendRegionRequest(int roomIndex, int x, int y);
|
||||||
void hRegionContent(RegionPacket* const);
|
void HandleRegionContent(RegionPacket* const);
|
||||||
void UpdateMap();
|
void UpdateMap();
|
||||||
|
|
||||||
//character management
|
//character management
|
||||||
void hCharacterUpdate(CharacterPacket* const);
|
void HandleCharacterCreate(CharacterPacket* const);
|
||||||
void hCharacterCreate(CharacterPacket* const);
|
void HandleCharacterDelete(CharacterPacket* const);
|
||||||
void hCharacterDelete(CharacterPacket* const);
|
void HandleCharacterQueryExists(CharacterPacket* const);
|
||||||
void hQueryCharacterExists(CharacterPacket* const);
|
void HandleCharacterSetRoom(CharacterPacket* const);
|
||||||
void hQueryCharacterStats(CharacterPacket* const);
|
void HandleCharacterSetOrigin(CharacterPacket* const);
|
||||||
void hQueryCharacterLocation(CharacterPacket* const);
|
void HandleCharacterSetMotion(CharacterPacket* const);
|
||||||
void hCharacterMovement(CharacterPacket* const);
|
|
||||||
void hCharacterAttack(CharacterPacket* const);
|
|
||||||
void hCharacterDamage(CharacterPacket* const);
|
|
||||||
|
|
||||||
//monster management
|
//player movement
|
||||||
void hMonsterCreate(MonsterPacket* const);
|
void SendLocalCharacterMotion();
|
||||||
void hMonsterDelete(MonsterPacket* const);
|
|
||||||
void hQueryMonsterExists(MonsterPacket* const);
|
|
||||||
void hQueryMonsterStats(MonsterPacket* const);
|
|
||||||
void hQueryMonsterLocation(MonsterPacket* const);
|
|
||||||
void hMonsterMovement(MonsterPacket* const);
|
|
||||||
void hMonsterAttack(MonsterPacket* const);
|
|
||||||
void hMonsterDamage(MonsterPacket* const);
|
|
||||||
|
|
||||||
//chat
|
|
||||||
void hTextBroadcast(TextPacket* const);
|
|
||||||
void hTextSpeech(TextPacket* const);
|
|
||||||
void hTextWhisper(TextPacket* const);
|
|
||||||
|
|
||||||
//general gameplay
|
|
||||||
void SendLocalCharacterMovement();
|
|
||||||
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
|
|
||||||
|
|
||||||
//indexes
|
//indexes
|
||||||
int& clientIndex;
|
int& clientIndex;
|
||||||
@@ -157,7 +133,7 @@ protected:
|
|||||||
LocalCharacter* localCharacter = nullptr;
|
LocalCharacter* localCharacter = nullptr;
|
||||||
|
|
||||||
//heartbeat
|
//heartbeat
|
||||||
//TODO: (2) Heartbeat needs it's own utility
|
//TODO: Heartbeat needs it's own utility
|
||||||
typedef std::chrono::steady_clock Clock;
|
typedef std::chrono::steady_clock Clock;
|
||||||
Clock::time_point lastBeat = Clock::now();
|
Clock::time_point lastBeat = Clock::now();
|
||||||
int attemptedBeats = 0;
|
int attemptedBeats = 0;
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
#include "lobby_menu.hpp"
|
#include "lobby_menu.hpp"
|
||||||
|
|
||||||
#include "channels.hpp"
|
#include "channels.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Public access members
|
//Public access members
|
||||||
@@ -100,15 +100,14 @@ void LobbyMenu::FrameEnd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::Render(SDL_Surface* const screen) {
|
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
|
//UI
|
||||||
search.DrawTo(screen);
|
search.DrawTo(screen);
|
||||||
join.DrawTo(screen);
|
join.DrawTo(screen);
|
||||||
back.DrawTo(screen);
|
back.DrawTo(screen);
|
||||||
|
|
||||||
//TODO: (3) draw headers for the server list
|
//TODO: draw headers for the server list
|
||||||
//TODO: (3) ping/delay displayed in the server list
|
|
||||||
for (int i = 0; i < serverInfo.size(); i++) {
|
for (int i = 0; i < serverInfo.size(); i++) {
|
||||||
//draw the selected server's highlight
|
//draw the selected server's highlight
|
||||||
if (selection == &serverInfo[i]) {
|
if (selection == &serverInfo[i]) {
|
||||||
@@ -124,14 +123,14 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
|
|||||||
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
||||||
|
|
||||||
//draw the player count
|
//draw the player count
|
||||||
std::ostringstream msg;
|
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
|
||||||
msg << serverInfo[i].playerCount;
|
|
||||||
font.DrawStringTo(msg.str(), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
|
|
||||||
|
|
||||||
//compatible?
|
//compatible?
|
||||||
if (!serverInfo[i].compatible) {
|
if (!serverInfo[i].compatible) {
|
||||||
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: ping/delay?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,11 +210,8 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
//handle errors
|
//handle errors
|
||||||
default: {
|
default:
|
||||||
std::ostringstream msg;
|
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast<int>(argPacket->type)) ));
|
||||||
msg << "Unknown SerialPacketType encountered in LobbyMenu: " << static_cast<int>(argPacket->type);
|
|
||||||
throw(std::runtime_error( msg.str() ));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,15 +245,15 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
|
|||||||
throw(std::runtime_error("Client index invalid during login"));
|
throw(std::runtime_error("Client index invalid during login"));
|
||||||
}
|
}
|
||||||
accountIndex = argPacket->accountIndex;
|
accountIndex = argPacket->accountIndex;
|
||||||
SetNextScene(SceneList::WORLD);
|
SetNextScene(SceneList::INWORLD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
||||||
//TODO: (9) LobbyMenu::HandleJoinRejection()
|
//TODO: Better output for join rejection
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
|
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
|
||||||
//TODO: (9) LobbyMenu::HandleLoginRejection
|
//TODO: Better output for login rejection
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -84,11 +84,6 @@ void MainMenu::Render(SDL_Surface* const screen) {
|
|||||||
startButton.DrawTo(screen);
|
startButton.DrawTo(screen);
|
||||||
optionsButton.DrawTo(screen);
|
optionsButton.DrawTo(screen);
|
||||||
quitButton.DrawTo(screen);
|
quitButton.DrawTo(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -108,7 +103,7 @@ void MainMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu::MouseButtonUp(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) {
|
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
|
||||||
SetNextScene(SceneList::LOBBYMENU);
|
SetNextScene(SceneList::LOBBYMENU);
|
||||||
}
|
}
|
||||||
@@ -125,9 +120,5 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
||||||
switch(key.keysym.sym) {
|
//
|
||||||
case SDLK_ESCAPE:
|
|
||||||
QuitEvent();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "raster_font.hpp"
|
#include "raster_font.hpp"
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
|
|
||||||
//NOTE: The options screen needs to be USED
|
//TODO: The options screen needs to be USED
|
||||||
class OptionsMenu : public BaseScene {
|
class OptionsMenu : public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ../map
|
INCLUDES+=.
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ../utilities
|
INCLUDES+=. ../graphics ../utilities
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* 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"
|
||||||
|
#include "tile_sheet_api.hpp"
|
||||||
|
|
||||||
|
//macros
|
||||||
|
#include "region.hpp"
|
||||||
|
|
||||||
|
//useful "globals"
|
||||||
|
static int getRegionWidth(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_WIDTH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRegionHeight(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_HEIGHT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRegionDepth(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_DEPTH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This mimics linit.c to create a nested collection of all map modules.
|
||||||
|
static const luaL_Reg funcs[] = {
|
||||||
|
//synonyms
|
||||||
|
{"GetRegionWidth", getRegionWidth},
|
||||||
|
{"GetRegionHeight", getRegionHeight},
|
||||||
|
{"GetRegionDepth", getRegionDepth},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const luaL_Reg libs[] = {
|
||||||
|
{"Region", openRegionAPI},
|
||||||
|
{"RegionPager", openRegionPagerAPI},
|
||||||
|
// {"TileSheet", openTileSheetAPI},
|
||||||
|
{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,16 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef CHARACTERAPI_HPP_
|
#ifndef MAPSYSTEMAPI_HPP_
|
||||||
#define CHARACTERAPI_HPP_
|
#define MAPSYSTEMAPI_APP_
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TORTUGA_CHARACTER_API "character"
|
#define TORTUGA_MAP_SYSTEM_API "map_system"
|
||||||
LUAMOD_API int openCharacterAPI(lua_State* L);
|
LUAMOD_API int openMapSystemAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+1
-25
@@ -21,9 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
int snapToBase(int base, int x) {
|
int snapToBase(int base, int x) {
|
||||||
return floor((double)x / base) * base;
|
return floor((double)x / base) * base;
|
||||||
@@ -42,41 +42,17 @@ Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
|
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) {
|
|
||||||
throw(std::out_of_range("Region::SetTile() argument out of range"));
|
|
||||||
}
|
|
||||||
return tiles[x][y][z] = v;
|
return tiles[x][y][z] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region::type_t Region::GetTile(int x, int y, int z) {
|
Region::type_t Region::GetTile(int x, int y, int z) {
|
||||||
if (x < 0 || y < 0 || z < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT || z >= REGION_DEPTH) {
|
|
||||||
throw(std::out_of_range("Region::GetTile() argument out of range"));
|
|
||||||
}
|
|
||||||
return tiles[x][y][z];
|
return tiles[x][y][z];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Region::SetSolid(int x, int y, bool b) {
|
bool Region::SetSolid(int x, int y, bool b) {
|
||||||
if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) {
|
|
||||||
throw(std::out_of_range("Region::SetSolid() argument out of range"));
|
|
||||||
}
|
|
||||||
return solid[x * REGION_WIDTH + y] = b;
|
return solid[x * REGION_WIDTH + y] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Region::GetSolid(int x, int y) {
|
bool Region::GetSolid(int x, int y) {
|
||||||
if (x < 0 || y < 0 || x >= REGION_WIDTH || y >= REGION_HEIGHT) {
|
|
||||||
throw(std::out_of_range("Region::GetSolid() argument out of range"));
|
|
||||||
}
|
|
||||||
return solid[x * REGION_WIDTH + y];
|
return solid[x * REGION_WIDTH + y];
|
||||||
}
|
|
||||||
|
|
||||||
int Region::GetX() const {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Region::GetY() const {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::bitset<REGION_WIDTH*REGION_HEIGHT>* Region::GetSolidBitset() {
|
|
||||||
return &solid;
|
|
||||||
}
|
}
|
||||||
@@ -48,10 +48,10 @@ public:
|
|||||||
bool GetSolid(int x, int y);
|
bool GetSolid(int x, int y);
|
||||||
|
|
||||||
//accessors
|
//accessors
|
||||||
int GetX() const;
|
int GetX() const { return x; }
|
||||||
int GetY() const;
|
int GetY() const { return y; }
|
||||||
|
|
||||||
std::bitset<REGION_WIDTH*REGION_HEIGHT>* GetSolidBitset();
|
std::bitset<REGION_WIDTH*REGION_HEIGHT>* GetSolidBitset() { return &solid; }
|
||||||
private:
|
private:
|
||||||
const int x;
|
const int x;
|
||||||
const int y;
|
const int y;
|
||||||
|
|||||||
@@ -85,8 +85,6 @@ static const luaL_Reg regionLib[] = {
|
|||||||
{"GetSolid",getSolid},
|
{"GetSolid",getSolid},
|
||||||
{"GetX",getX},
|
{"GetX",getX},
|
||||||
{"GetY",getY},
|
{"GetY",getY},
|
||||||
|
|
||||||
//the global macros
|
|
||||||
{"GetWidth",getWidth},
|
{"GetWidth",getWidth},
|
||||||
{"GetHeight",getHeight},
|
{"GetHeight",getHeight},
|
||||||
{"GetDepth",getDepth},
|
{"GetDepth",getDepth},
|
||||||
|
|||||||
@@ -22,9 +22,13 @@
|
|||||||
#ifndef REGIONAPI_HPP_
|
#ifndef REGIONAPI_HPP_
|
||||||
#define REGIONAPI_HPP_
|
#define REGIONAPI_HPP_
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TORTUGA_REGION_API "region"
|
#define TORTUGA_REGION_NAME "region"
|
||||||
LUAMOD_API int openRegionAPI(lua_State* L);
|
LUAMOD_API int openRegionAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
//DOCS: These glue functions simply wrap RegionPagerLua's methods
|
//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) {
|
static int setTile(lua_State* L) {
|
||||||
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||||
@@ -85,22 +84,7 @@ static int createRegion(lua_State* L) {
|
|||||||
|
|
||||||
static int unloadRegion(lua_State* L) {
|
static int unloadRegion(lua_State* L) {
|
||||||
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
||||||
|
pager->UnloadRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
|
||||||
//two argument types: coords & the region itself
|
|
||||||
switch(lua_type(L, 2)) {
|
|
||||||
case LUA_TNUMBER:
|
|
||||||
pager->UnloadIf([&](Region const& region) -> bool {
|
|
||||||
int x = lua_tointeger(L, 2);
|
|
||||||
int y = lua_tointeger(L, 3);
|
|
||||||
return region.GetX() == x && region.GetY() == y;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case LUA_TLIGHTUSERDATA:
|
|
||||||
pager->UnloadIf([&](Region const& region) -> bool {
|
|
||||||
return (®ion) == lua_touserdata(L, 2);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,13 +116,6 @@ static int setOnUnload(lua_State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//debugging
|
|
||||||
static int containerSize(lua_State* L) {
|
|
||||||
RegionPagerLua* pager = static_cast<RegionPagerLua*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, pager->GetContainer()->size());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const luaL_Reg regionPagerLib[] = {
|
static const luaL_Reg regionPagerLib[] = {
|
||||||
//curry
|
//curry
|
||||||
{"SetTile", setTile},
|
{"SetTile", setTile},
|
||||||
@@ -159,9 +136,6 @@ static const luaL_Reg regionPagerLib[] = {
|
|||||||
{"SetOnCreate",setOnCreate},
|
{"SetOnCreate",setOnCreate},
|
||||||
{"SetOnUnload",setOnUnload},
|
{"SetOnUnload",setOnUnload},
|
||||||
|
|
||||||
//debugging
|
|
||||||
{"ContainerSize", containerSize},
|
|
||||||
|
|
||||||
//sentinel
|
//sentinel
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,9 +22,13 @@
|
|||||||
#ifndef REGIONPAGERAPI_HPP_
|
#ifndef REGIONPAGERAPI_HPP_
|
||||||
#define REGIONPAGERAPI_HPP_
|
#define REGIONPAGERAPI_HPP_
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TORTUGA_REGION_PAGER_API "region_pager"
|
#define TORTUGA_REGION_PAGER_NAME "region_pager"
|
||||||
LUAMOD_API int openRegionPagerAPI(lua_State* L);
|
LUAMOD_API int openRegionPagerAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,10 +24,6 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
RegionPagerBase::~RegionPagerBase() {
|
|
||||||
UnloadAll();
|
|
||||||
};
|
|
||||||
|
|
||||||
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
|
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
|
||||||
Region* ptr = GetRegion(x, y);
|
Region* ptr = GetRegion(x, y);
|
||||||
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
|
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
|
||||||
@@ -70,7 +66,6 @@ Region* RegionPagerBase::FindRegion(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Region* RegionPagerBase::PushRegion(Region* const ptr) {
|
Region* RegionPagerBase::PushRegion(Region* const ptr) {
|
||||||
//BUG: #45 Some regions are occasionally losing their tile data
|
|
||||||
regionList.push_front(*ptr);
|
regionList.push_front(*ptr);
|
||||||
return ®ionList.front();
|
return ®ionList.front();
|
||||||
}
|
}
|
||||||
@@ -93,14 +88,12 @@ Region* RegionPagerBase::CreateRegion(int x, int y) {
|
|||||||
return ®ionList.front();
|
return ®ionList.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionPagerBase::UnloadIf(std::function<bool(Region const&)> fn) {
|
void RegionPagerBase::UnloadRegion(int x, int y) {
|
||||||
regionList.remove_if(fn);
|
regionList.remove_if([x, y](Region& region) -> bool {
|
||||||
|
return region.GetX() == x && region.GetY() == y;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionPagerBase::UnloadAll() {
|
void RegionPagerBase::UnloadAll() {
|
||||||
regionList.clear();
|
regionList.clear();
|
||||||
}
|
|
||||||
|
|
||||||
std::list<Region>* RegionPagerBase::GetContainer() {
|
|
||||||
return ®ionList;
|
|
||||||
}
|
}
|
||||||
@@ -24,13 +24,12 @@
|
|||||||
|
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class RegionPagerBase {
|
class RegionPagerBase {
|
||||||
public:
|
public:
|
||||||
RegionPagerBase() = default;
|
RegionPagerBase() = default;
|
||||||
virtual ~RegionPagerBase();
|
virtual ~RegionPagerBase() { UnloadAll(); };
|
||||||
|
|
||||||
//tile manipulation
|
//tile manipulation
|
||||||
virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v);
|
virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v);
|
||||||
@@ -48,12 +47,12 @@ public:
|
|||||||
virtual Region* LoadRegion(int x, int y);
|
virtual Region* LoadRegion(int x, int y);
|
||||||
virtual Region* SaveRegion(int x, int y);
|
virtual Region* SaveRegion(int x, int y);
|
||||||
virtual Region* CreateRegion(int x, int y);
|
virtual Region* CreateRegion(int x, int y);
|
||||||
|
virtual void UnloadRegion(int x, int y);
|
||||||
|
|
||||||
virtual void UnloadIf(std::function<bool(Region const&)> fn);
|
|
||||||
virtual void UnloadAll();
|
virtual void UnloadAll();
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
std::list<Region>* GetContainer();
|
std::list<Region>* GetContainer() { return ®ionList; }
|
||||||
protected:
|
protected:
|
||||||
std::list<Region> regionList;
|
std::list<Region> regionList;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
//DOCS: Load, Save and Create fail unless the lua function has been set
|
|
||||||
//DOCS: UnloadIf and UnloadAll will still continue without the function set
|
|
||||||
|
|
||||||
RegionPagerLua::~RegionPagerLua() {
|
RegionPagerLua::~RegionPagerLua() {
|
||||||
//unload all regions
|
//unload all regions
|
||||||
UnloadAll();
|
UnloadAll();
|
||||||
@@ -133,25 +130,23 @@ Region* RegionPagerLua::CreateRegion(int x, int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//no return
|
//no return
|
||||||
void RegionPagerLua::UnloadIf(std::function<bool(Region const&)> fn) {
|
void RegionPagerLua::UnloadRegion(int x, int y) {
|
||||||
//get the pager's function from the registry
|
//get the pager's function from the registry
|
||||||
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
|
||||||
|
|
||||||
//check if this function is available
|
//check if this function is available
|
||||||
if (lua_isnil(lua, -1)) {
|
if (lua_isnil(lua, -1)) {
|
||||||
lua_pop(lua, 1);
|
lua_pop(lua, 1);
|
||||||
//remove the regions anyway
|
|
||||||
regionList.remove_if(fn);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//run each region through this lambda
|
//run each region through this lambda
|
||||||
regionList.remove_if([&](Region& region) -> bool {
|
regionList.remove_if([&](Region& region) -> bool {
|
||||||
if (fn(region)) {
|
if (region.GetX() == x && region.GetY() == y) {
|
||||||
|
|
||||||
//push a copy of the function onto the stack with the region
|
//push a copy of the function onto the stack with the region
|
||||||
lua_pushvalue(lua, -1);
|
lua_pushvalue(lua, -1);
|
||||||
lua_pushlightuserdata(lua, static_cast<void*>(®ion));
|
lua_pushlightuserdata(lua, ®ion);
|
||||||
|
|
||||||
//call the function, 1 arg, 0 return
|
//call the function, 1 arg, 0 return
|
||||||
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
|
||||||
@@ -176,8 +171,6 @@ void RegionPagerLua::UnloadAll() {
|
|||||||
//check if this function is available
|
//check if this function is available
|
||||||
if (lua_isnil(lua, -1)) {
|
if (lua_isnil(lua, -1)) {
|
||||||
lua_pop(lua, 1);
|
lua_pop(lua, 1);
|
||||||
//remove the regions anyway
|
|
||||||
regionList.clear();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,12 @@
|
|||||||
|
|
||||||
#include "region_pager_base.hpp"
|
#include "region_pager_base.hpp"
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class RegionPagerLua : public RegionPagerBase {
|
class RegionPagerLua : public RegionPagerBase {
|
||||||
@@ -38,8 +41,8 @@ public:
|
|||||||
Region* LoadRegion(int x, int y) override;
|
Region* LoadRegion(int x, int y) override;
|
||||||
Region* SaveRegion(int x, int y) override;
|
Region* SaveRegion(int x, int y) override;
|
||||||
Region* CreateRegion(int x, int y) override;
|
Region* CreateRegion(int x, int y) override;
|
||||||
|
void UnloadRegion(int x, int y) override;
|
||||||
|
|
||||||
void UnloadIf(std::function<bool(Region const&)> fn) override;
|
|
||||||
void UnloadAll() override;
|
void UnloadAll() override;
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* 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 "tile_sheet_api.hpp"
|
||||||
|
|
||||||
|
#include "tile_sheet.hpp"
|
||||||
|
|
||||||
|
static int load(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
sheet->Load(lua_tostring(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unload(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
sheet->Unload();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getXCount(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, sheet->GetXCount());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getYCount(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, sheet->GetYCount());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getTileW(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, sheet->GetTileW());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getTileH(lua_State* L) {
|
||||||
|
TileSheet* sheet = reinterpret_cast<TileSheet*>(lua_touserdata(L, 1));
|
||||||
|
lua_pushinteger(L, sheet->GetTileH());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg tileSheetLib[] = {
|
||||||
|
{"Load",load},
|
||||||
|
{"Unload",unload},
|
||||||
|
{"GetXCount",getXCount},
|
||||||
|
{"GetYCount",getYCount},
|
||||||
|
{"GetTileW",getTileW},
|
||||||
|
{"GetTileH",getTileH},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int openTileSheetAPI(lua_State* L) {
|
||||||
|
luaL_newlib(L, tileSheetLib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -19,12 +19,16 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef ENTITYAPI_HPP_
|
#ifndef TILESHEETAPI_HPP_
|
||||||
#define ENTITYAPI_HPP_
|
#define TILESHEETAPI_HPP_
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TORTUGA_ENTITY_API "entity"
|
#define TORTUGA_TILE_SHEET_NAME "tile_sheet"
|
||||||
LUAMOD_API int openEntityAPI(lua_State* L);
|
LUAMOD_API int openTileSheetAPI(lua_State* L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -36,18 +36,11 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) {
|
|||||||
|
|
||||||
//location
|
//location
|
||||||
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
|
||||||
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
|
||||||
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
serialCopy(&buffer, &packet->motion.y, 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...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,17 +57,10 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) {
|
|||||||
|
|
||||||
//location
|
//location
|
||||||
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
||||||
|
|
||||||
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
||||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
||||||
|
|
||||||
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
||||||
deserialCopy(&buffer, &packet->motion.y, 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...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
|
|
||||||
#include "bounding_box.hpp"
|
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
struct CharacterPacket : SerialPacketBase {
|
struct CharacterPacket : SerialPacketBase {
|
||||||
@@ -35,12 +34,14 @@ struct CharacterPacket : SerialPacketBase {
|
|||||||
|
|
||||||
//the owner
|
//the owner
|
||||||
int accountIndex;
|
int accountIndex;
|
||||||
|
//TODO: Authentication token?
|
||||||
|
|
||||||
//location
|
//location
|
||||||
int roomIndex;
|
int roomIndex;
|
||||||
Vector2 origin;
|
Vector2 origin;
|
||||||
Vector2 motion;
|
Vector2 motion;
|
||||||
BoundingBox bounds;
|
|
||||||
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ struct ClientPacket : SerialPacketBase {
|
|||||||
int clientIndex;
|
int clientIndex;
|
||||||
int accountIndex;
|
int accountIndex;
|
||||||
char username[PACKET_STRING_SIZE];
|
char username[PACKET_STRING_SIZE];
|
||||||
//TODO: (3) password, auth token
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeClient(void* buffer, ClientPacket* packet);
|
void serializeClient(void* buffer, ClientPacket* packet);
|
||||||
|
|||||||
@@ -1,70 +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 "monster_packet.hpp"
|
|
||||||
|
|
||||||
#include "serial_utility.hpp"
|
|
||||||
|
|
||||||
void serializeMonster(void* buffer, MonsterPacket* packet) {
|
|
||||||
serialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
|
||||||
|
|
||||||
//identify the monster
|
|
||||||
serialCopy(&buffer, &packet->monsterIndex, sizeof(int));
|
|
||||||
serialCopy(&buffer, packet->handle, PACKET_STRING_SIZE);
|
|
||||||
serialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE);
|
|
||||||
|
|
||||||
//bounds
|
|
||||||
serialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
|
||||||
serialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
|
||||||
serialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
|
||||||
serialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
|
||||||
|
|
||||||
|
|
||||||
//location
|
|
||||||
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
|
||||||
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
|
||||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
|
||||||
serialCopy(&buffer, &packet->motion.x, sizeof(double));
|
|
||||||
serialCopy(&buffer, &packet->motion.y, sizeof(double));
|
|
||||||
}
|
|
||||||
|
|
||||||
void deserializeMonster(void* buffer, MonsterPacket* packet) {
|
|
||||||
deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
|
||||||
|
|
||||||
//identify the monster
|
|
||||||
deserialCopy(&buffer, &packet->monsterIndex, sizeof(int));
|
|
||||||
deserialCopy(&buffer, packet->handle, PACKET_STRING_SIZE);
|
|
||||||
deserialCopy(&buffer, packet->avatar, PACKET_STRING_SIZE);
|
|
||||||
|
|
||||||
//bounds
|
|
||||||
deserialCopy(&buffer, &packet->bounds.x, sizeof(int));
|
|
||||||
deserialCopy(&buffer, &packet->bounds.y, sizeof(int));
|
|
||||||
deserialCopy(&buffer, &packet->bounds.w, sizeof(int));
|
|
||||||
deserialCopy(&buffer, &packet->bounds.h, sizeof(int));
|
|
||||||
|
|
||||||
|
|
||||||
//location
|
|
||||||
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
|
||||||
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
|
||||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
|
||||||
deserialCopy(&buffer, &packet->motion.x, sizeof(double));
|
|
||||||
deserialCopy(&buffer, &packet->motion.y, sizeof(double));
|
|
||||||
}
|
|
||||||
@@ -1,46 +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 MONSTERPACKET_HPP_
|
|
||||||
#define MONSTERPACKET_HPP_
|
|
||||||
|
|
||||||
#include "serial_packet_base.hpp"
|
|
||||||
|
|
||||||
#include "bounding_box.hpp"
|
|
||||||
#include "vector2.hpp"
|
|
||||||
|
|
||||||
struct MonsterPacket : SerialPacketBase {
|
|
||||||
//identify the monster
|
|
||||||
int monsterIndex;
|
|
||||||
char handle[PACKET_STRING_SIZE];
|
|
||||||
char avatar[PACKET_STRING_SIZE];
|
|
||||||
BoundingBox bounds;
|
|
||||||
|
|
||||||
//location
|
|
||||||
int roomIndex;
|
|
||||||
Vector2 origin;
|
|
||||||
Vector2 motion;
|
|
||||||
};
|
|
||||||
|
|
||||||
void serializeMonster(void* buffer, MonsterPacket* packet);
|
|
||||||
void deserializeMonster(void* buffer, MonsterPacket* packet);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -29,12 +29,6 @@ void serializeText(void* buffer, TextPacket* packet) {
|
|||||||
//content
|
//content
|
||||||
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||||
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
//location
|
|
||||||
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
|
||||||
serialCopy(&buffer, &packet->origin.x, sizeof(double));
|
|
||||||
serialCopy(&buffer, &packet->origin.y, sizeof(double));
|
|
||||||
serialCopy(&buffer, &packet->range, sizeof(int));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void deserializeText(void* buffer, TextPacket* packet) {
|
void deserializeText(void* buffer, TextPacket* packet) {
|
||||||
@@ -43,10 +37,4 @@ void deserializeText(void* buffer, TextPacket* packet) {
|
|||||||
//content
|
//content
|
||||||
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||||
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
//location
|
|
||||||
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
|
|
||||||
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
|
|
||||||
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
|
|
||||||
deserialCopy(&buffer, &packet->range, sizeof(int));
|
|
||||||
}
|
}
|
||||||
@@ -24,14 +24,9 @@
|
|||||||
|
|
||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
|
|
||||||
#include "vector2.hpp"
|
|
||||||
|
|
||||||
struct TextPacket : SerialPacketBase {
|
struct TextPacket : SerialPacketBase {
|
||||||
char name[PACKET_STRING_SIZE];
|
char name[PACKET_STRING_SIZE];
|
||||||
char text[PACKET_STRING_SIZE];
|
char text[PACKET_STRING_SIZE];
|
||||||
int roomIndex;
|
|
||||||
Vector2 origin;
|
|
||||||
int range;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void serializeText(void* buffer, TextPacket* packet);
|
void serializeText(void* buffer, TextPacket* packet);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "serial_packet_base.hpp"
|
#include "serial_packet_base.hpp"
|
||||||
#include "character_packet.hpp"
|
#include "character_packet.hpp"
|
||||||
#include "client_packet.hpp"
|
#include "client_packet.hpp"
|
||||||
#include "monster_packet.hpp"
|
|
||||||
#include "region_packet.hpp"
|
#include "region_packet.hpp"
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "text_packet.hpp"
|
#include "text_packet.hpp"
|
||||||
@@ -34,15 +33,14 @@
|
|||||||
typedef SerialPacketBase SerialPacket;
|
typedef SerialPacketBase SerialPacket;
|
||||||
|
|
||||||
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
||||||
constexpr int NETWORK_VERSION = 20150304;
|
constexpr int NETWORK_VERSION = 20141227;
|
||||||
|
|
||||||
union MaxPacket {
|
union MaxPacket {
|
||||||
CharacterPacket a;
|
CharacterPacket a;
|
||||||
ClientPacket b;
|
ClientPacket b;
|
||||||
MonsterPacket c;
|
RegionPacket c;
|
||||||
RegionPacket d;
|
ServerPacket d;
|
||||||
ServerPacket e;
|
TextPacket e;
|
||||||
TextPacket f;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
|
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
|
||||||
|
|||||||
@@ -25,163 +25,107 @@
|
|||||||
/* DOCS: The headers indicate what packet type is used for each message
|
/* DOCS: The headers indicate what packet type is used for each message
|
||||||
* different messages under the same header will carry different amounts of
|
* different messages under the same header will carry different amounts of
|
||||||
* valid data, but it will still be carried in that packet's format.
|
* valid data, but it will still be carried in that packet's format.
|
||||||
* FORMAT_* is for internal use, deviding the different format bounds.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//TODO: This needs to be smoothed out
|
||||||
enum class SerialPacketType {
|
enum class SerialPacketType {
|
||||||
//default: there is something wrong
|
//default: there is something wrong
|
||||||
NONE,
|
NONE = 0,
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//ServerPacket
|
//ServerPacket
|
||||||
// name, player count, version
|
// name, player count, version
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
FORMAT_SERVER,
|
|
||||||
|
|
||||||
//heartbeat
|
//heartbeat
|
||||||
PING,
|
PING = 1,
|
||||||
PONG,
|
PONG = 2,
|
||||||
|
|
||||||
//Used for finding available servers
|
//Used for finding available servers
|
||||||
BROADCAST_REQUEST,
|
BROADCAST_REQUEST = 3,
|
||||||
BROADCAST_RESPONSE,
|
BROADCAST_RESPONSE = 4,
|
||||||
|
|
||||||
FORMAT_END_SERVER,
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//ClientPacket
|
//ClientPacket
|
||||||
// client index, account index, username
|
// client index, account index, username
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
FORMAT_CLIENT,
|
|
||||||
|
|
||||||
//Connecting to a server as a client
|
//Connecting to a server as a client
|
||||||
JOIN_REQUEST,
|
JOIN_REQUEST = 5,
|
||||||
JOIN_RESPONSE,
|
JOIN_RESPONSE = 6,
|
||||||
|
|
||||||
//disconnect from the server
|
//disconnect from the server
|
||||||
DISCONNECT_REQUEST,
|
DISCONNECT_REQUEST = 7,
|
||||||
DISCONNECT_RESPONSE,
|
DISCONNECT_RESPONSE = 8,
|
||||||
ADMIN_DISCONNECT_FORCED,
|
DISCONNECT_FORCED = 9,
|
||||||
|
|
||||||
//load the account
|
//load the account
|
||||||
LOGIN_REQUEST,
|
LOGIN_REQUEST = 10,
|
||||||
LOGIN_RESPONSE,
|
LOGIN_RESPONSE = 11,
|
||||||
|
|
||||||
//unload the account
|
//unload the account
|
||||||
LOGOUT_REQUEST,
|
LOGOUT_REQUEST = 12,
|
||||||
LOGOUT_RESPONSE,
|
LOGOUT_RESPONSE = 13,
|
||||||
|
|
||||||
//shut down the server
|
//shut down the server
|
||||||
ADMIN_SHUTDOWN_REQUEST,
|
SHUTDOWN_REQUEST = 14,
|
||||||
|
|
||||||
FORMAT_END_CLIENT,
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//RegionPacket
|
//RegionPacket
|
||||||
// room index, x, y, raw data
|
// room index, x, y, raw data
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
FORMAT_REGION,
|
|
||||||
|
|
||||||
//map data
|
//map data
|
||||||
REGION_REQUEST,
|
REGION_REQUEST = 15, //NOTE: technically a query
|
||||||
REGION_CONTENT,
|
REGION_CONTENT = 16,
|
||||||
|
|
||||||
FORMAT_END_REGION,
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//CharacterPacket
|
//CharacterPacket
|
||||||
// character index,
|
// character index,
|
||||||
// handle, avatar,
|
// handle, avatar,
|
||||||
// account index (owner),
|
// account index (owner),
|
||||||
// room index, origin, motion
|
// room index, origin, motion,
|
||||||
|
// statistics
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
FORMAT_CHARACTER,
|
|
||||||
|
|
||||||
//full data update
|
|
||||||
CHARACTER_UPDATE,
|
|
||||||
|
|
||||||
//character management
|
//character management
|
||||||
CHARACTER_CREATE,
|
CHARACTER_CREATE = 17,
|
||||||
CHARACTER_DELETE,
|
CHARACTER_DELETE = 18,
|
||||||
CHARACTER_LOAD,
|
CHARACTER_LOAD = 19,
|
||||||
CHARACTER_UNLOAD,
|
CHARACTER_UNLOAD = 20,
|
||||||
|
|
||||||
//find out info from the server
|
//find out info from the server
|
||||||
QUERY_CHARACTER_EXISTS,
|
QUERY_CHARACTER_EXISTS = 21,
|
||||||
QUERY_CHARACTER_STATS,
|
QUERY_CHARACTER_STATS = 22,
|
||||||
QUERY_CHARACTER_LOCATION,
|
QUERY_CHARACTER_LOCATION = 23,
|
||||||
|
|
||||||
//actions taken
|
//set the info in the server
|
||||||
CHARACTER_MOVEMENT,
|
CHARACTER_SET_ROOM = 24,
|
||||||
CHARACTER_ATTACK,
|
CHARACTER_SET_ORIGIN = 25,
|
||||||
CHARACTER_DAMAGE,
|
CHARACTER_SET_MOTION = 26,
|
||||||
|
|
||||||
//admin control
|
//TODO: enemy management
|
||||||
// ADMIN_SET_CHARACTER_ORIGIN,
|
|
||||||
|
|
||||||
FORMAT_END_CHARACTER,
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//MonsterPacket
|
|
||||||
// monster index,
|
|
||||||
// handle, avatar
|
|
||||||
// bounds
|
|
||||||
// room index, origin, motion
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
//actions taken
|
|
||||||
MONSTER_MOVEMENT,
|
|
||||||
MONSTER_ATTACK,
|
|
||||||
MONSTER_DAMAGE,
|
|
||||||
|
|
||||||
FORMAT_END_MONSTER,
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//TextPacket
|
//TextPacket
|
||||||
// name, text
|
// name, text
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
FORMAT_TEXT,
|
|
||||||
|
|
||||||
//general speech
|
//general speech
|
||||||
TEXT_BROADCAST,
|
TEXT_BROADCAST = 27,
|
||||||
TEXT_SPEECH,
|
|
||||||
TEXT_WHISPER,
|
|
||||||
|
|
||||||
//rejection/error messages
|
//rejection/error messages
|
||||||
JOIN_REJECTION,
|
JOIN_REJECTION = 28,
|
||||||
LOGIN_REJECTION,
|
LOGIN_REJECTION = 29,
|
||||||
REGION_REJECTION,
|
REGION_REJECTION = 30,
|
||||||
CHARACTER_REJECTION,
|
CHARACTER_REJECTION = 31,
|
||||||
MONSTER_REJECTION,
|
SHUTDOWN_REJECTION = 32,
|
||||||
SHUTDOWN_REJECTION,
|
|
||||||
QUERY_REJECTION,
|
|
||||||
|
|
||||||
FORMAT_END_TEXT,
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//not used
|
//not used
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
LAST
|
LAST = 33
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -24,16 +24,12 @@
|
|||||||
//packet types
|
//packet types
|
||||||
#include "character_packet.hpp"
|
#include "character_packet.hpp"
|
||||||
#include "client_packet.hpp"
|
#include "client_packet.hpp"
|
||||||
#include "monster_packet.hpp"
|
|
||||||
#include "region_packet.hpp"
|
#include "region_packet.hpp"
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "text_packet.hpp"
|
#include "text_packet.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
//macros
|
|
||||||
#define BOUNDS(type, lower, upper) ((type) > (lower) && (type) < (upper))
|
|
||||||
|
|
||||||
//raw memory copy
|
//raw memory copy
|
||||||
void serialCopy(void** buffer, void* data, int size) {
|
void serialCopy(void** buffer, void* data, int size) {
|
||||||
memcpy(*buffer, data, size);
|
memcpy(*buffer, data, size);
|
||||||
@@ -49,28 +45,49 @@ void deserialCopy(void** buffer, void* data, int size) {
|
|||||||
|
|
||||||
//main switch functions
|
//main switch functions
|
||||||
void serializePacket(void* buffer, SerialPacketBase* packet) {
|
void serializePacket(void* buffer, SerialPacketBase* packet) {
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
switch(packet->type) {
|
||||||
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
case SerialPacketType::PING:
|
||||||
}
|
case SerialPacketType::PONG:
|
||||||
|
case SerialPacketType::BROADCAST_REQUEST:
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
case SerialPacketType::BROADCAST_RESPONSE:
|
||||||
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
serializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||||
}
|
break;
|
||||||
|
case SerialPacketType::JOIN_REQUEST:
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
case SerialPacketType::JOIN_RESPONSE:
|
||||||
serializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
case SerialPacketType::DISCONNECT_REQUEST:
|
||||||
}
|
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||||
|
case SerialPacketType::DISCONNECT_FORCED:
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
case SerialPacketType::LOGIN_REQUEST:
|
||||||
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
case SerialPacketType::LOGIN_RESPONSE:
|
||||||
}
|
case SerialPacketType::LOGOUT_REQUEST:
|
||||||
|
case SerialPacketType::LOGOUT_RESPONSE:
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
case SerialPacketType::SHUTDOWN_REQUEST:
|
||||||
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
serializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||||
}
|
break;
|
||||||
|
case SerialPacketType::REGION_REQUEST:
|
||||||
if (BOUNDS(packet->type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
case SerialPacketType::REGION_CONTENT:
|
||||||
serializeText(buffer, static_cast<TextPacket*>(packet));
|
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_SET_ROOM:
|
||||||
|
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
||||||
|
case SerialPacketType::CHARACTER_SET_MOTION:
|
||||||
|
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::TEXT_BROADCAST:
|
||||||
|
case SerialPacketType::JOIN_REJECTION:
|
||||||
|
case SerialPacketType::LOGIN_REJECTION:
|
||||||
|
case SerialPacketType::REGION_REJECTION:
|
||||||
|
case SerialPacketType::CHARACTER_REJECTION:
|
||||||
|
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||||
|
serializeText(buffer, static_cast<TextPacket*>(packet));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,27 +96,48 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
|
|||||||
SerialPacketType type;
|
SerialPacketType type;
|
||||||
memcpy(&type, buffer, sizeof(SerialPacketType));
|
memcpy(&type, buffer, sizeof(SerialPacketType));
|
||||||
|
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
|
switch(type) {
|
||||||
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
case SerialPacketType::PING:
|
||||||
}
|
case SerialPacketType::PONG:
|
||||||
|
case SerialPacketType::BROADCAST_REQUEST:
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
|
case SerialPacketType::BROADCAST_RESPONSE:
|
||||||
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
deserializeServer(buffer, static_cast<ServerPacket*>(packet));
|
||||||
}
|
break;
|
||||||
|
case SerialPacketType::JOIN_REQUEST:
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
|
case SerialPacketType::JOIN_RESPONSE:
|
||||||
deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
|
case SerialPacketType::DISCONNECT_REQUEST:
|
||||||
}
|
case SerialPacketType::DISCONNECT_RESPONSE:
|
||||||
|
case SerialPacketType::DISCONNECT_FORCED:
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
|
case SerialPacketType::LOGIN_REQUEST:
|
||||||
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
case SerialPacketType::LOGIN_RESPONSE:
|
||||||
}
|
case SerialPacketType::LOGOUT_REQUEST:
|
||||||
|
case SerialPacketType::LOGOUT_RESPONSE:
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
|
case SerialPacketType::SHUTDOWN_REQUEST:
|
||||||
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
|
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
|
||||||
}
|
break;
|
||||||
|
case SerialPacketType::REGION_REQUEST:
|
||||||
if (BOUNDS(type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
|
case SerialPacketType::REGION_CONTENT:
|
||||||
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
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_SET_ROOM:
|
||||||
|
case SerialPacketType::CHARACTER_SET_ORIGIN:
|
||||||
|
case SerialPacketType::CHARACTER_SET_MOTION:
|
||||||
|
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||||
|
break;
|
||||||
|
case SerialPacketType::TEXT_BROADCAST:
|
||||||
|
case SerialPacketType::JOIN_REJECTION:
|
||||||
|
case SerialPacketType::LOGIN_REJECTION:
|
||||||
|
case SerialPacketType::REGION_REJECTION:
|
||||||
|
case SerialPacketType::CHARACTER_REJECTION:
|
||||||
|
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||||
|
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
//DOCS: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
//NOTE: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
||||||
//NOTE: don't confuse SerialPacketBase with UDPpacket
|
//NOTE: don't confuse SerialPacketBase with UDPpacket
|
||||||
|
|
||||||
void UDPNetworkUtility::Open(int port) {
|
void UDPNetworkUtility::Open(int port) {
|
||||||
@@ -140,6 +140,7 @@ int UDPNetworkUtility::SendToAllChannels(void* data, int len) {
|
|||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: put a void* and int* parameter list here
|
||||||
int UDPNetworkUtility::Receive() {
|
int UDPNetworkUtility::Receive() {
|
||||||
memset(packet->data, 0, packet->maxlen);
|
memset(packet->data, 0, packet->maxlen);
|
||||||
int ret = SDLNet_UDP_Recv(socket, packet);
|
int ret = SDLNet_UDP_Recv(socket, packet);
|
||||||
|
|||||||
@@ -19,21 +19,30 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "world.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
//-------------------------
|
#include <algorithm>
|
||||||
//chat
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void World::hTextBroadcast(TextPacket* const argPacket) {
|
std::string truncatePath(std::string pathname) {
|
||||||
//TODO: (9) World::hTextBroadcast()
|
return std::string(
|
||||||
|
std::find_if(
|
||||||
|
pathname.rbegin(),
|
||||||
|
pathname.rend(),
|
||||||
|
[](char ch) -> bool {
|
||||||
|
//windows & unix tested
|
||||||
|
return ch == '/' || ch == '\\';
|
||||||
|
}).base(),
|
||||||
|
pathname.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::hTextSpeech(TextPacket* const argPacket) {
|
std::string to_string_custom(int i) {
|
||||||
//TODO: (9) World::hTextSpeech()
|
char buffer[20];
|
||||||
}
|
snprintf(buffer, 20, "%d", i);
|
||||||
|
return std::string(buffer);
|
||||||
void World::hTextWhisper(TextPacket* const argPacket) {
|
|
||||||
//TODO: (9) World::hTextWhisper()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int to_integer_custom(std::string s) {
|
||||||
|
int ret = 0;
|
||||||
|
sscanf(s.c_str(), "%d", &ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -19,13 +19,16 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef IPOPERATORS_HPP_
|
#ifndef UTILITY_HPP_
|
||||||
#define IPOPERATORS_HPP_
|
#define UTILITY_HPP_
|
||||||
|
|
||||||
#include "SDL/SDL_net.h"
|
#include <string>
|
||||||
|
|
||||||
//these should've come standard
|
std::string truncatePath(std::string pathname);
|
||||||
bool operator==(IPaddress lhs, IPaddress rhs);
|
|
||||||
bool operator!=(IPaddress lhs, IPaddress rhs);
|
|
||||||
|
|
||||||
#endif
|
//fixing known bugs in g++
|
||||||
|
std::string to_string_custom(int i);
|
||||||
|
|
||||||
|
int to_integer_custom(std::string);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1
-1
@@ -2,7 +2,7 @@ Future versions (to be determined) may be released under a modified version of t
|
|||||||
|
|
||||||
The current version of Tortuga is released under the zlib license.
|
The current version of Tortuga is released under the zlib license.
|
||||||
|
|
||||||
Copyright (c) 2013-2015 Kayne Ruse
|
Copyright (c) 2013, 2014 Kayne Ruse
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#Windows 7:
|
#for use on Windows:
|
||||||
#RM=del /y
|
|
||||||
|
|
||||||
#Windows 8.1:
|
#MKDIR=mkdir
|
||||||
#RM=del /S
|
#RM=del /y
|
||||||
|
|
||||||
OUTDIR=out
|
OUTDIR=out
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ release: clean all package
|
|||||||
#For use on my machine ONLY
|
#For use on my machine ONLY
|
||||||
package:
|
package:
|
||||||
rar a -r -ep Tortuga.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll
|
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):
|
$(OUTDIR):
|
||||||
mkdir $(OUTDIR)
|
mkdir $(OUTDIR)
|
||||||
|
|||||||
+2
-2
@@ -12,8 +12,8 @@ server.dbname = database.db
|
|||||||
#client.screen.h = 600
|
#client.screen.h = 600
|
||||||
client.screen.f = false
|
client.screen.f = false
|
||||||
|
|
||||||
client.username = username
|
client.username = Kayne Ruse
|
||||||
client.handle = handle
|
client.handle = Ratstail91
|
||||||
client.avatar = elliot2.bmp
|
client.avatar = elliot2.bmp
|
||||||
|
|
||||||
#directories
|
#directories
|
||||||
|
|||||||
@@ -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
|
|
||||||
+16
-92
@@ -1,115 +1,39 @@
|
|||||||
local regionAPI = require("region")
|
local mapSystem = require "map_system"
|
||||||
|
|
||||||
local mapMaker = {}
|
local mapMaker = {}
|
||||||
|
|
||||||
--utility functions
|
--utility functions
|
||||||
function mapMaker.Sqr(x) return x*x end
|
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
|
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"
|
--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
|
|
||||||
mapMaker.grass = 18 + 3 * 3
|
|
||||||
mapMaker.dirt = 18 + 3 * 4
|
|
||||||
|
|
||||||
--"edge" macros
|
|
||||||
mapMaker.edges = {}
|
mapMaker.edges = {}
|
||||||
mapMaker.edges.north = -16
|
mapMaker.edges.north = -16
|
||||||
mapMaker.edges.south = 16
|
mapMaker.edges.south = 16
|
||||||
mapMaker.edges.east = 1
|
mapMaker.edges.east = 1
|
||||||
mapMaker.edges.west = -1
|
mapMaker.edges.west = -1
|
||||||
|
|
||||||
--TODO: (1) path system
|
mapMaker.water = 18 + 3 * 0
|
||||||
--use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges
|
mapMaker.sand = 18 + 3 * 1
|
||||||
function mapMaker.SmoothEdgesSimple(r)
|
mapMaker.plains = 18 + 3 * 2
|
||||||
--make and pad an array to use
|
mapMaker.grass = 18 + 3 * 3
|
||||||
local shiftArray = {}
|
mapMaker.dirt = 18 + 3 * 4
|
||||||
for i = 1, regionAPI.GetWidth(r) do
|
|
||||||
shiftArray[i] = {}
|
|
||||||
for j = 1, regionAPI.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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--custom generation systems here
|
--custom generation systems here
|
||||||
function mapMaker.DebugIsland(r)
|
function mapMaker.debugIsland(region)
|
||||||
--debug
|
for i = 1, mapSystem.Region.GetWidth(region) do
|
||||||
io.write("map_maker:DebugIsland(", regionAPI.GetX(r), ", ", regionAPI.GetY(r), ")\n")
|
for j = 1, mapSystem.Region.GetHeight(region) do
|
||||||
|
local dist = mapMaker.dist(0, 0, i + mapSystem.Region.GetX(region) -1, j + mapSystem.Region.GetY(region) -1)
|
||||||
--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)
|
|
||||||
if dist < 10 then
|
if dist < 10 then
|
||||||
regionAPI.SetTile(r, i, j, 1, mapMaker.plains)
|
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.plains)
|
||||||
elseif dist < 12 then
|
elseif dist < 12 then
|
||||||
regionAPI.SetTile(r, i, j, 1, mapMaker.sand)
|
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.sand)
|
||||||
else
|
else
|
||||||
regionAPI.SetTile(r, i, j, 1, mapMaker.water)
|
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.water)
|
||||||
regionAPI.SetSolid(r, i, j, true)
|
mapSystem.Region.SetSolid(region, i, j, true)
|
||||||
end
|
end
|
||||||
end
|
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)
|
|
||||||
|
|
||||||
regionAPI.SetTile(r, 10, j, 1, mapMaker.dirt)
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
|
|
||||||
--A generic edge system
|
|
||||||
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
|
end
|
||||||
|
|
||||||
return mapMaker
|
return mapMaker
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
local region = require("region")
|
|
||||||
|
|
||||||
local mapSaver = {}
|
local mapSaver = {}
|
||||||
|
function mapSaver.Load(region)
|
||||||
function mapSaver.Load(r)
|
|
||||||
--empty
|
--empty
|
||||||
-- io.write("map_saver:Load(", region.GetX(r), ", ", region.GetY(r), ")\n")
|
|
||||||
end
|
end
|
||||||
function mapSaver.Save(r)
|
function mapSaver.Save(region)
|
||||||
--empty
|
--empty
|
||||||
-- io.write("map_saver:Save(", region.GetX(r), ", ", region.GetY(r), ")\n")
|
|
||||||
end
|
end
|
||||||
|
--TODO: create a flexible saving & loading system
|
||||||
--TODO: (3) create a flexible saving & loading system
|
|
||||||
return mapSaver
|
return mapSaver
|
||||||
@@ -1,36 +1,32 @@
|
|||||||
print("Lua script check")
|
print("Lua script check")
|
||||||
|
|
||||||
--requirements
|
mapMaker = require "map_maker"
|
||||||
roomManagerAPI = require("room_manager")
|
mapSaver = require "map_saver"
|
||||||
roomAPI = require("room")
|
roomSystem = require "room_system"
|
||||||
|
|
||||||
mapMaker = require("map_maker")
|
local function dumpTable(t)
|
||||||
mapSaver = require("map_saver")
|
print(t)
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
print("",k, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
doorUtility = require("door_utility")
|
--create the overworld, set it's generator, loader & saver
|
||||||
|
--[[
|
||||||
|
local t = {
|
||||||
|
"overworld.bmp", --tileset name
|
||||||
|
mapSaver.load, --load function
|
||||||
|
mapSaver.save, --save function
|
||||||
|
mapMaker.debugIsland, --create function
|
||||||
|
mapSaver.save --unload function
|
||||||
|
}]]
|
||||||
|
|
||||||
--test the room hooks
|
dumpTable(roomSystem)
|
||||||
roomManagerAPI.SetOnCreate(function(room, index)
|
dumpTable(roomSystem.RoomManager)
|
||||||
print("", "Creating room: ", roomAPI.GetName(room), index)
|
dumpTable(roomSystem.Room)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
--NOTE: room 0 is the first that the client asks for, therefore it must exist
|
--NOTE: room 0 is the first that the client asks for, therefore it must exist
|
||||||
local overworld, uidOne = roomManagerAPI.CreateRoom("overworld", "overworld.bmp")
|
local overworld, uid = roomSystem.RoomManager.CreateRoom("overworld")
|
||||||
roomAPI.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
|
roomSystem.Room.Initialize(overworld, "overworld.bmp", 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)
|
|
||||||
|
|
||||||
print("Finished the lua script")
|
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 (
|
CREATE TABLE IF NOT EXISTS Accounts (
|
||||||
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
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),
|
-- passhash varchar(100),
|
||||||
-- passsalt varchar(100),
|
-- passsalt varchar(100),
|
||||||
|
|
||||||
@@ -24,14 +24,10 @@ CREATE TABLE IF NOT EXISTS Characters (
|
|||||||
avatar varchar(100),
|
avatar varchar(100),
|
||||||
birth timestamp NOT NULL DEFAULT (datetime()),
|
birth timestamp NOT NULL DEFAULT (datetime()),
|
||||||
|
|
||||||
--physically exists in the world
|
--position in the world
|
||||||
roomIndex INTEGER DEFAULT 0,
|
roomIndex INTEGER DEFAULT 0,
|
||||||
originX INTEGER DEFAULT 0,
|
originX INTEGER DEFAULT 0,
|
||||||
originY INTEGER DEFAULT 0,
|
originY INTEGER DEFAULT 0,
|
||||||
boundsX INTEGER DEFAULT 0,
|
|
||||||
boundsY INTEGER DEFAULT 0,
|
|
||||||
boundsW INTEGER DEFAULT 0,
|
|
||||||
boundsH INTEGER DEFAULT 0,
|
|
||||||
|
|
||||||
--statistics
|
--statistics
|
||||||
baseStats INTEGER REFERENCES StatisticSets(uid),
|
baseStats INTEGER REFERENCES StatisticSets(uid),
|
||||||
@@ -105,5 +101,5 @@ CREATE TABLE IF NOT EXISTS WornEquipment (
|
|||||||
--unique information
|
--unique information
|
||||||
durability INTEGER DEFAULT 0,
|
durability INTEGER DEFAULT 0,
|
||||||
stats INTEGER REFERENCES StatisticSets(uid)
|
stats INTEGER REFERENCES StatisticSets(uid)
|
||||||
--attached script?
|
--TODO: attached script?
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ private:
|
|||||||
|
|
||||||
int clientIndex;
|
int clientIndex;
|
||||||
std::string username;
|
std::string username;
|
||||||
//password/auth token
|
//TODO: password
|
||||||
|
|
||||||
//bit fields?
|
//bit fields?
|
||||||
bool blackListed = false;
|
bool blackListed = false;
|
||||||
|
|||||||
@@ -28,31 +28,15 @@
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);";
|
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);";
|
||||||
|
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM Accounts WHERE username = ?;";
|
||||||
static const char* LOAD_USER_ACCOUNT = "SELECT "
|
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted = ?2, whitelisted = ?3, mod = ?4, admin = ?5 WHERE uid = ?1;";
|
||||||
"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* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
|
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
|
||||||
|
|
||||||
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
|
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Define the public methods
|
//Define the public methods
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
//TODO: (1) block blacklisted accounts
|
|
||||||
int AccountManager::Create(std::string username, int clientIndex) {
|
int AccountManager::Create(std::string username, int clientIndex) {
|
||||||
//create this user account, failing if it exists, leave this account in memory
|
//create this user account, failing if it exists, leave this account in memory
|
||||||
sqlite3_stmt* statement = nullptr;
|
sqlite3_stmt* statement = nullptr;
|
||||||
@@ -110,11 +94,11 @@ int AccountManager::Load(std::string username, int clientIndex) {
|
|||||||
|
|
||||||
//extract the data into memory
|
//extract the data into memory
|
||||||
AccountData& newAccount = elementMap[uid];
|
AccountData& newAccount = elementMap[uid];
|
||||||
newAccount.username = username;
|
newAccount.username = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
||||||
newAccount.blackListed = sqlite3_column_int(statement, 1);
|
newAccount.blackListed = sqlite3_column_int(statement, 2);
|
||||||
newAccount.whiteListed = sqlite3_column_int(statement, 2);
|
newAccount.whiteListed = sqlite3_column_int(statement, 3);
|
||||||
newAccount.mod = sqlite3_column_int(statement, 3);
|
newAccount.mod = sqlite3_column_int(statement, 4);
|
||||||
newAccount.admin = sqlite3_column_int(statement, 4);
|
newAccount.admin = sqlite3_column_int(statement, 5);
|
||||||
newAccount.clientIndex = clientIndex;
|
newAccount.clientIndex = clientIndex;
|
||||||
|
|
||||||
//finish the routine
|
//finish the routine
|
||||||
@@ -216,7 +200,7 @@ void AccountManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountData const&>)> fn) {
|
void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountData>)> fn) {
|
||||||
//replicate std::remove_if, using custom code
|
//replicate std::remove_if, using custom code
|
||||||
std::map<int, AccountData>::iterator it = elementMap.begin();
|
std::map<int, AccountData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
@@ -235,6 +219,7 @@ void AccountManager::UnloadIf(std::function<bool(std::pair<const int, AccountDat
|
|||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
AccountData* AccountManager::Get(int uid) {
|
AccountData* AccountManager::Get(int uid) {
|
||||||
|
//TODO: could this load an account first?
|
||||||
std::map<int, AccountData>::iterator it = elementMap.find(uid);
|
std::map<int, AccountData>::iterator it = elementMap.find(uid);
|
||||||
|
|
||||||
if (it == elementMap.end()) {
|
if (it == elementMap.end()) {
|
||||||
|
|||||||
@@ -24,29 +24,37 @@
|
|||||||
|
|
||||||
#include "account_data.hpp"
|
#include "account_data.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
#include "manager_interface.hpp"
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#if defined(__MINGW32__)
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
#else
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class AccountManager: public Singleton<AccountManager> {
|
class AccountManager:
|
||||||
|
public Singleton<AccountManager>,
|
||||||
|
public ManagerInterface<AccountData, std::string, int>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(std::string username, int clientIndex);
|
int Create(std::string username, int clientIndex) override;
|
||||||
int Load(std::string username, int clientIndex);
|
int Load(std::string username, int clientIndex) override;
|
||||||
int Save(int uid);
|
int Save(int uid) override;
|
||||||
void Unload(int uid);
|
void Unload(int uid) override;
|
||||||
void Delete(int uid);
|
void Delete(int uid) override;
|
||||||
|
|
||||||
void UnloadAll();
|
void UnloadAll() override;
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, AccountData const&>)> fn);
|
void UnloadIf(std::function<bool(std::pair<const int, AccountData>)> fn) override;
|
||||||
|
|
||||||
//accessors and mutators
|
//accessors and mutators
|
||||||
AccountData* Get(int uid);
|
AccountData* Get(int uid) override;
|
||||||
int GetLoadedCount();
|
int GetLoadedCount() override;
|
||||||
int GetTotalCount();
|
int GetTotalCount() override;
|
||||||
std::map<int, AccountData>* GetContainer();
|
std::map<int, AccountData>* GetContainer() override;
|
||||||
|
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
sqlite3* GetDatabase();
|
sqlite3* GetDatabase();
|
||||||
@@ -57,8 +65,6 @@ private:
|
|||||||
AccountManager() = default;
|
AccountManager() = default;
|
||||||
~AccountManager() = default;
|
~AccountManager() = default;
|
||||||
|
|
||||||
//members
|
|
||||||
std::map<int, AccountData> elementMap;
|
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,129 +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 "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"
|
#include "character_data.hpp"
|
||||||
|
|
||||||
CharacterData::CharacterData(): Entity("character") {
|
|
||||||
//EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
int CharacterData::GetOwner() {
|
int CharacterData::GetOwner() {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,12 @@
|
|||||||
|
|
||||||
class CharacterData: public Entity {
|
class CharacterData: public Entity {
|
||||||
public:
|
public:
|
||||||
CharacterData();
|
CharacterData() = default;
|
||||||
~CharacterData() = default;
|
~CharacterData() = default;
|
||||||
|
|
||||||
|
//accessors and mutators
|
||||||
|
//...
|
||||||
|
|
||||||
//database stuff
|
//database stuff
|
||||||
int GetOwner();
|
int GetOwner();
|
||||||
std::string GetHandle();
|
std::string GetHandle();
|
||||||
@@ -43,7 +46,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class CharacterManager;
|
friend class CharacterManager;
|
||||||
|
|
||||||
int owner = -1;
|
int owner;
|
||||||
std::string handle;
|
std::string handle;
|
||||||
std::string avatar;
|
std::string avatar;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
#include "character_manager.hpp"
|
#include "character_manager.hpp"
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#if defined(__MINGW32__)
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
#include "character_defines.hpp"
|
#else
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -32,45 +34,10 @@
|
|||||||
//Define the queries
|
//Define the queries
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
//NOTE: Programmer set variables are NOT zero-indexed
|
static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, avatar) VALUES (?, ?, ?);";
|
||||||
//NOTE: SQLite3 returned variables (i.e. loading) ARE zero-indexed
|
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* 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* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
|
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
|
||||||
|
|
||||||
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
|
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -92,10 +59,6 @@ int CharacterManager::Create(int owner, std::string handle, std::string avatar)
|
|||||||
ret |= sqlite3_bind_int(statement, 1, owner);
|
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, 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_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
|
//check for binding errors
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -162,14 +125,9 @@ int CharacterManager::Load(int owner, std::string handle, std::string avatar) {
|
|||||||
//Don't cache the birth
|
//Don't cache the birth
|
||||||
|
|
||||||
//world origin
|
//world origin
|
||||||
newChar.roomIndex = sqlite3_column_int(statement, 4);
|
newChar.roomIndex = sqlite3_column_int(statement, 5);
|
||||||
newChar.origin.x = (double)sqlite3_column_int(statement, 5);
|
newChar.origin.x = (double)sqlite3_column_int(statement, 6);
|
||||||
newChar.origin.y = (double)sqlite3_column_int(statement, 6);
|
newChar.origin.y = (double)sqlite3_column_int(statement, 7);
|
||||||
//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);
|
|
||||||
|
|
||||||
//gameplay components: equipment, items, buffs, debuffs...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
|
|
||||||
@@ -211,10 +169,6 @@ int CharacterManager::Save(int uid) {
|
|||||||
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
|
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
|
||||||
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
|
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
|
||||||
ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != 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...
|
//gameplay components: equipment, items, buffs, debuffs...
|
||||||
|
|
||||||
@@ -243,7 +197,6 @@ void CharacterManager::Unload(int uid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CharacterManager::Delete(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
|
//delete this character from the database, then remove it from memory
|
||||||
sqlite3_stmt* statement = nullptr;
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
@@ -276,7 +229,7 @@ void CharacterManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterManager::UnloadIf(std::function<bool(std::pair<const int, CharacterData const&>)> fn) {
|
void CharacterManager::UnloadIf(std::function<bool(std::pair<const int, CharacterData>)> fn) {
|
||||||
std::map<int, CharacterData>::iterator it = elementMap.begin();
|
std::map<int, CharacterData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
if (fn(*it)) {
|
if (fn(*it)) {
|
||||||
@@ -303,15 +256,6 @@ CharacterData* CharacterManager::Get(int uid) {
|
|||||||
return &it->second;
|
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() {
|
int CharacterManager::GetLoadedCount() {
|
||||||
return elementMap.size();
|
return elementMap.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,46 +24,47 @@
|
|||||||
|
|
||||||
#include "character_data.hpp"
|
#include "character_data.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
#include "manager_interface.hpp"
|
||||||
|
|
||||||
#include "sqlite3.h"
|
#if defined(__MINGW32__)
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
#else
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class CharacterManager: public Singleton<CharacterManager> {
|
class CharacterManager:
|
||||||
|
public Singleton<CharacterManager>,
|
||||||
|
public ManagerInterface<CharacterData, int, std::string, std::string>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(int owner, std::string handle, std::string avatar);
|
int Create(int owner, std::string handle, std::string avatar) override;
|
||||||
int Load(int owner, std::string handle, std::string avatar);
|
int Load(int owner, std::string handle, std::string avatar) override;
|
||||||
int Save(int uid);
|
int Save(int uid) override;
|
||||||
void Unload(int uid);
|
void Unload(int uid) override;
|
||||||
void Delete(int uid);
|
void Delete(int uid) override;
|
||||||
|
|
||||||
void UnloadAll();
|
void UnloadAll() override;
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, CharacterData const&>)> fn);
|
void UnloadIf(std::function<bool(std::pair<const int, CharacterData>)> fn) override;
|
||||||
|
|
||||||
//accessors and mutators
|
//accessors and mutators
|
||||||
CharacterData* Get(int uid);
|
CharacterData* Get(int uid) override;
|
||||||
CharacterData* Get(std::string handle);
|
int GetLoadedCount() override;
|
||||||
int GetLoadedCount();
|
int GetTotalCount() override;
|
||||||
int GetTotalCount();
|
std::map<int, CharacterData>* GetContainer() override;
|
||||||
std::map<int, CharacterData>* GetContainer();
|
|
||||||
|
|
||||||
//API interface
|
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
sqlite3* GetDatabase();
|
sqlite3* GetDatabase();
|
||||||
|
|
||||||
//hooks
|
|
||||||
//TODO: character hooks
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Singleton<CharacterManager>;
|
friend Singleton<CharacterManager>;
|
||||||
|
|
||||||
CharacterManager() = default;
|
CharacterManager() = default;
|
||||||
~CharacterManager() = default;
|
~CharacterManager() = default;
|
||||||
|
|
||||||
//members
|
|
||||||
std::map<int, CharacterData> elementMap;
|
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,114 +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 "character_manager_api.hpp"
|
|
||||||
|
|
||||||
#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}
|
|
||||||
};
|
|
||||||
|
|
||||||
LUAMOD_API int openCharacterManagerAPI(lua_State* L) {
|
|
||||||
luaL_newlib(L, characterManagerLib);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#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+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
|
|||||||
@@ -21,15 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
#include "client_manager.hpp"
|
#include "client_manager.hpp"
|
||||||
|
|
||||||
#include "ip_operators.hpp"
|
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
std::list<int> ClientManager::CheckConnections() {
|
int ClientManager::CheckConnections() {
|
||||||
//list of clients to disconnect
|
|
||||||
std::list<int> returnList;
|
|
||||||
|
|
||||||
for (auto& it : elementMap) {
|
for (auto& it : elementMap) {
|
||||||
//3 seconds between beats
|
//3 seconds between beats
|
||||||
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
||||||
@@ -42,17 +38,21 @@ std::list<int> ClientManager::CheckConnections() {
|
|||||||
|
|
||||||
for (auto& it : elementMap) {
|
for (auto& it : elementMap) {
|
||||||
if (it.second.GetAttempts() > 2) {
|
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) {
|
void ClientManager::HandlePong(ServerPacket* const argPacket) {
|
||||||
//find and update the specified client
|
//find and update the specified client
|
||||||
for (auto& it : elementMap) {
|
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();
|
it.second.ResetAttempts();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,11 +73,12 @@ void ClientManager::UnloadAll() {
|
|||||||
elementMap.clear();
|
elementMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientManager::UnloadIf(std::function<bool(std::pair<const int, ClientData const&>)> fn) {
|
void ClientManager::UnloadIf(std::function<bool(std::pair<const int, ClientData>)> fn) {
|
||||||
std::map<int, ClientData>::iterator it = elementMap.begin();
|
std::map<int, ClientData>::iterator it = elementMap.begin();
|
||||||
while (it != elementMap.end()) {
|
while (it != elementMap.end()) {
|
||||||
if (fn(*it)) {
|
if (fn(*it)) {
|
||||||
it = elementMap.erase(it);
|
it = elementMap.erase(it);
|
||||||
|
//TODO: ? disconnect, unload characters, notify other clients
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
++it;
|
++it;
|
||||||
|
|||||||
@@ -23,33 +23,35 @@
|
|||||||
#define CLIENTMANAGER_HPP_
|
#define CLIENTMANAGER_HPP_
|
||||||
|
|
||||||
#include "client_data.hpp"
|
#include "client_data.hpp"
|
||||||
|
#include "manager_interface.hpp"
|
||||||
#include "server_packet.hpp"
|
#include "server_packet.hpp"
|
||||||
#include "singleton.hpp"
|
#include "singleton.hpp"
|
||||||
|
|
||||||
#include "SDL/SDL_net.h"
|
#include "SDL/SDL_net.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class ClientManager: public Singleton<ClientManager> {
|
class ClientManager:
|
||||||
|
public Singleton<ClientManager>,
|
||||||
|
public ManagerInterface<ClientData, IPaddress>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//methods
|
//methods
|
||||||
std::list<int> CheckConnections();
|
int CheckConnections();
|
||||||
void HandlePong(ServerPacket* const argPacket);
|
void HandlePong(ServerPacket* const argPacket);
|
||||||
|
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(IPaddress);
|
int Create(IPaddress) override;
|
||||||
void Unload(int uid);
|
void Unload(int uid) override;
|
||||||
|
|
||||||
void UnloadAll();
|
void UnloadAll() override;
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, ClientData const&>)> fn);
|
void UnloadIf(std::function<bool(std::pair<const int, ClientData>)> fn) override;
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
ClientData* Get(int uid);
|
ClientData* Get(int uid) override;
|
||||||
int GetLoadedCount();
|
int GetLoadedCount() override;
|
||||||
int GetTotalCount();
|
int GetTotalCount() override;
|
||||||
std::map<int, ClientData>* GetContainer();
|
std::map<int, ClientData>* GetContainer() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Singleton<ClientManager>;
|
friend Singleton<ClientManager>;
|
||||||
@@ -57,8 +59,11 @@ private:
|
|||||||
ClientManager() = default;
|
ClientManager() = default;
|
||||||
~ClientManager() = default;
|
~ClientManager() = default;
|
||||||
|
|
||||||
//members
|
//EMPTY
|
||||||
std::map<int, ClientData> elementMap;
|
int Load(IPaddress) override { return -1; }
|
||||||
|
int Save(int uid) override { return -1; }
|
||||||
|
void Delete(int uid) override { return; }
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,20 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "ip_operators.hpp"
|
#include "door_data.hpp"
|
||||||
|
|
||||||
bool operator==(IPaddress lhs, IPaddress rhs) {
|
std::string DoorData::SetRoomName(std::string s) {
|
||||||
return lhs.host == rhs.host && lhs.port == rhs.port;
|
return roomName = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(IPaddress lhs, IPaddress rhs) {
|
Vector2 DoorData::SetDestPosition(Vector2 v) {
|
||||||
return !(lhs == rhs);
|
return destPosition = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string DoorData::GetRoomName() {
|
||||||
|
return roomName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 DoorData::GetDestPosition() {
|
||||||
|
return destPosition;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/* 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 DOORDATA_HPP_
|
||||||
|
#define DOORDATA_HPP_
|
||||||
|
|
||||||
|
#include "entity.hpp"
|
||||||
|
#include "vector2.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class DoorData: public Entity {
|
||||||
|
public:
|
||||||
|
DoorData() = default;
|
||||||
|
~DoorData() = default;
|
||||||
|
|
||||||
|
//accessors & mutators
|
||||||
|
std::string SetRoomName(std::string);
|
||||||
|
Vector2 SetDestPosition(Vector2);
|
||||||
|
|
||||||
|
std::string GetRoomName();
|
||||||
|
Vector2 GetDestPosition();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class DoorManager;
|
||||||
|
|
||||||
|
std::string roomName;
|
||||||
|
Vector2 destPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,40 +19,48 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "trigger_data.hpp"
|
#include "door_manager.hpp"
|
||||||
|
|
||||||
std::string TriggerData::SetHandle(std::string s) {
|
int DoorManager::Create(std::string, Vector2) {
|
||||||
return handle = s;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TriggerData::GetHandle() const {
|
int DoorManager::Load(std::string, Vector2) {
|
||||||
return handle;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 TriggerData::SetOrigin(Vector2 v) {
|
int DoorManager::Save(int uid) {
|
||||||
return origin = v;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 TriggerData::GetOrigin() {
|
void DoorManager::Unload(int uid) {
|
||||||
return origin;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox TriggerData::SetBoundingBox(BoundingBox b) {
|
void DoorManager::Delete(int uid) {
|
||||||
return bounds = b;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox TriggerData::GetBoundingBox() {
|
void DoorManager::UnloadAll() {
|
||||||
return bounds;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
int TriggerData::SetScriptReference(int i) {
|
void DoorManager::UnloadIf(std::function<bool(std::pair<const int, DoorData>)> fn) {
|
||||||
return scriptRef = i;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
int TriggerData::GetScriptReference() {
|
DoorData* DoorManager::Get(int uid) {
|
||||||
return scriptRef;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Entity*>* TriggerData::GetExclusionList() {
|
int DoorManager::GetLoadedCount() {
|
||||||
return &exclusionList;
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DoorManager::GetTotalCount() {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<int, DoorData>* DoorManager::GetContainer() {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
@@ -19,43 +19,43 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef TRIGGERDATA_HPP_
|
#ifndef DOORMANAGER_HPP_
|
||||||
#define TRIGGERDATA_HPP_
|
#define DOORMANAGER_HPP_
|
||||||
|
|
||||||
#include "bounding_box.hpp"
|
#include "door_data.hpp"
|
||||||
#include "entity.hpp"
|
#include "manager_interface.hpp"
|
||||||
|
#include "singleton.hpp"
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
#include "lua.hpp"
|
#include <functional>
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class TriggerData {
|
class DoorManager:
|
||||||
|
public Singleton<DoorManager>,
|
||||||
|
public ManagerInterface<DoorData, std::string, Vector2>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
TriggerData() = default;
|
//common public methods
|
||||||
~TriggerData() = default;
|
int Create(std::string, Vector2) override;
|
||||||
|
int Load(std::string, Vector2) override;
|
||||||
|
int Save(int uid) override;
|
||||||
|
void Unload(int uid) override;
|
||||||
|
void Delete(int uid) override;
|
||||||
|
|
||||||
std::string SetHandle(std::string);
|
void UnloadAll() override;
|
||||||
std::string GetHandle() const;
|
void UnloadIf(std::function<bool(std::pair<const int, DoorData>)> fn) override;
|
||||||
|
|
||||||
Vector2 SetOrigin(Vector2 v);
|
//accessors & mutators
|
||||||
Vector2 GetOrigin();
|
DoorData* Get(int uid) override;
|
||||||
|
int GetLoadedCount() override;
|
||||||
BoundingBox SetBoundingBox(BoundingBox b);
|
int GetTotalCount() override;
|
||||||
BoundingBox GetBoundingBox();
|
std::map<int, DoorData>* GetContainer() override;
|
||||||
|
|
||||||
int SetScriptReference(int i);
|
|
||||||
int GetScriptReference();
|
|
||||||
|
|
||||||
std::list<Entity*>* GetExclusionList();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string handle;
|
friend Singleton<DoorManager>;
|
||||||
Vector2 origin;
|
|
||||||
BoundingBox bounds;
|
DoorManager() = default;
|
||||||
int scriptRef = LUA_NOREF;
|
~DoorManager() = default;
|
||||||
std::list<Entity*> exclusionList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,14 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
|
|
||||||
Entity::Entity(const char* _type): type(_type) {
|
|
||||||
//EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
void Entity::Update() {
|
|
||||||
origin += motion;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Entity::SetRoomIndex(int i) {
|
int Entity::SetRoomIndex(int i) {
|
||||||
return roomIndex = i;
|
return roomIndex = i;
|
||||||
}
|
}
|
||||||
@@ -41,26 +33,14 @@ Vector2 Entity::SetMotion(Vector2 v) {
|
|||||||
return motion = v;
|
return motion = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox Entity::SetBounds(BoundingBox b) {
|
int Entity::GetRoomIndex() {
|
||||||
return bounds = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Entity::GetRoomIndex() const {
|
|
||||||
return roomIndex;
|
return roomIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 Entity::GetOrigin() const {
|
Vector2 Entity::GetOrigin() {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 Entity::GetMotion() const {
|
Vector2 Entity::GetMotion() {
|
||||||
return motion;
|
return motion;
|
||||||
}
|
|
||||||
|
|
||||||
BoundingBox Entity::GetBounds() const {
|
|
||||||
return bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Entity::GetType() const {
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
@@ -22,38 +22,27 @@
|
|||||||
#ifndef ENTITY_HPP_
|
#ifndef ENTITY_HPP_
|
||||||
#define ENTITY_HPP_
|
#define ENTITY_HPP_
|
||||||
|
|
||||||
#include "bounding_box.hpp"
|
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
//The base class for all objects in the world
|
//The base class for all objects in the world
|
||||||
class Entity {
|
class Entity {
|
||||||
public:
|
public:
|
||||||
virtual void Update();
|
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
int SetRoomIndex(int i);
|
int SetRoomIndex(int i);
|
||||||
Vector2 SetOrigin(Vector2 v);
|
Vector2 SetOrigin(Vector2 v);
|
||||||
Vector2 SetMotion(Vector2 v);
|
Vector2 SetMotion(Vector2 v);
|
||||||
BoundingBox SetBounds(BoundingBox b);
|
|
||||||
|
|
||||||
int GetRoomIndex() const;
|
int GetRoomIndex();
|
||||||
Vector2 GetOrigin() const;
|
Vector2 GetOrigin();
|
||||||
Vector2 GetMotion() const;
|
Vector2 GetMotion();
|
||||||
BoundingBox GetBounds() const;
|
|
||||||
|
|
||||||
const char* GetType() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entity(const char*);
|
Entity() = default;
|
||||||
virtual ~Entity() = default;
|
~Entity() = default;
|
||||||
|
|
||||||
int roomIndex = -1;
|
int roomIndex = -1;
|
||||||
Vector2 origin = {0, 0};
|
Vector2 origin;
|
||||||
Vector2 motion = {0, 0};
|
Vector2 motion;
|
||||||
BoundingBox bounds = {0, 0, 0, 0};
|
|
||||||
const char* type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,106 +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 "entity_api.hpp"
|
|
||||||
|
|
||||||
#include "entity.hpp"
|
|
||||||
|
|
||||||
static int setRoomIndex(lua_State* L) {
|
|
||||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
|
||||||
entity->SetRoomIndex(lua_tointeger(L, 2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setOrigin(lua_State* L) {
|
|
||||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
|
||||||
entity->SetOrigin({lua_tonumber(L, 2), lua_tonumber(L, 3)});
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setMotion(lua_State* L) {
|
|
||||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
|
||||||
entity->SetMotion({lua_tonumber(L, 2), lua_tonumber(L, 3)});
|
|
||||||
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());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getOrigin(lua_State* L) {
|
|
||||||
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushnumber(L, entity->GetOrigin().x);
|
|
||||||
lua_pushnumber(L, entity->GetOrigin().y);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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}
|
|
||||||
};
|
|
||||||
|
|
||||||
LUAMOD_API int openEntityAPI(lua_State* L) {
|
|
||||||
luaL_newlib(L, entityLib);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
+10
-25
@@ -34,20 +34,14 @@
|
|||||||
#define linit_c
|
#define linit_c
|
||||||
#define LUA_LIB
|
#define LUA_LIB
|
||||||
|
|
||||||
#include "lua.hpp"
|
#if defined(__MINGW32__)
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#else
|
||||||
|
#include "lua.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "entity_api.hpp"
|
#include "map_system_api.hpp"
|
||||||
#include "character_api.hpp"
|
#include "room_system_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"
|
|
||||||
|
|
||||||
//these libs are loaded by lua.c and are readily available to any Lua program
|
//these libs are loaded by lua.c and are readily available to any Lua program
|
||||||
static const luaL_Reg loadedlibs[] = {
|
static const luaL_Reg loadedlibs[] = {
|
||||||
@@ -65,20 +59,11 @@ static const luaL_Reg loadedlibs[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//these libs are preloaded and must be required before used
|
//these libs are preloaded and must be required before used
|
||||||
static const luaL_Reg preloadedlibs[] = {
|
static const luaL_Reg preloadedlibs[] = {
|
||||||
{TORTUGA_ENTITY_API, openEntityAPI}, //required by derived classes
|
{TORTUGA_MAP_SYSTEM_API, openMapSystemAPI},
|
||||||
{TORTUGA_CHARACTER_API, openCharacterAPI},
|
{TORTUGA_ROOM_SYSTEM_API, openRoomSystemAPI},
|
||||||
{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},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#include "character_manager.hpp"
|
#include "character_manager.hpp"
|
||||||
#include "client_manager.hpp"
|
#include "client_manager.hpp"
|
||||||
#include "config_utility.hpp"
|
#include "config_utility.hpp"
|
||||||
|
#include "door_manager.hpp"
|
||||||
|
#include "monster_manager.hpp"
|
||||||
#include "room_manager.hpp"
|
#include "room_manager.hpp"
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
|
||||||
@@ -41,6 +43,8 @@ int main(int argc, char* argv[]) {
|
|||||||
CharacterManager::CreateSingleton();
|
CharacterManager::CreateSingleton();
|
||||||
ClientManager::CreateSingleton();
|
ClientManager::CreateSingleton();
|
||||||
ConfigUtility::CreateSingleton();
|
ConfigUtility::CreateSingleton();
|
||||||
|
DoorManager::CreateSingleton();
|
||||||
|
MonsterManager::CreateSingleton();
|
||||||
RoomManager::CreateSingleton();
|
RoomManager::CreateSingleton();
|
||||||
UDPNetworkUtility::CreateSingleton();
|
UDPNetworkUtility::CreateSingleton();
|
||||||
|
|
||||||
@@ -59,6 +63,8 @@ int main(int argc, char* argv[]) {
|
|||||||
CharacterManager::DeleteSingleton();
|
CharacterManager::DeleteSingleton();
|
||||||
ClientManager::DeleteSingleton();
|
ClientManager::DeleteSingleton();
|
||||||
ConfigUtility::DeleteSingleton();
|
ConfigUtility::DeleteSingleton();
|
||||||
|
DoorManager::DeleteSingleton();
|
||||||
|
MonsterManager::DeleteSingleton();
|
||||||
RoomManager::DeleteSingleton();
|
RoomManager::DeleteSingleton();
|
||||||
UDPNetworkUtility::DeleteSingleton();
|
UDPNetworkUtility::DeleteSingleton();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#include directories
|
#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 doors entities monsters rooms server_utilities ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
|
||||||
|
|
||||||
#libraries
|
#libraries
|
||||||
#the order of the $(LIBS) is important, at least for MinGW
|
#the order of the $(LIBS) is important, at least for MinGW
|
||||||
@@ -28,11 +28,11 @@ all: $(OBJ) $(OUT)
|
|||||||
$(MAKE) -C accounts
|
$(MAKE) -C accounts
|
||||||
$(MAKE) -C characters
|
$(MAKE) -C characters
|
||||||
$(MAKE) -C clients
|
$(MAKE) -C clients
|
||||||
|
$(MAKE) -C doors
|
||||||
$(MAKE) -C entities
|
$(MAKE) -C entities
|
||||||
$(MAKE) -C monsters
|
$(MAKE) -C monsters
|
||||||
$(MAKE) -C rooms
|
$(MAKE) -C rooms
|
||||||
$(MAKE) -C server_utilities
|
$(MAKE) -C server_utilities
|
||||||
$(MAKE) -C triggers
|
|
||||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|||||||
@@ -1,88 +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 "monster_api.hpp"
|
|
||||||
|
|
||||||
#include "monster_data.hpp"
|
|
||||||
|
|
||||||
#include "entity_api.hpp"
|
|
||||||
|
|
||||||
static int setAvatar(lua_State* L) {
|
|
||||||
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
|
||||||
monster->SetAvatar(lua_tostring(L, 2));
|
|
||||||
//TODO: send an update to the clients?
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getAvatar(lua_State* L) {
|
|
||||||
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushstring(L, monster->GetAvatar().c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setScript(lua_State* L) {
|
|
||||||
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, monster->GetScriptReference());
|
|
||||||
monster->SetScriptReference(luaL_ref(L, LUA_REGISTRYINDEX));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getScript(lua_State* L) {
|
|
||||||
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
|
|
||||||
lua_pushinteger(L, monster->GetScriptReference());
|
|
||||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const luaL_Reg monsterLib[] = {
|
|
||||||
{"SetAvatar", setAvatar},
|
|
||||||
{"GetAvatar", getAvatar},
|
|
||||||
{"SetScript", setScript},
|
|
||||||
{"GetScript", getScript},
|
|
||||||
{nullptr, nullptr}
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,30 +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 MONSTERAPI_HPP_
|
|
||||||
#define MONSTERAPI_HPP_
|
|
||||||
|
|
||||||
#include "lua.hpp"
|
|
||||||
|
|
||||||
#define TORTUGA_MONSTER_API "monster"
|
|
||||||
LUAMOD_API int openMonsterAPI(lua_State* L);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -21,22 +21,18 @@
|
|||||||
*/
|
*/
|
||||||
#include "monster_data.hpp"
|
#include "monster_data.hpp"
|
||||||
|
|
||||||
MonsterData::MonsterData(): Entity("monster") {
|
|
||||||
//EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string MonsterData::SetAvatar(std::string s) {
|
std::string MonsterData::SetAvatar(std::string s) {
|
||||||
return avatar = s;
|
return avatar = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MonsterData::GetAvatar() {
|
|
||||||
return avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MonsterData::SetScriptReference(int i) {
|
int MonsterData::SetScriptReference(int i) {
|
||||||
return scriptRef = i;
|
return scriptRef = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MonsterData::GetAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
int MonsterData::GetScriptReference() {
|
int MonsterData::GetScriptReference() {
|
||||||
return scriptRef;
|
return scriptRef;
|
||||||
}
|
}
|
||||||
@@ -24,26 +24,24 @@
|
|||||||
|
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
|
|
||||||
#include "lua.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MonsterData: public Entity {
|
class MonsterData: public Entity {
|
||||||
public:
|
public:
|
||||||
MonsterData();
|
MonsterData() = default;
|
||||||
~MonsterData() = default;
|
~MonsterData() = default;
|
||||||
|
|
||||||
std::string SetAvatar(std::string);
|
std::string SetAvatar(std::string);
|
||||||
std::string GetAvatar();
|
|
||||||
|
|
||||||
int SetScriptReference(int);
|
int SetScriptReference(int);
|
||||||
|
|
||||||
|
std::string GetAvatar();
|
||||||
int GetScriptReference();
|
int GetScriptReference();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MonsterManager;
|
friend class MonsterManager;
|
||||||
|
|
||||||
std::string avatar;
|
std::string avatar;
|
||||||
int scriptRef = LUA_NOREF;
|
int scriptRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,54 +21,62 @@
|
|||||||
*/
|
*/
|
||||||
#include "monster_manager.hpp"
|
#include "monster_manager.hpp"
|
||||||
|
|
||||||
MonsterManager::MonsterManager() {
|
|
||||||
//EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
MonsterManager::~MonsterManager() {
|
|
||||||
UnloadAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
int MonsterManager::Create(std::string) {
|
int MonsterManager::Create(std::string) {
|
||||||
//TODO: (9) MonsterManager::Create()
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int MonsterManager::Load(std::string) {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int MonsterManager::Save(int uid) {
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::Unload(int uid) {
|
void MonsterManager::Unload(int uid) {
|
||||||
//TODO: (9) MonsterManager::Unload()
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void MonsterManager::Delete(int uid) {
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::UnloadAll() {
|
void MonsterManager::UnloadAll() {
|
||||||
//TODO: (9) MonsterManager::UnloadAll()
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) {
|
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData>)> fn) {
|
||||||
//TODO: (9) MonsterManager::UnloadIf()
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
MonsterData* MonsterManager::Get(int uid) {
|
MonsterData* MonsterManager::Get(int uid) {
|
||||||
//TODO: (9) MonsterManager::Get()
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
int MonsterManager::GetLoadedCount() {
|
int MonsterManager::GetLoadedCount() {
|
||||||
//TODO: (9) MonsterManager::GetLoadedCount()
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int MonsterManager::GetTotalCount() {
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, MonsterData>* MonsterManager::GetContainer() {
|
std::map<int, MonsterData>* MonsterManager::GetContainer() {
|
||||||
//TODO: (9) MonsterManager::GetContainer()
|
//TODO
|
||||||
}
|
|
||||||
|
|
||||||
lua_State* MonsterManager::SetLuaState(lua_State* L) {
|
|
||||||
//TODO: (9) MonsterManager::SetLuaState()
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_State* MonsterManager::GetLuaState() {
|
|
||||||
//TODO: (9) MonsterManager::GetLuaState()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
|
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
|
||||||
//TODO: (9) MonsterManager::SetDatabase()
|
//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3* MonsterManager::GetDatabase() {
|
sqlite3* MonsterManager::GetDatabase() {
|
||||||
//TODO: (9) MonsterManager::GetDatabase()
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* MonsterManager::SetLuaState(lua_State* L) {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* MonsterManager::GetLuaState() {
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,43 +22,56 @@
|
|||||||
#ifndef MONSTERMANAGER_HPP_
|
#ifndef MONSTERMANAGER_HPP_
|
||||||
#define MONSTERMANAGER_HPP_
|
#define MONSTERMANAGER_HPP_
|
||||||
|
|
||||||
|
#include "manager_interface.hpp"
|
||||||
#include "monster_data.hpp"
|
#include "monster_data.hpp"
|
||||||
|
#include "singleton.hpp"
|
||||||
|
|
||||||
#include "lua.hpp"
|
#ifdef __unix__
|
||||||
#include "sqlite3.h"
|
#include "lua.hpp"
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#else
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MonsterManager {
|
class MonsterManager:
|
||||||
|
public Singleton<MonsterManager>,
|
||||||
|
public ManagerInterface<MonsterData, std::string>
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
MonsterManager();
|
|
||||||
~MonsterManager();
|
|
||||||
|
|
||||||
//common public methods
|
//common public methods
|
||||||
int Create(std::string);
|
int Create(std::string) override;
|
||||||
void Unload(int uid);
|
int Load(std::string) override;
|
||||||
|
int Save(int uid) override;
|
||||||
|
void Unload(int uid) override;
|
||||||
|
void Delete(int uid) override;
|
||||||
|
|
||||||
void UnloadAll();
|
void UnloadAll() override;
|
||||||
void UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn);
|
void UnloadIf(std::function<bool(std::pair<const int, MonsterData>)> fn) override;
|
||||||
|
|
||||||
//accessors & mutators
|
//accessors & mutators
|
||||||
MonsterData* Get(int uid);
|
MonsterData* Get(int uid) override;
|
||||||
int GetLoadedCount();
|
int GetLoadedCount() override;
|
||||||
std::map<int, MonsterData>* GetContainer();
|
int GetTotalCount() override;
|
||||||
|
std::map<int, MonsterData>* GetContainer() override;
|
||||||
|
|
||||||
//hooks
|
//hooks
|
||||||
lua_State* SetLuaState(lua_State* L);
|
|
||||||
lua_State* GetLuaState();
|
|
||||||
sqlite3* SetDatabase(sqlite3* db);
|
sqlite3* SetDatabase(sqlite3* db);
|
||||||
sqlite3* GetDatabase();
|
sqlite3* GetDatabase();
|
||||||
|
lua_State* SetLuaState(lua_State* L);
|
||||||
|
lua_State* GetLuaState();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//members
|
friend Singleton<MonsterManager>;
|
||||||
std::map<int, MonsterData> elementMap;
|
|
||||||
lua_State* lua = nullptr;
|
MonsterManager() = default;
|
||||||
|
~MonsterManager() = default;
|
||||||
|
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
|
lua_State* lua = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,30 +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 MONSTERMANAGERAPI_HPP_
|
|
||||||
#define MONSTERMANAGERAPI_HPP_
|
|
||||||
|
|
||||||
#include "lua.hpp"
|
|
||||||
|
|
||||||
#define TORTUGA_MONSTER_MANAGER_API "monster_manager"
|
|
||||||
LUAMOD_API int openMonsterManagerAPI(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;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user