Compare commits

..

6 Commits

Author SHA1 Message Date
Kayne Ruse 29a09cf71f Discarding: pointers to object to push/pop was a bad idea 2015-01-02 07:18:21 +11:00
Kayne Ruse e4d7ece99c Merge branch 'bugfix-lambda' into multiple-rooms
Conflicts:
	server/server_methods.cpp
2015-01-02 07:10:29 +11:00
Kayne Ruse b2452fb6fe Committing incomplete work; need to fix an urgent bug 2015-01-02 06:57:20 +11:00
Kayne Ruse 4579f9f388 Don't code while drunk; it never ends well 2015-01-01 12:53:32 +11:00
Kayne Ruse b4b7c0d877 Pop & Push don't work like they should 2015-01-01 03:37:13 +11:00
Kayne Ruse ebd8e54725 Added PushEntity() & PopEntity() to RoomManager
Calling them from server_character_methods.cpp.
2015-01-01 02:51:04 +11:00
110 changed files with 1660 additions and 2286 deletions
-4
View File
@@ -20,10 +20,6 @@ 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
* [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
(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).)
+6 -7
View File
@@ -14,10 +14,9 @@ Both a game server and game client are included in this package.
Instructions For Setup
-------------------------
1. To create a server, simply run server.exe
(a public server is provided by default)
2. To join a server, your player information must be input into rsc/config.cfg
(NOTE: This process will be streamlined later)
1. To create a server, simply run server.exe.
2. To join that server, run client.exe with config settings not already in use.
(Note: This process will be streamlined later).
3. To change the config settings, open rsc/config.cfg
4. These settings must be unique for each player:
@@ -29,7 +28,7 @@ Instructions For Setup
* client.avatar = elliot2.bmp #male
* client.avatar = coa2.bmp #female
6. When you've correctly set these values, run client.exe, and select 'Start'
from the main menu; this displays the list of available servers.
7. Select the name of a server (default is 'Public') and select 'Join'.
6. When you've correctly set these values (good luck), select 'Start' from the
main menu; this displays the list of available servers.
7. Select the name of your server (default is 'local') and select 'Join'.
8. Welcome to Tortuga, enjoy your stay.
+9 -14
View File
@@ -37,7 +37,7 @@
#include "main_menu.hpp"
#include "options_menu.hpp"
#include "lobby_menu.hpp"
#include "world.hpp"
#include "in_world.hpp"
#include "disconnected_screen.hpp"
//-------------------------
@@ -83,6 +83,7 @@ void ClientApplication::Init(int argc, char* argv[]) {
//debug output
//-------------------------
//TODO: enable/disable these with a switch
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
std::cout << "Internal sizes:" << std::endl;
@@ -136,17 +137,11 @@ void ClientApplication::Proc() {
realTime = Clock::now();
//simulate game time
if (simTime < realTime) {
while (simTime < realTime) {
//call each user defined function
activeScene->RunFrame();
//~60 FPS
simTime += std::chrono::duration<int, std::milli>(16);
}
}
else {
//give the machine a break
SDL_Delay(10);
while (simTime < realTime) {
//call each user defined function
activeScene->RunFrame();
//~60 FPS
simTime += std::chrono::duration<int, std::milli>(16);
}
//draw the game to the screen
@@ -185,8 +180,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
case SceneList::LOBBYMENU:
activeScene = new LobbyMenu(&clientIndex, &accountIndex);
break;
case SceneList::WORLD:
activeScene = new World(&clientIndex, &accountIndex);
case SceneList::INWORLD:
activeScene = new InWorld(&clientIndex, &accountIndex);
break;
case SceneList::DISCONNECTEDSCREEN:
activeScene = new DisconnectedScreen();
-23
View File
@@ -21,26 +21,3 @@
*/
#include "base_monster.hpp"
#include "config_utility.hpp"
void BaseMonster::CorrectSprite() {
//TODO: (9) empty
}
std::string BaseMonster::SetHandle(std::string s) {
return handle = s;
}
std::string BaseMonster::GetHandle() const {
return handle;
}
std::string BaseMonster::SetAvatar(std::string s) {
avatar = s;
sprite.LoadSurface(ConfigUtility::GetSingleton()["dir.sprites"] + avatar, 4, 1);
return avatar;
}
std::string BaseMonster::GetAvatar() const {
return avatar;
}
+1 -10
View File
@@ -29,17 +29,8 @@ public:
BaseMonster() = default;
virtual ~BaseMonster() = default;
void CorrectSprite();
std::string SetHandle(std::string s);
std::string GetHandle() const;
std::string SetAvatar(std::string s);
std::string GetAvatar() const;
protected:
//metadata
std::string handle;
std::string avatar;
//
};
#endif
-207
View File
@@ -1,207 +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::hCharacterCreate(CharacterPacket* const argPacket) {
//prevent double message
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
std::ostringstream msg;
msg << "Double character creation event; ";
msg << "Index: " << argPacket->characterIndex << "; ";
msg << "Handle: " << argPacket->handle;
throw(std::runtime_error(msg.str()));
}
//implicity create and retrieve the entity
BaseCharacter* character = &characterMap[argPacket->characterIndex];
//fill the character's info
character->SetOrigin(argPacket->origin);
character->SetMotion(argPacket->motion);
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); //TODO: (1) send the bounds from the server
character->SetHandle(argPacket->handle);
character->SetAvatar(argPacket->avatar);
character->SetOwner(argPacket->accountIndex);
character->CorrectSprite();
//check for this player's character
if (character->GetOwner() == accountIndex) {
localCharacter = static_cast<LocalCharacter*>(character);
//focus the camera on this character
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
//focus on this character's info
characterIndex = argPacket->characterIndex;
roomIndex = argPacket->roomIndex;
}
//debug
std::cout << "Character Create, total: " << characterMap.size() << std::endl;
}
void World::hCharacterDelete(CharacterPacket* const argPacket) {
//ignore if this character doesn't exist
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt == characterMap.end()) {
return;
}
//check for this player's character
if ((*characterIt).second.GetOwner() == accountIndex) {
localCharacter = nullptr;
//clear the camera
camera.marginX = 0;
camera.marginY = 0;
//clear the room
roomIndex = -1;
}
//remove this character
characterMap.erase(characterIt);
//debug
std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
}
void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
//prevent a double message about this player's character
if (argPacket->accountIndex == accountIndex) {
return;
}
//ignore characters in a different room (sub-optimal)
if (argPacket->roomIndex != roomIndex) {
return;
}
//implicitly construct the character if it doesn't exist
BaseCharacter* character = &characterMap[argPacket->characterIndex];
//set/update the character's info
character->SetOrigin(argPacket->origin);
character->SetMotion(argPacket->motion);
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
character->SetHandle(argPacket->handle);
character->SetAvatar(argPacket->avatar);
character->SetOwner(argPacket->accountIndex);
character->CorrectSprite();
//debug
std::cout << "Character Query, total: " << characterMap.size() << std::endl;
}
void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void World::hCharacterMovement(CharacterPacket* const argPacket) {
//TODO: (1) Authentication
if (argPacket->characterIndex == characterIndex) {
return;
}
//check that this character exists
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt != characterMap.end()) {
//set the origin and motion
characterIt->second.SetOrigin(argPacket->origin);
characterIt->second.SetMotion(argPacket->motion);
characterIt->second.CorrectSprite();
}
}
void World::hCharacterAttack(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void World::hCharacterDamage(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
//-------------------------
//player movement & collision
//-------------------------
void World::SendLocalCharacterMovement() {
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
newPacket.accountIndex = accountIndex;
newPacket.characterIndex = characterIndex;
newPacket.roomIndex = roomIndex;
newPacket.origin = localCharacter->GetOrigin();
newPacket.motion = localCharacter->GetMotion();
network.SendTo(Channels::SERVER, &newPacket);
}
std::list<BoundingBox> World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
//prepare for collisions
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
std::list<BoundingBox> boxList;
//NOTE: for loops were too dense to work with, so I've just used while loops
//outer loop
wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x);
while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) {
//inner loop
wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y);
while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) {
//check to see if this tile is solid
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
//push onto the box set
boxList.push_front(wallBounds);
}
//increment
wallBounds.y += wallBounds.h;
}
//increment
wallBounds.x += wallBounds.w;
}
return std::move(boxList);
}
@@ -1,135 +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) empty
}
void World::SendAdminShutdownRequest() {
ClientPacket newPacket;
//send a shutdown request
newPacket.type = SerialPacketType::ADMIN_SHUTDOWN_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void World::hLogoutResponse(ClientPacket* const argPacket) {
if (localCharacter) {
characterMap.erase(characterIndex);
localCharacter = nullptr;
}
accountIndex = -1;
characterIndex = -1;
//reset the camera
camera.marginX = camera.marginY = 0;
//because, why not? I guess...
SendDisconnectRequest();
}
void World::hDisconnectResponse(ClientPacket* const argPacket) {
hLogoutResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
}
void World::hAdminDisconnectForced(ClientPacket* const argPacket) {
hDisconnectResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
}
-418
View File
@@ -1,418 +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: (1) Tile size and tile sheet should be loaded elsewhere
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
//Send the character data
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_LOAD;
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
//query the world state
memset(&newPacket, 0, MAX_PACKET_SIZE);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
//set the camera's values
camera.width = GetScreen()->w;
camera.height = GetScreen()->h;
//debug
//
}
World::~World() {
//unload the local data
characterMap.clear();
monsterMap.clear();
}
//-------------------------
//Frame loop
//-------------------------
void World::FrameStart() {
//
}
void World::Update() {
//create and zero the buffer
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
memset(packetBuffer, 0, MAX_PACKET_SIZE);
try {
//suck in and process all waiting packets
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
}
catch(terminal_error& e) {
throw(e);
}
catch(std::exception& e) {
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
}
//free the buffer
delete reinterpret_cast<char*>(packetBuffer);
//heartbeat system
CheckHeartBeat();
//update all entities
for (auto& it : characterMap) {
it.second.Update();
}
for (auto& it : monsterMap) {
it.second.Update();
}
//update the map
UpdateMap();
//skip the rest without a local character
if (!localCharacter) {
return;
}
//get the collidable boxes
std::list<BoundingBox> boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH());
//process the collisions
if (localCharacter->ProcessCollisionGrid(boxList)) {
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
}
//update the camera
camera.x = localCharacter->GetOrigin().x - camera.marginX;
camera.y = localCharacter->GetOrigin().y - camera.marginY;
}
void World::FrameEnd() {
//
}
void World::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen());
SDL_Flip(GetScreen());
fps.Calculate();
}
void World::Render(SDL_Surface* const screen) {
//draw the map
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
}
//draw the entities
for (auto& it : characterMap) {
//TODO: (1) depth ordering
it.second.DrawTo(screen, camera.x, camera.y);
}
for (auto& it : monsterMap) {
it.second.DrawTo(screen, camera.x, camera.y);
}
//draw UI
disconnectButton.DrawTo(screen);
shutDownButton.DrawTo(screen);
std::ostringstream msg;
msg << fps.GetFrameRate();
font.DrawStringTo(msg.str(), screen, 0, 0);
}
//-------------------------
//Event handlers
//-------------------------
void World::QuitEvent() {
//two-step logout
SendDisconnectRequest();
SetNextScene(SceneList::QUIT);
}
void World::MouseMotion(SDL_MouseMotionEvent const& motion) {
disconnectButton.MouseMotion(motion);
shutDownButton.MouseMotion(motion);
}
void World::MouseButtonDown(SDL_MouseButtonEvent const& button) {
disconnectButton.MouseButtonDown(button);
shutDownButton.MouseButtonDown(button);
}
void World::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendLogoutRequest();
}
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendAdminShutdownRequest();
}
}
void World::KeyDown(SDL_KeyboardEvent const& key) {
//hotkeys
switch(key.keysym.sym) {
case SDLK_ESCAPE:
//TODO: (1) the escape key should actually control menus and stuff
SendLogoutRequest();
return;
}
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) {
case SDLK_w:
motion.y -= CHARACTER_WALKING_SPEED;
break;
case SDLK_a:
motion.x -= CHARACTER_WALKING_SPEED;
break;
case SDLK_s:
motion.y += CHARACTER_WALKING_SPEED;
break;
case SDLK_d:
motion.x += CHARACTER_WALKING_SPEED;
break;
default:
//DOCS: prevents wrong keys screwing with character movement
return;
}
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
}
void World::KeyUp(SDL_KeyboardEvent const& key) {
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) {
case SDLK_w:
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
break;
case SDLK_a:
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
break;
case SDLK_s:
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
break;
case SDLK_d:
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED);
break;
default:
//DOCS: prevents wrong keys screwing with character movement
return;
}
//BUGFIX: reset cardinal direction speed on key release
if (motion.x > 0) {
motion.x = CHARACTER_WALKING_SPEED;
}
else if (motion.x < 0) {
motion.x = -CHARACTER_WALKING_SPEED;
}
if (motion.y > 0) {
motion.y = CHARACTER_WALKING_SPEED;
}
else if (motion.y < 0) {
motion.y = -CHARACTER_WALKING_SPEED;
}
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMovement();
}
//-------------------------
//Direct incoming traffic
//-------------------------
void World::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
hPing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
hPong(static_cast<ServerPacket*>(argPacket));
break;
//game server connections
case SerialPacketType::LOGOUT_RESPONSE:
hLogoutResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_RESPONSE:
hDisconnectResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
hAdminDisconnectForced(static_cast<ClientPacket*>(argPacket));
break;
//map management
case SerialPacketType::REGION_CONTENT:
hRegionContent(static_cast<RegionPacket*>(argPacket));
break;
//character management
case SerialPacketType::CHARACTER_CREATE:
hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
hCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_EXISTS:
hQueryCharacterExists(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_STATS:
hQueryCharacterStats(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_LOCATION:
hQueryCharacterLocation(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_MOVEMENT:
hCharacterMovement(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_ATTACK:
hCharacterAttack(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DAMAGE:
hCharacterDamage(static_cast<CharacterPacket*>(argPacket));
break;
//monster management
case SerialPacketType::MONSTER_CREATE:
hMonsterCreate(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_DELETE:
hMonsterDelete(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_EXISTS:
hQueryMonsterExists(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_STATS:
hQueryMonsterStats(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_LOCATION:
hQueryMonsterLocation(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_MOVEMENT:
hMonsterMovement(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_ATTACK:
hMonsterAttack(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_DAMAGE:
hMonsterDamage(static_cast<MonsterPacket*>(argPacket));
break;
//chat
case SerialPacketType::TEXT_BROADCAST:
hTextBroadcast(static_cast<TextPacket*>(argPacket));
break;
case SerialPacketType::TEXT_SPEECH:
hTextSpeech(static_cast<TextPacket*>(argPacket));
break;
case SerialPacketType::TEXT_WHISPER:
hTextWhisper(static_cast<TextPacket*>(argPacket));
break;
//general rejection messages
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::QUERY_REJECTION:
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
break;
case SerialPacketType::SHUTDOWN_REJECTION:
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
break;
//errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in World: " << static_cast<int>(argPacket->type);
throw(std::runtime_error(msg.str()));
}
break;
}
}
-79
View File
@@ -1,79 +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"
//-------------------------
//map management
//-------------------------
void World::SendRegionRequest(int roomIndex, int x, int y) {
RegionPacket packet;
//pack the region's data
packet.type = SerialPacketType::REGION_REQUEST;
packet.roomIndex = roomIndex;
packet.x = x;
packet.y = y;
network.SendTo(Channels::SERVER, &packet);
}
void World::hRegionContent(RegionPacket* const argPacket) {
//replace existing regions
regionPager.UnloadIf([&](Region const& region) -> bool {
return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
});
regionPager.PushRegion(argPacket->region);
//clean up after the serial code
delete argPacket->region;
argPacket->region = nullptr;
}
void World::UpdateMap() {
if (roomIndex == -1) {
return;
}
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
});
//request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
SendRegionRequest(roomIndex, i, j);
}
}
}
}
-126
View File
@@ -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) empty
}
void World::hQueryMonsterLocation(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
void World::hMonsterMovement(MonsterPacket* const argPacket) {
//ignore if this monster doesn't exist
std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex);
if (monsterIt == monsterMap.end()) {
return;
}
monsterIt->second.SetOrigin(argPacket->origin);
monsterIt->second.SetOrigin(argPacket->motion);
}
void World::hMonsterAttack(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
void World::hMonsterDamage(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
+2 -3
View File
@@ -1,5 +1,5 @@
#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
#the order of the $(LIBS) is important, at least for MinGW
@@ -27,8 +27,7 @@ OUT=$(addprefix $(OUTDIR)/,client)
all: $(OBJ) $(OUT)
$(MAKE) -C client_utilities
$(MAKE) -C entities
$(MAKE) -C gameplay_scenes
$(MAKE) -C menu_scenes
$(MAKE) -C scenes
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(OBJ): | $(OBJDIR)
-37
View File
@@ -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
+1 -1
View File
@@ -33,7 +33,7 @@ enum class SceneList {
MAINMENU,
OPTIONSMENU,
LOBBYMENU,
WORLD,
INWORLD,
DISCONNECTEDSCREEN,
};
@@ -127,7 +127,7 @@ void BaseScene::HandleEvents() {
break;
#ifdef USE_EVENT_JOYSTICK
//EMPTY
//TODO: joystick/gamepad support
#endif
#ifdef USE_EVENT_UNKNOWN
@@ -59,7 +59,7 @@ protected:
virtual void KeyUp(SDL_KeyboardEvent const&) {}
#ifdef USE_EVENT_JOYSTICK
//EMPTY
//TODO: joystick/gamepad support
#endif
#ifdef USE_EVENT_UNKNOWN
+757
View File
@@ -0,0 +1,757 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "in_world.hpp"
#include "channels.hpp"
#include "utility.hpp"
#include "terminal_error.hpp"
#include <stdexcept>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <sstream>
//-------------------------
//these should've come standard
//-------------------------
bool operator==(IPaddress lhs, IPaddress rhs) {
return lhs.host == rhs.host && lhs.port == rhs.port;
}
bool operator!=(IPaddress lhs, IPaddress rhs) {
return !(lhs == rhs);
}
//-------------------------
//Public access members
//-------------------------
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
clientIndex(*argClientIndex),
accountIndex(*argAccountIndex)
{
//setup the utility objects
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
buttonImage.SetClipH(buttonImage.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects
disconnectButton.SetImage(&buttonImage);
disconnectButton.SetFont(&font);
shutDownButton.SetImage(&buttonImage);
shutDownButton.SetFont(&font);
//set the button positions
disconnectButton.SetX(50);
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
shutDownButton.SetX(50);
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
//set the button texts
disconnectButton.SetText("Disconnect");
shutDownButton.SetText("Shut Down");
//load the tilesheet
//TODO: add the tilesheet to the map system
//TODO: Tile size and tile sheet should be loaded elsewhere
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
//Send the character data
//TODO: login scene, prompt, etc.
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_LOAD;
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
//query the world state
memset(&newPacket, 0, MAX_PACKET_SIZE);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
//set the camera's values
camera.width = GetScreen()->w;
camera.height = GetScreen()->h;
//debug
//
}
InWorld::~InWorld() {
//unload the local data
characterMap.clear();
monsterMap.clear();
}
//-------------------------
//Frame loop
//-------------------------
void InWorld::FrameStart() {
//
}
void InWorld::Update() {
//create and zero the buffer
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
memset(packetBuffer, 0, MAX_PACKET_SIZE);
try {
//suck in and process all waiting packets
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
}
catch(terminal_error& e) {
throw(e);
}
catch(std::exception& e) {
std::cerr << "HandlePacket Error: " << e.what() << std::endl;
}
//free the buffer
delete reinterpret_cast<char*>(packetBuffer);
//heartbeat system
CheckHeartBeat();
//update all entities
for (auto& it : characterMap) {
it.second.Update();
}
for (auto& it : monsterMap) {
it.second.Update();
}
//update the map
UpdateMap();
//skip the rest without a local character
if (!localCharacter) {
return;
}
//get the collidable boxes
std::list<BoundingBox> boxList = GenerateCollisionGrid(localCharacter, tileSheet.GetTileW(), tileSheet.GetTileH());
//process the collisions
if (localCharacter->ProcessCollisionGrid(boxList)) {
localCharacter->CorrectSprite();
SendLocalCharacterMotion();
}
//update the camera
camera.x = localCharacter->GetOrigin().x - camera.marginX;
camera.y = localCharacter->GetOrigin().y - camera.marginY;
}
void InWorld::FrameEnd() {
//
}
void InWorld::RenderFrame() {
SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen());
SDL_Flip(GetScreen());
fps.Calculate();
}
void InWorld::Render(SDL_Surface* const screen) {
//draw the map
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
}
//draw the entities
for (auto& it : characterMap) {
//TODO: depth ordering
it.second.DrawTo(screen, camera.x, camera.y);
}
for (auto& it : monsterMap) {
//TODO: depth ordering
it.second.DrawTo(screen, camera.x, camera.y);
}
//draw UI
disconnectButton.DrawTo(screen);
shutDownButton.DrawTo(screen);
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
}
//-------------------------
//Event handlers
//-------------------------
void InWorld::QuitEvent() {
//two-step logout
SendDisconnectRequest();
SetNextScene(SceneList::QUIT);
}
void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) {
disconnectButton.MouseMotion(motion);
shutDownButton.MouseMotion(motion);
}
void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) {
disconnectButton.MouseButtonDown(button);
shutDownButton.MouseButtonDown(button);
}
void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendLogoutRequest();
}
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendShutdownRequest();
}
}
void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
//hotkeys
switch(key.keysym.sym) {
case SDLK_ESCAPE:
//TODO: the escape key should actually control menus and stuff
SendLogoutRequest();
return;
}
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) {
case SDLK_w:
motion.y -= CHARACTER_WALKING_SPEED;
break;
case SDLK_a:
motion.x -= CHARACTER_WALKING_SPEED;
break;
case SDLK_s:
motion.y += CHARACTER_WALKING_SPEED;
break;
case SDLK_d:
motion.x += CHARACTER_WALKING_SPEED;
break;
default:
//DOCS: prevents wrong keys screwing with character movement
return;
}
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMotion();
}
void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
//character movement
if (!localCharacter) {
return;
}
Vector2 motion = localCharacter->GetMotion();
switch(key.keysym.sym) {
case SDLK_w:
motion.y = std::min(0.0, motion.y += CHARACTER_WALKING_SPEED);
break;
case SDLK_a:
motion.x = std::min(0.0, motion.x += CHARACTER_WALKING_SPEED);
break;
case SDLK_s:
motion.y = std::max(0.0, motion.y -= CHARACTER_WALKING_SPEED);
break;
case SDLK_d:
motion.x = std::max(0.0, motion.x -= CHARACTER_WALKING_SPEED);
break;
default:
//DOCS: prevents wrong keys screwing with character movement
return;
}
//BUGFIX: reset cardinal direction speed on key release
if (motion.x > 0) {
motion.x = CHARACTER_WALKING_SPEED;
}
else if (motion.x < 0) {
motion.x = -CHARACTER_WALKING_SPEED;
}
if (motion.y > 0) {
motion.y = CHARACTER_WALKING_SPEED;
}
else if (motion.y < 0) {
motion.y = -CHARACTER_WALKING_SPEED;
}
//handle diagonals
if (motion.x != 0 && motion.y != 0) {
motion *= CHARACTER_WALKING_MOD;
}
//set the info
localCharacter->SetMotion(motion);
localCharacter->CorrectSprite();
SendLocalCharacterMotion();
}
//-------------------------
//Basic connections
//-------------------------
void InWorld::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
HandlePing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
HandlePong(static_cast<ServerPacket*>(argPacket));
break;
//game server connections
case SerialPacketType::LOGOUT_RESPONSE:
HandleLogoutResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_RESPONSE:
HandleDisconnectResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_FORCED:
HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
break;
//map management
case SerialPacketType::REGION_CONTENT:
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
break;
//character management
case SerialPacketType::CHARACTER_CREATE:
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_EXISTS:
HandleCharacterQueryExists(static_cast<CharacterPacket*>(argPacket));
break;
//character movement
case SerialPacketType::CHARACTER_SET_ROOM:
HandleCharacterSetRoom(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_SET_ORIGIN:
HandleCharacterSetOrigin(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_SET_MOTION:
HandleCharacterSetMotion(static_cast<CharacterPacket*>(argPacket));
break;
//rejection messages
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
break;
case SerialPacketType::SHUTDOWN_REJECTION:
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
break;
//errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in InWorld: " << static_cast<int>(argPacket->type);
throw(std::runtime_error(msg.str()));
}
break;
}
}
void InWorld::HandlePing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void InWorld::HandlePong(ServerPacket* const argPacket) {
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
throw(std::runtime_error("Heartbeat message received from an unknown source"));
}
attemptedBeats = 0;
lastBeat = Clock::now();
}
//-------------------------
//Connection control
//-------------------------
void InWorld::SendLogoutRequest() {
ClientPacket newPacket;
//send a logout request
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::SendDisconnectRequest() {
ClientPacket newPacket;
//send a disconnect request
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
newPacket.clientIndex = clientIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::SendShutdownRequest() {
ClientPacket newPacket;
//send a shutdown request
newPacket.type = SerialPacketType::SHUTDOWN_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::HandleLogoutResponse(ClientPacket* const argPacket) {
if (localCharacter) {
characterMap.erase(characterIndex);
localCharacter = nullptr;
}
accountIndex = -1;
characterIndex = -1;
//reset the camera
camera.marginX = camera.marginY = 0;
//because, why not? I guess...
SendDisconnectRequest();
}
void InWorld::HandleDisconnectResponse(ClientPacket* const argPacket) {
HandleLogoutResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
}
void InWorld::HandleDisconnectForced(ClientPacket* const argPacket) {
HandleDisconnectResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
}
void InWorld::CheckHeartBeat() {
//check the connection (heartbeat)
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
if (attemptedBeats > 2) {
//escape to the disconnect screen
SendDisconnectRequest();
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
}
else {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PING;
network.SendTo(Channels::SERVER, &newPacket);
attemptedBeats++;
lastBeat = Clock::now();
}
}
}
//-------------------------
//map management
//-------------------------
void InWorld::SendRegionRequest(int roomIndex, int x, int y) {
RegionPacket packet;
//pack the region's data
packet.type = SerialPacketType::REGION_REQUEST;
packet.roomIndex = roomIndex;
packet.x = x;
packet.y = y;
network.SendTo(Channels::SERVER, &packet);
}
void InWorld::HandleRegionContent(RegionPacket* const argPacket) {
//replace existing regions
regionPager.UnloadIf([&](Region const& region) -> bool {
return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
});
regionPager.PushRegion(argPacket->region);
//clean up after the serial code
delete argPacket->region;
argPacket->region = nullptr;
}
void InWorld::UpdateMap() {
if (roomIndex == -1) {
return;
}
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
});
//request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
SendRegionRequest(roomIndex, i, j);
}
}
}
}
//-------------------------
//entity management
//-------------------------
//DOCS: preexisting characters will result in query responses
//DOCS: new characters will result in create messages
//DOCS: this client's character will exist in both (skipped)
void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) {
//prevent double message
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
std::ostringstream msg;
msg << "Double character creation event; ";
msg << "Index: " << argPacket->characterIndex << "; ";
msg << "Handle: " << argPacket->handle;
throw(std::runtime_error(msg.str()));
}
//implicity create and retrieve the entity
BaseCharacter* character = &characterMap[argPacket->characterIndex];
//fill the character's info
character->SetOrigin(argPacket->origin);
character->SetMotion(argPacket->motion);
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT});
character->SetHandle(argPacket->handle);
character->SetAvatar(argPacket->avatar);
character->SetOwner(argPacket->accountIndex);
character->CorrectSprite();
//check for this player's character
if (character->GetOwner() == accountIndex) {
localCharacter = static_cast<LocalCharacter*>(character);
//focus the camera on this character
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
//focus on this character's info
characterIndex = argPacket->characterIndex;
roomIndex = argPacket->roomIndex;
}
//debug
std::cout << "Create, total: " << characterMap.size() << std::endl;
}
void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) {
//ignore if this character doesn't exist
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt == characterMap.end()) {
//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) {
//TODO: Authentication
if (argPacket->characterIndex == characterIndex) {
return;
}
//check that this character exists
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt != characterMap.end()) {
//set the origin and motion
characterIt->second.SetOrigin(argPacket->origin);
characterIt->second.SetMotion(argPacket->motion);
characterIt->second.CorrectSprite();
}
}
void InWorld::HandleCharacterSetMotion(CharacterPacket* const argPacket) {
//TODO: Authentication
if (argPacket->characterIndex == characterIndex) {
return;
}
//check that this character exists
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt != characterMap.end()) {
//set the origin and motion
characterIt->second.SetOrigin(argPacket->origin);
characterIt->second.SetMotion(argPacket->motion);
characterIt->second.CorrectSprite();
}
}
//-------------------------
//player movement
//-------------------------
//TODO: add a "movement" packet type
void InWorld::SendLocalCharacterMotion() {
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_SET_MOTION;
newPacket.accountIndex = accountIndex;
newPacket.characterIndex = characterIndex;
newPacket.roomIndex = roomIndex;
newPacket.origin = localCharacter->GetOrigin();
newPacket.motion = localCharacter->GetMotion();
network.SendTo(Channels::SERVER, &newPacket);
}
std::list<BoundingBox> InWorld::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
//prepare for collisions
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
std::list<BoundingBox> boxList;
//NOTE: for loops were too dense to work with, so I've just used while loops
//outer loop
wallBounds.x = snapToBase((double)wallBounds.w, ptr->GetOrigin().x);
while(wallBounds.x < (ptr->GetOrigin() + ptr->GetBounds()).x + ptr->GetBounds().w) {
//inner loop
wallBounds.y = snapToBase((double)wallBounds.h, ptr->GetOrigin().y);
while(wallBounds.y < (ptr->GetOrigin() + ptr->GetBounds()).y + ptr->GetBounds().h) {
//check to see if this tile is solid
if (regionPager.GetSolid(wallBounds.x / wallBounds.w, wallBounds.y / wallBounds.h)) {
//push onto the box set
boxList.push_front(wallBounds);
}
//increment
wallBounds.y += wallBounds.h;
}
//increment
wallBounds.x += wallBounds.w;
}
return std::move(boxList);
}
@@ -49,11 +49,11 @@
#include <chrono>
class World: public BaseScene {
class InWorld : public BaseScene {
public:
//Public access members
World(int* const argClientIndex, int* const argAccountIndex);
~World();
InWorld(int* const argClientIndex, int* const argAccountIndex);
~InWorld();
protected:
//Frame loop
@@ -71,57 +71,37 @@ protected:
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//handle incoming traffic
//Basic connections
void HandlePacket(SerialPacket* const);
void HandlePing(ServerPacket* const);
void HandlePong(ServerPacket* const);
//heartbeat system
void hPing(ServerPacket* const);
void hPong(ServerPacket* const);
//Connection control
void SendLogoutRequest();
void SendDisconnectRequest();
void SendShutdownRequest();
void HandleLogoutResponse(ClientPacket* const);
void HandleDisconnectResponse(ClientPacket* const);
void HandleDisconnectForced(ClientPacket* const);
void CheckHeartBeat();
//basic connections
void SendLogoutRequest();
void SendDisconnectRequest();
void SendAdminDisconnectForced();
void SendAdminShutdownRequest();
void hLogoutResponse(ClientPacket* const);
void hDisconnectResponse(ClientPacket* const);
void hAdminDisconnectForced(ClientPacket* const);
//map management
void SendRegionRequest(int roomIndex, int x, int y);
void hRegionContent(RegionPacket* const);
void HandleRegionContent(RegionPacket* const);
void UpdateMap();
//character management
void hCharacterCreate(CharacterPacket* const);
void hCharacterDelete(CharacterPacket* const);
void hQueryCharacterExists(CharacterPacket* const);
void hQueryCharacterStats(CharacterPacket* const);
void hQueryCharacterLocation(CharacterPacket* const);
void hCharacterMovement(CharacterPacket* const);
void hCharacterAttack(CharacterPacket* const);
void hCharacterDamage(CharacterPacket* const);
void HandleCharacterCreate(CharacterPacket* const);
void HandleCharacterDelete(CharacterPacket* const);
void HandleCharacterQueryExists(CharacterPacket* const);
void HandleCharacterSetRoom(CharacterPacket* const);
void HandleCharacterSetOrigin(CharacterPacket* const);
void HandleCharacterSetMotion(CharacterPacket* const);
//monster management
void hMonsterCreate(MonsterPacket* const);
void hMonsterDelete(MonsterPacket* const);
void hQueryMonsterExists(MonsterPacket* const);
void hQueryMonsterStats(MonsterPacket* const);
void hQueryMonsterLocation(MonsterPacket* const);
void hMonsterMovement(MonsterPacket* const);
void hMonsterAttack(MonsterPacket* const);
void hMonsterDamage(MonsterPacket* const);
//chat
void hTextBroadcast(TextPacket* const);
void hTextSpeech(TextPacket* const);
void hTextWhisper(TextPacket* const);
//general gameplay
void SendLocalCharacterMovement();
//player movement
void SendLocalCharacterMotion();
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
//indexes
@@ -156,7 +136,7 @@ protected:
LocalCharacter* localCharacter = nullptr;
//heartbeat
//TODO: (2) Heartbeat needs it's own utility
//TODO: Heartbeat needs it's own utility
typedef std::chrono::steady_clock Clock;
Clock::time_point lastBeat = Clock::now();
int attemptedBeats = 0;
@@ -22,9 +22,9 @@
#include "lobby_menu.hpp"
#include "channels.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <sstream>
//-------------------------
//Public access members
@@ -100,14 +100,14 @@ void LobbyMenu::FrameEnd() {
}
void LobbyMenu::Render(SDL_Surface* const screen) {
//TODO: (2) I need a proper UI system for the entire client and the editor
//TODO: I need a proper UI system for the entire client and the editor
//UI
search.DrawTo(screen);
join.DrawTo(screen);
back.DrawTo(screen);
//TODO: (1) draw headers for the server list
//TODO: draw headers for the server list
for (int i = 0; i < serverInfo.size(); i++) {
//draw the selected server's highlight
if (selection == &serverInfo[i]) {
@@ -123,14 +123,14 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
//draw the player count
std::ostringstream msg;
msg << serverInfo[i].playerCount;
font.DrawStringTo(msg.str(), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
//compatible?
if (!serverInfo[i].compatible) {
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
}
//TODO: ping/delay?
}
}
@@ -210,11 +210,8 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) {
break;
//handle errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in LobbyMenu: " << static_cast<int>(argPacket->type);
throw(std::runtime_error( msg.str() ));
}
default:
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast<int>(argPacket->type)) ));
break;
}
}
@@ -248,15 +245,15 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
throw(std::runtime_error("Client index invalid during login"));
}
accountIndex = argPacket->accountIndex;
SetNextScene(SceneList::WORLD);
SetNextScene(SceneList::INWORLD);
}
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
//TODO: (9) empty
//TODO: Better output for join rejection
}
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
//TODO: (9) empty
//TODO: Better output for login rejection
}
//-------------------------
@@ -84,11 +84,6 @@ void MainMenu::Render(SDL_Surface* const screen) {
startButton.DrawTo(screen);
optionsButton.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) {
//TODO: (2) Buttons should only register as "selected" when the left button is used
//TODO: Buttons should only register as "selected" when the left button is used
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
SetNextScene(SceneList::LOBBYMENU);
}
@@ -125,9 +120,5 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
}
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE:
QuitEvent();
break;
}
//
}
@@ -28,7 +28,7 @@
#include "raster_font.hpp"
#include "button.hpp"
//NOTE: The options screen needs to be USED
//TODO: The options screen needs to be USED
class OptionsMenu : public BaseScene {
public:
//Public access members
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. ../map
INCLUDES+=.
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. ../utilities
INCLUDES+=. ../graphics ../utilities
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
+2
View File
@@ -24,6 +24,7 @@
//all map API headers
#include "region_api.hpp"
#include "region_pager_api.hpp"
#include "tile_sheet_api.hpp"
//useful "globals"
//...
@@ -36,6 +37,7 @@ static const luaL_Reg funcs[] = {
static const luaL_Reg libs[] = {
{"Region", openRegionAPI},
{"RegionPager", openRegionPagerAPI},
// {"TileSheet", openTileSheetAPI},
{nullptr, nullptr}
};
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef MAPSYSTEMAPI_HPP_
#define MAPSYSTEMAPI_APP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_MAP_SYSTEM_API "map_system"
LUAMOD_API int openMapSystemAPI(lua_State* L);
-12
View File
@@ -42,30 +42,18 @@ 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) {
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;
}
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];
}
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;
}
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];
}
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef REGIONAPI_HPP_
#define REGIONAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_REGION_NAME "region"
LUAMOD_API int openRegionAPI(lua_State* L);
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef REGIONPAGERAPI_HPP_
#define REGIONPAGERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_REGION_PAGER_NAME "region_pager"
LUAMOD_API int openRegionPagerAPI(lua_State* L);
+5 -1
View File
@@ -24,7 +24,11 @@
#include "region_pager_base.hpp"
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#include <functional>
#include <string>
+75
View File
@@ -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
* distribution.
*/
#ifndef MONSTERSYSTEMAPI_HPP_
#define MONSTERSYSTEMAPI_HPP_
#ifndef TILESHEETAPI_HPP_
#define TILESHEETAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_MONSTER_SYSTEM_API "monster_system"
LUAMOD_API int openMonsterSystemAPI(lua_State* L);
#define TORTUGA_TILE_SHEET_NAME "tile_sheet"
LUAMOD_API int openTileSheetAPI(lua_State* L);
#endif
#endif
@@ -34,11 +34,14 @@ struct CharacterPacket : SerialPacketBase {
//the owner
int accountIndex;
//TODO: Authentication token?
//location
int roomIndex;
Vector2 origin;
Vector2 motion;
//gameplay components: equipment, items, buffs, debuffs...
};
void serializeCharacter(void* buffer, CharacterPacket* packet);
@@ -28,7 +28,6 @@ struct ClientPacket : SerialPacketBase {
int clientIndex;
int accountIndex;
char username[PACKET_STRING_SIZE];
//TODO: (9) password, auth token
};
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
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
//location
serialCopy(&buffer, &packet->roomIndex, sizeof(int));
serialCopy(&buffer, &packet->origin.x, sizeof(double));
serialCopy(&buffer, &packet->origin.y, sizeof(double));
serialCopy(&buffer, &packet->range, sizeof(int));
}
void deserializeText(void* buffer, TextPacket* packet) {
@@ -43,10 +37,4 @@ void deserializeText(void* buffer, TextPacket* packet) {
//content
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
//location
deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
deserialCopy(&buffer, &packet->origin.x, sizeof(double));
deserialCopy(&buffer, &packet->origin.y, sizeof(double));
deserialCopy(&buffer, &packet->range, sizeof(int));
}
@@ -24,14 +24,9 @@
#include "serial_packet_base.hpp"
#include "vector2.hpp"
struct TextPacket : SerialPacketBase {
char name[PACKET_STRING_SIZE];
char text[PACKET_STRING_SIZE];
int roomIndex;
Vector2 origin;
int range;
};
void serializeText(void* buffer, TextPacket* packet);
+4 -6
View File
@@ -25,7 +25,6 @@
#include "serial_packet_base.hpp"
#include "character_packet.hpp"
#include "client_packet.hpp"
#include "monster_packet.hpp"
#include "region_packet.hpp"
#include "server_packet.hpp"
#include "text_packet.hpp"
@@ -34,15 +33,14 @@
typedef SerialPacketBase SerialPacket;
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
constexpr int NETWORK_VERSION = 20150214;
constexpr int NETWORK_VERSION = 20141227;
union MaxPacket {
CharacterPacket a;
ClientPacket b;
MonsterPacket c;
RegionPacket d;
ServerPacket e;
TextPacket f;
RegionPacket c;
ServerPacket d;
TextPacket e;
};
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
+38 -60
View File
@@ -27,9 +27,10 @@
* valid data, but it will still be carried in that packet's format.
*/
//TODO: This needs to be smoothed out
enum class SerialPacketType {
//default: there is something wrong
NONE,
NONE = 0,
//-------------------------
//ServerPacket
@@ -37,12 +38,12 @@ enum class SerialPacketType {
//-------------------------
//heartbeat
PING,
PONG,
PING = 1,
PONG = 2,
//Used for finding available servers
BROADCAST_REQUEST,
BROADCAST_RESPONSE,
BROADCAST_REQUEST = 3,
BROADCAST_RESPONSE = 4,
//-------------------------
//ClientPacket
@@ -50,24 +51,24 @@ enum class SerialPacketType {
//-------------------------
//Connecting to a server as a client
JOIN_REQUEST,
JOIN_RESPONSE,
JOIN_REQUEST = 5,
JOIN_RESPONSE = 6,
//disconnect from the server
DISCONNECT_REQUEST,
DISCONNECT_RESPONSE,
ADMIN_DISCONNECT_FORCED,
DISCONNECT_REQUEST = 7,
DISCONNECT_RESPONSE = 8,
DISCONNECT_FORCED = 9,
//load the account
LOGIN_REQUEST,
LOGIN_RESPONSE,
LOGIN_REQUEST = 10,
LOGIN_RESPONSE = 11,
//unload the account
LOGOUT_REQUEST,
LOGOUT_RESPONSE,
LOGOUT_REQUEST = 12,
LOGOUT_RESPONSE = 13,
//shut down the server
ADMIN_SHUTDOWN_REQUEST,
SHUTDOWN_REQUEST = 14,
//-------------------------
//RegionPacket
@@ -75,54 +76,35 @@ enum class SerialPacketType {
//-------------------------
//map data
REGION_REQUEST,
REGION_CONTENT,
REGION_REQUEST = 15, //NOTE: technically a query
REGION_CONTENT = 16,
//-------------------------
//CharacterPacket
// character index,
// handle, avatar,
// account index (owner),
// room index, origin, motion
// room index, origin, motion,
// statistics
//-------------------------
//character management
CHARACTER_CREATE,
CHARACTER_DELETE,
CHARACTER_LOAD,
CHARACTER_UNLOAD,
CHARACTER_CREATE = 17,
CHARACTER_DELETE = 18,
CHARACTER_LOAD = 19,
CHARACTER_UNLOAD = 20,
//find out info from the server
QUERY_CHARACTER_EXISTS,
QUERY_CHARACTER_STATS,
QUERY_CHARACTER_LOCATION,
QUERY_CHARACTER_EXISTS = 21,
QUERY_CHARACTER_STATS = 22,
QUERY_CHARACTER_LOCATION = 23,
//set the info in the server
CHARACTER_MOVEMENT,
CHARACTER_ATTACK,
CHARACTER_DAMAGE,
CHARACTER_SET_ROOM = 24,
CHARACTER_SET_ORIGIN = 25,
CHARACTER_SET_MOTION = 26,
//admin control
// ADMIN_SET_CHARACTER_ORIGIN,
//-------------------------
//MonsterPacket
// monster index,
// handle, avatar
// bounds
// room index, origin, motion
//-------------------------
MONSTER_CREATE,
MONSTER_DELETE,
QUERY_MONSTER_EXISTS,
QUERY_MONSTER_STATS,
QUERY_MONSTER_LOCATION,
MONSTER_MOVEMENT,
MONSTER_ATTACK,
MONSTER_DAMAGE,
//TODO: enemy management
//-------------------------
//TextPacket
@@ -130,24 +112,20 @@ enum class SerialPacketType {
//-------------------------
//general speech
TEXT_BROADCAST,
TEXT_SPEECH,
TEXT_WHISPER,
TEXT_BROADCAST = 27,
//rejection/error messages
JOIN_REJECTION,
LOGIN_REJECTION,
REGION_REJECTION,
CHARACTER_REJECTION,
MONSTER_REJECTION,
SHUTDOWN_REJECTION,
QUERY_REJECTION,
JOIN_REJECTION = 28,
LOGIN_REJECTION = 29,
REGION_REJECTION = 30,
CHARACTER_REJECTION = 31,
SHUTDOWN_REJECTION = 32,
//-------------------------
//not used
//-------------------------
LAST
LAST = 33
};
#endif
+10 -39
View File
@@ -24,7 +24,6 @@
//packet types
#include "character_packet.hpp"
#include "client_packet.hpp"
#include "monster_packet.hpp"
#include "region_packet.hpp"
#include "server_packet.hpp"
#include "text_packet.hpp"
@@ -57,12 +56,12 @@ void serializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::JOIN_RESPONSE:
case SerialPacketType::DISCONNECT_REQUEST:
case SerialPacketType::DISCONNECT_RESPONSE:
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
case SerialPacketType::DISCONNECT_FORCED:
case SerialPacketType::LOGIN_REQUEST:
case SerialPacketType::LOGIN_RESPONSE:
case SerialPacketType::LOGOUT_REQUEST:
case SerialPacketType::LOGOUT_RESPONSE:
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST:
case SerialPacketType::SHUTDOWN_REQUEST:
serializeClient(buffer, static_cast<ClientPacket*>(packet));
break;
case SerialPacketType::REGION_REQUEST:
@@ -76,31 +75,17 @@ void serializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::QUERY_CHARACTER_EXISTS:
case SerialPacketType::QUERY_CHARACTER_STATS:
case SerialPacketType::QUERY_CHARACTER_LOCATION:
case SerialPacketType::CHARACTER_MOVEMENT:
case SerialPacketType::CHARACTER_ATTACK:
case SerialPacketType::CHARACTER_DAMAGE:
case SerialPacketType::CHARACTER_SET_ROOM:
case SerialPacketType::CHARACTER_SET_ORIGIN:
case SerialPacketType::CHARACTER_SET_MOTION:
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
break;
case SerialPacketType::MONSTER_CREATE:
case SerialPacketType::MONSTER_DELETE:
case SerialPacketType::QUERY_MONSTER_EXISTS:
case SerialPacketType::QUERY_MONSTER_STATS:
case SerialPacketType::QUERY_MONSTER_LOCATION:
case SerialPacketType::MONSTER_MOVEMENT:
case SerialPacketType::MONSTER_ATTACK:
case SerialPacketType::MONSTER_DAMAGE:
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break;
case SerialPacketType::TEXT_BROADCAST:
case SerialPacketType::TEXT_SPEECH:
case SerialPacketType::TEXT_WHISPER:
case SerialPacketType::JOIN_REJECTION:
case SerialPacketType::LOGIN_REJECTION:
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
serializeText(buffer, static_cast<TextPacket*>(packet));
break;
}
@@ -122,12 +107,12 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::JOIN_RESPONSE:
case SerialPacketType::DISCONNECT_REQUEST:
case SerialPacketType::DISCONNECT_RESPONSE:
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
case SerialPacketType::DISCONNECT_FORCED:
case SerialPacketType::LOGIN_REQUEST:
case SerialPacketType::LOGIN_RESPONSE:
case SerialPacketType::LOGOUT_REQUEST:
case SerialPacketType::LOGOUT_RESPONSE:
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST:
case SerialPacketType::SHUTDOWN_REQUEST:
deserializeClient(buffer, static_cast<ClientPacket*>(packet));
break;
case SerialPacketType::REGION_REQUEST:
@@ -141,31 +126,17 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::QUERY_CHARACTER_EXISTS:
case SerialPacketType::QUERY_CHARACTER_STATS:
case SerialPacketType::QUERY_CHARACTER_LOCATION:
case SerialPacketType::CHARACTER_MOVEMENT:
case SerialPacketType::CHARACTER_ATTACK:
case SerialPacketType::CHARACTER_DAMAGE:
case SerialPacketType::CHARACTER_SET_ROOM:
case SerialPacketType::CHARACTER_SET_ORIGIN:
case SerialPacketType::CHARACTER_SET_MOTION:
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
break;
case SerialPacketType::MONSTER_CREATE:
case SerialPacketType::MONSTER_DELETE:
case SerialPacketType::QUERY_MONSTER_EXISTS:
case SerialPacketType::QUERY_MONSTER_STATS:
case SerialPacketType::QUERY_MONSTER_LOCATION:
case SerialPacketType::MONSTER_MOVEMENT:
case SerialPacketType::MONSTER_ATTACK:
case SerialPacketType::MONSTER_DAMAGE:
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break;
case SerialPacketType::TEXT_BROADCAST:
case SerialPacketType::TEXT_SPEECH:
case SerialPacketType::TEXT_WHISPER:
case SerialPacketType::JOIN_REJECTION:
case SerialPacketType::LOGIN_REJECTION:
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
deserializeText(buffer, static_cast<TextPacket*>(packet));
break;
}
+1
View File
@@ -140,6 +140,7 @@ int UDPNetworkUtility::SendToAllChannels(void* data, int len) {
return sent;
}
//TODO: put a void* and int* parameter list here
int UDPNetworkUtility::Receive() {
memset(packet->data, 0, packet->maxlen);
int ret = SDLNet_UDP_Recv(socket, packet);
-30
View File
@@ -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.
*/
#include "ip_operators.hpp"
bool operator==(IPaddress lhs, IPaddress rhs) {
return lhs.host == rhs.host && lhs.port == rhs.port;
}
bool operator!=(IPaddress lhs, IPaddress rhs) {
return !(lhs == rhs);
}
@@ -19,21 +19,30 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "world.hpp"
#include "utility.hpp"
//-------------------------
//chat
//-------------------------
#include <algorithm>
void World::hTextBroadcast(TextPacket* const argPacket) {
//TODO: (9) empty
std::string truncatePath(std::string pathname) {
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) {
//TODO: (9) empty
}
void World::hTextWhisper(TextPacket* const argPacket) {
//TODO: (9) empty
std::string to_string_custom(int i) {
char buffer[20];
snprintf(buffer, 20, "%d", i);
return std::string(buffer);
}
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
* distribution.
*/
#ifndef IPOPERATORS_HPP_
#define IPOPERATORS_HPP_
#ifndef UTILITY_HPP_
#define UTILITY_HPP_
#include "SDL/SDL_net.h"
#include <string>
//these should've come standard
bool operator==(IPaddress lhs, IPaddress rhs);
bool operator!=(IPaddress lhs, IPaddress rhs);
std::string truncatePath(std::string pathname);
#endif
//fixing known bugs in g++
std::string to_string_custom(int i);
int to_integer_custom(std::string);
#endif
+3 -4
View File
@@ -1,8 +1,7 @@
#Windows 7:
#RM=del /y
#for use on Windows:
#Windows 8.1:
#RM=del /S
#MKDIR=mkdir
#RM=del /y
OUTDIR=out
+2 -2
View File
@@ -12,8 +12,8 @@ server.dbname = database.db
#client.screen.h = 600
client.screen.f = false
client.username = username
client.handle = handle
client.username = Kayne Ruse
client.handle = Ratstail91
client.avatar = elliot2.bmp
#directories
+24 -72
View File
@@ -1,95 +1,47 @@
local Region = require("map_system").Region
local mapSystem = require "map_system"
local mapMaker = {}
--utility functions
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.sqr(x) return x*x end
function mapMaker.dist(x, y, i, j) return math.sqrt(mapMaker.sqr(x - i) + mapMaker.sqr(y - j)) end
--tile macros, mapped to the tilesheet "overworld.bmp"
mapMaker.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.north = -16
mapMaker.edges.south = 16
mapMaker.edges.east = 1
mapMaker.edges.west = -1
--use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges
function mapMaker.SmoothEdgesSimple(r)
--make and pad an array to use
local shiftArray = {}
for i = 1, Region.GetWidth(r) do
shiftArray[i] = {}
for j = 1, Region.GetHeight(r) do
shiftArray[i][j] = 0
end
end
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
--build the array
for i = 1, Region.GetWidth(r) do
for j = 1, Region.GetHeight(r) do
--if (not region edge) and (west tile < this tile), etc.
if i > 1 and Region.GetTile(r, i - 1, j, 1) < Region.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.west
end
if j > 1 and Region.GetTile(r, i, j - 1, 1) < Region.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.north
end
if i < Region.GetWidth(r) and Region.GetTile(r, i + 1, j, 1) < Region.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.east
end
if j < Region.GetHeight(r) and Region.GetTile(r, i, j + 1, 1) < Region.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.south
end
end
end
--finally apply this
for i = 1, Region.GetWidth(r) do
for j = 1, Region.GetHeight(r) do
if shiftArray[i][j] ~= 0 then
Region.SetTile(r, i, j, 2, Region.GetTile(r, i, j, 1) + shiftArray[i][j])
Region.SetTile(r, i, j, 1, Region.GetTile(r, i, j, 1) - 3)
--custom generation systems here
function mapMaker.debugIsland(region)
for i = 1, mapSystem.Region.GetWidth(region) do
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)
if dist < 10 then
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.plains)
elseif dist < 12 then
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.sand)
else
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.water)
mapSystem.Region.SetSolid(region, i, j, true)
end
end
end
end
--custom generation systems here
function mapMaker.DebugIsland(r)
--basic distance check for each tile, placing an island around the world origin
for i = 1, Region.GetWidth(r) do
for j = 1, Region.GetHeight(r) do
local dist = mapMaker.Dist(0, 0, i + Region.GetX(r) -1, j + Region.GetY(r) -1)
if dist < 10 then
Region.SetTile(r, i, j, 1, mapMaker.plains)
elseif dist < 12 then
Region.SetTile(r, i, j, 1, mapMaker.sand)
else
Region.SetTile(r, i, j, 1, mapMaker.water)
Region.SetSolid(r, i, j, true)
end
function mapMaker.dirtLand(region)
for i = 1, mapSystem.Region.GetWidth(region) do
for j = 1, mapSystem.Region.GetHeight(region) do
mapSystem.Region.SetTile(region, i, j, 1, mapMaker.dirt)
end
end
--examples of the smoothing function NOT working correctly
--[[
for j = 1, Region.GetHeight(r) do
Region.SetTile(r, 3, j, 1, mapMaker.dirt)
Region.SetTile(r, 4, j, 1, mapMaker.dirt)
Region.SetTile(r, 10, j, 1, mapMaker.dirt)
end
--]]
--A generic edge system
mapMaker.SmoothEdgesSimple(r)
end
return mapMaker
+5 -9
View File
@@ -1,15 +1,11 @@
local Region = require("map_system").Region
local mapSaver = {}
function mapSaver.Load(r)
function mapSaver.Load(region)
--empty
io.write("map_saver:Load(", Region.GetX(r), ", ", Region.GetY(r), ")\n")
print("map_saver.lua:mapSaver.Load(region)")
end
function mapSaver.Save(r)
function mapSaver.Save(region)
--empty
io.write("map_saver:Save(", Region.GetX(r), ", ", Region.GetY(r), ")\n")
print("map_saver.lua:mapSaver.Save(region)")
end
--TODO: (9) create a flexible saving & loading system
--TODO: create a flexible saving & loading system
return mapSaver
+57 -4
View File
@@ -1,8 +1,10 @@
print("Lua script check")
mapMaker = require("map_maker")
mapSaver = require("map_saver")
roomSystem = require("room_system")
mapSystem = require "map_system"
mapMaker = require "map_maker"
mapSaver = require "map_saver"
roomSystem = require "room_system"
waypointSystem = require "waypoint_system"
local function dumpTable(t)
print(t)
@@ -13,6 +15,57 @@ end
--NOTE: room 0 is the first that the client asks for, therefore it must exist
local overworld, uid = roomSystem.RoomManager.CreateRoom("overworld", "overworld.bmp")
roomSystem.Room.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
--NOTE: This is horrible; room initialization is important
mapSystem.RegionPager.SetOnLoad(roomSystem.Room.GetPager(overworld), mapSaver.Load)
mapSystem.RegionPager.SetOnSave(roomSystem.Room.GetPager(overworld), mapSaver.Save)
mapSystem.RegionPager.SetOnCreate(roomSystem.Room.GetPager(overworld), mapMaker.debugIsland)
mapSystem.RegionPager.SetOnUnload(roomSystem.Room.GetPager(overworld), mapSaver.Save)
--Dirt Land
local dirtLand = roomSystem.RoomManager.CreateRoom("dirt land", "overworld.bmp")
roomSystem.Room.Initialize(dirtLand, mapSaver.Load, mapSaver.Save, mapMaker.dirtLand, mapSaver.Save)
print("Finished the lua script")
--[[
debugging test
Ideal output:
-------------------------
pager: userdata: [memory location]
Size 0: 0
[debug output from load]
Size 1: 1
[debug output from save]
Size 2: 0
[debug output from load]
Size 3: 1
[debug output from save]
Size 4: 0
-------------------------
--]-]
print("-------------------------")
local pager = roomSystem.Room.GetPager(overworld)
print("pager:", pager)
print("Size 0:", mapSystem.RegionPager.ContainerSize(pager))
local regionFoo = mapSystem.RegionPager.GetRegion(pager, 0, 0)
print("Size 1:", mapSystem.RegionPager.ContainerSize(pager))
mapSystem.RegionPager.UnloadRegion(pager, regionFoo)
print("Size 2:", mapSystem.RegionPager.ContainerSize(pager))
local regionFoo = mapSystem.RegionPager.GetRegion(pager, 0, 0)
print("Size 3:", mapSystem.RegionPager.ContainerSize(pager))
mapSystem.RegionPager.UnloadRegion(pager, 0, 0)
print("Size 4:", mapSystem.RegionPager.ContainerSize(pager))
print("-------------------------")
--]]
+4 -4
View File
@@ -1,10 +1,10 @@
--TODO: (9) An archive table of all dead characters
--TODO: An archive table of all dead characters
CREATE TABLE IF NOT EXISTS Accounts (
uid INTEGER PRIMARY KEY AUTOINCREMENT,
username varchar(100) UNIQUE, --TODO: (9) Swap username for email address
username varchar(100) UNIQUE,
--server-client security
--TODO: server-client security
-- passhash varchar(100),
-- passsalt varchar(100),
@@ -101,5 +101,5 @@ CREATE TABLE IF NOT EXISTS WornEquipment (
--unique information
durability INTEGER DEFAULT 0,
stats INTEGER REFERENCES StatisticSets(uid)
--attached script?
--TODO: attached script?
);
+1 -1
View File
@@ -47,7 +47,7 @@ private:
int clientIndex;
std::string username;
//password/auth token
//TODO: password
//bit fields?
bool blackListed = false;
+5 -1
View File
@@ -25,7 +25,11 @@
#include "account_data.hpp"
#include "singleton.hpp"
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "sqlite3/sqlite3.h"
#else
#include "sqlite3.h"
#endif
#include <functional>
#include <map>
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef CHARACTERAPI_HPP_
#define CHARACTERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_CHARACTER_API "character"
LUAMOD_API int openCharacterAPI(lua_State* L);
+24
View File
@@ -30,9 +30,33 @@
#include <string>
#include <cmath>
#include <iostream>
class CharacterData: public Entity {
public:
CharacterData() = default;
CharacterData(CharacterData const& rhs) {
std::cerr << "Character copy detected" << std::endl;
owner = rhs.owner;
handle = rhs.handle;
avatar = rhs.avatar;
//entity stuff
roomIndex = rhs.roomIndex;
origin = rhs.origin;
motion = rhs.motion;
}
CharacterData(CharacterData&& rhs) {
std::cerr << "Character move detected" << std::endl;
owner = rhs.owner;
handle = rhs.handle;
avatar = rhs.avatar;
//entity stuff
roomIndex = rhs.roomIndex;
origin = rhs.origin;
motion = rhs.motion;
}
~CharacterData() = default;
//accessors and mutators
+6 -2
View File
@@ -21,7 +21,11 @@
*/
#include "character_manager.hpp"
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "sqlite3/sqlite3.h"
#else
#include "sqlite3.h"
#endif
#include <algorithm>
#include <stdexcept>
@@ -249,7 +253,7 @@ CharacterData* CharacterManager::Get(int uid) {
return nullptr;
}
return &it->second;
return &(it->second);
}
int CharacterManager::GetLoadedCount() {
+5 -1
View File
@@ -25,7 +25,11 @@
#include "character_data.hpp"
#include "singleton.hpp"
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "sqlite3/sqlite3.h"
#else
#include "sqlite3.h"
#endif
#include <functional>
#include <map>
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef CHARACTERMANAGERAPI_HPP_
#define CHARACTERMANAGERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_CHARACTER_MANAGER_API "character_manager"
LUAMOD_API int openCharacterManagerAPI(lua_State* L);
+3 -3
View File
@@ -33,14 +33,14 @@ Vector2 Entity::SetMotion(Vector2 v) {
return motion = v;
}
int Entity::GetRoomIndex() const {
int Entity::GetRoomIndex() {
return roomIndex;
}
Vector2 Entity::GetOrigin() const {
Vector2 Entity::GetOrigin() {
return origin;
}
Vector2 Entity::GetMotion() const {
Vector2 Entity::GetMotion() {
return motion;
}
+3 -3
View File
@@ -32,9 +32,9 @@ public:
Vector2 SetOrigin(Vector2 v);
Vector2 SetMotion(Vector2 v);
int GetRoomIndex() const;
Vector2 GetOrigin() const;
Vector2 GetMotion() const;
int GetRoomIndex();
Vector2 GetOrigin();
Vector2 GetMotion();
protected:
Entity() = default;
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef ENTITYAPI_HPP_
#define ENTITYAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_ENTITY_API "entity"
LUAMOD_API int openEntityAPI(lua_State* L);
+5 -5
View File
@@ -34,11 +34,13 @@
#define linit_c
#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 "monster_system_api.hpp"
#include "room_system_api.hpp"
#include "waypoint_system_api.hpp"
@@ -61,9 +63,7 @@ static const luaL_Reg loadedlibs[] = {
//these libs are preloaded and must be required before used
static const luaL_Reg preloadedlibs[] = {
{TORTUGA_ENTITY_API, openEntityAPI},
{TORTUGA_MAP_SYSTEM_API, openMapSystemAPI},
{TORTUGA_MONSTER_SYSTEM_API, openMonsterSystemAPI},
{TORTUGA_ROOM_SYSTEM_API, openRoomSystemAPI},
{TORTUGA_WAYPOINT_SYSTEM_API, openWaypointSystemAPI},
{NULL, NULL}
+5
View File
@@ -26,6 +26,7 @@
#include "character_manager.hpp"
#include "client_manager.hpp"
#include "config_utility.hpp"
#include "monster_manager.hpp"
#include "room_manager.hpp"
#include "udp_network_utility.hpp"
#include "waypoint_manager.hpp"
@@ -42,8 +43,10 @@ int main(int argc, char* argv[]) {
CharacterManager::CreateSingleton();
ClientManager::CreateSingleton();
ConfigUtility::CreateSingleton();
MonsterManager::CreateSingleton();
RoomManager::CreateSingleton();
UDPNetworkUtility::CreateSingleton();
WaypointManager::CreateSingleton();
//call the server's routines
ServerApplication::CreateSingleton();
@@ -60,8 +63,10 @@ int main(int argc, char* argv[]) {
CharacterManager::DeleteSingleton();
ClientManager::DeleteSingleton();
ConfigUtility::DeleteSingleton();
MonsterManager::DeleteSingleton();
RoomManager::DeleteSingleton();
UDPNetworkUtility::DeleteSingleton();
WaypointManager::DeleteSingleton();
}
catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl;
-55
View File
@@ -23,66 +23,11 @@
#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) {
//the local table
luaL_newlib(L, monsterLib);
//get the parent table
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
//clone the parent table into the local table
lua_pushnil(L); //first key
while(lua_next(L, -2)) {
//copy the key-value pair
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
//push the copy to the local table
lua_settable(L, -6);
//pop the original value before continuing
lua_pop(L, 1);
}
//remove the parent table, leaving the expanded child table
lua_pop(L, 1);
return 1;
}
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef MONSTERAPI_HPP_
#define MONSTERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_MONSTER_API "monster"
LUAMOD_API int openMonsterAPI(lua_State* L);
+4 -4
View File
@@ -25,14 +25,14 @@ std::string MonsterData::SetAvatar(std::string s) {
return avatar = s;
}
std::string MonsterData::GetAvatar() {
return avatar;
}
int MonsterData::SetScriptReference(int i) {
return scriptRef = i;
}
std::string MonsterData::GetAvatar() {
return avatar;
}
int MonsterData::GetScriptReference() {
return scriptRef;
}
+2 -2
View File
@@ -32,9 +32,9 @@ public:
~MonsterData() = default;
std::string SetAvatar(std::string);
std::string GetAvatar();
int SetScriptReference(int);
std::string GetAvatar();
int GetScriptReference();
private:
+33 -25
View File
@@ -21,54 +21,62 @@
*/
#include "monster_manager.hpp"
MonsterManager::MonsterManager() {
//EMPTY
}
MonsterManager::~MonsterManager() {
UnloadAll();
}
int MonsterManager::Create(std::string) {
//Create
//TODO
}
int MonsterManager::Load(std::string) {
//TODO
}
int MonsterManager::Save(int uid) {
//TODO
}
void MonsterManager::Unload(int uid) {
//Unload
//TODO
}
void MonsterManager::Delete(int uid) {
//TODO
}
void MonsterManager::UnloadAll() {
//UnloadAll
//TODO
}
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) {
//UnloadIf
//TODO
}
MonsterData* MonsterManager::Get(int uid) {
//Get
//TODO
}
int MonsterManager::GetLoadedCount() {
//GetLoadedCount
//TODO
}
int MonsterManager::GetTotalCount() {
//TODO
}
std::map<int, MonsterData>* MonsterManager::GetContainer() {
//GetContainer
}
lua_State* MonsterManager::SetLuaState(lua_State* L) {
//SetLuaState
}
lua_State* MonsterManager::GetLuaState() {
//GetLuaState
//TODO
}
sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
//SetDatabase
//TODO
}
sqlite3* MonsterManager::GetDatabase() {
//GetDatabase
//TODO
}
lua_State* MonsterManager::SetLuaState(lua_State* L) {
//TODO
}
lua_State* MonsterManager::GetLuaState() {
//TODO
}
+21 -9
View File
@@ -23,22 +23,28 @@
#define MONSTERMANAGER_HPP_
#include "monster_data.hpp"
#include "singleton.hpp"
#include "lua.hpp"
#include "sqlite3.h"
#ifdef __unix__
#include "lua.hpp"
#include "sqlite3.h"
#else
#include "lua/lua.hpp"
#include "sqlite3/sqlite3.h"
#endif
#include <functional>
#include <map>
#include <string>
class MonsterManager {
class MonsterManager: public Singleton<MonsterManager> {
public:
MonsterManager();
~MonsterManager();
//common public methods
int Create(std::string);
int Load(std::string);
int Save(int uid);
void Unload(int uid);
void Delete(int uid);
void UnloadAll();
void UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn);
@@ -46,19 +52,25 @@ public:
//accessors & mutators
MonsterData* Get(int uid);
int GetLoadedCount();
int GetTotalCount();
std::map<int, MonsterData>* GetContainer();
//hooks
lua_State* SetLuaState(lua_State* L);
lua_State* GetLuaState();
sqlite3* SetDatabase(sqlite3* db);
sqlite3* GetDatabase();
lua_State* SetLuaState(lua_State* L);
lua_State* GetLuaState();
private:
friend Singleton<MonsterManager>;
MonsterManager() = default;
~MonsterManager() = default;
//members
std::map<int, MonsterData> elementMap;
lua_State* lua = nullptr;
sqlite3* database = nullptr;
lua_State* lua = nullptr;
};
#endif
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef MONSTERMANAGERAPI_HPP_
#define MONSTERMANAGERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_MONSTER_MANAGER_API "monster_manager"
LUAMOD_API int openMonsterManagerAPI(lua_State* L);
-55
View File
@@ -1,55 +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_system_api.hpp"
//all monster API headers
#include "monster_api.hpp"
#include "monster_manager_api.hpp"
//useful "globals"
//...
//This mimics linit.c to create a nested collection of all monster modules.
static const luaL_Reg funcs[] = {
{nullptr, nullptr}
};
static const luaL_Reg libs[] = {
{"Monster", openMonsterAPI},
{"MonsterManager", openMonsterManagerAPI},
{nullptr, nullptr}
};
int openMonsterSystemAPI(lua_State* L) {
//create the table
luaL_newlibtable(L, libs);
//push the "global" functions
luaL_setfuncs(L, funcs, 0);
//push the substable
for (const luaL_Reg* lib = libs; lib->func; lib++) {
lib->func(L);
lua_setfield(L, -2, lib->name);
}
return 1;
}
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. ../characters ../entities ../monsters ../server_utilities ../waypoints ../../common/gameplay ../../common/map ../../common/utilities
INCLUDES+=. ../entities ../server_utilities ../../common/map ../../common/utilities
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
+2 -17
View File
@@ -53,19 +53,8 @@ static int getPager(lua_State* L) {
return 1;
}
static int getMonsterMgr(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetMonsterMgr()) );
return 1;
}
static int getWaypointMgr(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetWaypointMgr()) );
return 1;
}
static int initialize(lua_State* L) {
//set the members of the given room
RoomData* room = static_cast<RoomData*>(lua_touserdata(L, 1));
//set the refs of these parameters (backwards, since it pops from the top of the stack)
@@ -79,15 +68,11 @@ static int initialize(lua_State* L) {
}
static const luaL_Reg roomLib[] = {
{"GetPager",getPager},
{"SetName", setRoomName},
{"GetName", getRoomName},
{"SetTileset", setTilesetName},
{"GetTileset", getTilesetName},
{"GetPager",getPager},
{"GetMonsterMgr",getMonsterMgr},
{"GetWaypointMgr",getWaypointMgr},
{"Initialize", initialize},
{nullptr, nullptr}
};
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef ROOMAPI_HPP_
#define ROOMAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_ROOM_API "room"
LUAMOD_API int openRoomAPI(lua_State* L);
+2 -10
View File
@@ -41,14 +41,6 @@ RegionPagerLua* RoomData::GetPager() {
return &pager;
}
MonsterManager* RoomData::GetMonsterMgr() {
return &monsterMgr;
}
WaypointManager* RoomData::GetWaypointMgr() {
return &waypointMgr;
}
std::list<CharacterData*>* RoomData::GetCharacterList() {
return &characterList;
std::list<Entity*>* RoomData::GetEntityList() {
return &entityList;
}
+8 -10
View File
@@ -22,12 +22,14 @@
#ifndef ROOMDATA_HPP_
#define ROOMDATA_HPP_
#include "character_data.hpp"
#include "monster_manager.hpp"
#include "entity.hpp"
#include "region_pager_lua.hpp"
#include "waypoint_manager.hpp"
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#include <list>
#include <string>
@@ -45,9 +47,7 @@ public:
std::string GetTileset();
RegionPagerLua* GetPager();
MonsterManager* GetMonsterMgr();
WaypointManager* GetWaypointMgr();
std::list<CharacterData*>* GetCharacterList();
std::list<Entity*>* GetEntityList();
//TODO: triggers for unload, save, per-second, player enter, player exit, etc.
@@ -59,9 +59,7 @@ private:
std::string tilesetName;
RegionPagerLua pager;
MonsterManager monsterMgr;
WaypointManager waypointMgr;
std::list<CharacterData*> characterList;
std::list<Entity*> entityList;
};
#endif
+45 -42
View File
@@ -24,6 +24,10 @@
#include "room_api.hpp"
#include <stdexcept>
#include <sstream>
//debug
#include <iostream>
//-------------------------
//public access methods
@@ -36,14 +40,52 @@ int RoomManager::Create(std::string roomName, std::string tileset) {
newRoom->SetTileset(tileset);
newRoom->pager.SetLuaState(lua);
newRoom->monsterMgr.SetLuaState(lua);
newRoom->monsterMgr.SetDatabase(database);
newRoom->waypointMgr.SetLuaState(lua);
//finish the routine
return counter++;
}
void RoomManager::PushEntity(Entity const* entity) {
if (!entity) {
throw(std::runtime_error("Failed to push null entity"));
}
std::map<int, RoomData>::iterator it = elementMap.find(entity->GetRoomIndex());
if (it == elementMap.end()) {
std::ostringstream msg;
// msg << "Failed to push entity; Room index not found: " << entity->GetRoomIndex() << std::endl;
throw(std::runtime_error(msg.str()));
}
it->second.entityList.push_back(const_cast<Entity*>(entity));
std::cout << "\troom[" << it->first << "].entityList.size(): " << it->second.entityList.size() << std::endl;
std::cout << "\tEntity: " << int(entity) << "," << int(it->second.entityList.front()) << std::endl;
}
void RoomManager::PopEntity(Entity const* entity) {
if (!entity) {
throw(std::runtime_error("Failed to pop null entity"));
}
std::map<int, RoomData>::iterator it = elementMap.find(entity->GetRoomIndex());
if (it == elementMap.end()) {
std::ostringstream msg;
msg << "Failed to pop entity; Room index not found: " << entity->GetRoomIndex() << std::endl;
throw(std::runtime_error(msg.str()));
}
it->second.entityList.remove_if([entity](Entity* ptr) -> bool {
bool b = (entity == ptr);
std::cout << "\tmatch(" << int(ptr) << "," << int(entity) << "): " << b << std::endl;
return b;
});
std::cout << "\troom[" << it->first << "].entityList.size(): " << it->second.entityList.size() << std::endl;
}
void RoomManager::UnloadAll() {
elementMap.clear();
}
@@ -60,37 +102,6 @@ void RoomManager::UnloadIf(std::function<bool(std::pair<const int, RoomData cons
}
}
void RoomManager::PushCharacter(CharacterData* character) {
if (!character) {
throw(std::runtime_error("Failed to push a null character to a room"));
}
RoomData* room = Get(character->GetRoomIndex());
if (!room) {
throw(std::runtime_error("Failed to push an character to a non-existant room"));
}
room->characterList.push_back(character);
}
void RoomManager::PopCharacter(CharacterData const* character) {
//NOTE: to pop an character from a room, the character must first exist
if (!character) {
throw(std::runtime_error("Failed to pop a null character to a room"));
}
RoomData* room = Get(character->GetRoomIndex());
if (!room) {
throw(std::runtime_error("Failed to pop an character to a non-existant room"));
}
room->characterList.remove_if([character](CharacterData* ptr) {
return character == ptr;
});
}
RoomData* RoomManager::Get(int uid) {
std::map<int, RoomData>::iterator it = elementMap.find(uid);
@@ -125,11 +136,3 @@ lua_State* RoomManager::SetLuaState(lua_State* L) {
lua_State* RoomManager::GetLuaState() {
return lua;
}
sqlite3* RoomManager::SetDatabase(sqlite3* db) {
return database = db;
}
sqlite3* RoomManager::GetDatabase() {
return database;
}
+9 -9
View File
@@ -22,12 +22,15 @@
#ifndef ROOMMANAGER_HPP_
#define ROOMMANAGER_HPP_
#include "character_data.hpp"
#include "entity.hpp"
#include "room_data.hpp"
#include "singleton.hpp"
#include "lua.hpp"
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#include <functional>
#include <map>
@@ -37,12 +40,12 @@ public:
//common public methods
int Create(std::string name, std::string tileset);
void PushEntity(Entity const* entity);
void PopEntity(Entity const* entity);
void UnloadAll();
void UnloadIf(std::function<bool(std::pair<const int, RoomData const&>)> fn);
void PushCharacter(CharacterData* character);
void PopCharacter(CharacterData const* character);
//accessors and mutators
RoomData* Get(int uid);
RoomData* Get(std::string name);
@@ -52,8 +55,6 @@ public:
//hooks
lua_State* SetLuaState(lua_State* L);
lua_State* GetLuaState();
sqlite3* SetDatabase(sqlite3* db);
sqlite3* GetDatabase();
private:
friend Singleton<RoomManager>;
@@ -64,7 +65,6 @@ private:
//members
std::map<int, RoomData> elementMap;
lua_State* lua = nullptr;
sqlite3* database = nullptr;
int counter = 0;
};
+1 -1
View File
@@ -71,7 +71,7 @@ int unloadRoom(lua_State* L) {
}
int getRoom(lua_State* L) {
//integer vs name for getRoom()
//TODO: integer vs name for getRoom()
RoomManager& roomMgr = RoomManager::GetSingleton();
RoomData* room = nullptr;
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef ROOMMANAGERAPI_HPP_
#define ROOMMANAGERAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_ROOM_MANAGER_API "room_manager"
LUAMOD_API int openRoomManagerAPI(lua_State* L);
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef ROOMSYSTEMAPI_HPP_
#define ROOMSYSTEMAPI_HPP_
#include "lua.hpp"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#else
#include "lua.hpp"
#endif
#define TORTUGA_ROOM_SYSTEM_API "room_system"
LUAMOD_API int openRoomSystemAPI(lua_State* L);
+42 -44
View File
@@ -28,19 +28,24 @@
#include "client_manager.hpp"
#include "monster_manager.hpp"
#include "room_manager.hpp"
#include "waypoint_manager.hpp"
//utilities
#include "config_utility.hpp"
#include "udp_network_utility.hpp"
//common utilities
#include "ip_operators.hpp"
#include "serial_packet.hpp"
#include "singleton.hpp"
//APIs
#include "lua.hpp"
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "lua/lua.hpp"
#include "sqlite3/sqlite3.h"
#else
#include "lua.hpp"
#include "sqlite3.h"
#endif
#include "SDL/SDL.h"
@@ -48,6 +53,10 @@
#include <map>
#include <string>
//global utility functions
bool operator==(IPaddress lhs, IPaddress rhs);
bool operator!=(IPaddress lhs, IPaddress rhs);
//The main application class
class ServerApplication: public Singleton<ServerApplication> {
public:
@@ -65,69 +74,58 @@ private:
//handle incoming traffic
void HandlePacket(SerialPacket* const);
//heartbeat system
void hPing(ServerPacket* const);
void hPong(ServerPacket* const);
//heartbeat sustem
void HandlePing(ServerPacket* const);
void HandlePong(ServerPacket* const);
//basic connections
void hBroadcastRequest(ServerPacket* const);
void hJoinRequest(ClientPacket* const);
void hLoginRequest(ClientPacket* const);
void HandleBroadcastRequest(ServerPacket* const);
void HandleJoinRequest(ClientPacket* const);
void HandleLoginRequest(ClientPacket* const);
//client disconnections
void hLogoutRequest(ClientPacket* const);
void hDisconnectRequest(ClientPacket* const);
void HandleLogoutRequest(ClientPacket* const);
void HandleDisconnectRequest(ClientPacket* const);
//server commands
void hAdminDisconnectForced(ClientPacket* const);
void hAdminShutdownRequest(ClientPacket* const);
void HandleDisconnectForced(ClientPacket* const);
void HandleShutdownRequest(ClientPacket* const);
//data management
void hRegionRequest(RegionPacket* const);
void hQueryCharacterExists(CharacterPacket* const);
void hQueryCharacterStats(CharacterPacket* const);
void hQueryCharacterLocation(CharacterPacket* const);
void hQueryMonsterExists(MonsterPacket* const);
void hQueryMonsterStats(MonsterPacket* const);
void hQueryMonsterLocation(MonsterPacket* const);
void HandleRegionRequest(RegionPacket* const);
void HandleCharacterExists(CharacterPacket* const);
//character management
void hCharacterCreate(CharacterPacket* const);
void hCharacterDelete(CharacterPacket* const);
void hCharacterLoad(CharacterPacket* const);
void hCharacterUnload(CharacterPacket* const);
//character movement
void hCharacterMovement(CharacterPacket* const);
void hCharacterAttack(CharacterPacket* const);
void hCharacterDamage(CharacterPacket* const);
//character management
void hMonsterDamage(MonsterPacket* const);
//chat
void hTextBroadcast(TextPacket* const);
void hTextSpeech(TextPacket* const);
void hTextWhisper(TextPacket* const);
//utility methods
void PumpPacket(SerialPacket* const);
void PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance);
void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
void SaveServerState();
void FullClientUnload(int index);
void FullAccountUnload(int index);
void FullCharacterUnload(int index);
//character management
void HandleCharacterCreate(CharacterPacket* const);
void HandleCharacterDelete(CharacterPacket* const);
void HandleCharacterLoad(CharacterPacket* const);
void HandleCharacterUnload(CharacterPacket* const);
//character movement
void HandleCharacterSetRoom(CharacterPacket* const);
void HandleCharacterSetOrigin(CharacterPacket* const);
void HandleCharacterSetMotion(CharacterPacket* const);
//utility methods
void PumpPacket(SerialPacket* const);
void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
//APIs and utilities
sqlite3* database = nullptr;
lua_State* luaState = nullptr;
//ugly references; I hate this
ClientManager& clientMgr = ClientManager::GetSingleton();
AccountManager& accountMgr = AccountManager::GetSingleton();
CharacterManager& characterMgr = CharacterManager::GetSingleton();
ClientManager& clientMgr = ClientManager::GetSingleton();
MonsterManager& monsterMgr = MonsterManager::GetSingleton();
RoomManager& roomMgr = RoomManager::GetSingleton();
WaypointManager& waypointMgr = WaypointManager::GetSingleton();
ConfigUtility& config = ConfigUtility::GetSingleton();
UDPNetworkUtility& network = UDPNetworkUtility::GetSingleton();
+116 -57
View File
@@ -28,7 +28,7 @@
//Character Management
//-------------------------
void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterCreate(CharacterPacket* const argPacket) {
int characterIndex = characterMgr.Create(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
if (characterIndex < 0) {
@@ -45,8 +45,8 @@ void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
return;
}
//push to the rooms
roomMgr.PushCharacter(characterMgr.Get(characterIndex));
//push this character to the rooms
// roomMgr.PushEntity(static_cast<Entity*>(characterMgr.Get(characterIndex)));
//pump this character to all clients
CharacterPacket newPacket;
@@ -55,7 +55,7 @@ void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
PumpPacket(&newPacket);
}
void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket) {
//get the user's data
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
if (!accountData) {
@@ -89,10 +89,8 @@ void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
return;
}
//pop from the rooms
roomMgr.PopCharacter(characterMgr.Get(characterIndex));
//delete the character
// roomMgr.PopEntity(static_cast<Entity*>(characterMgr.Get(characterIndex)));
characterMgr.Delete(characterIndex);
//pump character delete
@@ -102,7 +100,7 @@ void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
PumpPacket(static_cast<SerialPacket*>(&newPacket));
}
void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterLoad(CharacterPacket* const argPacket) {
int characterIndex = characterMgr.Load(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
if (characterIndex < 0) {
@@ -125,8 +123,9 @@ void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
return;
}
//push to the rooms
roomMgr.PushCharacter(characterMgr.Get(characterIndex));
//push this character to the rooms
std::cout << "pushing index " << characterIndex << std::endl;
roomMgr.PushEntity(static_cast<Entity*>(characterMgr.Get(characterIndex)));
//pump this character to all clients
CharacterPacket newPacket;
@@ -135,7 +134,7 @@ void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
PumpPacket(&newPacket);
}
void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterUnload(CharacterPacket* const argPacket) {
//get the entries
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
if (!characterData) {
@@ -144,12 +143,12 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
AccountData* accountData = accountMgr.Get(characterData->GetOwner());
if (!accountData) {
return;
return; //TODO: logic_error
}
ClientData* clientData = clientMgr.Get(accountData->GetClientIndex());
if (!clientData) {
return;
return; //TODO: logic_error
}
//check for fraud
@@ -158,10 +157,9 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
return;
}
//pop from the rooms
roomMgr.PopCharacter(characterData);
//unload the character
std::cout << "poping index " << argPacket->characterIndex << std::endl;
roomMgr.PopEntity(static_cast<Entity*>(characterData));
characterMgr.Unload(argPacket->characterIndex);
//pump character delete
@@ -175,15 +173,105 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
//character movement
//-------------------------
//TODO: (2) Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments
//TODO: ? Could replace this verbosity with a "verify" method, taking a client, account and character ptr as arguments
void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterSetRoom(CharacterPacket* const argPacket) {
//get the specified objects
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
if (!accountData || !characterData) {
throw(std::runtime_error("Failed to move a character, missing data"));
throw(std::runtime_error("Failed to set character room, missing data"));
}
//get this account's client
ClientData* clientData = clientMgr.Get(accountData->GetClientIndex());
//check for fraud
if (clientData->GetAddress() != argPacket->srcAddress) {
std::cerr << "Falsified set character origin targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return;
}
//check if allowed
if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) {
//TODO: send to the client?
std::cerr << "Failed to set character room due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return;
}
//pop from the rooms
roomMgr.PopEntity(static_cast<Entity*>(characterData));
//set the character's room, zero it's origin, zero it's motion
characterData->SetRoomIndex(argPacket->roomIndex);
characterData->SetOrigin({0, 0});
characterData->SetMotion({0, 0});
//push to the rooms
roomMgr.PushEntity(static_cast<Entity*>(characterData));
//update the clients
CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_SET_ROOM;
PumpPacket(&newPacket);
}
void ServerApplication::HandleCharacterSetOrigin(CharacterPacket* const argPacket) {
//get the specified objects
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
if (!accountData || !characterData) {
throw(std::runtime_error("Failed to set character origin, missing data"));
}
//get this account's client
ClientData* clientData = clientMgr.Get(accountData->GetClientIndex());
//check for fraud
if (clientData->GetAddress() != argPacket->srcAddress) {
std::cerr << "Falsified set character origin targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return;
}
//check if allowed
if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) {
//TODO: send to the client?
std::cerr << "Failed to set character origin due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return;
}
//set the character's origin, zero it's motion
characterData->SetOrigin(argPacket->origin);
characterData->SetMotion({0, 0});
//update the clients
CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_SET_ORIGIN;
PumpPacket(&newPacket);
}
void ServerApplication::HandleCharacterSetMotion(CharacterPacket* const argPacket) {
//get the specified objects
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
if (!accountData) {
std::ostringstream msg;
msg << "Failed to set character motion, missing account: Index " << argPacket->accountIndex << "; ";
msg << "Number of accounts loaded: " << accountMgr.GetContainer()->size();
throw(std::runtime_error(msg.str()));
}
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
if (!characterData) {
std::ostringstream msg;
msg << "Failed to set character motion, missing character: Index " << argPacket->characterIndex << "; ";
msg << "Number of characters loaded: " << characterMgr.GetContainer()->size();
throw(std::runtime_error(msg.str()));
}
//get this account's client
@@ -197,47 +285,18 @@ void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
//check if allowed
if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) {
//TODO: (2) send to the client?
//TODO: send to the client?
std::cerr << "Failed to set character motion due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return;
}
//check if moving rooms
if (characterData->GetRoomIndex() != argPacket->roomIndex) {
//delete from the old room
CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_DELETE;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
//set the character's origin and motion
characterData->SetOrigin(argPacket->origin);
characterData->SetMotion(argPacket->motion);
//move the character between rooms
roomMgr.PopCharacter(characterData);
characterData->SetRoomIndex(argPacket->roomIndex);
roomMgr.PushCharacter(characterData);
//create in the new room
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_CREATE;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
}
//if not moving between rooms
else {
//set the character's origin and motion
characterData->SetOrigin(argPacket->origin);
characterData->SetMotion(argPacket->motion);
//update the clients
CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
}
//update the clients
CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_SET_MOTION;
PumpPacket(&newPacket);
}
void ServerApplication::hCharacterAttack(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hCharacterDamage(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
-34
View File
@@ -1,34 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "server_application.hpp"
void ServerApplication::hTextBroadcast(TextPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hTextSpeech(TextPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hTextWhisper(TextPacket* const argPacket) {
//TODO: (9) empty
}
+11 -7
View File
@@ -28,13 +28,13 @@
//heartbeat system
//-------------------------
void ServerApplication::hPing(ServerPacket* const argPacket) {
void ServerApplication::HandlePing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void ServerApplication::hPong(ServerPacket* const argPacket) {
void ServerApplication::HandlePong(ServerPacket* const argPacket) {
clientMgr.HandlePong(argPacket);
}
@@ -42,7 +42,7 @@ void ServerApplication::hPong(ServerPacket* const argPacket) {
//basic connections
//-------------------------
void ServerApplication::hBroadcastRequest(ServerPacket* const argPacket) {
void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) {
//send the server's data
ServerPacket newPacket;
@@ -54,7 +54,7 @@ void ServerApplication::hBroadcastRequest(ServerPacket* const argPacket) {
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
}
void ServerApplication::hJoinRequest(ClientPacket* const argPacket) {
void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
//register the client
int clientIndex = clientMgr.Create(argPacket->srcAddress);
@@ -69,7 +69,7 @@ void ServerApplication::hJoinRequest(ClientPacket* const argPacket) {
std::cout << "New join, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::hLoginRequest(ClientPacket* const argPacket) {
void ServerApplication::HandleLoginRequest(ClientPacket* const argPacket) {
//get the client data
ClientData* clientData = clientMgr.Get(argPacket->clientIndex);
@@ -110,7 +110,7 @@ void ServerApplication::hLoginRequest(ClientPacket* const argPacket) {
std::cout << "New login, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) {
void ServerApplication::HandleLogoutRequest(ClientPacket* const argPacket) {
//get the account and client data
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
if (!accountData) {
@@ -144,7 +144,7 @@ void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) {
std::cout << "New logout, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) {
void ServerApplication::HandleDisconnectRequest(ClientPacket* const argPacket) {
//get the client data
ClientData* clientData = clientMgr.Get(argPacket->clientIndex);
if (!clientData) {
@@ -170,3 +170,7 @@ void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) {
//finished this routine
std::cout << "New disconnection, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::HandleDisconnectForced(ClientPacket* const argPacket) {
//TODO: HandleDisconnectForced
}
@@ -25,10 +25,20 @@
#include <sstream>
//-------------------------
//Queries
//General data management
//-------------------------
void ServerApplication::hRegionRequest(RegionPacket* const argPacket) {
//TODO: Queries
void ServerApplication::SaveServerState() {
//TODO: SaveServerState
}
//-------------------------
//Map management
//-------------------------
void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) {
//get the region object, send a rejection on error
RoomData* room = roomMgr.Get(argPacket->roomIndex);
if (!room) {
@@ -61,7 +71,7 @@ void ServerApplication::hRegionRequest(RegionPacket* const argPacket) {
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
}
void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket) {
void ServerApplication::HandleCharacterExists(CharacterPacket* const argPacket) {
//respond with all character data
CharacterPacket newPacket;
@@ -74,23 +84,3 @@ void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket)
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
}
}
void ServerApplication::hQueryCharacterStats(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hQueryCharacterLocation(CharacterPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hQueryMonsterExists(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hQueryMonsterStats(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hQueryMonsterLocation(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
+45 -59
View File
@@ -23,6 +23,7 @@
//utility functions
#include "sql_tools.hpp"
#include "utility.hpp"
//std & STL
#include <stdexcept>
@@ -104,7 +105,7 @@ void ServerApplication::Init(int argc, char* argv[]) {
characterMgr.SetDatabase(database);
roomMgr.SetLuaState(luaState);
roomMgr.SetDatabase(database);
waypointMgr.SetLuaState(luaState);
std::cout << "Internal managers initialized" << std::endl;
@@ -128,6 +129,7 @@ void ServerApplication::Init(int argc, char* argv[]) {
//debug output
//-------------------------
//TODO: enable/disable these with a switch
#define DEBUG_OUTPUT_VAR(x) std::cout << "\t" << #x << ": " << x << std::endl;
std::cout << "Internal sizes:" << std::endl;
@@ -185,7 +187,7 @@ void ServerApplication::Proc() {
std::cerr << "Client dropped: " << disconnected << std::endl;
}
//give the machine a break
//give the computer a break
SDL_Delay(10);
}
delete reinterpret_cast<char*>(packetBuffer);
@@ -194,14 +196,15 @@ void ServerApplication::Proc() {
void ServerApplication::Quit() {
std::cout << "Shutting down" << std::endl;
//save the server state
SaveServerState();
//TODO: save the server state
//close the managers
accountMgr.UnloadAll();
characterMgr.UnloadAll();
clientMgr.UnloadAll();
monsterMgr.UnloadAll();
roomMgr.UnloadAll();
waypointMgr.UnloadAll();
//APIs
lua_close(luaState);
@@ -214,116 +217,99 @@ void ServerApplication::Quit() {
}
//-------------------------
//handle incoming traffic
//direct incoming traffic
//-------------------------
void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
hPing(static_cast<ServerPacket*>(argPacket));
HandlePing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
hPong(static_cast<ServerPacket*>(argPacket));
HandlePong(static_cast<ServerPacket*>(argPacket));
break;
//client connections
case SerialPacketType::BROADCAST_REQUEST:
hBroadcastRequest(static_cast<ServerPacket*>(argPacket));
HandleBroadcastRequest(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::JOIN_REQUEST:
hJoinRequest(static_cast<ClientPacket*>(argPacket));
HandleJoinRequest(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::LOGIN_REQUEST:
hLoginRequest(static_cast<ClientPacket*>(argPacket));
HandleLoginRequest(static_cast<ClientPacket*>(argPacket));
break;
//client disconnections
case SerialPacketType::LOGOUT_REQUEST:
hLogoutRequest(static_cast<ClientPacket*>(argPacket));
HandleLogoutRequest(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_REQUEST:
hDisconnectRequest(static_cast<ClientPacket*>(argPacket));
HandleDisconnectRequest(static_cast<ClientPacket*>(argPacket));
break;
//server commands
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
hAdminDisconnectForced(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST:
hAdminShutdownRequest(static_cast<ClientPacket*>(argPacket));
// case SerialPacketType::DISCONNECT_FORCED:
// HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
// break;
case SerialPacketType::SHUTDOWN_REQUEST:
HandleShutdownRequest(static_cast<ClientPacket*>(argPacket));
break;
//data management & queries
case SerialPacketType::REGION_REQUEST:
hRegionRequest(static_cast<RegionPacket*>(argPacket));
HandleRegionRequest(static_cast<RegionPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_EXISTS:
hQueryCharacterExists(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_STATS:
hQueryCharacterStats(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_LOCATION:
hQueryCharacterLocation(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_EXISTS:
hQueryMonsterExists(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_STATS:
hQueryMonsterStats(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_LOCATION:
hQueryMonsterLocation(static_cast<MonsterPacket*>(argPacket));
HandleCharacterExists(static_cast<CharacterPacket*>(argPacket));
break;
//character management
case SerialPacketType::CHARACTER_CREATE:
hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
hCharacterDelete(static_cast<CharacterPacket*>(argPacket));
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_LOAD:
hCharacterLoad(static_cast<CharacterPacket*>(argPacket));
HandleCharacterLoad(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_UNLOAD:
hCharacterUnload(static_cast<CharacterPacket*>(argPacket));
HandleCharacterUnload(static_cast<CharacterPacket*>(argPacket));
break;
//character movement
case SerialPacketType::CHARACTER_MOVEMENT:
hCharacterMovement(static_cast<CharacterPacket*>(argPacket));
case SerialPacketType::CHARACTER_SET_ROOM:
HandleCharacterSetRoom(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_ATTACK:
hCharacterAttack(static_cast<CharacterPacket*>(argPacket));
case SerialPacketType::CHARACTER_SET_ORIGIN:
HandleCharacterSetOrigin(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DAMAGE:
hCharacterDamage(static_cast<CharacterPacket*>(argPacket));
case SerialPacketType::CHARACTER_SET_MOTION:
HandleCharacterSetMotion(static_cast<CharacterPacket*>(argPacket));
break;
//monster management
case SerialPacketType::MONSTER_DAMAGE:
hMonsterDamage(static_cast<MonsterPacket*>(argPacket));
/*
case SerialPacketType::QUERY_CHARACTER_STATS:
// HandleCharacterStatsRequest(static_cast<RegionPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_LOCATION:
// HandleCharacterStatsRequest(static_cast<RegionPacket*>(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));
// HandleCharacterStatsRequest(static_cast<RegionPacket*>(argPacket));
break;
//enemy management
//TODO: enemy management
//TODO: text
*/
//handle errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in the server: ";
msg << static_cast<int>(argPacket->type);
msg << to_string_custom(static_cast<int>(argPacket->type));
throw(std::runtime_error(msg.str()));
}
break;
+17 -27
View File
@@ -25,15 +25,23 @@
#include <iostream>
#include <sstream>
//-------------------------
//these should've come standard
//-------------------------
bool operator==(IPaddress lhs, IPaddress rhs) {
return lhs.host == rhs.host && lhs.port == rhs.port;
}
bool operator!=(IPaddress lhs, IPaddress rhs) {
return !(lhs == rhs);
}
//-------------------------
//server commands
//-------------------------
void ServerApplication::hAdminDisconnectForced(ClientPacket* const argPacket) {
//TODO: (9) empty
}
void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
void ServerApplication::HandleShutdownRequest(ClientPacket* const argPacket) {
//get the account and client data
AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
if (!accountData) {
@@ -76,7 +84,7 @@ void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
//disconnect all clients
TextPacket newPacket;
newPacket.type = SerialPacketType::ADMIN_DISCONNECT_FORCED;
newPacket.type = SerialPacketType::DISCONNECT_FORCED;
strncpy(newPacket.text, "Server shutdown", PACKET_STRING_SIZE);
PumpPacket(&newPacket);
@@ -84,10 +92,6 @@ void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
std::cout << "Shutdown signal accepted" << std::endl;
}
void ServerApplication::SaveServerState() {
//TODO: (9) empty
}
//-------------------------
//full unload methods
//-------------------------
@@ -139,6 +143,7 @@ void ServerApplication::FullAccountUnload(int index) {
}
void ServerApplication::FullCharacterUnload(int index) {
//BUG: #38 UnloadIf() lambas are taking COPIES of data structures, rather than the structures themselves
characterMgr.UnloadIf([&](std::pair<const int, CharacterData const&> character) -> bool {
//skip the wrong characters
if (character.first != index) {
@@ -146,7 +151,8 @@ void ServerApplication::FullCharacterUnload(int index) {
}
//pop from the rooms
roomMgr.PopCharacter(&character.second);
std::cout << "popping index " << index << std::endl;
roomMgr.PopEntity(reinterpret_cast<Entity const*>(&character.second));
//pump character unload
CharacterPacket newPacket;
@@ -171,22 +177,6 @@ void ServerApplication::PumpPacket(SerialPacket* const argPacket) {
}
}
void ServerApplication::PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance) {
RoomData* room = roomMgr.Get(roomIndex);
if (!room) {
throw(std::runtime_error("Failed to pump to a non-existant room"));
}
for (auto& character : *room->GetCharacterList()) {
if (distance == -1 || (character->GetOrigin() - position).Length() <= distance) {
AccountData* account = accountMgr.Get(character->GetOwner());
ClientData* client = clientMgr.Get(account->GetClientIndex());
network.SendTo(client->GetAddress(), argPacket);
}
}
}
void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
CharacterData* character = characterMgr.Get(characterIndex);
if (!character) {
-26
View File
@@ -1,26 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "server_application.hpp"
void ServerApplication::hMonsterDamage(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=.
INCLUDES+=. ../../common/utilities
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
+4 -4
View File
@@ -21,9 +21,10 @@
*/
#include "sql_tools.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <fstream>
#include <sstream>
#include <cstdlib>
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**), void* argPtr) {
@@ -41,10 +42,9 @@ int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char*
int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg);
if (ret != SQLITE_OK) {
//handle any errors received from the SQL
std::ostringstream msg;
msg << "SQL Script Error " << ret << ": " << errmsg;
std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg);
free(errmsg);
throw(std::runtime_error( msg.str() ));
throw(e);
}
return ret;
}
+5 -1
View File
@@ -22,7 +22,11 @@
#ifndef SERVERUTILITY_HPP_
#define SERVERUTILITY_HPP_
#include "sqlite3.h"
#if defined(__MINGW32__)
#include "sqlite3/sqlite3.h"
#else
#include "sqlite3.h"
#endif
#include <string>

Some files were not shown because too many files have changed in this diff Show More