Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5a98efd7d | |||
| 14b330009b | |||
| 288b62d3f8 | |||
| c5e8f1b3af | |||
| 980717f9fd | |||
| 68475eee0f | |||
| eeb2400e79 | |||
| 01244005e9 | |||
| c5005b9b07 | |||
| 80a26341b1 | |||
| b7877962f1 | |||
| 688d064085 | |||
| 1c4d53e3ef | |||
| a53a134163 | |||
| 4d12788c53 | |||
| 1beb7cbd5d | |||
| 8358d72a98 | |||
| 4ebff4a25a | |||
| 0ff787abda | |||
| 9b5b48a8ab | |||
| 5dd0fb9e23 | |||
| 7c210e04a5 | |||
| 9236e02101 | |||
| 8f4ebf20da | |||
| 910e51f637 | |||
| 92fc9b4e25 | |||
| 2b8e7241c9 | |||
| 124cb3ad13 | |||
| 6d3400d948 | |||
| 5031352fe3 | |||
| 624369f147 | |||
| 9a7f7b8684 | |||
| fa9487c2f2 | |||
| 9ec1ddab99 | |||
| 6f1c2d0555 | |||
| 01b50d5590 | |||
| 9c673928e6 | |||
| d55dfb90e4 | |||
| 235a05d006 | |||
| dabb7b3b2e | |||
| e756289c2b | |||
| c534158c2e | |||
| b47191a0c1 | |||
| 6c6a025f2a | |||
| 60edc97ea5 | |||
| a5b209d9e0 | |||
| fd673a415f | |||
| 4270765146 | |||
| f56cb58dfb | |||
| f315f4bf35 | |||
| 69765de433 | |||
| 35d463d4ba | |||
| 894b46c5db | |||
| eb0b18af6f | |||
| fba183fa27 | |||
| c5a627004a | |||
| ac27fb0ca7 | |||
| be4a8311d5 | |||
| 6d32d44fa3 | |||
| 9bacfb1424 | |||
| c3464be589 | |||
| 7fe71c60d0 | |||
| 0c6537fb36 | |||
| 854dc0eb45 | |||
| e90afb7e4a | |||
| 0453f6becf | |||
| c8a58ab515 | |||
| 553f8dbfa5 | |||
| 2bacdcdab7 | |||
| 99aecbfdbb | |||
| 27bda5dc28 | |||
| 962f3f5dd0 | |||
| 41077b43b3 | |||
| 4410ab892f | |||
| 60000cb0cf | |||
| 66b00255d5 | |||
| a5b68cf1fd | |||
| 4cff57fe71 | |||
| 38b603fc8f | |||
| 47684380a9 | |||
| e4bfbfb906 | |||
| 9db86c19f6 | |||
| d5b551cec3 | |||
| 7e500027e3 | |||
| dd786ba579 | |||
| 5a57888305 | |||
| 706aa5e1d7 | |||
| 19c1b1197d | |||
| 5cf62f5517 | |||
| 56d02ad8d4 | |||
| 006a72174f | |||
| 0cbc9dd9db | |||
| 60c31ff56d | |||
| 6a204643f6 | |||
| 59285d1630 | |||
| a850d6b1af | |||
| f17fa0f345 | |||
| 756d4e770d | |||
| 7bb5e8ce0d | |||
| 975533afba | |||
| 19749f7c87 | |||
| 7703c4b0ad | |||
| dc8f594eec | |||
| 4629b7302b | |||
| 02d83d1f16 | |||
| 91c9cef56d | |||
| f7d4912942 | |||
| eb8674b84f | |||
| ff44e4d916 | |||
| e66540f114 | |||
| 639c0c70e3 | |||
| 37b02352e2 | |||
| 31c8bd7fd2 | |||
| 808fe570a3 | |||
| e706cc9d13 | |||
| eb02cc4b6a |
@@ -1,26 +1,26 @@
|
|||||||
You can find the [latest nightly build here](https://dl.dropboxusercontent.com/u/46669050/Tortuga.rar).
|
The most recent stable windows build can be found [here](https://dl.dropboxusercontent.com/u/46669050/Tortuga.rar).
|
||||||
|
|
||||||
Tortuga is an open source 2D multiplayer role playing game featuring permadeath (deletion of a character upon death). The emphasis of this game is on multiplayer cooperation, competition, and customization. The game runs on customizable server software that can support up to 150 simultaneous players or more.
|
Tortuga is an open source 2D multiplayer role playing game featuring permadeath (deletion of a character upon death). The emphasis of this game is on multiplayer cooperation, competition, exploration and customization. The game runs on customizable server software that can support up to 150 simultaneous players or more.
|
||||||
|
|
||||||
This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. This project is currently independently created and funded, with the goal of creating a game that will engage user's imagination and inspire a large modding community.
|
This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. This project is currently independently created and funded, with the goal of creating a game that will engage user's imagination and inspire a large modding community.
|
||||||
|
|
||||||
## External Dependencies
|
## External Dependencies
|
||||||
|
|
||||||
* [SDL 1.6](http://www.libsdl.org/) - Simple DirectMedia Layer API
|
* [SDL 1.2](http://www.libsdl.org/) - Simple DirectMedia Layer API
|
||||||
* [SDL_net 1.2](http://www.libsdl.org/projects/SDL_net/) - SDL's networking extension
|
* [SDL_net 1.2](http://www.libsdl.org/projects/SDL_net/) - SDL's networking extension
|
||||||
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
* [lua 5.2](http://www.lua.org/) - The lua programming language
|
||||||
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
[Tortuga Game Design Document](https://docs.google.com/document/d/17SjOTdacKKWX0Z-UkaiFnVnjfEeMsc5LRmARtnjh5UI/edit?usp=sharing)
|
[Tortuga Game Design Document](https://github.com/Ratstail91/Tortuga/blob/docs/design%20doc.docx?raw=true)
|
||||||
[Tortuga Technical Document](https://docs.google.com/document/d/1ASTfM_1e0yE1cFP-IZey_rHEC6k2kmVY56X4K407sw0/edit?usp=sharing)
|
[Tortuga Technical Document](https://github.com/Ratstail91/Tortuga/blob/docs/technical%20doc.docx?raw=true)
|
||||||
|
|
||||||
## Copyright
|
## Copyright
|
||||||
|
|
||||||
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
|
||||||
|
|
||||||
Copyright (c) 2013 Kayne Ruse
|
Copyright (c) 2013, 2014 Kayne Ruse
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
|||||||
@@ -21,15 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
#include "client_application.hpp"
|
#include "client_application.hpp"
|
||||||
|
|
||||||
|
#include "serial.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Static declarations
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
ClientApplication ClientApplication::instance;
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Scene headers
|
//Scene headers
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -46,15 +42,7 @@ ClientApplication ClientApplication::instance;
|
|||||||
//Public access members
|
//Public access members
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
ClientApplication::ClientApplication() {
|
void ClientApplication::Init(int argc, char** argv) {
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientApplication::~ClientApplication() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientApplication::Init() {
|
|
||||||
//load the prerequisites
|
//load the prerequisites
|
||||||
config.Load("rsc\\config.cfg");
|
config.Load("rsc\\config.cfg");
|
||||||
|
|
||||||
@@ -62,13 +50,13 @@ void ClientApplication::Init() {
|
|||||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
throw(std::runtime_error("Failed to initialize SDL"));
|
throw(std::runtime_error("Failed to initialize SDL"));
|
||||||
}
|
}
|
||||||
BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF : SDL_HWSURFACE);
|
BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN : SDL_HWSURFACE|SDL_DOUBLEBUF);
|
||||||
|
|
||||||
//initialize SDL_net
|
//initialize SDL_net
|
||||||
if (SDLNet_Init()) {
|
if (SDLNet_Init()) {
|
||||||
throw(std::runtime_error("Failed to initialize SDL_net"));
|
throw(std::runtime_error("Failed to initialize SDL_net"));
|
||||||
}
|
}
|
||||||
network.Open(0, sizeof(NetworkPacket));
|
network.Open(0, PACKET_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientApplication::Proc() {
|
void ClientApplication::Proc() {
|
||||||
@@ -77,7 +65,7 @@ void ClientApplication::Proc() {
|
|||||||
//prepare the time system
|
//prepare the time system
|
||||||
typedef std::chrono::steady_clock Clock;
|
typedef std::chrono::steady_clock Clock;
|
||||||
|
|
||||||
Clock::duration delta(16 * Clock::duration::period::den / std::milli::den);
|
std::chrono::duration<int, std::milli> delta(16);
|
||||||
Clock::time_point simTime = Clock::now();
|
Clock::time_point simTime = Clock::now();
|
||||||
Clock::time_point realTime;
|
Clock::time_point realTime;
|
||||||
|
|
||||||
@@ -95,15 +83,12 @@ void ClientApplication::Proc() {
|
|||||||
//simulate game time
|
//simulate game time
|
||||||
while (simTime < realTime) {
|
while (simTime < realTime) {
|
||||||
//call each user defined function
|
//call each user defined function
|
||||||
activeScene->RunFrame(double(delta.count()) / Clock::duration::period::den);
|
activeScene->RunFrame(double(delta.count()) / std::chrono::duration<int, std::milli>::period::den);
|
||||||
simTime += delta;
|
simTime += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw the game to the screen
|
//draw the game to the screen
|
||||||
activeScene->RenderFrame();
|
activeScene->RenderFrame();
|
||||||
|
|
||||||
//give the computer a break
|
|
||||||
SDL_Delay(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnloadScene();
|
UnloadScene();
|
||||||
@@ -121,7 +106,6 @@ void ClientApplication::Quit() {
|
|||||||
|
|
||||||
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
void ClientApplication::LoadScene(SceneList sceneIndex) {
|
||||||
UnloadScene();
|
UnloadScene();
|
||||||
|
|
||||||
switch(sceneIndex) {
|
switch(sceneIndex) {
|
||||||
//add scene creation calls here
|
//add scene creation calls here
|
||||||
case SceneList::FIRST:
|
case SceneList::FIRST:
|
||||||
@@ -135,15 +119,14 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
|
|||||||
activeScene = new OptionsMenu(&config);
|
activeScene = new OptionsMenu(&config);
|
||||||
break;
|
break;
|
||||||
case SceneList::LOBBYMENU:
|
case SceneList::LOBBYMENU:
|
||||||
activeScene = new LobbyMenu(&config, &network, &clientIndex);
|
activeScene = new LobbyMenu(&config, &network, &clientIndex, &accountIndex, &characterIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::INWORLD:
|
case SceneList::INWORLD:
|
||||||
activeScene = new InWorld(&config, &network, &clientIndex);
|
activeScene = new InWorld(&config, &network, &clientIndex, &accountIndex, &characterIndex);
|
||||||
break;
|
break;
|
||||||
case SceneList::INCOMBAT:
|
case SceneList::INCOMBAT:
|
||||||
activeScene = new InCombat();
|
activeScene = new InCombat();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw(std::logic_error("Failed to recognize the scene index"));
|
throw(std::logic_error("Failed to recognize the scene index"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,19 +26,14 @@
|
|||||||
#include "base_scene.hpp"
|
#include "base_scene.hpp"
|
||||||
|
|
||||||
#include "config_utility.hpp"
|
#include "config_utility.hpp"
|
||||||
#include "network_packet.hpp"
|
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
|
||||||
class ClientApplication {
|
class ClientApplication {
|
||||||
private:
|
|
||||||
ClientApplication();
|
|
||||||
~ClientApplication();
|
|
||||||
static ClientApplication instance;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ClientApplication* GetInstance() { return &instance; }
|
ClientApplication() = default;
|
||||||
|
~ClientApplication() = default;
|
||||||
|
|
||||||
void Init();
|
void Init(int argc, char** argv);
|
||||||
void Proc();
|
void Proc();
|
||||||
void Quit();
|
void Quit();
|
||||||
|
|
||||||
@@ -49,9 +44,12 @@ private:
|
|||||||
|
|
||||||
BaseScene* activeScene = nullptr;
|
BaseScene* activeScene = nullptr;
|
||||||
|
|
||||||
|
//shared parameters
|
||||||
ConfigUtility config;
|
ConfigUtility config;
|
||||||
UDPNetworkUtility network;
|
UDPNetworkUtility network;
|
||||||
int clientIndex = -1; //replace with a struct?
|
int clientIndex = -1;
|
||||||
|
int accountIndex = -1;
|
||||||
|
int characterIndex = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+5
-4
@@ -26,12 +26,13 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int, char**) {
|
int main(int argc, char** argv) {
|
||||||
cout << "Beginning client" << endl;
|
cout << "Beginning client" << endl;
|
||||||
try {
|
try {
|
||||||
ClientApplication::GetInstance()->Init();
|
ClientApplication app;
|
||||||
ClientApplication::GetInstance()->Proc();
|
app.Init(argc, argv);
|
||||||
ClientApplication::GetInstance()->Quit();
|
app.Proc();
|
||||||
|
app.Quit();
|
||||||
}
|
}
|
||||||
catch(exception& e) {
|
catch(exception& e) {
|
||||||
cerr << "Fatal exception thrown: " << e.what() << endl;
|
cerr << "Fatal exception thrown: " << e.what() << endl;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
#include "sprite_sheet.hpp"
|
#include "sprite_sheet.hpp"
|
||||||
|
|
||||||
|
//TODO: correct the PlayerCharacter class and it's movement system
|
||||||
class PlayerCharacter {
|
class PlayerCharacter {
|
||||||
public:
|
public:
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
@@ -36,7 +37,7 @@ public:
|
|||||||
|
|
||||||
void Update(double delta);
|
void Update(double delta);
|
||||||
|
|
||||||
void DrawTo(SDL_Surface* const dest) { sprite.DrawTo(dest, position.x, position.y); }
|
void DrawTo(SDL_Surface* const dest, int camX, int camY) { sprite.DrawTo(dest, position.x - camX, position.y - camY); }
|
||||||
|
|
||||||
//clunky code results in smooth movement and controls
|
//clunky code results in smooth movement and controls
|
||||||
void AdjustDirection(Direction);
|
void AdjustDirection(Direction);
|
||||||
|
|||||||
+226
-101
@@ -23,53 +23,59 @@
|
|||||||
|
|
||||||
#include "channels.hpp"
|
#include "channels.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//Public access members
|
//Public access members
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex):
|
InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, int* const argAccountIndex, int* const argCharacterIndex):
|
||||||
config(*argConfig),
|
config(*argConfig),
|
||||||
network(*argNetwork),
|
network(*argNetwork),
|
||||||
clientIndex(*argClientIndex)
|
clientIndex(*argClientIndex),
|
||||||
|
accountIndex(*argAccountIndex),
|
||||||
|
characterIndex(*argCharacterIndex)
|
||||||
{
|
{
|
||||||
//setup the utility objects
|
//setup the utility objects
|
||||||
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
||||||
image.SetClipH(image.GetClipH()/3);
|
buttonImage.SetClipH(buttonImage.GetClipH()/3);
|
||||||
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
||||||
|
|
||||||
//pass the utility objects
|
//pass the utility objects
|
||||||
disconnectButton.SetImage(&image);
|
disconnectButton.SetImage(&buttonImage);
|
||||||
disconnectButton.SetFont(&font);
|
disconnectButton.SetFont(&font);
|
||||||
shutDownButton.SetImage(&image);
|
shutDownButton.SetImage(&buttonImage);
|
||||||
shutDownButton.SetFont(&font);
|
shutDownButton.SetFont(&font);
|
||||||
|
|
||||||
//set the button positions
|
//set the button positions
|
||||||
disconnectButton.SetX(50);
|
disconnectButton.SetX(50);
|
||||||
disconnectButton.SetY(50 + image.GetClipH() * 0);
|
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
|
||||||
shutDownButton.SetX(50);
|
shutDownButton.SetX(50);
|
||||||
shutDownButton.SetY(50 + image.GetClipH() * 1);
|
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
|
||||||
|
|
||||||
//set the button texts
|
//set the button texts
|
||||||
disconnectButton.SetText("Disconnect");
|
disconnectButton.SetText("Disconnect");
|
||||||
shutDownButton.SetText("Shut Down");
|
shutDownButton.SetText("Shut Down");
|
||||||
|
|
||||||
//create the server-side player object
|
//load the tilesheet
|
||||||
NetworkPacket packet;
|
//TODO: add the tilesheet to the map system?
|
||||||
packet.meta.type = NetworkPacket::Type::PLAYER_NEW;
|
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
|
||||||
packet.playerInfo.clientIndex = clientIndex;
|
|
||||||
snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str());
|
|
||||||
snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str());
|
|
||||||
packet.playerInfo.position = {0,0};
|
|
||||||
packet.playerInfo.motion = {0,0};
|
|
||||||
|
|
||||||
//send it
|
|
||||||
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
|
|
||||||
|
|
||||||
|
//TODO: move this into it's own function
|
||||||
//request a sync
|
//request a sync
|
||||||
packet.meta.type = NetworkPacket::Type::SYNCHRONIZE;
|
SerialPacket packet;
|
||||||
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
|
char buffer[PACKET_STRING_SIZE];
|
||||||
|
packet.meta.type = SerialPacket::Type::SYNCHRONIZE;
|
||||||
|
packet.clientInfo.clientIndex = clientIndex;
|
||||||
|
packet.clientInfo.accountIndex = accountIndex;
|
||||||
|
packet.clientInfo.characterIndex = characterIndex;
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// RequestRegion(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
InWorld::~InWorld() {
|
InWorld::~InWorld() {
|
||||||
@@ -85,29 +91,57 @@ void InWorld::FrameStart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::Update(double delta) {
|
void InWorld::Update(double delta) {
|
||||||
|
SerialPacket packet;
|
||||||
|
|
||||||
//suck in all waiting packets
|
//suck in all waiting packets
|
||||||
NetworkPacket packet;
|
|
||||||
while(network.Receive()) {
|
while(network.Receive()) {
|
||||||
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
|
deserialize(&packet, network.GetInData());
|
||||||
packet.meta.srcAddress = network.GetInPacket()->address;
|
packet.meta.srcAddress = network.GetInPacket()->address;
|
||||||
HandlePacket(packet);
|
HandlePacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update the characters
|
||||||
for (auto& it : playerCharacters) {
|
for (auto& it : playerCharacters) {
|
||||||
it.second.Update(delta);
|
it.second.Update(delta);
|
||||||
}
|
}
|
||||||
|
//TODO: sort the players and entities by Y position
|
||||||
|
|
||||||
|
//update the camera
|
||||||
|
if(localCharacter) {
|
||||||
|
camera.x = localCharacter->GetPosition().x - camera.marginX;
|
||||||
|
camera.y = localCharacter->GetPosition().y - camera.marginY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check the map
|
||||||
|
UpdateMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::FrameEnd() {
|
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) {
|
void InWorld::Render(SDL_Surface* const screen) {
|
||||||
for (auto& it : playerCharacters) {
|
//draw the map
|
||||||
it.second.DrawTo(screen);
|
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
|
||||||
|
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//draw characters
|
||||||
|
for (auto& it : playerCharacters) {
|
||||||
|
it.second.DrawTo(screen, camera.x, camera.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//draw UI
|
||||||
disconnectButton.DrawTo(screen);
|
disconnectButton.DrawTo(screen);
|
||||||
shutDownButton.DrawTo(screen);
|
shutDownButton.DrawTo(screen);
|
||||||
|
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
@@ -149,28 +183,28 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
|
|||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -182,134 +216,225 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
|
|||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
if (localCharacter) {
|
if (localCharacter) {
|
||||||
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
|
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
|
||||||
SendState();
|
SendPlayerUpdate();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::HandlePacket(NetworkPacket packet) {
|
//-------------------------
|
||||||
|
//Network handlers
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::HandlePacket(SerialPacket packet) {
|
||||||
switch(packet.meta.type) {
|
switch(packet.meta.type) {
|
||||||
case NetworkPacket::Type::DISCONNECT:
|
case SerialPacket::Type::DISCONNECT:
|
||||||
HandleDisconnect(packet);
|
HandleDisconnect(packet);
|
||||||
break;
|
break;
|
||||||
|
case SerialPacket::Type::REGION_CONTENT:
|
||||||
case NetworkPacket::Type::PLAYER_NEW:
|
HandleRegionContent(packet);
|
||||||
HandlePlayerNew(packet);
|
|
||||||
break;
|
break;
|
||||||
|
case SerialPacket::Type::CHARACTER_UPDATE:
|
||||||
case NetworkPacket::Type::PLAYER_DELETE:
|
HandleCharacterUpdate(packet);
|
||||||
HandlePlayerDelete(packet);
|
|
||||||
break;
|
break;
|
||||||
|
case SerialPacket::Type::CHARACTER_NEW:
|
||||||
case NetworkPacket::Type::PLAYER_UPDATE:
|
HandleCharacterNew(packet);
|
||||||
HandlePlayerUpdate(packet);
|
break;
|
||||||
|
case SerialPacket::Type::CHARACTER_DELETE:
|
||||||
|
HandleCharacterDelete(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//handle errors
|
//handle errors
|
||||||
default:
|
default:
|
||||||
throw(std::runtime_error("Unknown NetworkPacket::Type encountered"));
|
throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in InWorld: " + to_string_custom(int(packet.meta.type))));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::HandleDisconnect(NetworkPacket packet) {
|
void InWorld::HandleDisconnect(SerialPacket packet) {
|
||||||
network.Unbind(Channels::SERVER);
|
network.Unbind(Channels::SERVER);
|
||||||
clientIndex = -1;
|
clientIndex = -1;
|
||||||
|
accountIndex = -1;
|
||||||
|
characterIndex = -1;
|
||||||
SetNextScene(SceneList::MAINMENU);
|
SetNextScene(SceneList::MAINMENU);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::HandlePlayerNew(NetworkPacket packet) {
|
void InWorld::HandleRegionContent(SerialPacket packet) {
|
||||||
if (playerCharacters.find(packet.playerInfo.playerIndex) != playerCharacters.end()) {
|
//replace existing regions
|
||||||
throw(std::runtime_error("Cannot create duplicate players"));
|
if (regionPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
|
||||||
}
|
regionPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y);
|
||||||
|
|
||||||
playerCharacters[packet.playerInfo.playerIndex].GetSprite()->LoadSurface(config["dir.sprites"] + packet.playerInfo.avatar, 4, 4);
|
|
||||||
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position);
|
|
||||||
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion);
|
|
||||||
playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
|
|
||||||
|
|
||||||
//catch this client's player object
|
|
||||||
if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) {
|
|
||||||
playerIndex = packet.playerInfo.playerIndex;
|
|
||||||
localCharacter = &playerCharacters[playerIndex];
|
|
||||||
}
|
}
|
||||||
|
regionPager.PushRegion(packet.regionInfo.region);
|
||||||
|
packet.regionInfo.region = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::HandlePlayerDelete(NetworkPacket packet) {
|
void InWorld::HandleCharacterUpdate(SerialPacket packet) {
|
||||||
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
|
if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
|
||||||
throw(std::runtime_error("Cannot delete non-existant players"));
|
HandleCharacterNew(packet);
|
||||||
}
|
|
||||||
|
|
||||||
playerCharacters.erase(packet.playerInfo.playerIndex);
|
|
||||||
|
|
||||||
//catch this client's player object
|
|
||||||
if (packet.playerInfo.clientIndex == clientIndex) {
|
|
||||||
playerIndex = -1;
|
|
||||||
localCharacter = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InWorld::HandlePlayerUpdate(NetworkPacket packet) {
|
|
||||||
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
|
|
||||||
HandlePlayerNew(packet);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//update only if the message didn't originate from here
|
//update only if the message didn't originate from here
|
||||||
if (packet.playerInfo.clientIndex != clientIndex) {
|
if (packet.characterInfo.clientIndex != clientIndex) {
|
||||||
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position);
|
playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
|
||||||
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion);
|
playerCharacters[packet.characterInfo.characterIndex].SetMotion(packet.characterInfo.motion);
|
||||||
}
|
}
|
||||||
playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
|
playerCharacters[packet.characterInfo.characterIndex].ResetDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::SendState() {
|
void InWorld::HandleCharacterNew(SerialPacket packet) {
|
||||||
NetworkPacket packet;
|
if (playerCharacters.find(packet.characterInfo.characterIndex) != playerCharacters.end()) {
|
||||||
packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
|
throw(std::runtime_error("Cannot create duplicate characters"));
|
||||||
packet.playerInfo.clientIndex = clientIndex;
|
}
|
||||||
packet.playerInfo.playerIndex = playerIndex;
|
|
||||||
// snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str());
|
|
||||||
// snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str());
|
|
||||||
packet.playerInfo.position = localCharacter->GetPosition();
|
|
||||||
packet.playerInfo.motion = localCharacter->GetMotion();
|
|
||||||
|
|
||||||
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
|
//TODO: set the player's handle
|
||||||
|
playerCharacters[packet.characterInfo.characterIndex].GetSprite()->LoadSurface(config["dir.sprites"] + packet.characterInfo.avatar, 4, 4);
|
||||||
|
playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
|
||||||
|
playerCharacters[packet.characterInfo.characterIndex].SetMotion(packet.characterInfo.motion);
|
||||||
|
playerCharacters[packet.characterInfo.characterIndex].ResetDirection();
|
||||||
|
|
||||||
|
//catch this client's player object
|
||||||
|
if (packet.characterInfo.characterIndex == characterIndex && !localCharacter) {
|
||||||
|
localCharacter = &playerCharacters[characterIndex];
|
||||||
|
|
||||||
|
//setup the camera
|
||||||
|
camera.width = GetScreen()->w;
|
||||||
|
camera.height = GetScreen()->h;
|
||||||
|
//center on the player's character
|
||||||
|
camera.marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
|
||||||
|
camera.marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::HandleCharacterDelete(SerialPacket packet) {
|
||||||
|
//TODO: authenticate
|
||||||
|
if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
|
||||||
|
throw(std::runtime_error("Cannot delete non-existant characters"));
|
||||||
|
}
|
||||||
|
|
||||||
|
playerCharacters.erase(packet.characterInfo.characterIndex);
|
||||||
|
|
||||||
|
//catch this client's player object
|
||||||
|
if (packet.characterInfo.characterIndex == characterIndex) {
|
||||||
|
characterIndex = -1;
|
||||||
|
localCharacter = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Server control
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void InWorld::SendPlayerUpdate() {
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
|
//pack the packet
|
||||||
|
packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
|
||||||
|
packet.characterInfo.clientIndex = clientIndex;
|
||||||
|
packet.characterInfo.accountIndex = accountIndex;
|
||||||
|
packet.characterInfo.characterIndex = characterIndex;
|
||||||
|
packet.characterInfo.position = localCharacter->GetPosition();
|
||||||
|
packet.characterInfo.motion = localCharacter->GetMotion();
|
||||||
|
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::RequestDisconnect() {
|
void InWorld::RequestDisconnect() {
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
//send a disconnect request
|
//send a disconnect request
|
||||||
NetworkPacket packet;
|
packet.meta.type = SerialPacket::Type::DISCONNECT;
|
||||||
packet.meta.type = NetworkPacket::Type::DISCONNECT;
|
packet.clientInfo.clientIndex = clientIndex;
|
||||||
packet.clientInfo.index = clientIndex;
|
packet.clientInfo.accountIndex = accountIndex;
|
||||||
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
|
packet.clientInfo.characterIndex = characterIndex;
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InWorld::RequestShutDown() {
|
void InWorld::RequestShutDown() {
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
//send a shutdown request
|
//send a shutdown request
|
||||||
NetworkPacket packet;
|
packet.meta.type = SerialPacket::Type::SHUTDOWN;
|
||||||
packet.meta.type = NetworkPacket::Type::SHUTDOWN;
|
packet.clientInfo.clientIndex = clientIndex;
|
||||||
packet.clientInfo.index = clientIndex;
|
packet.clientInfo.accountIndex = accountIndex;
|
||||||
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
|
packet.clientInfo.characterIndex = characterIndex;
|
||||||
}
|
serialize(&packet, buffer);
|
||||||
|
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InWorld::RequestRegion(int mapIndex, int x, int y) {
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
|
//pack the region's data
|
||||||
|
packet.meta.type = SerialPacket::Type::REGION_REQUEST;
|
||||||
|
packet.regionInfo.mapIndex = mapIndex;
|
||||||
|
packet.regionInfo.x = x;
|
||||||
|
packet.regionInfo.y = y;
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Utilities
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//TODO: convert this into a more generic function?; using parameters for the bounds
|
||||||
|
void InWorld::UpdateMap() {
|
||||||
|
//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
|
||||||
|
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
|
||||||
|
//check if the region is outside off this area
|
||||||
|
if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) {
|
||||||
|
|
||||||
|
//clunky, but the alternative was time consuming
|
||||||
|
int tmpX = (*it)->GetX();
|
||||||
|
int tmpY = (*it)->GetY();
|
||||||
|
++it;
|
||||||
|
|
||||||
|
regionPager.UnloadRegion(tmpX, tmpY);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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)) {
|
||||||
|
RequestRegion(0, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+53
-14
@@ -22,22 +22,37 @@
|
|||||||
#ifndef INWORLD_HPP_
|
#ifndef INWORLD_HPP_
|
||||||
#define INWORLD_HPP_
|
#define INWORLD_HPP_
|
||||||
|
|
||||||
#include "base_scene.hpp"
|
//maps
|
||||||
|
#include "map_allocator.hpp"
|
||||||
|
#include "map_file_format.hpp"
|
||||||
|
#include "region_pager.hpp"
|
||||||
|
|
||||||
#include "config_utility.hpp"
|
//networking
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
#include "network_packet.hpp"
|
#include "serial_packet.hpp"
|
||||||
|
#include "serial.hpp"
|
||||||
|
|
||||||
|
//graphics
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
#include "raster_font.hpp"
|
#include "raster_font.hpp"
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
|
#include "tile_sheet.hpp"
|
||||||
|
|
||||||
|
//common
|
||||||
|
#include "config_utility.hpp"
|
||||||
|
#include "frame_rate.hpp"
|
||||||
|
|
||||||
|
//client
|
||||||
|
#include "base_scene.hpp"
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
|
|
||||||
|
//STL
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class InWorld : public BaseScene {
|
class InWorld : public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
InWorld(ConfigUtility* const, UDPNetworkUtility* const, int* const);
|
InWorld(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const, int* const);
|
||||||
~InWorld();
|
~InWorld();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -45,6 +60,7 @@ protected:
|
|||||||
void FrameStart();
|
void FrameStart();
|
||||||
void Update(double delta);
|
void Update(double delta);
|
||||||
void FrameEnd();
|
void FrameEnd();
|
||||||
|
void RenderFrame();
|
||||||
void Render(SDL_Surface* const);
|
void Render(SDL_Surface* const);
|
||||||
|
|
||||||
//Event handlers
|
//Event handlers
|
||||||
@@ -55,29 +71,52 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
void HandlePacket(NetworkPacket);
|
//Network handlers
|
||||||
void HandleDisconnect(NetworkPacket);
|
void HandlePacket(SerialPacket);
|
||||||
void HandlePlayerNew(NetworkPacket);
|
void HandleDisconnect(SerialPacket);
|
||||||
void HandlePlayerDelete(NetworkPacket);
|
void HandleCharacterNew(SerialPacket);
|
||||||
void HandlePlayerUpdate(NetworkPacket);
|
void HandleCharacterDelete(SerialPacket);
|
||||||
|
void HandleCharacterUpdate(SerialPacket);
|
||||||
|
void HandleRegionContent(SerialPacket);
|
||||||
|
|
||||||
void SendState();
|
//Server control
|
||||||
|
void SendPlayerUpdate();
|
||||||
void RequestDisconnect();
|
void RequestDisconnect();
|
||||||
void RequestShutDown();
|
void RequestShutDown();
|
||||||
|
void RequestRegion(int mapIndex, int x, int y);
|
||||||
|
|
||||||
//global
|
//utilities
|
||||||
|
void UpdateMap();
|
||||||
|
|
||||||
|
//shared parameters
|
||||||
ConfigUtility& config;
|
ConfigUtility& config;
|
||||||
UDPNetworkUtility& network;
|
UDPNetworkUtility& network;
|
||||||
int& clientIndex;
|
int& clientIndex;
|
||||||
|
int& accountIndex;
|
||||||
|
int& characterIndex;
|
||||||
|
|
||||||
//members
|
//graphics
|
||||||
Image image;
|
Image buttonImage;
|
||||||
RasterFont font;
|
RasterFont font;
|
||||||
|
TileSheet tileSheet;
|
||||||
|
|
||||||
|
//map
|
||||||
|
RegionPager<BlankAllocator, DummyFormat> regionPager;
|
||||||
|
|
||||||
|
//UI
|
||||||
Button disconnectButton;
|
Button disconnectButton;
|
||||||
Button shutDownButton;
|
Button shutDownButton;
|
||||||
|
//TODO: Fix the camera
|
||||||
|
struct {
|
||||||
|
int x = 0, y = 0;
|
||||||
|
int width = 0, height = 0;
|
||||||
|
int marginX = 0, marginY = 0;
|
||||||
|
} camera;
|
||||||
|
FrameRate fps;
|
||||||
|
|
||||||
|
//game
|
||||||
std::map<int, PlayerCharacter> playerCharacters;
|
std::map<int, PlayerCharacter> playerCharacters;
|
||||||
PlayerCharacter* localCharacter = nullptr;
|
PlayerCharacter* localCharacter = nullptr;
|
||||||
int playerIndex = -1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "lobby_menu.hpp"
|
#include "lobby_menu.hpp"
|
||||||
|
|
||||||
#include "channels.hpp"
|
#include "channels.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@@ -29,10 +30,12 @@
|
|||||||
//Public access members
|
//Public access members
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
|
||||||
LobbyMenu::LobbyMenu(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex):
|
LobbyMenu::LobbyMenu(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, int* const argAccountIndex, int* const argCharacterIndex):
|
||||||
config(*argConfig),
|
config(*argConfig),
|
||||||
network(*argNetwork),
|
network(*argNetwork),
|
||||||
clientIndex(*argClientIndex)
|
clientIndex(*argClientIndex),
|
||||||
|
accountIndex(*argAccountIndex),
|
||||||
|
characterIndex(*argCharacterIndex)
|
||||||
{
|
{
|
||||||
//setup the utility objects
|
//setup the utility objects
|
||||||
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
||||||
@@ -78,9 +81,9 @@ void LobbyMenu::FrameStart() {
|
|||||||
|
|
||||||
void LobbyMenu::Update(double delta) {
|
void LobbyMenu::Update(double delta) {
|
||||||
//suck in all waiting packets
|
//suck in all waiting packets
|
||||||
NetworkPacket packet;
|
SerialPacket packet;
|
||||||
while(network.Receive()) {
|
while(network.Receive()) {
|
||||||
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
|
deserialize(&packet, network.GetInData());
|
||||||
packet.meta.srcAddress = network.GetInPacket()->address;
|
packet.meta.srcAddress = network.GetInPacket()->address;
|
||||||
HandlePacket(packet);
|
HandlePacket(packet);
|
||||||
}
|
}
|
||||||
@@ -91,9 +94,13 @@ void LobbyMenu::FrameEnd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::Render(SDL_Surface* const screen) {
|
void LobbyMenu::Render(SDL_Surface* const screen) {
|
||||||
|
//TODO: I need a proper UI system for the entire client and the editor
|
||||||
|
//UI
|
||||||
search.DrawTo(screen);
|
search.DrawTo(screen);
|
||||||
join.DrawTo(screen);
|
join.DrawTo(screen);
|
||||||
back.DrawTo(screen);
|
back.DrawTo(screen);
|
||||||
|
|
||||||
|
//TODO: draw headers for the server list
|
||||||
for (int i = 0; i < serverInfo.size(); i++) {
|
for (int i = 0; i < serverInfo.size(); i++) {
|
||||||
//draw the selected server's highlight
|
//draw the selected server's highlight
|
||||||
if (selection == &serverInfo[i]) {
|
if (selection == &serverInfo[i]) {
|
||||||
@@ -104,6 +111,16 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
|
|||||||
|
|
||||||
//draw the server name
|
//draw the server name
|
||||||
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
|
||||||
|
|
||||||
|
//draw the player count
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ping?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,21 +142,34 @@ void LobbyMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|||||||
|
|
||||||
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
||||||
if (search.MouseButtonUp(button) == Button::State::HOVER) {
|
if (search.MouseButtonUp(button) == Button::State::HOVER) {
|
||||||
|
//the vars
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
//broadcast to the network, or a specific server
|
//broadcast to the network, or a specific server
|
||||||
NetworkPacket packet;
|
packet.meta.type = SerialPacket::Type::BROADCAST_REQUEST;
|
||||||
packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST;
|
serialize(&packet, buffer);
|
||||||
network.Send(config["server.host"].c_str(), config.Int("server.port"), reinterpret_cast<void*>(&packet), sizeof(NetworkPacket));
|
network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE);
|
||||||
|
|
||||||
//reset the server list
|
//reset the server list
|
||||||
serverInfo.clear();
|
serverInfo.clear();
|
||||||
selection = nullptr;
|
selection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) {
|
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) {
|
||||||
|
//the vars
|
||||||
|
SerialPacket packet;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
|
//pack the packet
|
||||||
|
packet.meta.type = SerialPacket::Type::JOIN_REQUEST;
|
||||||
|
strncpy(packet.clientInfo.username, config["client.username"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(packet.clientInfo.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(packet.clientInfo.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
||||||
|
|
||||||
//join the selected server
|
//join the selected server
|
||||||
NetworkPacket packet;
|
serialize(&packet, buffer);
|
||||||
packet.meta.type = NetworkPacket::Type::JOIN_REQUEST;
|
network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
|
||||||
network.Send(&selection->address, &packet, sizeof(NetworkPacket));
|
|
||||||
selection = nullptr;
|
selection = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,24 +203,34 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
void LobbyMenu::HandlePacket(NetworkPacket packet) {
|
void LobbyMenu::HandlePacket(SerialPacket packet) {
|
||||||
switch(packet.meta.type) {
|
switch(packet.meta.type) {
|
||||||
case NetworkPacket::Type::BROADCAST_RESPONSE: {
|
case SerialPacket::Type::BROADCAST_RESPONSE: {
|
||||||
|
//extract the data
|
||||||
ServerInformation server;
|
ServerInformation server;
|
||||||
server.name = packet.serverInfo.name;
|
|
||||||
server.address = packet.meta.srcAddress;
|
server.address = packet.meta.srcAddress;
|
||||||
|
server.networkVersion = packet.serverInfo.networkVersion;
|
||||||
|
server.name = packet.serverInfo.name;
|
||||||
|
server.playerCount = packet.serverInfo.playerCount;
|
||||||
|
|
||||||
|
//NOTE: Check compatibility here
|
||||||
|
server.compatible = server.networkVersion == NETWORK_VERSION;
|
||||||
|
|
||||||
|
//push
|
||||||
serverInfo.push_back(server);
|
serverInfo.push_back(server);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NetworkPacket::Type::JOIN_RESPONSE:
|
case SerialPacket::Type::JOIN_RESPONSE:
|
||||||
clientIndex = packet.clientInfo.index;
|
clientIndex = packet.clientInfo.clientIndex;
|
||||||
|
accountIndex = packet.clientInfo.accountIndex;
|
||||||
|
characterIndex = packet.clientInfo.characterIndex;
|
||||||
network.Bind(&packet.meta.srcAddress, Channels::SERVER);
|
network.Bind(&packet.meta.srcAddress, Channels::SERVER);
|
||||||
SetNextScene(SceneList::INWORLD);
|
SetNextScene(SceneList::INWORLD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//handle errors
|
//handle errors
|
||||||
default:
|
default:
|
||||||
throw(std::runtime_error("Unknown NetworkPacket::Type encountered"));
|
throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in LobbyMenu: " + to_string_custom(int(packet.meta.type))));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,22 +22,27 @@
|
|||||||
#ifndef LOBBYMENU_HPP_
|
#ifndef LOBBYMENU_HPP_
|
||||||
#define LOBBYMENU_HPP_
|
#define LOBBYMENU_HPP_
|
||||||
|
|
||||||
#include "base_scene.hpp"
|
//graphics & utilities
|
||||||
|
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
#include "raster_font.hpp"
|
#include "raster_font.hpp"
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
|
|
||||||
#include "config_utility.hpp"
|
#include "config_utility.hpp"
|
||||||
#include "udp_network_utility.hpp"
|
|
||||||
#include "network_packet.hpp"
|
|
||||||
|
|
||||||
|
//network
|
||||||
|
#include "udp_network_utility.hpp"
|
||||||
|
#include "serial_packet.hpp"
|
||||||
|
#include "serial.hpp"
|
||||||
|
|
||||||
|
//client
|
||||||
|
#include "base_scene.hpp"
|
||||||
|
|
||||||
|
//STL
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class LobbyMenu : public BaseScene {
|
class LobbyMenu : public BaseScene {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
//Public access members
|
||||||
LobbyMenu(ConfigUtility* const, UDPNetworkUtility* const, int* const);
|
LobbyMenu(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const, int* const);
|
||||||
~LobbyMenu();
|
~LobbyMenu();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -54,12 +59,14 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
void HandlePacket(NetworkPacket);
|
void HandlePacket(SerialPacket);
|
||||||
|
|
||||||
//global
|
//shared parameters
|
||||||
ConfigUtility& config;
|
ConfigUtility& config;
|
||||||
UDPNetworkUtility& network;
|
UDPNetworkUtility& network;
|
||||||
int& clientIndex;
|
int& clientIndex;
|
||||||
|
int& accountIndex;
|
||||||
|
int& characterIndex;
|
||||||
|
|
||||||
//members
|
//members
|
||||||
Image image;
|
Image image;
|
||||||
@@ -70,8 +77,11 @@ protected:
|
|||||||
|
|
||||||
//server list
|
//server list
|
||||||
struct ServerInformation {
|
struct ServerInformation {
|
||||||
std::string name;
|
|
||||||
IPaddress address;
|
IPaddress address;
|
||||||
|
int networkVersion;
|
||||||
|
std::string name;
|
||||||
|
int playerCount;
|
||||||
|
bool compatible;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<ServerInformation> serverInfo;
|
std::vector<ServerInformation> serverInfo;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
//globals
|
//shared parameters
|
||||||
ConfigUtility& config;
|
ConfigUtility& config;
|
||||||
|
|
||||||
//members
|
//members
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ protected:
|
|||||||
void KeyDown(SDL_KeyboardEvent const&);
|
void KeyDown(SDL_KeyboardEvent const&);
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
void KeyUp(SDL_KeyboardEvent const&);
|
||||||
|
|
||||||
//globals
|
//shared parameters
|
||||||
ConfigUtility& config;
|
ConfigUtility& config;
|
||||||
|
|
||||||
//members
|
//members
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ protected:
|
|||||||
void Update(double delta);
|
void Update(double delta);
|
||||||
void Render(SDL_Surface* const);
|
void Render(SDL_Surface* const);
|
||||||
|
|
||||||
//globals
|
//shared parameters
|
||||||
ConfigUtility& config;
|
ConfigUtility& config;
|
||||||
|
|
||||||
//members
|
//members
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013, 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#ifndef BBOX_HPP_
|
||||||
|
#define BBOX_HPP_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
//TODO: This is supposed to interact with the vector
|
||||||
|
class BBox {
|
||||||
|
public:
|
||||||
|
double x, y;
|
||||||
|
double w, h;
|
||||||
|
|
||||||
|
BBox() = default;
|
||||||
|
BBox(double i, double j, double k, double l): x(i), y(j), w(k), h(l) {};
|
||||||
|
~BBox() = default;
|
||||||
|
BBox& operator=(BBox const&) = default;
|
||||||
|
|
||||||
|
double Size() {
|
||||||
|
return std::max(w*h,0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCollision(BBox rhs) {
|
||||||
|
return not (
|
||||||
|
x >= rhs.x + rhs.w ||
|
||||||
|
y >= rhs.y + rhs.h ||
|
||||||
|
rhs.x >= x + w ||
|
||||||
|
rhs.y >= y + h
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BBox Intersection(BBox rhs) {
|
||||||
|
if (!IsCollision(rhs)) {
|
||||||
|
return {0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
BBox ret;
|
||||||
|
ret.x = std::max(x, rhs.x);
|
||||||
|
ret.y = std::max(y, rhs.y);
|
||||||
|
ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x;
|
||||||
|
ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
double operator[](size_t i) {
|
||||||
|
if (i >= 4)
|
||||||
|
throw(std::domain_error("Out of range"));
|
||||||
|
return *(&x+i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//This is explicitly a POD
|
||||||
|
static_assert(std::is_pod<BBox>::value, "BBox is not a POD");
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,35 +19,30 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef EDITORAPPLICATION_HPP_
|
#ifndef FRAMERATE_HPP_
|
||||||
#define EDITORAPPLICATION_HPP_
|
#define FRAMERATE_HPP_
|
||||||
|
|
||||||
#include "scene_list.hpp"
|
#include <chrono>
|
||||||
#include "base_scene.hpp"
|
|
||||||
#include "config_utility.hpp"
|
|
||||||
|
|
||||||
class EditorApplication {
|
|
||||||
private:
|
|
||||||
EditorApplication();
|
|
||||||
~EditorApplication();
|
|
||||||
static EditorApplication instance;
|
|
||||||
|
|
||||||
|
class FrameRate {
|
||||||
public:
|
public:
|
||||||
static EditorApplication* GetInstance() { return &instance; }
|
typedef std::chrono::high_resolution_clock Clock;
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Proc();
|
|
||||||
void Quit();
|
|
||||||
|
|
||||||
|
FrameRate() = default;
|
||||||
|
int Calculate() {
|
||||||
|
frameCount++;
|
||||||
|
if (Clock::now() - tick >= std::chrono::duration<int>(1)) {
|
||||||
|
lastFrameRate = frameCount;
|
||||||
|
frameCount = 0;
|
||||||
|
tick = Clock::now();
|
||||||
|
}
|
||||||
|
return lastFrameRate;
|
||||||
|
}
|
||||||
|
int GetFrameRate() { return lastFrameRate; }
|
||||||
private:
|
private:
|
||||||
//Private access members
|
int frameCount = 0;
|
||||||
void LoadScene(SceneList sceneIndex);
|
int lastFrameRate = 0;
|
||||||
void UnloadScene();
|
Clock::time_point tick = Clock::now();
|
||||||
|
|
||||||
//globals
|
|
||||||
ConfigUtility config;
|
|
||||||
|
|
||||||
BaseScene* activeScene = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ..
|
INCLUDES+=. .. ../map
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "tile_sheet.hpp"
|
||||||
|
|
||||||
|
void TileSheet::Load(std::string fname, int xc, int yc) {
|
||||||
|
XCount = xc;
|
||||||
|
YCount = yc;
|
||||||
|
image.LoadSurface(fname);
|
||||||
|
image.SetClipW(image.GetClipW()/XCount);
|
||||||
|
image.SetClipH(image.GetClipH()/YCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSheet::Unload() {
|
||||||
|
image.FreeSurface();
|
||||||
|
XCount = YCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile) {
|
||||||
|
//0 is invisible
|
||||||
|
if (tile == 0) return;
|
||||||
|
image.SetClipX((tile-1) % XCount * image.GetClipW());
|
||||||
|
image.SetClipY((tile-1) / XCount * image.GetClipH());
|
||||||
|
image.DrawTo(dest, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) {
|
||||||
|
Region::type_t tile = 0;
|
||||||
|
for (register int i = 0; i < REGION_WIDTH; ++i) {
|
||||||
|
for (register int j = 0; j < REGION_HEIGHT; ++j) {
|
||||||
|
for (register int k = 0; k < REGION_DEPTH; ++k) {
|
||||||
|
tile = region->GetTile(i, j, k);
|
||||||
|
//0 is invisible
|
||||||
|
if (tile == 0) continue;
|
||||||
|
image.SetClipX((tile-1) % XCount * image.GetClipW());
|
||||||
|
image.SetClipY((tile-1) / XCount * image.GetClipH());
|
||||||
|
image.DrawTo(dest,
|
||||||
|
(region->GetX() + i) * image.GetClipW() - camX,
|
||||||
|
(region->GetY() + j) * image.GetClipH() - camY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,33 +19,36 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef TILESHEETMANAGER_HPP_
|
#ifndef TILESHEET_HPP_
|
||||||
#define TILESHEETMANAGER_HPP_
|
#define TILESHEET_HPP_
|
||||||
|
|
||||||
#include "tile_sheet.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class TileSheetManager {
|
class TileSheet {
|
||||||
public:
|
public:
|
||||||
TileSheetManager() = default;
|
TileSheet() = default;
|
||||||
~TileSheetManager() = default;
|
TileSheet(std::string f, int x, int y) { Load(f, x, y); }
|
||||||
|
~TileSheet() = default;
|
||||||
|
|
||||||
TileSheet* LoadSheet(std::string fname, Uint16 w, Uint16 h);
|
void Load(std::string fname, int XCount, int YCount);
|
||||||
TileSheet* GetSheet(std::string name);
|
void Unload();
|
||||||
TileSheet* GetSheetByIndex(int tileIndex);
|
|
||||||
void UnloadSheet(std::string name);
|
|
||||||
|
|
||||||
void DrawTo(SDL_Surface* const, int x, int y, int tileIndex);
|
void DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile);
|
||||||
|
void DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY);
|
||||||
|
|
||||||
int SetRangeEnd(int i) { return rangeEnd += i; }
|
//accessors
|
||||||
int GetRangeEnd() const { return rangeEnd; }
|
Image* GetImage() { return ℑ }
|
||||||
|
int GetXCount() { return XCount; }
|
||||||
std::map<std::string, TileSheet>* GetSheetMap() { return &sheetMap; }
|
int GetYCount() { return YCount; }
|
||||||
|
int GetTileW() { return image.GetClipW(); }
|
||||||
|
int GetTileH() { return image.GetClipH(); }
|
||||||
private:
|
private:
|
||||||
std::map<std::string, TileSheet> sheetMap;
|
Image image;
|
||||||
int rangeEnd = 0;
|
int XCount = 0, YCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -22,6 +22,7 @@ all: $(OBJ) $(OUT)
|
|||||||
ar -crs $(OUT) $(OBJ)
|
ar -crs $(OUT) $(OBJ)
|
||||||
$(MAKE) -C graphics
|
$(MAKE) -C graphics
|
||||||
$(MAKE) -C map
|
$(MAKE) -C map
|
||||||
|
$(MAKE) -C script
|
||||||
$(MAKE) -C network
|
$(MAKE) -C network
|
||||||
$(MAKE) -C ui
|
$(MAKE) -C ui
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "map_allocator.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
void BlankAllocator::Create(Region** const ptr, int x, int y) {
|
||||||
|
(*ptr) = new Region(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlankAllocator::Unload(Region* const ptr) {
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaAllocator::Create(Region** const ptr, int x, int y) {
|
||||||
|
//something to work on
|
||||||
|
(*ptr) = new Region(x, y);
|
||||||
|
|
||||||
|
//API hook
|
||||||
|
lua_getglobal(state, "map");
|
||||||
|
lua_getfield(state, -1, "create");
|
||||||
|
lua_pushlightuserdata(state, *ptr);
|
||||||
|
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
|
||||||
|
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
|
||||||
|
}
|
||||||
|
lua_pop(state, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaAllocator::Unload(Region* const ptr) {
|
||||||
|
//API hook
|
||||||
|
lua_getglobal(state, "map");
|
||||||
|
lua_getfield(state, -1, "unload");
|
||||||
|
lua_pushlightuserdata(state, ptr);
|
||||||
|
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
|
||||||
|
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
|
||||||
|
}
|
||||||
|
lua_pop(state, 1);
|
||||||
|
|
||||||
|
//clean up the memory
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#ifndef MAPALLOCATOR_HPP_
|
||||||
|
#define MAPALLOCATOR_HPP_
|
||||||
|
|
||||||
|
#include "region.hpp"
|
||||||
|
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
class BlankAllocator {
|
||||||
|
public:
|
||||||
|
void Create(Region** const, int x, int y);
|
||||||
|
void Unload(Region* const);
|
||||||
|
private:
|
||||||
|
//
|
||||||
|
};
|
||||||
|
|
||||||
|
class LuaAllocator {
|
||||||
|
public:
|
||||||
|
void Create(Region** const, int x, int y);
|
||||||
|
void Unload(Region* const);
|
||||||
|
|
||||||
|
lua_State* SetLuaState(lua_State* L) { return state = L; }
|
||||||
|
lua_State* GetLuaState() { return state; }
|
||||||
|
private:
|
||||||
|
lua_State* state = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "map_file_format.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
void DummyFormat::Load(Region** const ptr, int x, int y) {
|
||||||
|
//EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
void DummyFormat::Save(Region* const ptr) {
|
||||||
|
//EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaFormat::Load(Region** const ptr, int x, int y) {
|
||||||
|
//something to load into
|
||||||
|
|
||||||
|
if (!(*ptr)) {
|
||||||
|
(*ptr) = new Region(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//API hook
|
||||||
|
lua_getglobal(state, "map");
|
||||||
|
lua_getfield(state, -1, "load");
|
||||||
|
lua_pushlightuserdata(state, *ptr);
|
||||||
|
lua_pushstring(state, saveDir.c_str());
|
||||||
|
if (lua_pcall(state, 2, 1, 0) != LUA_OK) {
|
||||||
|
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
|
||||||
|
}
|
||||||
|
if (lua_toboolean(state, -1) == false) {
|
||||||
|
delete (*ptr);
|
||||||
|
(*ptr) = nullptr;
|
||||||
|
}
|
||||||
|
lua_pop(state, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaFormat::Save(Region* const ptr) {
|
||||||
|
//API hook
|
||||||
|
lua_getglobal(state, "map");
|
||||||
|
lua_getfield(state, -1, "save");
|
||||||
|
lua_pushlightuserdata(state, ptr);
|
||||||
|
lua_pushstring(state, saveDir.c_str());
|
||||||
|
if (lua_pcall(state, 2, 0, 0) != LUA_OK) {
|
||||||
|
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
|
||||||
|
}
|
||||||
|
lua_pop(state, 1);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,41 +19,42 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef TESTIFICATESCENE_HPP_
|
#ifndef MAPFILEFORMAT_HPP_
|
||||||
#define TESTIFICATESCENE_HPP_
|
#define MAPFILEFORMAT_HPP_
|
||||||
|
|
||||||
#include "base_scene.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
#include "config_utility.hpp"
|
#include "lua/lua.hpp"
|
||||||
#include "tile_Sheet_manager.hpp"
|
|
||||||
#include "region_pager.hpp"
|
|
||||||
|
|
||||||
class TestificateScene : public BaseScene {
|
#include <string>
|
||||||
|
|
||||||
|
class DummyFormat {
|
||||||
public:
|
public:
|
||||||
//Public access members
|
void Load(Region** const, int x, int y);
|
||||||
TestificateScene(ConfigUtility* const);
|
void Save(Region* const);
|
||||||
~TestificateScene();
|
|
||||||
|
|
||||||
protected:
|
std::string SetSaveDir(std::string s) { return saveDir = s; }
|
||||||
//Frame loop
|
std::string GetSaveDir() { return saveDir; }
|
||||||
void FrameStart();
|
private:
|
||||||
void Update(double delta);
|
std::string saveDir;
|
||||||
void FrameEnd();
|
};
|
||||||
void Render(SDL_Surface* const);
|
|
||||||
|
|
||||||
//Event handlers
|
//TODO: verbose save file format
|
||||||
void MouseMotion(SDL_MouseMotionEvent const&);
|
//TODO: compact save file format
|
||||||
void MouseButtonDown(SDL_MouseButtonEvent const&);
|
|
||||||
void MouseButtonUp(SDL_MouseButtonEvent const&);
|
|
||||||
void KeyDown(SDL_KeyboardEvent const&);
|
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
|
||||||
|
|
||||||
//globals
|
class LuaFormat {
|
||||||
ConfigUtility& config;
|
public:
|
||||||
|
void Load(Region** const, int x, int y);
|
||||||
|
void Save(Region* const);
|
||||||
|
|
||||||
//members
|
std::string SetSaveDir(std::string s) { return saveDir = s; }
|
||||||
TileSheetManager sheetMgr;
|
std::string GetSaveDir() { return saveDir; }
|
||||||
RegionPager pager;
|
|
||||||
|
lua_State* SetLuaState(lua_State* L) { return state = L; }
|
||||||
|
lua_State* GetLuaState() { return state; }
|
||||||
|
private:
|
||||||
|
std::string saveDir;
|
||||||
|
lua_State* state = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+10
-94
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -21,103 +21,19 @@
|
|||||||
*/
|
*/
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
|
|
||||||
#include "utility.hpp"
|
Region::Region(int argX, int argY):
|
||||||
|
x(argX),
|
||||||
#include <stdexcept>
|
y(argY)
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
Region::Region(int _x, int _y, int _w, int _h):
|
|
||||||
x(_x),
|
|
||||||
y(_y),
|
|
||||||
width(_w),
|
|
||||||
height(_h)
|
|
||||||
{
|
{
|
||||||
//make sure that the region's position lines up
|
for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) {
|
||||||
if (x != snapToBase(width, x) || y != snapToBase(height, y)) {
|
*(reinterpret_cast<type_t*>(tiles) + i) = 0;
|
||||||
std::ostringstream os;
|
|
||||||
os << "Region is unaligned; x: " << x << ", y: " << y << ", width: " << width << ", height: " << height;
|
|
||||||
throw(std::runtime_error(os.str()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Region::NewTileR(Tile const& tile) {
|
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
|
||||||
//return 1 for overwrite, 0 for insert
|
return tiles[x][y][z] = v;
|
||||||
if (!InBoundsR(tile.x, tile.y)) {
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "New tile location out of bounds: " <<
|
|
||||||
"(" << x << "," << y << ")->" <<
|
|
||||||
"(" << tile.x << "," << tile.y << ")"
|
|
||||||
;
|
|
||||||
throw(std::runtime_error(os.str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = tiles.erase(tile);
|
|
||||||
tiles.insert(tile);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile Region::GetTileR(int tx, int ty, int minDepth) {
|
Region::type_t Region::GetTile(int x, int y, int z) {
|
||||||
std::set<Tile>::iterator ptr = tiles.begin();
|
return tiles[x][y][z];
|
||||||
|
|
||||||
//skip the tiles that are too deep
|
|
||||||
while(ptr != tiles.end()) {
|
|
||||||
if (ptr->depth >= minDepth) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//find the first tile here
|
|
||||||
while(ptr != tiles.end()) {
|
|
||||||
//bounds
|
|
||||||
if ((ptr->x <= tx) && (ptr->y <= ty) && (ptr->x + ptr->width > tx) && (ptr->y + ptr->height > ty)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//found it
|
|
||||||
if (ptr != tiles.end()) {
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//a tileIndex of -1 is an error code, the rest is for show
|
|
||||||
return {0,0,0,-1,-1,-1};
|
|
||||||
}
|
|
||||||
|
|
||||||
int Region::DeleteTileR(Tile const& tile) {
|
|
||||||
if (!InBoundsR(tile.x, tile.y)) {
|
|
||||||
throw(std::runtime_error("Deleted tile location out of bounds"));
|
|
||||||
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "Deleted tile location out of bounds: " <<
|
|
||||||
"(" << x << "," << y << ")->" <<
|
|
||||||
"(" << tile.x << "," << tile.y << ")"
|
|
||||||
;
|
|
||||||
throw(std::runtime_error(os.str()));
|
|
||||||
}
|
|
||||||
//sentinel/error code
|
|
||||||
if (tile.tileIndex == -1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return tiles.erase(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(Region const& lhs, Region const& rhs) {
|
|
||||||
//sort by y -> x
|
|
||||||
if (lhs.y == rhs.y) {
|
|
||||||
return lhs.x < rhs.x;
|
|
||||||
}
|
|
||||||
return lhs.y < rhs.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator>(Region const& lhs, Region const& rhs) {
|
|
||||||
//wrap the other operator
|
|
||||||
return rhs < lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator==(Region const& lhs, Region const& rhs) {
|
|
||||||
//comparisons work on the location ONLY
|
|
||||||
//this function is redundant as far as the std::set object is concerned
|
|
||||||
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-76
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -22,91 +22,29 @@
|
|||||||
#ifndef REGION_HPP_
|
#ifndef REGION_HPP_
|
||||||
#define REGION_HPP_
|
#define REGION_HPP_
|
||||||
|
|
||||||
#include "tile.hpp"
|
#define REGION_WIDTH 20
|
||||||
|
#define REGION_HEIGHT 20
|
||||||
|
#define REGION_DEPTH 3
|
||||||
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
/* A single section of the map.
|
|
||||||
* This class stores the tiles relative to it's own position, but
|
|
||||||
* there are functions for referencing the tiles' absolute position.
|
|
||||||
* These functions simply wrap the normal functions.
|
|
||||||
*/
|
|
||||||
class Region {
|
class Region {
|
||||||
public:
|
public:
|
||||||
|
typedef unsigned short type_t;
|
||||||
|
|
||||||
Region() = delete;
|
Region() = delete;
|
||||||
Region(int x, int y, int width, int height);
|
Region(int x, int y);
|
||||||
~Region() = default;
|
~Region() = default;
|
||||||
|
|
||||||
//create and insert a new tile, overwriting an existing tile at that location
|
type_t SetTile(int x, int y, int z, type_t v);
|
||||||
int NewTileR(Tile const& tile);
|
type_t GetTile(int x, int y, int z);
|
||||||
int NewTileA(Tile const& tile) {
|
|
||||||
//these can change, if the Tile class is changed
|
|
||||||
return NewTileR({
|
|
||||||
tile.x - x,
|
|
||||||
tile.y - y,
|
|
||||||
tile.depth,
|
|
||||||
tile.width,
|
|
||||||
tile.height,
|
|
||||||
tile.tileIndex
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//find the first tile at this location, with the specified minimum depth
|
//accessors
|
||||||
Tile GetTileR(int tx, int ty, int minDepth);
|
|
||||||
Tile GetTileA(int tx, int ty, int minDepth) {
|
|
||||||
return GetTileR(tx - x, ty - y, minDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
//wrap the other delete functions
|
|
||||||
int DeleteTileR(int tx, int ty, int minDepth) {
|
|
||||||
return DeleteTileR(GetTileR(tx, ty, minDepth));
|
|
||||||
}
|
|
||||||
int DeleteTileA(int tx, int ty, int minDepth) {
|
|
||||||
//explicitly skip one function call by adjusting from A to R
|
|
||||||
return DeleteTileR(GetTileR(tx - x, ty - y, minDepth));
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete the specified tile
|
|
||||||
int DeleteTileR(Tile const& tile);
|
|
||||||
int DeleteTileA(Tile const& tile) {
|
|
||||||
//these can change, if the Tile class is changed
|
|
||||||
return DeleteTileR({
|
|
||||||
tile.x - x,
|
|
||||||
tile.y - y,
|
|
||||||
tile.depth,
|
|
||||||
tile.width,
|
|
||||||
tile.height,
|
|
||||||
tile.tileIndex
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//find if the specified location exists within the region's bounds
|
|
||||||
bool InBoundsR(int i, int j) {
|
|
||||||
return (i >= 0) && (j >= 0) && (i < width) && (j < height);
|
|
||||||
}
|
|
||||||
bool InBoundsA(int i, int j) {
|
|
||||||
return InBoundsR(i - x, j - y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Raw accessors & mutators
|
|
||||||
int GetX() const { return x; }
|
int GetX() const { return x; }
|
||||||
int GetY() const { return y; }
|
int GetY() const { return y; }
|
||||||
int GetWidth() const { return width; }
|
|
||||||
int GetHeight() const { return height; }
|
|
||||||
|
|
||||||
std::set<Tile>* GetTiles() { return &tiles; }
|
|
||||||
|
|
||||||
//sorting the regions by the locations
|
|
||||||
friend bool operator<(Region const& lhs, Region const& rhs);
|
|
||||||
friend bool operator>(Region const& lhs, Region const& rhs);
|
|
||||||
friend bool operator==(Region const& lhs, Region const& rhs);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int const x;
|
const int x;
|
||||||
int const y;
|
const int y;
|
||||||
int const width;
|
|
||||||
int const height;
|
type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH];
|
||||||
std::set<Tile> tiles;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+37
-91
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,99 +23,45 @@
|
|||||||
|
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
|
||||||
#include <string>
|
Region* ptr = GetRegion(x, y);
|
||||||
|
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
|
||||||
RegionPager::RegionPager() {
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionPager::~RegionPager() {
|
Region::type_t RegionPagerBase::GetTile(int x, int y, int z) {
|
||||||
if (onDelete) {
|
Region* ptr = GetRegion(x, y);
|
||||||
for (auto& i : regionList) {
|
return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z);
|
||||||
onDelete(&i);
|
}
|
||||||
|
|
||||||
|
Region* RegionPagerBase::GetRegion(int x, int y) {
|
||||||
|
//snap the coords
|
||||||
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
|
//get the region by various means
|
||||||
|
Region* ptr = nullptr;
|
||||||
|
ptr = FindRegion(x, y);
|
||||||
|
if (ptr) return ptr;
|
||||||
|
ptr = LoadRegion(x, y);
|
||||||
|
if (ptr) return ptr;
|
||||||
|
return CreateRegion(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Region* RegionPagerBase::FindRegion(int x, int y) {
|
||||||
|
//snap the coords
|
||||||
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
|
//find the region
|
||||||
|
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) {
|
||||||
|
if ((*it)->GetX() == x && (*it)->GetY() == y) {
|
||||||
|
return *it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Region* RegionPager::NewRegion(int x, int y) {
|
Region* RegionPagerBase::PushRegion(Region* ptr) {
|
||||||
for (auto& i : regionList) {
|
regionList.push_front(ptr);
|
||||||
if (i.GetX() == x && i.GetY() == y) {
|
return regionList.front();
|
||||||
throw(std::runtime_error("Duplicate Regions detected"));
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regionList.push_front({x, y, regionWidth, regionHeight});
|
|
||||||
if (onNew) {
|
|
||||||
onNew(®ionList.front());
|
|
||||||
}
|
|
||||||
return ®ionList.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
Region* RegionPager::GetRegion(int x, int y) {
|
|
||||||
for (auto& i : regionList) {
|
|
||||||
if (i.GetX() == x && i.GetY() == y) {
|
|
||||||
return &i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//create, insert and return
|
|
||||||
regionList.push_front({x, y, regionWidth, regionHeight});
|
|
||||||
if (onNew) {
|
|
||||||
onNew(®ionList.front());
|
|
||||||
}
|
|
||||||
return ®ionList.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegionPager::DeleteRegion(int x, int y) {
|
|
||||||
for (std::list<Region>::iterator i = regionList.begin(); i != regionList.end(); i++) {
|
|
||||||
if (i->GetX() == x && i->GetY() == y) {
|
|
||||||
if (onDelete) {
|
|
||||||
onDelete(&(*i));
|
|
||||||
}
|
|
||||||
regionList.erase(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegionPager::DrawTo(SDL_Surface* const dest, TileSheetManager* const sheetMgr, int camX, int camY) {
|
|
||||||
for (auto& regionIter : regionList) {
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
//draw the region's location
|
|
||||||
SDL_Rect box = {
|
|
||||||
Sint16(regionIter.GetX() - camX),
|
|
||||||
Sint16(regionIter.GetY() - camY),
|
|
||||||
Uint16(regionIter.GetWidth()),
|
|
||||||
Uint16(regionIter.GetHeight())
|
|
||||||
};
|
|
||||||
SDL_FillRect(dest, &box, SDL_MapRGB(dest->format, 10, 10, 20));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//draw each tile
|
|
||||||
for (auto& tileIter : *regionIter.GetTiles()) {
|
|
||||||
sheetMgr->DrawTo(
|
|
||||||
dest,
|
|
||||||
tileIter.x + regionIter.GetX() - camX,
|
|
||||||
tileIter.y + regionIter.GetY() - camY,
|
|
||||||
tileIter.tileIndex
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegionPager::Prune(int left, int top, int right, int bottom) {
|
|
||||||
std::list<Region>::iterator it = regionList.begin();
|
|
||||||
|
|
||||||
while(it != regionList.end()) {
|
|
||||||
if (it->GetX() >= right || it->GetY() >= bottom || it->GetX() + it->GetWidth() < left || it->GetY() + it->GetHeight() < top) {
|
|
||||||
if (onDelete) {
|
|
||||||
onDelete(&(*it));
|
|
||||||
}
|
|
||||||
regionList.erase(it);
|
|
||||||
it = regionList.begin();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+92
-28
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -23,47 +23,111 @@
|
|||||||
#define REGIONPAGER_HPP_
|
#define REGIONPAGER_HPP_
|
||||||
|
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
#include "tile_sheet_manager.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class RegionPager {
|
class RegionPagerBase {
|
||||||
public:
|
public:
|
||||||
//for simplicity and consistency
|
RegionPagerBase() {};
|
||||||
typedef void (*regionCallback_t)(Region* const);
|
virtual ~RegionPagerBase() {};
|
||||||
|
|
||||||
RegionPager();
|
//tile manipulation
|
||||||
~RegionPager();
|
Region::type_t SetTile(int x, int y, int z, Region::type_t v);
|
||||||
|
Region::type_t GetTile(int x, int y, int z);
|
||||||
|
|
||||||
//these parameters MUST be multiples of the width & height
|
//region manipulation
|
||||||
Region* NewRegion(int x, int y);
|
|
||||||
Region* GetRegion(int x, int y);
|
Region* GetRegion(int x, int y);
|
||||||
void DeleteRegion(int x, int y);
|
Region* FindRegion(int x, int y);
|
||||||
|
Region* PushRegion(Region*);
|
||||||
|
|
||||||
//call this to draw to the screen
|
//interface
|
||||||
void DrawTo(SDL_Surface* const, TileSheetManager* const, int camX, int camY);
|
virtual Region* LoadRegion(int x, int y) = 0;
|
||||||
|
virtual Region* SaveRegion(int x, int y) = 0;
|
||||||
|
virtual Region* CreateRegion(int x, int y) = 0;
|
||||||
|
virtual void UnloadRegion(int x, int y) = 0;
|
||||||
|
//TODO: delete existing regions
|
||||||
|
|
||||||
//callback hooks
|
//accessors & mutators
|
||||||
void SetOnNew(regionCallback_t f) { onNew = f; }
|
std::list<Region*>* GetContainer() { return ®ionList; }
|
||||||
void SetOnDelete(regionCallback_t f) { onDelete = f; }
|
protected:
|
||||||
|
std::list<Region*> regionList;
|
||||||
|
};
|
||||||
|
|
||||||
//params: Absolute values
|
template<typename Allocator, typename FileFormat>
|
||||||
void Prune(int left, int top, int right, int bottom);
|
class RegionPager : public RegionPagerBase {
|
||||||
|
public:
|
||||||
|
RegionPager() {};
|
||||||
|
~RegionPager() {
|
||||||
|
UnloadAll();
|
||||||
|
}
|
||||||
|
|
||||||
//accessors and mutators
|
Region* LoadRegion(int x, int y) {
|
||||||
int SetWidth(int i) { return regionWidth = i; }
|
//snap the coords
|
||||||
int SetHeight(int i) { return regionHeight = i; }
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
int GetWidth() const { return regionWidth; }
|
//load the region if possible
|
||||||
int GetHeight() const { return regionHeight; }
|
Region* ptr = nullptr;
|
||||||
|
format.Load(&ptr, x, y);
|
||||||
|
if (ptr) {
|
||||||
|
return PushRegion(ptr);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::list<Region>* GetRegions() { return ®ionList; }
|
Region* SaveRegion(int x, int y) {
|
||||||
private:
|
//snap the coords
|
||||||
std::list<Region> regionList;
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
int regionWidth = 0, regionHeight = 0;
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
regionCallback_t onNew = nullptr;
|
//find & save the region
|
||||||
regionCallback_t onDelete = nullptr;
|
Region* ptr = FindRegion(x, y);
|
||||||
|
if (ptr) {
|
||||||
|
format.Save(ptr);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Region* CreateRegion(int x, int y) {
|
||||||
|
//snap the coords
|
||||||
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
|
//create and push the object
|
||||||
|
Region* ptr = nullptr;
|
||||||
|
allocator.Create(&ptr, x, y);
|
||||||
|
return PushRegion(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnloadRegion(int x, int y) {
|
||||||
|
//snap the coords
|
||||||
|
x = snapToBase(REGION_WIDTH, x);
|
||||||
|
y = snapToBase(REGION_HEIGHT, y);
|
||||||
|
|
||||||
|
//custom loop
|
||||||
|
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
|
||||||
|
if ((*it)->GetX() == x && (*it)->GetY() == y) {
|
||||||
|
allocator.Unload(*it);
|
||||||
|
it = regionList.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void UnloadAll() {
|
||||||
|
for (auto& it : regionList) {
|
||||||
|
allocator.Unload(it);
|
||||||
|
}
|
||||||
|
regionList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//accessors
|
||||||
|
Allocator* GetAllocator() { return &allocator; }
|
||||||
|
FileFormat* GetFormat() { return &format; }
|
||||||
|
protected:
|
||||||
|
Allocator allocator;
|
||||||
|
FileFormat format;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
void TileSheet::Load(std::string fname, Uint16 w, Uint16 h) {
|
|
||||||
//setup the image
|
|
||||||
image.LoadSurface(fname);
|
|
||||||
image.SetClipW(w);
|
|
||||||
image.SetClipH(h);
|
|
||||||
|
|
||||||
//get the tile counts
|
|
||||||
xCount = image.GetSurface()->w / w;
|
|
||||||
yCount = image.GetSurface()->h / h;
|
|
||||||
totalCount = xCount * yCount;
|
|
||||||
|
|
||||||
//set begin & end (usually temporary)
|
|
||||||
begin = 0;
|
|
||||||
end = totalCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileSheet::Unload() {
|
|
||||||
image.FreeSurface();
|
|
||||||
totalCount = xCount = yCount = 0;
|
|
||||||
begin = end = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex) {
|
|
||||||
if (!InRange(tileIndex)) {
|
|
||||||
throw(std::invalid_argument("Tile index out of range"));
|
|
||||||
}
|
|
||||||
Sint16 clipX = (tileIndex-begin) % xCount * image.GetClipW();
|
|
||||||
Sint16 clipY = (tileIndex-begin) / xCount * image.GetClipH();
|
|
||||||
|
|
||||||
image.SetClipX(clipX);
|
|
||||||
image.SetClipY(clipY);
|
|
||||||
|
|
||||||
image.DrawTo(dest, x, y);
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 TILESHEET_HPP_
|
|
||||||
#define TILESHEET_HPP_
|
|
||||||
|
|
||||||
#include "image.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/* The TileSheet class is used for drawing tiles of the map to the screen.
|
|
||||||
* This class also tracks the range of the tile images.
|
|
||||||
*/
|
|
||||||
class TileSheet {
|
|
||||||
public:
|
|
||||||
TileSheet() = default;
|
|
||||||
~TileSheet() = default;
|
|
||||||
|
|
||||||
//these load/set functions need to be followed by bookkeeping code
|
|
||||||
//w & h are the width & height of individual tiles
|
|
||||||
//TODO: rename these
|
|
||||||
void Load(std::string fname, Uint16 w, Uint16 h);
|
|
||||||
void Unload();
|
|
||||||
|
|
||||||
void DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex);
|
|
||||||
|
|
||||||
bool InRange(int i) { return i >= begin && i < end; }
|
|
||||||
|
|
||||||
//accessors and mutators
|
|
||||||
Image* GetImage() { return ℑ }
|
|
||||||
|
|
||||||
int GetTileW() const { return image.GetClipW(); }
|
|
||||||
int GetTileH() const { return image.GetClipH(); }
|
|
||||||
|
|
||||||
int GetTotalCount() const { return totalCount; }
|
|
||||||
int GetXCount() const { return xCount; }
|
|
||||||
int GetYCount() const { return yCount; }
|
|
||||||
|
|
||||||
int SetBegin(int i) { return begin = i; }
|
|
||||||
int SetEnd(int i) { return end = i; }
|
|
||||||
|
|
||||||
int GetBegin() const { return begin; }
|
|
||||||
int GetEnd() const { return end; }
|
|
||||||
private:
|
|
||||||
Image image;
|
|
||||||
|
|
||||||
//these are generated and used by internal processes
|
|
||||||
int totalCount = 0, xCount = 0, yCount = 0;
|
|
||||||
int begin = -1, end = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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_manager.hpp"
|
|
||||||
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
TileSheet* TileSheetManager::LoadSheet(std::string fname, Uint16 w, Uint16 h) {
|
|
||||||
//get the key
|
|
||||||
std::string key = truncatePath(fname);
|
|
||||||
|
|
||||||
//don't override what's already here
|
|
||||||
if (sheetMap.find(key) != sheetMap.end()) {
|
|
||||||
throw(std::runtime_error("Cannot load duplicate tile sheets"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//load & setup the sheet object
|
|
||||||
sheetMap[key].Load(fname, w, h);
|
|
||||||
sheetMap[key].SetBegin(rangeEnd);
|
|
||||||
rangeEnd += sheetMap[key].GetTotalCount();
|
|
||||||
sheetMap[key].SetEnd(rangeEnd);
|
|
||||||
|
|
||||||
//you can modify the object, say, during the save & load routines...
|
|
||||||
return &sheetMap[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
TileSheet* TileSheetManager::GetSheet(std::string name) {
|
|
||||||
return &sheetMap.at(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
TileSheet* TileSheetManager::GetSheetByIndex(int tileIndex) {
|
|
||||||
for (auto& it : sheetMap) {
|
|
||||||
if (it.second.InRange(tileIndex)) {
|
|
||||||
return &it.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileSheetManager::UnloadSheet(std::string name) {
|
|
||||||
sheetMap.erase(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileSheetManager::DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex) {
|
|
||||||
for (auto& it : sheetMap) {
|
|
||||||
if (it.second.InRange(tileIndex)) {
|
|
||||||
it.second.DrawTo(dest, x, y, tileIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//No matching tile index
|
|
||||||
throw(std::invalid_argument("Tile index is out of range of all tile sheets"));
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ..
|
INCLUDES+=. .. ../map
|
||||||
LIBS+=
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
|
|||||||
@@ -0,0 +1,286 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "serial.hpp"
|
||||||
|
|
||||||
|
#include "map_allocator.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Convenience Macros
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
#define SERIALIZE(buffer, data, size) memcpy(buffer, data, size); buffer += size;
|
||||||
|
#define DESERIALIZE(buffer, data, size) memcpy(data, buffer, size); buffer += size;
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//internal serialization functions
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void serializeType(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeServer(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//server info
|
||||||
|
SERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
|
||||||
|
SERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
|
||||||
|
SERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeClient(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
|
||||||
|
|
||||||
|
//texts
|
||||||
|
SERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
|
||||||
|
SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
|
||||||
|
SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeRegionFormat(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//format
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeRegionContent(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//format
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
|
||||||
|
|
||||||
|
//content
|
||||||
|
for (register int i = 0; i < REGION_WIDTH; i++) {
|
||||||
|
for (register int j = 0; j < REGION_HEIGHT; j++) {
|
||||||
|
for (register int k = 0; k < REGION_DEPTH; k++) {
|
||||||
|
*reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k);
|
||||||
|
buffer += sizeof(Region::type_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeCharacter(SerialPacket* packet, char* buffer) {
|
||||||
|
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int));
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int));
|
||||||
|
|
||||||
|
//texts
|
||||||
|
SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
|
||||||
|
SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//vectors
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.position.x, sizeof(double));
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.position.y, sizeof(double));
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double));
|
||||||
|
SERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//internal deserialization functions
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void deserializeType(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeServer(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//server info
|
||||||
|
DESERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
|
||||||
|
DESERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeClient(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
|
||||||
|
|
||||||
|
//texts
|
||||||
|
DESERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
|
||||||
|
DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
|
||||||
|
DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//format
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeRegionContent(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//format
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
|
||||||
|
|
||||||
|
//an object to work on
|
||||||
|
BlankAllocator().Create(
|
||||||
|
&packet->regionInfo.region,
|
||||||
|
packet->regionInfo.x,
|
||||||
|
packet->regionInfo.y
|
||||||
|
);
|
||||||
|
|
||||||
|
//content
|
||||||
|
for (register int i = 0; i < REGION_WIDTH; i++) {
|
||||||
|
for (register int j = 0; j < REGION_HEIGHT; j++) {
|
||||||
|
for (register int k = 0; k < REGION_DEPTH; k++) {
|
||||||
|
packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast<Region::type_t*>(buffer));
|
||||||
|
buffer += sizeof(Region::type_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeCharacter(SerialPacket* packet, char* buffer) {
|
||||||
|
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
|
||||||
|
|
||||||
|
//indexes
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int));
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int));
|
||||||
|
|
||||||
|
//texts
|
||||||
|
DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
|
||||||
|
DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
|
||||||
|
|
||||||
|
//vectors
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.position.x, sizeof(double));
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.position.y, sizeof(double));
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double));
|
||||||
|
DESERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//the interface functions
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void serialize(SerialPacket* packet, void* buffer) {
|
||||||
|
switch(packet->meta.type) {
|
||||||
|
//No extra data
|
||||||
|
case SerialPacket::Type::NONE:
|
||||||
|
case SerialPacket::Type::PING:
|
||||||
|
case SerialPacket::Type::PONG:
|
||||||
|
case SerialPacket::Type::BROADCAST_REQUEST:
|
||||||
|
serializeType(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Server info
|
||||||
|
case SerialPacket::Type::BROADCAST_RESPONSE:
|
||||||
|
serializeServer(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Client info
|
||||||
|
case SerialPacket::Type::JOIN_REQUEST:
|
||||||
|
case SerialPacket::Type::JOIN_RESPONSE:
|
||||||
|
case SerialPacket::Type::SYNCHRONIZE:
|
||||||
|
case SerialPacket::Type::DISCONNECT:
|
||||||
|
case SerialPacket::Type::SHUTDOWN:
|
||||||
|
serializeClient(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//region info
|
||||||
|
case SerialPacket::Type::REGION_REQUEST:
|
||||||
|
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SerialPacket::Type::REGION_CONTENT:
|
||||||
|
serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Character info
|
||||||
|
case SerialPacket::Type::CHARACTER_NEW:
|
||||||
|
case SerialPacket::Type::CHARACTER_DELETE:
|
||||||
|
case SerialPacket::Type::CHARACTER_UPDATE:
|
||||||
|
serializeCharacter(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserialize(SerialPacket* packet, void* buffer) {
|
||||||
|
//find the type, so that you can actually deserialize the packet!
|
||||||
|
deserializeType(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
switch(packet->meta.type) {
|
||||||
|
//No extra data
|
||||||
|
case SerialPacket::Type::NONE:
|
||||||
|
case SerialPacket::Type::PING:
|
||||||
|
case SerialPacket::Type::PONG:
|
||||||
|
case SerialPacket::Type::BROADCAST_REQUEST:
|
||||||
|
//NOTHING
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Server info
|
||||||
|
case SerialPacket::Type::BROADCAST_RESPONSE:
|
||||||
|
deserializeServer(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Client info
|
||||||
|
case SerialPacket::Type::JOIN_REQUEST:
|
||||||
|
case SerialPacket::Type::JOIN_RESPONSE:
|
||||||
|
case SerialPacket::Type::SYNCHRONIZE:
|
||||||
|
case SerialPacket::Type::DISCONNECT:
|
||||||
|
case SerialPacket::Type::SHUTDOWN:
|
||||||
|
deserializeClient(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//region info
|
||||||
|
case SerialPacket::Type::REGION_REQUEST:
|
||||||
|
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SerialPacket::Type::REGION_CONTENT:
|
||||||
|
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Character info
|
||||||
|
case SerialPacket::Type::CHARACTER_NEW:
|
||||||
|
case SerialPacket::Type::CHARACTER_DELETE:
|
||||||
|
case SerialPacket::Type::CHARACTER_UPDATE:
|
||||||
|
deserializeCharacter(packet, reinterpret_cast<char*>(buffer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#ifndef SERIAL_HPP_
|
||||||
|
#define SERIAL_HPP_
|
||||||
|
|
||||||
|
#include "serial_packet.hpp"
|
||||||
|
|
||||||
|
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date
|
||||||
|
* NOTE: REGION_CONTENT is currently the largest type of packet
|
||||||
|
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
|
||||||
|
* map format: sizeof(int) * 3
|
||||||
|
* metadata: sizeof(metadata)
|
||||||
|
*/
|
||||||
|
#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacket::Metadata)
|
||||||
|
|
||||||
|
void serialize(SerialPacket* const, void*);
|
||||||
|
void deserialize(SerialPacket* const, void*);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,18 +19,20 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef NETWORKPACKET_HPP_
|
#ifndef SERIALPACKET_HPP_
|
||||||
#define NETWORKPACKET_HPP_
|
#define SERIALPACKET_HPP_
|
||||||
|
|
||||||
|
#include "vector2.hpp"
|
||||||
|
#include "region.hpp"
|
||||||
|
|
||||||
#include "SDL/SDL_net.h"
|
#include "SDL/SDL_net.h"
|
||||||
|
|
||||||
#include "vector2.hpp"
|
#define NETWORK_VERSION 20140512
|
||||||
|
|
||||||
#define PACKET_STRING_SIZE 100
|
#define PACKET_STRING_SIZE 100
|
||||||
|
|
||||||
#pragma pack(push, 0)
|
#pragma pack(push, 0)
|
||||||
|
|
||||||
union NetworkPacket {
|
union SerialPacket {
|
||||||
//types of packets
|
//types of packets
|
||||||
enum class Type {
|
enum class Type {
|
||||||
//default: there is something wrong
|
//default: there is something wrong
|
||||||
@@ -40,6 +42,8 @@ union NetworkPacket {
|
|||||||
PING = 1,
|
PING = 1,
|
||||||
PONG = 2,
|
PONG = 2,
|
||||||
|
|
||||||
|
//TODO: rejection message
|
||||||
|
|
||||||
//Searching for a server to join
|
//Searching for a server to join
|
||||||
BROADCAST_REQUEST = 3,
|
BROADCAST_REQUEST = 3,
|
||||||
BROADCAST_RESPONSE = 4,
|
BROADCAST_RESPONSE = 4,
|
||||||
@@ -48,19 +52,25 @@ union NetworkPacket {
|
|||||||
JOIN_REQUEST = 5,
|
JOIN_REQUEST = 5,
|
||||||
JOIN_RESPONSE = 6,
|
JOIN_RESPONSE = 6,
|
||||||
|
|
||||||
//disconnect from the server
|
|
||||||
DISCONNECT = 7,
|
|
||||||
|
|
||||||
//mass update
|
//mass update
|
||||||
SYNCHRONIZE = 8,
|
SYNCHRONIZE = 7,
|
||||||
|
|
||||||
|
//disconnect from the server
|
||||||
|
DISCONNECT = 8,
|
||||||
|
|
||||||
//shut down the server
|
//shut down the server
|
||||||
SHUTDOWN = 9,
|
SHUTDOWN = 9,
|
||||||
|
|
||||||
//Player movement, etc.
|
//map data
|
||||||
PLAYER_NEW = 10,
|
REGION_REQUEST = 10,
|
||||||
PLAYER_DELETE = 11,
|
REGION_CONTENT = 11,
|
||||||
PLAYER_UPDATE = 12,
|
|
||||||
|
//Character movement, etc.
|
||||||
|
CHARACTER_NEW = 12,
|
||||||
|
CHARACTER_DELETE = 13,
|
||||||
|
CHARACTER_UPDATE = 14,
|
||||||
|
|
||||||
|
//TODO: combat packets
|
||||||
};
|
};
|
||||||
|
|
||||||
//metadata on the packet itself
|
//metadata on the packet itself
|
||||||
@@ -72,30 +82,45 @@ union NetworkPacket {
|
|||||||
//information about the server
|
//information about the server
|
||||||
struct ServerInformation {
|
struct ServerInformation {
|
||||||
Metadata meta;
|
Metadata meta;
|
||||||
//TODO: version info
|
int networkVersion;
|
||||||
char name[PACKET_STRING_SIZE];
|
char name[PACKET_STRING_SIZE];
|
||||||
//TODO: player count
|
int playerCount;
|
||||||
}serverInfo;
|
}serverInfo;
|
||||||
|
|
||||||
//information about the client
|
//information about the client
|
||||||
struct ClientInformation {
|
struct ClientInformation {
|
||||||
Metadata meta;
|
|
||||||
int index;
|
|
||||||
}clientInfo;
|
|
||||||
|
|
||||||
//information about a player
|
|
||||||
struct PlayerInformation {
|
|
||||||
Metadata meta;
|
Metadata meta;
|
||||||
int clientIndex;
|
int clientIndex;
|
||||||
int playerIndex;
|
int accountIndex;
|
||||||
|
int characterIndex;
|
||||||
|
char username[PACKET_STRING_SIZE];
|
||||||
char handle[PACKET_STRING_SIZE];
|
char handle[PACKET_STRING_SIZE];
|
||||||
char avatar[PACKET_STRING_SIZE];
|
char avatar[PACKET_STRING_SIZE];
|
||||||
|
}clientInfo;
|
||||||
|
|
||||||
|
//map data
|
||||||
|
struct RegionInformation {
|
||||||
|
Metadata meta;
|
||||||
|
int mapIndex;
|
||||||
|
int x, y;
|
||||||
|
Region* region;
|
||||||
|
}regionInfo;
|
||||||
|
|
||||||
|
//information about a character
|
||||||
|
struct CharacterInformation {
|
||||||
|
Metadata meta;
|
||||||
|
int clientIndex;
|
||||||
|
int accountIndex;
|
||||||
|
int characterIndex;
|
||||||
|
char handle[PACKET_STRING_SIZE];
|
||||||
|
char avatar[PACKET_STRING_SIZE];
|
||||||
|
int mapIndex;
|
||||||
Vector2 position;
|
Vector2 position;
|
||||||
Vector2 motion;
|
Vector2 motion;
|
||||||
}playerInfo;
|
}characterInfo;
|
||||||
|
|
||||||
//defaults
|
//defaults
|
||||||
NetworkPacket() {
|
SerialPacket() {
|
||||||
meta.type = Type::NONE;
|
meta.type = Type::NONE;
|
||||||
meta.srcAddress = {0,0};
|
meta.srcAddress = {0,0};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
|
||||||
|
** Initialization of libraries for lua.c and other clients
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Modified for use in Tortuga, renamed to linit.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If you embed Lua in your program and need to open the standard
|
||||||
|
** libraries, call luaL_openlibs in your program. If you need a
|
||||||
|
** different set of libraries, copy this file to your project and edit
|
||||||
|
** it to suit your needs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define linit_c
|
||||||
|
#define LUA_LIB
|
||||||
|
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
#include "map_api.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** these libs are loaded by lua.c and are readily available to any Lua
|
||||||
|
** program
|
||||||
|
*/
|
||||||
|
static const luaL_Reg loadedlibs[] = {
|
||||||
|
/* Standard libs */
|
||||||
|
{"_G", luaopen_base},
|
||||||
|
{LUA_LOADLIBNAME, luaopen_package},
|
||||||
|
{LUA_COLIBNAME, luaopen_coroutine},
|
||||||
|
{LUA_TABLIBNAME, luaopen_table},
|
||||||
|
{LUA_IOLIBNAME, luaopen_io},
|
||||||
|
{LUA_OSLIBNAME, luaopen_os},
|
||||||
|
{LUA_STRLIBNAME, luaopen_string},
|
||||||
|
{LUA_BITLIBNAME, luaopen_bit32},
|
||||||
|
{LUA_MATHLIBNAME, luaopen_math},
|
||||||
|
{LUA_DBLIBNAME, luaopen_debug},
|
||||||
|
|
||||||
|
/* custom libs */
|
||||||
|
{LUA_MAPLIBNAME, luaopen_mapapi},
|
||||||
|
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** these libs are preloaded and must be required before used
|
||||||
|
*/
|
||||||
|
static const luaL_Reg preloadedlibs[] = {
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API void luaL_openlibs (lua_State *L) {
|
||||||
|
const luaL_Reg *lib;
|
||||||
|
/* call open functions from 'loadedlibs' and set results to global table */
|
||||||
|
for (lib = loadedlibs; lib->func; lib++) {
|
||||||
|
luaL_requiref(L, lib->name, lib->func, 1);
|
||||||
|
lua_pop(L, 1); /* remove lib */
|
||||||
|
}
|
||||||
|
/* add open functions from 'preloadedlibs' into 'package.preload' table */
|
||||||
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
|
||||||
|
for (lib = preloadedlibs; lib->func; lib++) {
|
||||||
|
lua_pushcfunction(L, lib->func);
|
||||||
|
lua_setfield(L, -2, lib->name);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1); /* remove _PRELOAD table */
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=../common ../common/graphics ../common/map ../common/ui
|
INCLUDES+=. .. ../map
|
||||||
LIBS+=../libcommon.a -lmingw32 -lSDLmain -lSDL
|
LIBS+=
|
||||||
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o))
|
|||||||
OBJ+=$(addprefix $(OBJDIR)/,$(CSRC:.c=.o))
|
OBJ+=$(addprefix $(OBJDIR)/,$(CSRC:.c=.o))
|
||||||
|
|
||||||
#output
|
#output
|
||||||
OUTDIR=../out
|
OUTDIR=../..
|
||||||
OUT=$(addprefix $(OUTDIR)/,editor)
|
OUT=$(addprefix $(OUTDIR)/,libcommon.a)
|
||||||
|
|
||||||
#targets
|
#targets
|
||||||
all: $(OBJ) $(OUT)
|
all: $(OBJ) $(OUT)
|
||||||
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
|
ar -crs $(OUT) $(OBJ)
|
||||||
|
|
||||||
$(OBJ): | $(OBJDIR)
|
$(OBJ): | $(OBJDIR)
|
||||||
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "map_api.hpp"
|
||||||
|
|
||||||
|
//map headers
|
||||||
|
#include "map_allocator.hpp"
|
||||||
|
#include "map_file_format.hpp"
|
||||||
|
#include "region_pager.hpp"
|
||||||
|
|
||||||
|
//NOTE: When operating on a region, setTile() & getTile() *are not* zero indexed, but when operating on the entire map they *are* zero indexed.
|
||||||
|
|
||||||
|
static int setTile(lua_State* L) {
|
||||||
|
if (lua_gettop(L) == 5) {
|
||||||
|
//operating on a region
|
||||||
|
Region* ptr = (Region*)lua_touserdata(L, 1);
|
||||||
|
ptr->SetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1, lua_tointeger(L, 5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//operating on the whole map
|
||||||
|
lua_pushstring(L, "pager");
|
||||||
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
//assume the pager is using lua
|
||||||
|
RegionPager<LuaAllocator, LuaFormat>* pager = reinterpret_cast<RegionPager<LuaAllocator, LuaFormat>*>(lua_touserdata(L, -1));
|
||||||
|
|
||||||
|
//balance the stack
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
pager->SetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getTile(lua_State* L) {
|
||||||
|
if (lua_gettop(L) == 4) {
|
||||||
|
//operating on a region
|
||||||
|
Region* ptr = (Region*)lua_touserdata(L, 1);
|
||||||
|
int ret = ptr->GetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1);
|
||||||
|
lua_pushnumber(L, ret);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//operating on the whole map
|
||||||
|
lua_pushstring(L, "pager");
|
||||||
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
//assume the pager is using lua
|
||||||
|
RegionPager<LuaAllocator, LuaFormat>* pager = reinterpret_cast<RegionPager<LuaAllocator, LuaFormat>*>(lua_touserdata(L, -1));
|
||||||
|
|
||||||
|
//balance the stack
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
int ret = pager->GetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3));
|
||||||
|
lua_pushnumber(L, ret);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getX(lua_State* L) {
|
||||||
|
Region* ptr = (Region*)lua_touserdata(L, 1);
|
||||||
|
lua_pushinteger(L, ptr->GetX());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getY(lua_State* L) {
|
||||||
|
Region* ptr = (Region*)lua_touserdata(L, 1);
|
||||||
|
lua_pushinteger(L, ptr->GetY());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRegionWidth(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_WIDTH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRegionHeight(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_HEIGHT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getRegionDepth(lua_State* L) {
|
||||||
|
lua_pushinteger(L, REGION_DEPTH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy(lua_State* L) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const luaL_Reg regionlib[] = {
|
||||||
|
{"create", dummy},
|
||||||
|
{"unload", dummy},
|
||||||
|
{"load", dummy},
|
||||||
|
{"save", dummy},
|
||||||
|
{"settile",setTile},
|
||||||
|
{"gettile",getTile},
|
||||||
|
{"getx",getX},
|
||||||
|
{"gety",getY},
|
||||||
|
{"getregionwidth",getRegionWidth},
|
||||||
|
{"getregionheight",getRegionHeight},
|
||||||
|
{"getregiondepth",getRegionDepth},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
LUAMOD_API int luaopen_mapapi(lua_State* L) {
|
||||||
|
luaL_newlib(L, regionlib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,18 +19,12 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef SCENELIST_HPP_
|
#ifndef MAPAPI_HPP_
|
||||||
#define SCENELIST_HPP_
|
#define MAPAPI_HPP_
|
||||||
|
|
||||||
enum class SceneList {
|
#include "lua/lua.hpp"
|
||||||
//these are reserved
|
|
||||||
QUIT,
|
|
||||||
CONTINUE,
|
|
||||||
FIRST,
|
|
||||||
|
|
||||||
//custom indexes
|
#define LUA_MAPLIBNAME "map"
|
||||||
TESTIFICATESCENE,
|
LUAMOD_API int luaopen_mapapi(lua_State* L);
|
||||||
EDITORSCENE,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,26 +19,32 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "tile.hpp"
|
#include "sql_utility.hpp"
|
||||||
|
|
||||||
bool operator<(Tile const& lhs, Tile const& rhs) {
|
#include "utility.hpp"
|
||||||
//sort by depth -> y -> x
|
|
||||||
if (lhs.depth == rhs.depth) {
|
#include <stdexcept>
|
||||||
if (lhs.y == rhs.y) {
|
#include <fstream>
|
||||||
return lhs.x < rhs.x;
|
#include <cstdlib>
|
||||||
}
|
|
||||||
return lhs.y < rhs.y;
|
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**), void* argPtr) {
|
||||||
|
//load the file into a string
|
||||||
|
std::ifstream is(fname);
|
||||||
|
if (!is.is_open()) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return lhs.depth < rhs.depth;
|
std::string script;
|
||||||
}
|
getline(is, script, '\0');
|
||||||
|
is.close();
|
||||||
|
|
||||||
inline bool operator>(Tile const& lhs, Tile const& rhs) {
|
//run the SQL loaded from the file
|
||||||
//wrap the other operator
|
char* errmsg = nullptr;
|
||||||
return rhs < lhs;
|
int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg);
|
||||||
}
|
if (ret != SQLITE_OK) {
|
||||||
|
//handle any errors received from the SQL
|
||||||
inline bool operator==(Tile const& lhs, Tile const& rhs) {
|
std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg);
|
||||||
//comparisons work on the location ONLY
|
free(errmsg);
|
||||||
//this function is redundant as far as the std::set object is concerned
|
throw(e);
|
||||||
return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.depth == rhs.depth);
|
}
|
||||||
}
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,24 +19,13 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#include "editor_application.hpp"
|
#ifndef SERVERUTILITY_HPP_
|
||||||
|
#define SERVERUTILITY_HPP_
|
||||||
|
|
||||||
#include <stdexcept>
|
#include "sqlite3/sqlite3.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
#include <string>
|
||||||
|
|
||||||
int main(int, char**) {
|
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**) = nullptr, void* argPtr = nullptr);
|
||||||
cout << "Beginning editor" << endl;
|
|
||||||
try {
|
#endif
|
||||||
EditorApplication::GetInstance()->Init();
|
|
||||||
EditorApplication::GetInstance()->Proc();
|
|
||||||
EditorApplication::GetInstance()->Quit();
|
|
||||||
}
|
|
||||||
catch(exception& e) {
|
|
||||||
cerr << "Fatal exception thrown: " << e.what() << endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cout << "Clean exit" << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+2
-2
@@ -27,9 +27,9 @@ int snapToBase(int base, int x) {
|
|||||||
//snap to a grid
|
//snap to a grid
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
x++;
|
x++;
|
||||||
return x - x % base - base;
|
return x / base * base - base;
|
||||||
}
|
}
|
||||||
return x - x % base;
|
return x / base * base;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string truncatePath(std::string pathname) {
|
std::string truncatePath(std::string pathname) {
|
||||||
|
|||||||
+4
-1
@@ -22,6 +22,7 @@
|
|||||||
#ifndef VECTOR2_HPP_
|
#ifndef VECTOR2_HPP_
|
||||||
#define VECTOR2_HPP_
|
#define VECTOR2_HPP_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -29,7 +30,6 @@ class Vector2 {
|
|||||||
public:
|
public:
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|
||||||
//This is explicitly a POD
|
|
||||||
Vector2() = default;
|
Vector2() = default;
|
||||||
Vector2(double i, double j): x(i), y(j) {};
|
Vector2(double i, double j): x(i), y(j) {};
|
||||||
~Vector2() = default;
|
~Vector2() = default;
|
||||||
@@ -112,4 +112,7 @@ template<typename T> Vector2 operator/(T t, Vector2 v) { return v / t; }
|
|||||||
template<typename T> bool operator==(T t, Vector2 v) { return v == t; }
|
template<typename T> bool operator==(T t, Vector2 v) { return v == t; }
|
||||||
template<typename T> bool operator!=(T t, Vector2 v) { return v != t; }
|
template<typename T> bool operator!=(T t, Vector2 v) { return v != t; }
|
||||||
|
|
||||||
|
//This is explicitly a POD
|
||||||
|
static_assert(std::is_pod<Vector2>::value, "Vector2 is not a POD");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 "base_scene.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Static declarations
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
SDL_Surface* BaseScene::screen = nullptr;
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Public access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
BaseScene::BaseScene() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseScene::~BaseScene() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Program control
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
SDL_Surface* BaseScene::SetScreen(int w, int h, int bpp, Uint32 flags) {
|
|
||||||
if (!bpp) {
|
|
||||||
bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen = SDL_SetVideoMode(w, h, bpp, flags);
|
|
||||||
|
|
||||||
if (!screen) {
|
|
||||||
throw(std::runtime_error("Failed to create the screen surface"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Surface* BaseScene::GetScreen() {
|
|
||||||
return screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneList BaseScene::SetNextScene(SceneList sceneIndex) {
|
|
||||||
return nextScene = sceneIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneList BaseScene::GetNextScene() const {
|
|
||||||
return nextScene;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Frame loop
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void BaseScene::RunFrame(double delta) {
|
|
||||||
FrameStart();
|
|
||||||
HandleEvents();
|
|
||||||
Update(delta);
|
|
||||||
FrameEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseScene::RenderFrame() {
|
|
||||||
SDL_FillRect(screen, 0, 0);
|
|
||||||
Render(screen);
|
|
||||||
SDL_Flip(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Event handlers
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void BaseScene::HandleEvents() {
|
|
||||||
SDL_Event event;
|
|
||||||
|
|
||||||
while(SDL_PollEvent(&event)) {
|
|
||||||
switch(event.type) {
|
|
||||||
case SDL_QUIT:
|
|
||||||
QuitEvent();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_VIDEORESIZE:
|
|
||||||
SetScreen(event.resize.w, event.resize.h, 0, screen->flags);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_MOUSEMOTION:
|
|
||||||
MouseMotion(event.motion);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
|
||||||
MouseButtonDown(event.button);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONUP:
|
|
||||||
MouseButtonUp(event.button);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
KeyDown(event.key);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_KEYUP:
|
|
||||||
KeyUp(event.key);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
|
||||||
//TODO: joystick/gamepad support
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
|
||||||
default:
|
|
||||||
UnknownEvent(event);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}//switch
|
|
||||||
}//while
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 BASESCENE_HPP_
|
|
||||||
#define BASESCENE_HPP_
|
|
||||||
|
|
||||||
#include "scene_list.hpp"
|
|
||||||
|
|
||||||
#include "SDL/SDL.h"
|
|
||||||
|
|
||||||
class BaseScene {
|
|
||||||
public:
|
|
||||||
//Public access members
|
|
||||||
BaseScene();
|
|
||||||
virtual ~BaseScene();
|
|
||||||
|
|
||||||
//Program control
|
|
||||||
static SDL_Surface* SetScreen(int w, int h, int bpp = 0, Uint32 flags = SDL_HWSURFACE|SDL_DOUBLEBUF);
|
|
||||||
static SDL_Surface* GetScreen();
|
|
||||||
|
|
||||||
SceneList SetNextScene(SceneList sceneIndex);
|
|
||||||
SceneList GetNextScene() const;
|
|
||||||
|
|
||||||
//Frame loop
|
|
||||||
virtual void RunFrame(double delta);
|
|
||||||
virtual void RenderFrame();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void FrameStart() {}
|
|
||||||
virtual void HandleEvents();
|
|
||||||
virtual void Update(double delta) {}
|
|
||||||
virtual void FrameEnd() {}
|
|
||||||
virtual void Render(SDL_Surface* const screen) {}
|
|
||||||
|
|
||||||
//Event handlers
|
|
||||||
virtual void QuitEvent() { SetNextScene(SceneList::QUIT); }
|
|
||||||
virtual void MouseMotion(SDL_MouseMotionEvent const&) {}
|
|
||||||
virtual void MouseButtonDown(SDL_MouseButtonEvent const&) {}
|
|
||||||
virtual void MouseButtonUp(SDL_MouseButtonEvent const&) {}
|
|
||||||
virtual void KeyDown(SDL_KeyboardEvent const&) {}
|
|
||||||
virtual void KeyUp(SDL_KeyboardEvent const&) {}
|
|
||||||
|
|
||||||
#ifdef USE_EVENT_JOYSTICK
|
|
||||||
//TODO: joystick/gamepad support
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_EVENT_UNKNOWN
|
|
||||||
virtual void UnknownEvent(SDL_Event const&) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
static SDL_Surface* screen;
|
|
||||||
SceneList nextScene = SceneList::CONTINUE;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 EditorApplications, 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 "editor_application.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Static declarations
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
EditorApplication EditorApplication::instance;
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Scene headers
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
//Add the custom scene headers here
|
|
||||||
#include "editor_scene.hpp"
|
|
||||||
#include "testificate_scene.hpp"
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Public access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
EditorApplication::EditorApplication() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorApplication::~EditorApplication() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorApplication::Init() {
|
|
||||||
config.Load("rsc\\config.cfg");
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO))
|
|
||||||
throw(std::runtime_error("Failed to initialize SDL"));
|
|
||||||
|
|
||||||
BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorApplication::Proc() {
|
|
||||||
LoadScene(SceneList::FIRST);
|
|
||||||
|
|
||||||
//prepare the time system
|
|
||||||
typedef std::chrono::steady_clock Clock;
|
|
||||||
|
|
||||||
Clock::duration delta(16 * Clock::duration::period::den / std::milli::den);
|
|
||||||
Clock::time_point simTime = Clock::now();
|
|
||||||
Clock::time_point realTime;
|
|
||||||
|
|
||||||
//The main loop
|
|
||||||
while(activeScene->GetNextScene() != SceneList::QUIT) {
|
|
||||||
//switch scenes when necessary
|
|
||||||
if (activeScene->GetNextScene() != SceneList::CONTINUE) {
|
|
||||||
LoadScene(activeScene->GetNextScene());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the current time
|
|
||||||
realTime = Clock::now();
|
|
||||||
|
|
||||||
//simulate game time
|
|
||||||
while (simTime < realTime) {
|
|
||||||
//call each user defined function
|
|
||||||
activeScene->RunFrame(double(delta.count()) / Clock::duration::period::den);
|
|
||||||
simTime += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw the game to the screen
|
|
||||||
activeScene->RenderFrame();
|
|
||||||
|
|
||||||
//give the computer a break
|
|
||||||
SDL_Delay(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
UnloadScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorApplication::Quit() {
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Private access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void EditorApplication::LoadScene(SceneList sceneIndex) {
|
|
||||||
UnloadScene();
|
|
||||||
|
|
||||||
switch(sceneIndex) {
|
|
||||||
//add scene creation calls here
|
|
||||||
case SceneList::FIRST:
|
|
||||||
case SceneList::EDITORSCENE:
|
|
||||||
activeScene = new EditorScene(&config);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SceneList::TESTIFICATESCENE:
|
|
||||||
activeScene = new TestificateScene(&config);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw(std::logic_error("Failed to recognize the scene index"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorApplication::UnloadScene() {
|
|
||||||
delete activeScene;
|
|
||||||
activeScene = nullptr;
|
|
||||||
}
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 "editor_scene.hpp"
|
|
||||||
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Public access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
EditorScene::EditorScene(ConfigUtility* const arg1):
|
|
||||||
config(*arg1)
|
|
||||||
{
|
|
||||||
//create the debugging "window"
|
|
||||||
debugInfo.CreateSurface(256, 256);
|
|
||||||
|
|
||||||
//setup the utility objects
|
|
||||||
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
|
|
||||||
|
|
||||||
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
|
|
||||||
buttonImage.SetClipH(buttonImage.GetClipH()/3);
|
|
||||||
|
|
||||||
//setup the menu bar
|
|
||||||
menuBar.SetFont(&font);
|
|
||||||
menuBar.SetImage(&buttonImage);
|
|
||||||
|
|
||||||
menuBar.SetEntries({
|
|
||||||
{"File", "-New", "-Open", "-Save", "-Save As...", "-Close", "Exit"},
|
|
||||||
{"Edit", "-Set Tile", "-Load Sheet", "-Delete Sheet", "-Metadata", "-Run Script"},
|
|
||||||
{"Debugging", "Debug On", "Debug Off", "Toggle Debug", "Testificate"}
|
|
||||||
});
|
|
||||||
|
|
||||||
//setup the pager
|
|
||||||
pager.SetOnNew([](Region* const ptr){
|
|
||||||
printf("New Region: %d, %d\n", ptr->GetX(), ptr->GetY());
|
|
||||||
});
|
|
||||||
|
|
||||||
pager.SetOnDelete([](Region* const ptr){
|
|
||||||
printf("Delete Region: %d, %d\n", ptr->GetX(), ptr->GetY());
|
|
||||||
});
|
|
||||||
|
|
||||||
//Set a resonable size for the regions
|
|
||||||
pager.SetWidth(32*4);
|
|
||||||
pager.SetHeight(32*4);
|
|
||||||
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "terrain.bmp", 32, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorScene::~EditorScene() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Frame loop
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void EditorScene::FrameStart() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::Update(double delta) {
|
|
||||||
pager.Prune(camera.x, camera.y, camera.x + GetScreen()->w, camera.y + GetScreen()->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::FrameEnd() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::Render(SDL_Surface* const screen) {
|
|
||||||
//draw the map
|
|
||||||
pager.DrawTo(screen, &sheetMgr, camera.x, camera.y);
|
|
||||||
|
|
||||||
//draw a big bar across the top
|
|
||||||
buttonImage.SetClipY(0);
|
|
||||||
for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) {
|
|
||||||
buttonImage.DrawTo(screen, i, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//draw the menu bar
|
|
||||||
menuBar.DrawTo(screen);
|
|
||||||
|
|
||||||
//draw some debugging info
|
|
||||||
if (debugOpen) {
|
|
||||||
SDL_FillRect(debugInfo.GetSurface(), 0, 0);
|
|
||||||
DrawToDebugInfo(string("camera.x: ") + to_string_custom(camera.x), 0);
|
|
||||||
DrawToDebugInfo(string("camera.y: ") + to_string_custom(camera.y), 1);
|
|
||||||
debugInfo.DrawTo(screen, screen->w - debugInfo.GetClipW(), buttonImage.GetClipH());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::DrawToDebugInfo(std::string str, int line) {
|
|
||||||
//draw the debug info on the right
|
|
||||||
font.DrawStringTo(
|
|
||||||
str,
|
|
||||||
debugInfo.GetSurface(),
|
|
||||||
debugInfo.GetClipW() - str.size() * font.GetCharW(),
|
|
||||||
font.GetCharH() * line
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Event handlers
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
|
|
||||||
menuBar.MouseMotion(motion);
|
|
||||||
|
|
||||||
if (motion.state & SDL_BUTTON_LMASK && motion.y >= buttonImage.GetClipH()) {
|
|
||||||
Region* regionPtr = pager.GetRegion(
|
|
||||||
snapToBase(pager.GetWidth(), motion.x + camera.x),
|
|
||||||
snapToBase(pager.GetHeight(), motion.y + camera.y)
|
|
||||||
);
|
|
||||||
|
|
||||||
TileSheet* sheetPtr = sheetMgr.GetSheetByIndex(tileCounter);
|
|
||||||
|
|
||||||
regionPtr->NewTileA({
|
|
||||||
snapToBase(sheetPtr->GetTileW(), motion.x + camera.x), //x
|
|
||||||
snapToBase(sheetPtr->GetTileH(), motion.y + camera.y), //y
|
|
||||||
0, //depth
|
|
||||||
sheetPtr->GetTileW(), //width
|
|
||||||
sheetPtr->GetTileH(), //height
|
|
||||||
tileCounter++ //value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motion.state & SDL_BUTTON_RMASK) {
|
|
||||||
camera.x -= motion.xrel;
|
|
||||||
camera.y -= motion.yrel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|
||||||
menuBar.MouseButtonDown(button);
|
|
||||||
|
|
||||||
if (button.button == SDL_BUTTON_LEFT && button.y >= buttonImage.GetClipH()) {
|
|
||||||
Region* regionPtr = pager.GetRegion(
|
|
||||||
snapToBase(pager.GetWidth(), button.x + camera.x),
|
|
||||||
snapToBase(pager.GetHeight(), button.y + camera.y)
|
|
||||||
);
|
|
||||||
|
|
||||||
TileSheet* sheetPtr = sheetMgr.GetSheetByIndex(tileCounter);
|
|
||||||
|
|
||||||
regionPtr->NewTileA({
|
|
||||||
snapToBase(sheetPtr->GetTileW(), button.x + camera.x), //x
|
|
||||||
snapToBase(sheetPtr->GetTileH(), button.y + camera.y), //y
|
|
||||||
0, //depth
|
|
||||||
sheetPtr->GetTileW(), //width
|
|
||||||
sheetPtr->GetTileH(), //height
|
|
||||||
tileCounter++ //value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
|
||||||
int entry, drop;
|
|
||||||
menuBar.MouseButtonUp(button, &entry, &drop);
|
|
||||||
|
|
||||||
//manage input from the menu bar
|
|
||||||
switch(entry) {
|
|
||||||
case 0: //File
|
|
||||||
switch(drop) {
|
|
||||||
case 0:
|
|
||||||
//TODO: NEW
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
//TODO: OPEN
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
//TODO: SAVE
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
//TODO: SAVE AS
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
//TODO: CLOSE
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5: {
|
|
||||||
//Quit
|
|
||||||
SDL_Event e;
|
|
||||||
e.type = SDL_QUIT;
|
|
||||||
SDL_PushEvent(&e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: //Edit
|
|
||||||
switch(drop) {
|
|
||||||
case 0:
|
|
||||||
//TODO: SET TILE
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
//TODO: LOAD SHEET
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
//TODO: DELETE SHEET
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
//TODO: METADATA
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
//TODO: RUN SCRIPT
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: //Debug
|
|
||||||
switch(drop) {
|
|
||||||
case 0:
|
|
||||||
debugOpen = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
debugOpen = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
debugOpen = !debugOpen;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
SetNextScene(SceneList::TESTIFICATESCENE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
|
|
||||||
switch(key.keysym.sym) {
|
|
||||||
case SDLK_ESCAPE:
|
|
||||||
QuitEvent();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDLK_SPACE:
|
|
||||||
camera.x = 0;
|
|
||||||
camera.y = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDLK_TAB:
|
|
||||||
debugOpen = !debugOpen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorScene::KeyUp(SDL_KeyboardEvent const& key) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 EDITORSCENE_HPP_
|
|
||||||
#define EDITORSCENE_HPP_
|
|
||||||
|
|
||||||
#include "base_scene.hpp"
|
|
||||||
|
|
||||||
#include "region_pager.hpp"
|
|
||||||
#include "tile_sheet_manager.hpp"
|
|
||||||
|
|
||||||
#include "config_utility.hpp"
|
|
||||||
#include "image.hpp"
|
|
||||||
#include "raster_font.hpp"
|
|
||||||
#include "menu_bar.hpp"
|
|
||||||
|
|
||||||
//#include "map_loader.hpp"
|
|
||||||
|
|
||||||
class EditorScene : public BaseScene {
|
|
||||||
public:
|
|
||||||
//Public access members
|
|
||||||
EditorScene(ConfigUtility* const);
|
|
||||||
~EditorScene();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//Frame loop
|
|
||||||
void FrameStart();
|
|
||||||
void Update(double delta);
|
|
||||||
void FrameEnd();
|
|
||||||
void Render(SDL_Surface* const);
|
|
||||||
|
|
||||||
//Event handlers
|
|
||||||
void MouseMotion(SDL_MouseMotionEvent const&);
|
|
||||||
void MouseButtonDown(SDL_MouseButtonEvent const&);
|
|
||||||
void MouseButtonUp(SDL_MouseButtonEvent const&);
|
|
||||||
void KeyDown(SDL_KeyboardEvent const&);
|
|
||||||
void KeyUp(SDL_KeyboardEvent const&);
|
|
||||||
|
|
||||||
//globals
|
|
||||||
ConfigUtility& config;
|
|
||||||
|
|
||||||
//debugging tools
|
|
||||||
void DrawToDebugInfo(std::string, int line);
|
|
||||||
Image debugInfo;
|
|
||||||
bool debugOpen = true;
|
|
||||||
|
|
||||||
RegionPager pager;
|
|
||||||
TileSheetManager sheetMgr;
|
|
||||||
|
|
||||||
RasterFont font;
|
|
||||||
Image buttonImage;
|
|
||||||
|
|
||||||
MenuBar menuBar;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int x = 0, y = 0;
|
|
||||||
} camera;
|
|
||||||
|
|
||||||
int tileCounter = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* 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 "testificate_scene.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Public access members
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
TestificateScene::TestificateScene(ConfigUtility* const arg1):
|
|
||||||
config(*arg1)
|
|
||||||
{
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "grass.bmp", 32, 32);
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "longgrass.bmp", 32, 32);
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "sand.bmp", 32, 32);
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "dirt.bmp", 32, 32);
|
|
||||||
sheetMgr.LoadSheet(config["dir.tilesets"] + "water.bmp", 32, 32);
|
|
||||||
|
|
||||||
cout << "Range End: " << sheetMgr.GetRangeEnd() << endl;
|
|
||||||
|
|
||||||
pager.SetWidth(128);
|
|
||||||
pager.SetHeight(128);
|
|
||||||
|
|
||||||
pager.GetRegion(0, 0)->NewTileR({0, 0, 0, 32, 32, 0});
|
|
||||||
}
|
|
||||||
|
|
||||||
TestificateScene::~TestificateScene() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Frame loop
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void TestificateScene::FrameStart() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::Update(double delta) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::FrameEnd() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::Render(SDL_Surface* const screen) {
|
|
||||||
//dump all tile graphics to the screen
|
|
||||||
for (int i = 0; i < sheetMgr.GetRangeEnd(); i++) {
|
|
||||||
sheetMgr.DrawTo(screen, i * 32 % screen->w, i * 32 / screen->w * 32, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pager.DrawTo(screen, &sheetMgr, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Event handlers
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
void TestificateScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void TestificateScene::MouseButtonDown(SDL_MouseButtonEvent const& button) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::MouseButtonUp(SDL_MouseButtonEvent const& button) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::KeyDown(SDL_KeyboardEvent const& key) {
|
|
||||||
switch(key.keysym.sym) {
|
|
||||||
case SDLK_ESCAPE:
|
|
||||||
// QuitEvent();
|
|
||||||
SetNextScene(SceneList::EDITORSCENE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestificateScene::KeyUp(SDL_KeyboardEvent const& key) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#TODO: The build process needs revising
|
||||||
#for use on Windows:
|
#for use on Windows:
|
||||||
|
|
||||||
#MKDIR=mkdir
|
#MKDIR=mkdir
|
||||||
@@ -14,7 +15,6 @@ all: $(OUTDIR)
|
|||||||
$(MAKE) -C common
|
$(MAKE) -C common
|
||||||
$(MAKE) -C server
|
$(MAKE) -C server
|
||||||
$(MAKE) -C client
|
$(MAKE) -C client
|
||||||
$(MAKE) -C editor
|
|
||||||
|
|
||||||
$(OUTDIR):
|
$(OUTDIR):
|
||||||
mkdir $(OUTDIR)
|
mkdir $(OUTDIR)
|
||||||
|
|||||||
+8
-2
@@ -17,8 +17,14 @@ dir.tilesets = rsc/graphics/tilesets/
|
|||||||
dir.interface = rsc/graphics/interface/
|
dir.interface = rsc/graphics/interface/
|
||||||
dir.scripts = rsc/scripts/
|
dir.scripts = rsc/scripts/
|
||||||
|
|
||||||
|
#map system
|
||||||
|
map.pager.width = 20
|
||||||
|
map.pager.height = 20
|
||||||
|
map.pager.depth = 3
|
||||||
|
|
||||||
#player options
|
#player options
|
||||||
player.handle = username
|
client.username = Kayne Ruse
|
||||||
player.avatar = elliot2.bmp
|
client.handle = Ratstail91
|
||||||
|
client.avatar = elliot2.bmp
|
||||||
|
|
||||||
#debugging
|
#debugging
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,27 @@
|
|||||||
|
print("Lua script check OK (./rsc)")
|
||||||
|
|
||||||
|
function map.create(region)
|
||||||
|
for i = 1, map.getregionwidth() do
|
||||||
|
for j = 1, map.getregionheight() do
|
||||||
|
if math.abs(map.getx(region) + i -1) == math.abs(map.gety(region) + j -1) then
|
||||||
|
map.settile(region, i, j, 1, 50)
|
||||||
|
else
|
||||||
|
map.settile(region, i, j, 1, 14)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function map.unload(region)
|
||||||
|
--
|
||||||
|
end
|
||||||
|
|
||||||
|
--return true if file loaded, otherwise return false
|
||||||
|
function map.load(region, dir)
|
||||||
|
--
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function map.save(region, dir)
|
||||||
|
--
|
||||||
|
end
|
||||||
|
|||||||
@@ -3,42 +3,43 @@
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS UserAccounts (
|
CREATE TABLE IF NOT EXISTS UserAccounts (
|
||||||
userAccountID INTEGER PRIMARY KEY AUTOINCREMENT,
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username varchar(30) UNIQUE,
|
username varchar(100) UNIQUE,
|
||||||
password varchar(30),
|
--TODO: server-client security
|
||||||
|
-- password varchar(100),
|
||||||
blacklisted BIT DEFAULT 0,
|
blacklisted BIT DEFAULT 0,
|
||||||
whitelisted BIT DEFAULT 1
|
whitelisted BIT DEFAULT 1
|
||||||
|
-- TODO: moderator
|
||||||
);
|
);
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
--Items
|
--Items
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS GlobalItemList (
|
|
||||||
globalItemListID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
itemName varchar(30) UNIQUE,
|
|
||||||
itemImage varchar(30),
|
|
||||||
type varchar(15), --{'mundane', 'consumable', 'equipment'}
|
|
||||||
maxStackSize INTEGER, --{1-max; 0 for non-stackable}
|
|
||||||
maxUniqueCopies INTEGER --{1-max; 0 for unlimited}
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS MundaneItems (
|
CREATE TABLE IF NOT EXISTS MundaneItems (
|
||||||
mundaneItemID INTEGER PRIMARY KEY AUTOINCREMENT,
|
--metadata
|
||||||
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID)
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
--holds whatever
|
itemID INTEGER,
|
||||||
|
stackSize INTEGER DEFAULT 0,
|
||||||
|
owner INTEGER REFERENCES PlayerCharacters(uid)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Consumables (
|
CREATE TABLE IF NOT EXISTS Consumables (
|
||||||
consumableID INTEGER PRIMARY KEY AUTOINCREMENT,
|
--metadata
|
||||||
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID)
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
itemID INTEGER,
|
||||||
|
stackSize INTEGER DEFAULT 0,
|
||||||
|
owner INTEGER REFERENCES PlayerCharacters(uid)
|
||||||
--holds all consumable items info (food, potions, etc.)
|
--holds all consumable items info (food, potions, etc.)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Equipment (
|
CREATE TABLE IF NOT EXISTS Equipment (
|
||||||
equipmentID INTEGER PRIMARY KEY AUTOINCREMENT,
|
--metadata
|
||||||
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID)
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
itemID INTEGER,
|
||||||
|
owner INTEGER REFERENCES PlayerCharacters(uid)
|
||||||
--hold all equipment info
|
--hold all equipment info
|
||||||
|
--stat mods, special effects, etc.
|
||||||
);
|
);
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -46,28 +47,37 @@ CREATE TABLE IF NOT EXISTS Equipment (
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS PlayerCharacters (
|
CREATE TABLE IF NOT EXISTS PlayerCharacters (
|
||||||
playerCharacterID INTEGER PRIMARY KEY AUTOINCREMENT,
|
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name varchar(30) UNIQUE,
|
|
||||||
|
|
||||||
--stats
|
--metadata
|
||||||
currentLevel INTEGER DEFAULT 0,
|
owner INTEGER REFERENCES UserAccounts(uid),
|
||||||
currentExperience INTEGER DEFAULT 0,
|
handle varchar(100) UNIQUE,
|
||||||
maxHealth INTEGER DEFAULT 0,
|
avatar varchar(100),
|
||||||
maxMana INTEGER DEFAULT 0,
|
birth timestamp NOT NULL DEFAULT (datetime()),
|
||||||
currentHealth INTEGER DEFAULT 0,
|
|
||||||
currentMana INTEGER DEFAULT 0,
|
--position
|
||||||
attack INTEGER DEFAULT 0,
|
mapIndex INTEGER DEFAULT 0,
|
||||||
defence INTEGER DEFAULT 0,
|
positionX INTEGER DEFAULT 0,
|
||||||
--etc.
|
positionY INTEGER DEFAULT 0,
|
||||||
|
|
||||||
|
--statistics
|
||||||
|
level INTEGER DEFAULT 0,
|
||||||
|
exp INTEGER DEFAULT 0,
|
||||||
|
maxHP INTEGER DEFAULT 0,
|
||||||
|
health INTEGER DEFAULT 0,
|
||||||
|
maxMP INTEGER DEFAULT 0,
|
||||||
|
mana INTEGER DEFAULT 0,
|
||||||
|
attack INTEGER DEFAULT 0,
|
||||||
|
defence INTEGER DEFAULT 0,
|
||||||
|
intelligence INTEGER DEFAULT 0,
|
||||||
|
resistance INTEGER DEFAULT 0,
|
||||||
|
accuracy REAL DEFAULT 0.0,
|
||||||
|
evasion REAL DEFAULT 0.0,
|
||||||
|
luck REAL DEFAULT 0.0,
|
||||||
|
|
||||||
--equipment
|
--equipment
|
||||||
weapon INTEGER REFERENCES Equipment(equipmentID),
|
weapon INTEGER REFERENCES Equipment(uid),
|
||||||
helmet INTEGER REFERENCES Equipment(equipmentID),
|
helmet INTEGER REFERENCES Equipment(uid),
|
||||||
armour INTEGER REFERENCES Equipment(equipmentID)
|
armour INTEGER REFERENCES Equipment(uid)
|
||||||
--etc.
|
--etc.
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS PlayerInventoryItems (
|
|
||||||
characterID INTEGER REFERENCES PlayerCharacters(characterID),
|
|
||||||
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID)
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,25 +19,18 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef PLAYER_HPP_
|
#ifndef ACCOUNTDATA_HPP_
|
||||||
#define PLAYER_HPP_
|
#define ACCOUNTDATA_HPP_
|
||||||
|
|
||||||
#include "vector2.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
/* Hold the player info.
|
struct AccountData {
|
||||||
*/
|
std::string username;
|
||||||
|
//TODO: password
|
||||||
|
bool blackListed = false;
|
||||||
|
bool whiteListed = true;
|
||||||
|
|
||||||
struct Player {
|
|
||||||
int clientIndex;
|
int clientIndex;
|
||||||
std::string handle;
|
|
||||||
std::string avatar;
|
|
||||||
Vector2 position;
|
|
||||||
Vector2 motion;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<int, Player> PlayerMap;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "server_application.hpp"
|
||||||
|
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the queries
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
static const char* CREATE_USER_ACCOUNT = "INSERT INTO UserAccounts (username) VALUES (?);";
|
||||||
|
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM UserAccounts WHERE username = ?;";
|
||||||
|
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL UserAccounts SET blacklisted = ?2, whitelisted = ?3 WHERE uid = ?1;";
|
||||||
|
static const char* DELETE_USER_ACCOUNT = "DELETE FROM UserAccounts WHERE uid = ?;";
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the methods
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
int ServerApplication::CreateUserAccount(std::string username, int clientIndex) {
|
||||||
|
//create this user account, failing if it exists, leave this account in memory
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, CREATE_USER_ACCOUNT, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter
|
||||||
|
if (sqlite3_bind_text(statement, 1, username.c_str(), username.size() + 1, SQLITE_STATIC) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than this account exists
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
//load this account into memory
|
||||||
|
return LoadUserAccount(username, clientIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServerApplication::LoadUserAccount(std::string username, int clientIndex) {
|
||||||
|
//load this user account, failing if it is in memory, creating it if it doesn't exist
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, LOAD_USER_ACCOUNT, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter
|
||||||
|
if (sqlite3_bind_text(statement, 1, username.c_str(), username.size() + 1, SQLITE_STATIC) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
int ret = sqlite3_step(statement);
|
||||||
|
|
||||||
|
//process the result
|
||||||
|
if (ret == SQLITE_ROW) {
|
||||||
|
//get the index
|
||||||
|
int uid = sqlite3_column_int(statement, 0);
|
||||||
|
|
||||||
|
//check to see if this account is already loaded
|
||||||
|
if (accountMap.find(uid) != accountMap.end()) {
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract the data into memory
|
||||||
|
AccountData& newAccount = accountMap[uid];
|
||||||
|
newAccount.username = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
||||||
|
newAccount.blackListed = sqlite3_column_int(statement, 2);
|
||||||
|
newAccount.whiteListed = sqlite3_column_int(statement, 3);
|
||||||
|
newAccount.clientIndex = clientIndex;
|
||||||
|
|
||||||
|
//finish the routine
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
if (ret == SQLITE_DONE) {
|
||||||
|
//create the non-existant account instead
|
||||||
|
return CreateUserAccount(username, clientIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw(std::runtime_error(std::string() + "Unknown SQL error in LoadUserAccount: " + sqlite3_errmsg(database) ));
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServerApplication::SaveUserAccount(int uid) {
|
||||||
|
//save this user account from memory, replacing it if it exists in the database
|
||||||
|
//DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID.
|
||||||
|
|
||||||
|
//this method fails if this account is not loaded
|
||||||
|
if (accountMap.find(uid) == accountMap.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountData& account = accountMap[uid];
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, SAVE_USER_ACCOUNT, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameters
|
||||||
|
bool ret = false;
|
||||||
|
ret |= sqlite3_bind_int(statement, 1, uid) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 2, account.blackListed) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 3, account.whiteListed) != SQLITE_OK;
|
||||||
|
|
||||||
|
//check for binding errors
|
||||||
|
if (ret) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than something went horribly wrong
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
throw( std::runtime_error(std::string() + "Unknown SQL error when saving an account: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
//successful execution
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::UnloadUserAccount(int uid) {
|
||||||
|
//save this user account, and then unload it
|
||||||
|
//NOTE: the associated characters are unloaded externally
|
||||||
|
SaveUserAccount(uid);
|
||||||
|
accountMap.erase(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::DeleteUserAccount(int uid) {
|
||||||
|
//delete a user account from the database, and remove it from memory
|
||||||
|
//NOTE: the associated characters are unloaded externally
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, DELETE_USER_ACCOUNT, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter
|
||||||
|
if (sqlite3_bind_int(statement, 1, uid) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than something went horribly wrong
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
throw( std::runtime_error(std::string() + "Unknown SQL error when deleting an account: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//finish the routine
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
accountMap.erase(uid);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,32 +19,41 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef TILE_HPP_
|
#ifndef CHARACTERDATA_HPP_
|
||||||
#define TILE_HPP_
|
#define CHARACTERDATA_HPP_
|
||||||
|
|
||||||
//explicitly a POD
|
//POD members
|
||||||
struct Tile {
|
#include "bbox.hpp"
|
||||||
//position relative to the Region
|
#include "vector2.hpp"
|
||||||
int x, y, depth;
|
|
||||||
|
|
||||||
//graphics
|
#include <string>
|
||||||
int width, height;
|
|
||||||
int tileIndex;
|
|
||||||
|
|
||||||
Tile() = default;
|
struct CharacterData {
|
||||||
Tile(int _x, int _y, int _depth, int _width, int _height, int _tileIndex) {
|
//metadata
|
||||||
//The order of the arguments should be explicit
|
int owner;
|
||||||
x = _x;
|
std::string handle;
|
||||||
y = _y;
|
std::string avatar;
|
||||||
depth = _depth;
|
|
||||||
width = _width;
|
//world position
|
||||||
height = _height;
|
int mapIndex = 0;
|
||||||
tileIndex = _tileIndex;
|
Vector2 position = {0.0,0.0};
|
||||||
}
|
Vector2 motion = {0.0,0.0};
|
||||||
|
BBox bbox = {0,0,0,0};
|
||||||
|
|
||||||
|
//statistics
|
||||||
|
int level = 0;
|
||||||
|
int exp = 0;
|
||||||
|
int maxHP = 0;
|
||||||
|
int health = 0;
|
||||||
|
int maxMP = 0;
|
||||||
|
int mana = 0;
|
||||||
|
int attack = 0;
|
||||||
|
int defence = 0;
|
||||||
|
int intelligence = 0;
|
||||||
|
int resistance = 0;
|
||||||
|
float accuracy = 0.0;
|
||||||
|
float evasion = 0.0;
|
||||||
|
float luck = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator<(Tile const& lhs, Tile const& rhs);
|
|
||||||
bool operator>(Tile const& lhs, Tile const& rhs);
|
|
||||||
bool operator==(Tile const& lhs, Tile const& rhs);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "server_application.hpp"
|
||||||
|
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the queries
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
static const char* CREATE_CHARACTER = "INSERT INTO PlayerCharacters (owner, handle, avatar) VALUES (?, ?, ?);";
|
||||||
|
static const char* LOAD_CHARACTER = "SELECT * FROM PlayerCharacters WHERE handle = ?;";
|
||||||
|
static const char* SAVE_CHARACTER = "UPDATE OR FAIL PlayerCharacters SET mapIndex = ?2, positionX = ?3, positionY = ?4 WHERE uid = ?1;";
|
||||||
|
static const char* DELETE_CHARACTER = "DELETE FROM PlayerCharacters WHERE uid = ?;";
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the methods
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
int ServerApplication::CreateCharacter(int owner, std::string handle, std::string avatar) {
|
||||||
|
//Create the character, failing if it exists
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, CREATE_CHARACTER, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameters
|
||||||
|
bool ret = false;
|
||||||
|
ret |= sqlite3_bind_int(statement, 1, owner);
|
||||||
|
ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC);
|
||||||
|
ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC);
|
||||||
|
|
||||||
|
//check for binding errors
|
||||||
|
if (ret) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than this character exists
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
//load this character into memory
|
||||||
|
return LoadCharacter(owner, handle, avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServerApplication::LoadCharacter(int owner, std::string handle, std::string avatar) {
|
||||||
|
//load the specified character, creating it if it doesn't exist
|
||||||
|
//fail if it is already loaded, or does not belong to this account
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, LOAD_CHARACTER, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter
|
||||||
|
if (sqlite3_bind_text(statement, 1, handle.c_str(), handle.size() + 1, SQLITE_STATIC) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
int ret = sqlite3_step(statement);
|
||||||
|
|
||||||
|
//process the result
|
||||||
|
if (ret == SQLITE_ROW) {
|
||||||
|
//get the index
|
||||||
|
int uid = sqlite3_column_int(statement, 0);
|
||||||
|
|
||||||
|
//check to see if this character is already loaded
|
||||||
|
if (characterMap.find(uid) != characterMap.end()) {
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check the owner
|
||||||
|
if (owner != sqlite3_column_int(statement, 1)) {
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract the data into memory
|
||||||
|
CharacterData& newChar = characterMap[uid];
|
||||||
|
|
||||||
|
//metadata
|
||||||
|
newChar.owner = owner;
|
||||||
|
newChar.handle = reinterpret_cast<const char*>(sqlite3_column_text(statement, 2));
|
||||||
|
newChar.avatar = reinterpret_cast<const char*>(sqlite3_column_text(statement, 3));
|
||||||
|
//Don't cache the birth
|
||||||
|
|
||||||
|
//world position
|
||||||
|
newChar.mapIndex = sqlite3_column_int(statement, 5);
|
||||||
|
newChar.position.x = (double)sqlite3_column_int(statement, 6);
|
||||||
|
newChar.position.y = (double)sqlite3_column_int(statement, 7);
|
||||||
|
|
||||||
|
//statistics
|
||||||
|
newChar.level = sqlite3_column_int(statement, 8);
|
||||||
|
newChar.exp = sqlite3_column_int(statement, 9);
|
||||||
|
newChar.maxHP = sqlite3_column_int(statement, 10);
|
||||||
|
newChar.health = sqlite3_column_int(statement, 11);
|
||||||
|
newChar.maxMP = sqlite3_column_int(statement, 12);
|
||||||
|
newChar.mana = sqlite3_column_int(statement, 13);
|
||||||
|
newChar.attack = sqlite3_column_int(statement, 14);
|
||||||
|
newChar.defence = sqlite3_column_int(statement, 15);
|
||||||
|
newChar.intelligence = sqlite3_column_int(statement, 16);
|
||||||
|
newChar.resistance = sqlite3_column_int(statement, 17);
|
||||||
|
newChar.accuracy = sqlite3_column_double(statement, 18);
|
||||||
|
newChar.evasion = sqlite3_column_double(statement, 19);
|
||||||
|
newChar.luck = sqlite3_column_double(statement, 20);
|
||||||
|
|
||||||
|
//TODO: equipment
|
||||||
|
|
||||||
|
//finish the routine
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
if (ret == SQLITE_DONE) {
|
||||||
|
//create the non-existant character instead
|
||||||
|
return CreateCharacter(owner, handle, avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw(std::runtime_error(std::string() + "Unknown SQL error in LoadCharacter: " + sqlite3_errmsg(database) ));
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServerApplication::SaveCharacter(int uid) {
|
||||||
|
//save this character from memory, replacing it if it exists in the database
|
||||||
|
//DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID.
|
||||||
|
|
||||||
|
//this method fails if this character is not loaded
|
||||||
|
if (characterMap.find(uid) == characterMap.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterData& character = characterMap[uid];
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, SAVE_CHARACTER, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameters
|
||||||
|
bool ret = false;
|
||||||
|
ret |= sqlite3_bind_int(statement, 1, uid) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 2, character.mapIndex) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 3, (int)character.position.x) != SQLITE_OK;
|
||||||
|
ret |= sqlite3_bind_int(statement, 4, (int)character.position.y) != SQLITE_OK;
|
||||||
|
//TODO: stats, etc.
|
||||||
|
|
||||||
|
//check for binding errors
|
||||||
|
if (ret) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than something went horribly wrong
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
throw( std::runtime_error(std::string() + "Unknown SQL error when saving an account: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
//successful execution
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::UnloadCharacter(int uid) {
|
||||||
|
//save this character, then unload it
|
||||||
|
SaveCharacter(uid);
|
||||||
|
characterMap.erase(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::DeleteCharacter(int uid) {
|
||||||
|
//delete this character from the database, then remove it from memory
|
||||||
|
sqlite3_stmt* statement = nullptr;
|
||||||
|
|
||||||
|
//prep
|
||||||
|
if (sqlite3_prepare_v2(database, DELETE_CHARACTER, -1, &statement, nullptr) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter
|
||||||
|
if (sqlite3_bind_int(statement, 1, uid) != SQLITE_OK) {
|
||||||
|
throw( std::runtime_error(std::string() + "Failed to replace a prepared statement's parameter: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//execute
|
||||||
|
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||||
|
//if this fails, than something went horribly wrong
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
throw( std::runtime_error(std::string() + "Unknown SQL error when deleting an account: " + sqlite3_errmsg(database)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//finish the routine
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
characterMap.erase(uid);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -19,20 +19,14 @@
|
|||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*/
|
*/
|
||||||
#ifndef CLIENT_HPP_
|
#ifndef CLIENTDATA_HPP_
|
||||||
#define CLIENT_HPP_
|
#define CLIENTDATA_HPP_
|
||||||
|
|
||||||
#include "SDL/SDL_net.h"
|
#include "SDL/SDL_net.h"
|
||||||
|
|
||||||
#include <map>
|
struct ClientData {
|
||||||
|
IPaddress address = {0,0};
|
||||||
/* Hold the client info.
|
static int uidCounter;
|
||||||
*/
|
|
||||||
|
|
||||||
struct Client {
|
|
||||||
IPaddress address;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<int, Client> ClientMap;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+1
-1
@@ -33,7 +33,7 @@ int main(int argc, char** argv) {
|
|||||||
try {
|
try {
|
||||||
ServerApplication app;
|
ServerApplication app;
|
||||||
app.Init(argc, argv);
|
app.Init(argc, argv);
|
||||||
app.Loop();
|
app.Proc();
|
||||||
app.Quit();
|
app.Quit();
|
||||||
}
|
}
|
||||||
catch(exception& e) {
|
catch(exception& e) {
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
#config
|
#config
|
||||||
INCLUDES+=. ../common ../common/map ../common/network
|
INCLUDES+=. ../common ../common/map ../common/script ../common/network
|
||||||
LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3
|
LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3
|
||||||
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
|
||||||
|
|||||||
@@ -1,300 +0,0 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
|
||||||
*
|
|
||||||
* This software is provided 'as-is', without any express or implied
|
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
|
||||||
* arising from the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software
|
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
*
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
*
|
|
||||||
* 3. This notice may not be removed or altered from any source
|
|
||||||
* distribution.
|
|
||||||
*/
|
|
||||||
#include "server_application.hpp"
|
|
||||||
|
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
//-------------------------
|
|
||||||
//Define the ServerApplication
|
|
||||||
//-------------------------
|
|
||||||
|
|
||||||
ServerApplication::ServerApplication() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerApplication::~ServerApplication() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::Init(int argc, char** argv) {
|
|
||||||
//TODO: proper command line option parsing
|
|
||||||
|
|
||||||
//load config
|
|
||||||
config.Load("rsc\\config.cfg");
|
|
||||||
|
|
||||||
//Init SDL
|
|
||||||
if (SDL_Init(0)) {
|
|
||||||
throw(runtime_error("Failed to initialize SDL"));
|
|
||||||
}
|
|
||||||
cout << "initialized SDL" << endl;
|
|
||||||
|
|
||||||
//Init SDL_net
|
|
||||||
if (SDLNet_Init()) {
|
|
||||||
throw(runtime_error("Failed to init SDL_net"));
|
|
||||||
}
|
|
||||||
network.Open(config.Int("server.port"), sizeof(NetworkPacket));
|
|
||||||
cout << "initialized SDL_net" << endl;
|
|
||||||
|
|
||||||
//Init SQL
|
|
||||||
string dbname = (config["server.dbname"].size()) ? config["server.dbname"] : std::string(argv[0]) + ".db"; //fancy and unnecessary
|
|
||||||
int ret = sqlite3_open_v2(dbname.c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, nullptr);
|
|
||||||
if (ret != SQLITE_OK || !database) {
|
|
||||||
throw(runtime_error("Failed to open the server database"));
|
|
||||||
}
|
|
||||||
cout << "initialized SQL" << endl;
|
|
||||||
cout << "Database filename: " << dbname << endl;
|
|
||||||
|
|
||||||
//TODO: move this into a function?
|
|
||||||
//Run setup scripts
|
|
||||||
ifstream is("rsc\\scripts\\setup_server.sql");
|
|
||||||
if (!is.is_open()) {
|
|
||||||
throw(runtime_error("Failed to run database setup script"));
|
|
||||||
}
|
|
||||||
string script;
|
|
||||||
getline(is, script, '\0');
|
|
||||||
is.close();
|
|
||||||
sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::Loop() {
|
|
||||||
NetworkPacket packet;
|
|
||||||
|
|
||||||
while(running) {
|
|
||||||
//suck in the waiting packets & process them
|
|
||||||
try {
|
|
||||||
while(network.Receive()) {
|
|
||||||
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
|
|
||||||
packet.meta.srcAddress = network.GetInPacket()->address;
|
|
||||||
HandlePacket(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(exception& e) {
|
|
||||||
cerr << "Network Error: " << e.what() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//give the computer a break
|
|
||||||
SDL_Delay(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::Quit() {
|
|
||||||
//members
|
|
||||||
network.Close();
|
|
||||||
|
|
||||||
//APIs
|
|
||||||
sqlite3_close_v2(database);
|
|
||||||
SDLNet_Quit();
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandlePacket(NetworkPacket packet) {
|
|
||||||
switch(packet.meta.type) {
|
|
||||||
case NetworkPacket::Type::BROADCAST_REQUEST:
|
|
||||||
HandleBroadcastRequest(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::JOIN_REQUEST:
|
|
||||||
HandleJoinRequest(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::DISCONNECT:
|
|
||||||
HandleDisconnect(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::SYNCHRONIZE:
|
|
||||||
HandleSynchronize(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::SHUTDOWN:
|
|
||||||
HandleShutdown(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::PLAYER_NEW:
|
|
||||||
HandlePlayerNew(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::PLAYER_DELETE:
|
|
||||||
HandlePlayerDelete(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NetworkPacket::Type::PLAYER_UPDATE:
|
|
||||||
HandlePlayerUpdate(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//handle errors
|
|
||||||
default:
|
|
||||||
throw(runtime_error("Unknown NetworkPacket::Type encountered"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) {
|
|
||||||
//send back the server's name
|
|
||||||
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE;
|
|
||||||
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
|
|
||||||
network.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
|
|
||||||
//TODO: prevent duplicate logins from the same address?
|
|
||||||
|
|
||||||
//create the new client, filling it with the correct info
|
|
||||||
Client newClient;
|
|
||||||
newClient.address = packet.meta.srcAddress;
|
|
||||||
|
|
||||||
//push the new client
|
|
||||||
clientMap[clientCounter] = newClient;
|
|
||||||
|
|
||||||
//send the client their info
|
|
||||||
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
|
|
||||||
packet.clientInfo.index = clientCounter;
|
|
||||||
network.Send(&newClient.address, &packet, sizeof(NetworkPacket));
|
|
||||||
|
|
||||||
//finished this routine
|
|
||||||
clientCounter++;
|
|
||||||
cout << "connect, total: " << clientMap.size() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandleDisconnect(NetworkPacket packet) {
|
|
||||||
//disconnect the specified client
|
|
||||||
network.Send(&clientMap[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket));
|
|
||||||
clientMap.erase(packet.clientInfo.index);
|
|
||||||
|
|
||||||
//delete players
|
|
||||||
erase_if(playerMap, [&](pair<int, Player> it) -> bool {
|
|
||||||
if (it.second.clientIndex == packet.clientInfo.index) {
|
|
||||||
NetworkPacket delPacket;
|
|
||||||
|
|
||||||
//data to delete one specific player
|
|
||||||
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
|
|
||||||
delPacket.playerInfo.playerIndex = it.first;
|
|
||||||
|
|
||||||
//send to all
|
|
||||||
PumpPacket(delPacket);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
cout << "disconnect, total: " << clientMap.size() << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandleSynchronize(NetworkPacket packet) {
|
|
||||||
//send all the server's data to this client
|
|
||||||
NetworkPacket newPacket;
|
|
||||||
|
|
||||||
//players
|
|
||||||
newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
|
|
||||||
for (auto& it : playerMap) {
|
|
||||||
newPacket.playerInfo.playerIndex = it.first;
|
|
||||||
snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
|
|
||||||
snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
|
|
||||||
newPacket.playerInfo.position = it.second.position;
|
|
||||||
newPacket.playerInfo.motion = it.second.motion;
|
|
||||||
network.Send(&clientMap[packet.clientInfo.index].address, &newPacket, sizeof(NetworkPacket));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandleShutdown(NetworkPacket packet) {
|
|
||||||
//end the server
|
|
||||||
running = false;
|
|
||||||
|
|
||||||
//disconnect all clients
|
|
||||||
packet.meta.type = NetworkPacket::Type::DISCONNECT;
|
|
||||||
PumpPacket(packet);
|
|
||||||
|
|
||||||
cout << "shutting down" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandlePlayerNew(NetworkPacket packet) {
|
|
||||||
//create the new player object
|
|
||||||
Player newPlayer;
|
|
||||||
newPlayer.clientIndex = packet.playerInfo.clientIndex;
|
|
||||||
newPlayer.handle = packet.playerInfo.handle;
|
|
||||||
newPlayer.avatar = packet.playerInfo.avatar;
|
|
||||||
newPlayer.position = {0,0};
|
|
||||||
newPlayer.motion = {0,0};
|
|
||||||
|
|
||||||
//push this player
|
|
||||||
playerMap[playerCounter] = newPlayer;
|
|
||||||
|
|
||||||
//send the client their info
|
|
||||||
packet.playerInfo.playerIndex = playerCounter;
|
|
||||||
packet.playerInfo.position = playerMap[playerCounter].position;
|
|
||||||
packet.playerInfo.motion = playerMap[playerCounter].motion;
|
|
||||||
|
|
||||||
//actually send to everyone
|
|
||||||
PumpPacket(packet);
|
|
||||||
|
|
||||||
//finish this routine
|
|
||||||
playerCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandlePlayerDelete(NetworkPacket packet) {
|
|
||||||
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
|
|
||||||
throw(std::runtime_error("Cannot delete a non-existant player"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete players
|
|
||||||
erase_if(playerMap, [&](pair<int, Player> it) -> bool {
|
|
||||||
if (it.first == packet.playerInfo.playerIndex) {
|
|
||||||
NetworkPacket delPacket;
|
|
||||||
|
|
||||||
//data to delete one specific player
|
|
||||||
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
|
|
||||||
delPacket.playerInfo.playerIndex = it.first;
|
|
||||||
|
|
||||||
//send to all
|
|
||||||
PumpPacket(delPacket);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) {
|
|
||||||
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
|
|
||||||
throw(std::runtime_error("Cannot update a non-existant player"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//server is the slave to the clients, but only for now
|
|
||||||
playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position;
|
|
||||||
playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion;
|
|
||||||
|
|
||||||
PumpPacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApplication::PumpPacket(NetworkPacket packet) {
|
|
||||||
//send this packet to all clients
|
|
||||||
for (auto& it : clientMap) {
|
|
||||||
network.Send(&it.second.address, &packet, sizeof(NetworkPacket));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright: (c) Kayne Ruse 2013
|
/* Copyright: (c) Kayne Ruse 2013, 2014
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -22,20 +22,29 @@
|
|||||||
#ifndef SERVERAPPLICATION_HPP_
|
#ifndef SERVERAPPLICATION_HPP_
|
||||||
#define SERVERAPPLICATION_HPP_
|
#define SERVERAPPLICATION_HPP_
|
||||||
|
|
||||||
|
//server specific stuff
|
||||||
|
#include "client_data.hpp"
|
||||||
|
#include "account_data.hpp"
|
||||||
|
#include "character_data.hpp"
|
||||||
|
|
||||||
|
//maps
|
||||||
|
#include "map_allocator.hpp"
|
||||||
|
#include "map_file_format.hpp"
|
||||||
|
#include "region_pager.hpp"
|
||||||
|
|
||||||
//networking
|
//networking
|
||||||
#include "network_packet.hpp"
|
#include "serial_packet.hpp"
|
||||||
#include "udp_network_utility.hpp"
|
#include "udp_network_utility.hpp"
|
||||||
|
#include "serial.hpp"
|
||||||
|
|
||||||
//APIs
|
//common
|
||||||
#include "sqlite3/sqlite3.h"
|
|
||||||
#include "SDL/SDL.h"
|
|
||||||
|
|
||||||
//misc
|
|
||||||
#include "config_utility.hpp"
|
#include "config_utility.hpp"
|
||||||
#include "vector2.hpp"
|
#include "vector2.hpp"
|
||||||
|
|
||||||
#include "client.hpp"
|
//APIs
|
||||||
#include "player.hpp"
|
#include "lua/lua.hpp"
|
||||||
|
#include "sqlite3/sqlite3.h"
|
||||||
|
#include "SDL/SDL.h"
|
||||||
|
|
||||||
//STL
|
//STL
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -45,44 +54,63 @@
|
|||||||
class ServerApplication {
|
class ServerApplication {
|
||||||
public:
|
public:
|
||||||
//standard functions
|
//standard functions
|
||||||
ServerApplication();
|
ServerApplication() = default;
|
||||||
~ServerApplication();
|
~ServerApplication() = default;
|
||||||
|
|
||||||
void Init(int argc, char** argv);
|
void Init(int argc, char** argv);
|
||||||
void Loop();
|
void Proc();
|
||||||
void Quit();
|
void Quit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandlePacket(NetworkPacket);
|
void HandlePacket(SerialPacket);
|
||||||
|
|
||||||
//high cohesion utility functions
|
//handle incoming traffic
|
||||||
void HandleBroadcastRequest(NetworkPacket);
|
void HandleBroadcastRequest(SerialPacket);
|
||||||
void HandleJoinRequest(NetworkPacket);
|
void HandleJoinRequest(SerialPacket);
|
||||||
void HandleDisconnect(NetworkPacket);
|
void HandleSynchronize(SerialPacket);
|
||||||
void HandleSynchronize(NetworkPacket);
|
void HandleDisconnect(SerialPacket);
|
||||||
void HandleShutdown(NetworkPacket);
|
void HandleShutdown(SerialPacket);
|
||||||
void HandlePlayerNew(NetworkPacket);
|
void HandleCharacterUpdate(SerialPacket);
|
||||||
void HandlePlayerDelete(NetworkPacket);
|
void HandleRegionRequest(SerialPacket);
|
||||||
void HandlePlayerUpdate(NetworkPacket);
|
|
||||||
|
|
||||||
void PumpPacket(NetworkPacket);
|
//TODO: a function that only sends to characters in a certain proximity
|
||||||
|
void PumpPacket(SerialPacket);
|
||||||
|
void PumpCharacterUnload(int uid);
|
||||||
|
|
||||||
//networking
|
//Account management
|
||||||
|
int CreateUserAccount(std::string username, int clientIndex);
|
||||||
|
int LoadUserAccount(std::string username, int clientIndex);
|
||||||
|
int SaveUserAccount(int uid);
|
||||||
|
void UnloadUserAccount(int uid);
|
||||||
|
void DeleteUserAccount(int uid);
|
||||||
|
|
||||||
|
//TODO: character management
|
||||||
|
int CreateCharacter(int owner, std::string handle, std::string avatar);
|
||||||
|
int LoadCharacter(int owner, std::string handle, std::string avatar);
|
||||||
|
int SaveCharacter(int uid);
|
||||||
|
void UnloadCharacter(int uid);
|
||||||
|
void DeleteCharacter(int uid);
|
||||||
|
|
||||||
|
//TODO: combat systems
|
||||||
|
|
||||||
|
//APIs
|
||||||
UDPNetworkUtility network;
|
UDPNetworkUtility network;
|
||||||
|
|
||||||
//database
|
|
||||||
sqlite3* database = nullptr;
|
sqlite3* database = nullptr;
|
||||||
|
lua_State* luaState = nullptr;
|
||||||
|
|
||||||
|
//server tables
|
||||||
|
std::map<int, ClientData> clientMap;
|
||||||
|
std::map<int, AccountData> accountMap;
|
||||||
|
std::map<int, CharacterData> characterMap;
|
||||||
|
|
||||||
|
//maps
|
||||||
|
//TODO: I need to handle multiple map objects
|
||||||
|
//TODO: Unload regions that are distant from any characters
|
||||||
|
RegionPager<LuaAllocator, LuaFormat> regionPager;
|
||||||
|
|
||||||
//misc
|
//misc
|
||||||
bool running = true;
|
bool running = true;
|
||||||
ConfigUtility config;
|
ConfigUtility config;
|
||||||
|
|
||||||
//global lists
|
|
||||||
ClientMap clientMap;
|
|
||||||
PlayerMap playerMap;
|
|
||||||
|
|
||||||
int clientCounter = 0;
|
|
||||||
int playerCounter = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2013, 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "server_application.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Handle various network input
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
|
||||||
|
//pack the server's data
|
||||||
|
packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
|
||||||
|
packet.serverInfo.networkVersion = NETWORK_VERSION;
|
||||||
|
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
|
||||||
|
packet.serverInfo.playerCount = characterMap.size();
|
||||||
|
|
||||||
|
//bounce this packet
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleJoinRequest(SerialPacket packet) {
|
||||||
|
//create the new client
|
||||||
|
ClientData newClient;
|
||||||
|
newClient.address = packet.meta.srcAddress;
|
||||||
|
|
||||||
|
//load the user account
|
||||||
|
int accountIndex = LoadUserAccount(packet.clientInfo.username, ClientData::uidCounter);
|
||||||
|
if (accountIndex < 0) {
|
||||||
|
//TODO: send rejection packet
|
||||||
|
std::cerr << "Error: Account already loaded: " << accountIndex << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//load the new character
|
||||||
|
int characterIndex = LoadCharacter(accountIndex, packet.clientInfo.handle, packet.clientInfo.avatar);
|
||||||
|
if (characterIndex < 0) {
|
||||||
|
//TODO: send rejection packet
|
||||||
|
std::cerr << "Error: Character already loaded: " << characterIndex << std::endl;
|
||||||
|
UnloadUserAccount(accountIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//send the client their info
|
||||||
|
packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
|
||||||
|
packet.clientInfo.clientIndex = ClientData::uidCounter;
|
||||||
|
packet.clientInfo.accountIndex = accountIndex;
|
||||||
|
packet.clientInfo.characterIndex = characterIndex;
|
||||||
|
|
||||||
|
//bounce this packet
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(&newClient.address, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
|
||||||
|
//send the new character to all clients
|
||||||
|
packet.meta.type = SerialPacket::Type::CHARACTER_NEW;
|
||||||
|
packet.characterInfo.characterIndex = characterIndex;
|
||||||
|
strncpy(packet.characterInfo.handle, characterMap[characterIndex].handle.c_str(), PACKET_STRING_SIZE);
|
||||||
|
strncpy(packet.characterInfo.avatar, characterMap[characterIndex].avatar.c_str(), PACKET_STRING_SIZE);
|
||||||
|
packet.characterInfo.position = characterMap[characterIndex].position;
|
||||||
|
packet.characterInfo.motion = characterMap[characterIndex].motion;
|
||||||
|
PumpPacket(packet);
|
||||||
|
|
||||||
|
//TODO: don't send anything to a certain client until they send the OK (the sync packet? or ignore client side?)
|
||||||
|
//finished this routine
|
||||||
|
clientMap[ClientData::uidCounter++] = newClient;
|
||||||
|
std::cout << "Connect, total: " << clientMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleSynchronize(SerialPacket packet) {
|
||||||
|
//TODO: compensate for large distances
|
||||||
|
|
||||||
|
//send all the server's data to this client
|
||||||
|
SerialPacket newPacket;
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
|
//characters
|
||||||
|
newPacket.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
|
||||||
|
for (auto& it : characterMap) {
|
||||||
|
//TODO: update this for the expanded CharacterData structure
|
||||||
|
newPacket.characterInfo.characterIndex = it.first;
|
||||||
|
snprintf(newPacket.characterInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
|
||||||
|
snprintf(newPacket.characterInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
|
||||||
|
newPacket.characterInfo.mapIndex = it.second.mapIndex;
|
||||||
|
newPacket.characterInfo.position = it.second.position;
|
||||||
|
newPacket.characterInfo.motion = it.second.motion;
|
||||||
|
serialize(&newPacket, buffer);
|
||||||
|
network.Send(&clientMap[packet.clientInfo.clientIndex].address, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleDisconnect(SerialPacket packet) {
|
||||||
|
//TODO: authenticate who is disconnecting/kicking
|
||||||
|
|
||||||
|
//forward to the specified client
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(&clientMap[accountMap[packet.clientInfo.accountIndex].clientIndex].address, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
|
||||||
|
//unload client and server-side characters
|
||||||
|
for (std::map<int, CharacterData>::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) {
|
||||||
|
if (it->second.owner == packet.clientInfo.accountIndex) {
|
||||||
|
PumpCharacterUnload(it->first);
|
||||||
|
SaveCharacter(it->first);
|
||||||
|
it = characterMap.erase(it); //efficient
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//erase the in-memory stuff
|
||||||
|
clientMap.erase(accountMap[packet.clientInfo.accountIndex].clientIndex);
|
||||||
|
UnloadUserAccount(packet.clientInfo.accountIndex);
|
||||||
|
|
||||||
|
//finished this routine
|
||||||
|
std::cout << "Disconnect, total: " << clientMap.size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleShutdown(SerialPacket packet) {
|
||||||
|
//TODO: authenticate who is shutting the server down
|
||||||
|
|
||||||
|
//end the server
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
//disconnect all clients
|
||||||
|
packet.meta.type = SerialPacket::Type::DISCONNECT;
|
||||||
|
PumpPacket(packet);
|
||||||
|
|
||||||
|
//finished this routine
|
||||||
|
std::cout << "Shutdown signal accepted" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleCharacterUpdate(SerialPacket packet) {
|
||||||
|
//TODO: this should be moved elsewhere
|
||||||
|
if (characterMap.find(packet.characterInfo.characterIndex) == characterMap.end()) {
|
||||||
|
throw(std::runtime_error("Cannot update a non-existant character"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: the server needs it's own movement system too
|
||||||
|
characterMap[packet.characterInfo.characterIndex].position = packet.characterInfo.position;
|
||||||
|
characterMap[packet.characterInfo.characterIndex].motion = packet.characterInfo.motion;
|
||||||
|
|
||||||
|
PumpPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::HandleRegionRequest(SerialPacket packet) {
|
||||||
|
//TODO: this should be moved elsewhere
|
||||||
|
packet.meta.type = SerialPacket::Type::REGION_CONTENT;
|
||||||
|
packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
|
||||||
|
|
||||||
|
//send the content
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::PumpPacket(SerialPacket packet) {
|
||||||
|
//NOTE: I don't really like this, but it'll do for now
|
||||||
|
char buffer[PACKET_BUFFER_SIZE];
|
||||||
|
serialize(&packet, buffer);
|
||||||
|
for (auto& it : clientMap) {
|
||||||
|
network.Send(&it.second.address, buffer, PACKET_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::PumpCharacterUnload(int uid) {
|
||||||
|
//delete the client-side character(s)
|
||||||
|
SerialPacket delPacket;
|
||||||
|
delPacket.meta.type = SerialPacket::Type::CHARACTER_DELETE;
|
||||||
|
delPacket.characterInfo.characterIndex = uid;
|
||||||
|
PumpPacket(delPacket);
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
/* Copyright: (c) Kayne Ruse 2014
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
*/
|
||||||
|
#include "server_application.hpp"
|
||||||
|
|
||||||
|
#include "sql_utility.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the various UIDs
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
int ClientData::uidCounter = 0;
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the public members
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void ServerApplication::Init(int argc, char** argv) {
|
||||||
|
//NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed.
|
||||||
|
std::cout << "Beginning startup" << std::endl;
|
||||||
|
|
||||||
|
//initial setup
|
||||||
|
config.Load("rsc\\config.cfg");
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Initialize the APIs
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//Init SDL
|
||||||
|
if (SDL_Init(0)) {
|
||||||
|
throw(std::runtime_error("Failed to initialize SDL"));
|
||||||
|
}
|
||||||
|
std::cout << "Initialized SDL" << std::endl;
|
||||||
|
|
||||||
|
//Init SDL_net
|
||||||
|
if (SDLNet_Init()) {
|
||||||
|
throw(std::runtime_error("Failed to initialize SDL_net"));
|
||||||
|
}
|
||||||
|
network.Open(config.Int("server.port"), PACKET_BUFFER_SIZE);
|
||||||
|
std::cout << "Initialized SDL_net" << std::endl;
|
||||||
|
|
||||||
|
//Init SQL
|
||||||
|
int ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
|
||||||
|
if (ret != SQLITE_OK || !database) {
|
||||||
|
throw(std::runtime_error(std::string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
|
||||||
|
}
|
||||||
|
std::cout << "Initialized SQL" << std::endl;
|
||||||
|
|
||||||
|
//Init lua
|
||||||
|
luaState = luaL_newstate();
|
||||||
|
if (!luaState) {
|
||||||
|
throw(std::runtime_error("Failed to initialize lua"));
|
||||||
|
}
|
||||||
|
luaL_openlibs(luaState);
|
||||||
|
std::cout << "Initialized lua" << std::endl;
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Setup the objects
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//setup the map object
|
||||||
|
regionPager.GetAllocator()->SetLuaState(luaState);
|
||||||
|
regionPager.GetFormat()->SetLuaState(luaState);
|
||||||
|
//TODO: config parameter
|
||||||
|
regionPager.GetFormat()->SetSaveDir("save/mapname/");
|
||||||
|
std::cout << "Prepared the map system" << std::endl;
|
||||||
|
|
||||||
|
//push the pager onto the lua registry
|
||||||
|
lua_pushstring(luaState, "pager");
|
||||||
|
lua_pushlightuserdata(luaState, reinterpret_cast<void*>(®ionPager));
|
||||||
|
lua_settable(luaState, LUA_REGISTRYINDEX);
|
||||||
|
std::cout << "Registered the map system in lua" << std::endl;
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Run the startup scripts
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
//setup the database
|
||||||
|
if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
|
||||||
|
throw(std::runtime_error("Failed to initialize SQL's setup script"));
|
||||||
|
}
|
||||||
|
std::cout << "Completed SQL's setup script" << std::endl;
|
||||||
|
|
||||||
|
//run lua's startup script
|
||||||
|
if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
|
||||||
|
throw(std::runtime_error(std::string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
|
||||||
|
}
|
||||||
|
std::cout << "Completed lua's setup script" << std::endl;
|
||||||
|
|
||||||
|
//debug output
|
||||||
|
std::cout << "Internal sizes:" << std::endl;
|
||||||
|
std::cout << "\tsizeof(SerialPacket): " << sizeof(SerialPacket) << std::endl;
|
||||||
|
std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl;
|
||||||
|
|
||||||
|
//finalize the startup
|
||||||
|
std::cout << "Startup completed successfully" << std::endl;
|
||||||
|
|
||||||
|
//debugging
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::Proc() {
|
||||||
|
SerialPacket packet;
|
||||||
|
while(running) {
|
||||||
|
//suck in the waiting packets & process them
|
||||||
|
while(network.Receive()) {
|
||||||
|
//get the packet
|
||||||
|
deserialize(&packet, network.GetInData());
|
||||||
|
//cache the source address
|
||||||
|
packet.meta.srcAddress = network.GetInPacket()->address;
|
||||||
|
//we need to go deeper
|
||||||
|
HandlePacket(packet);
|
||||||
|
}
|
||||||
|
//update the internals
|
||||||
|
//TODO: update the internals i.e. player positions
|
||||||
|
//give the computer a break
|
||||||
|
SDL_Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerApplication::Quit() {
|
||||||
|
std::cout << "Shutting down" << std::endl;
|
||||||
|
|
||||||
|
//save the server state
|
||||||
|
for (auto& it : accountMap) {
|
||||||
|
SaveUserAccount(it.first);
|
||||||
|
}
|
||||||
|
for (auto& it : characterMap) {
|
||||||
|
SaveCharacter(it.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
//empty the members
|
||||||
|
accountMap.clear();
|
||||||
|
characterMap.clear();
|
||||||
|
regionPager.UnloadAll();
|
||||||
|
|
||||||
|
//APIs
|
||||||
|
lua_close(luaState);
|
||||||
|
sqlite3_close_v2(database);
|
||||||
|
network.Close();
|
||||||
|
SDLNet_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
std::cout << "Shutdown finished" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------
|
||||||
|
//Define the uber switch
|
||||||
|
//-------------------------
|
||||||
|
|
||||||
|
void ServerApplication::HandlePacket(SerialPacket packet) {
|
||||||
|
switch(packet.meta.type) {
|
||||||
|
case SerialPacket::Type::BROADCAST_REQUEST:
|
||||||
|
HandleBroadcastRequest(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::JOIN_REQUEST:
|
||||||
|
HandleJoinRequest(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::SYNCHRONIZE:
|
||||||
|
HandleSynchronize(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::DISCONNECT:
|
||||||
|
HandleDisconnect(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::SHUTDOWN:
|
||||||
|
HandleShutdown(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::CHARACTER_UPDATE:
|
||||||
|
HandleCharacterUpdate(packet);
|
||||||
|
break;
|
||||||
|
case SerialPacket::Type::REGION_REQUEST:
|
||||||
|
HandleRegionRequest(packet);
|
||||||
|
break;
|
||||||
|
//handle errors
|
||||||
|
default:
|
||||||
|
throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
* I need to keep the documentation up to date. Namely, the GDD is getting out of date.
|
||||||
|
* How many lookups is the map system using?
|
||||||
|
* Add the serial packet to the network utility
|
||||||
|
|
||||||
|
--Naming conventions--
|
||||||
|
|
||||||
|
I need to define the differences between several different terms i.e. naming conventions.
|
||||||
|
I may also need to rewrite some variable names.
|
||||||
|
|
||||||
|
* User: This is the individual who is playing the game
|
||||||
|
* Player: A synonym for a user
|
||||||
|
* Character: This is the actual player character in the game
|
||||||
|
* Username: This is the name of the player; ususally kept private
|
||||||
|
* Handle: This is the name of a character
|
||||||
|
* Avatar: This is the name of the sprite used by a character
|
||||||
|
|
||||||
|
--ServerApplication's methods--
|
||||||
|
|
||||||
|
These interact with the database file, making the server a persistent system.
|
||||||
|
|
||||||
|
* CreateUserAccount
|
||||||
|
* LoadUserAccount
|
||||||
|
* SaveUserAccount
|
||||||
|
* UnloadUserAccount
|
||||||
|
* DeleteUserAccount
|
||||||
|
|
||||||
|
* CreateCharacter
|
||||||
|
* LoadCharacter
|
||||||
|
* SaveCharacter
|
||||||
|
* UnloadCharacter
|
||||||
|
* DeleteCharacter
|
||||||
|
|
||||||
|
--Battle System--
|
||||||
|
|
||||||
|
CombatPortal:
|
||||||
|
x, y
|
||||||
|
list<Character>
|
||||||
|
list<Monster>
|
||||||
|
//...
|
||||||
Reference in New Issue
Block a user