Compare commits

...

61 Commits

Author SHA1 Message Date
Kayne Ruse 288b62d3f8 Merge branch 'develop' 2014-05-13 03:26:13 +10:00
Kayne Ruse c5e8f1b3af Added account and character saving on shutdown 2014-05-13 03:25:50 +10:00
Kayne Ruse 980717f9fd Merge branch 'develop' 2014-05-13 03:01:26 +10:00
Kayne Ruse 68475eee0f Created PumpCharacterUnload 2014-05-13 02:51:50 +10:00
Kayne Ruse eeb2400e79 Rearranged the server-side object hierarchy (read more)
This has been a long-running problem for days, but I've finally
implemented a correctly working hierarchy between the ClientData,
AccountData and CharacterData objects:

CharacterData -> AccountData -> ClientData

There doesn't seem to be any issues with it right now, touch wood.
2014-05-13 02:09:00 +10:00
Kayne Ruse 01244005e9 Minor file renaming and tweaks 2014-05-13 00:23:04 +10:00
Kayne Ruse c5005b9b07 Merge branch 'develop' 2014-05-12 22:40:21 +10:00
Kayne Ruse 80a26341b1 Finished the character management, but it needs testing. 2014-05-11 20:13:27 +10:00
Kayne Ruse b7877962f1 Implemented CreateCharacter() and LoadCharacter() (read more)
There are issues with the indexes. That is, the accounts and the
characters need each other's indexes upon creation. I'll need to rectify
this now.
2014-05-10 20:30:33 +10:00
Kayne Ruse 688d064085 Merge branch 'database'
Conflicts:
	todo.txt

Merging todo.txt into the master branch, despite trying to keep it
separate.
2014-05-07 21:12:22 +10:00
Kayne Ruse 1c4d53e3ef Updated TODO, might as well merge this into the master 2014-05-07 21:07:42 +10:00
Kayne Ruse a53a134163 Merge branch 'account'
Added the "accountIndex" variable to the SerialPacket.
2014-05-07 20:55:43 +10:00
Kayne Ruse 4d12788c53 Finished the server-side modifications (read more)
* There seems to be something iffy with this branch
* The size of SerialPacket may have changed

I've implemented the accountIndex variable as best I can, but I really
shouldn't code at night. I'll need to go over the changes again before
merging this.
2014-05-07 20:55:09 +10:00
Kayne Ruse 1beb7cbd5d Began adding basic authentication 2014-05-06 21:35:07 +10:00
Kayne Ruse 8358d72a98 Merge branch 'database' (read more)
* Implemented user accounts.
* Other minor tweaks

I think the general "clientIndex" variable needs to be changed to
"accountIndex", since this will allow for much easier authentication.
2014-05-06 19:21:52 +10:00
Kayne Ruse 4ebff4a25a Minor tweaks, prepping for a merge 2014-05-06 19:18:53 +10:00
Kayne Ruse 0ff787abda Added Unloading and Deletion of user accounts 2014-05-06 18:57:49 +10:00
Kayne Ruse 9b5b48a8ab Implemented saving of user accounts (read more)
To modify an existing user account, change the in memory copy and then
call the function SaveUserAccount(uid), where uid is the index of the
modified account. If the save function is not called immediately, then the
behaviour of the server is undefined.
2014-05-06 18:33:20 +10:00
Kayne Ruse 5dd0fb9e23 BUGFIX: Signal when a duplicate account is being loaded
If a duplicate account is being created or loaded then the functions
return -1. The higher code can take it from there.
2014-05-06 16:41:08 +10:00
Kayne Ruse 7c210e04a5 Switched to using a wildcard symbol 2014-05-06 00:17:50 +10:00
Kayne Ruse 9236e02101 Merge branch 'master' into database (read more)
Conflicts:
	todo.txt (kept)

Just merging the editor's deletion into this branch, nothing else major.
2014-05-06 00:08:06 +10:00
Kayne Ruse 8f4ebf20da Removed the editor, since it isn't currently needed 2014-05-06 00:07:02 +10:00
Kayne Ruse 910e51f637 Began to implement user accounts using the database
I'm mostly just testing the waters at this stage, and i've left some debug
code in. There's no way to unload, delete, etc. the accounts, but that
comes later.
2014-05-05 23:57:07 +10:00
Kayne Ruse 92fc9b4e25 Adjusted the lua's map API, requiring a large rewrite
One the whole nothing major has changed, but I think this makes things
more logical. I just hope its stable, since I'm releasing a new tag.
2014-04-29 15:53:04 +10:00
Kayne Ruse 2b8e7241c9 Merge branch 'tweaks'; nothing major 2014-04-29 13:12:39 +10:00
Kayne Ruse 124cb3ad13 Did some renaming and comment tweaks 2014-04-29 06:34:23 +10:00
Kayne Ruse 6d3400d948 Merge branch 'network' (read more)
I've refactored the network layout. Here is a brief list of changes:

* The new player object is created server-side rather than client-side
* serial.cpp now uses macros to prevent hard-to-find logic errors
* A few method definitions have been re-ordered
* SerialPacket's internals have been slightly changed
* SerialPacket now carries a datestamp defining the network protocol
* server_application.cpp has been split into two separate files
* HandleJoinRequest() has been modified to create the new player object
2014-04-29 02:14:25 +10:00
Kayne Ruse 5031352fe3 Fixed the bug (read more)
The bug was being caused by a lack of a new player object being sent to
some clients. Fixed this by adding in the sending code, and preventing the
new entries being "registered" until the end of the HandleJoinRequest()
method.

Hopefully I can simply abstract away some of this code soon.
2014-04-29 01:47:01 +10:00
Kayne Ruse 624369f147 Discovered a bug 2014-04-27 22:46:19 +10:00
Kayne Ruse 9a7f7b8684 Rewrote the TODO list 2014-04-27 03:55:44 +10:00
Kayne Ruse fa9487c2f2 Fixed the previous bug (read more)
The bug was being caused by not assigning default values to the player
objects' internals. I've added a quick fix to these structs, but I think
it's best to expand them into proper classes now.
2014-04-27 02:37:20 +10:00
Kayne Ruse 9ec1ddab99 Exceptions are being thrown; retiring for the night
I don't know what's causing these issues, so I'm leaving it for tonight.
2014-04-26 02:48:15 +10:00
Kayne Ruse 6f1c2d0555 Merge branch 'fragmented-server' into network (read more)
I've divided the server's source into several different files. This should hopefully make it a bit easier to manage.

Please note that I do know there's an exception being thrown by the client
in this build.
2014-04-26 02:34:17 +10:00
Kayne Ruse 01b50d5590 I guess it was easier to compile the fragmented server than I thought 2014-04-26 02:31:48 +10:00
Kayne Ruse 9c673928e6 Began segmenting the server's code
I've created a separate branch for this because it's gonna be a bitch to
get compiled, and then I'll still have to ensure that the client & server
are work together correctly.

This build does not compile.
2014-04-26 02:09:32 +10:00
Kayne Ruse d55dfb90e4 Worked the new protocol into the client (read more)
I've added the handle and avatar fields back into the PlayerInfo section
in the network code, because I need to be able to load a specific file
when a new player is created. This wasn't forseen, but it's fine. i'm
leaving the fields in ClientInfo as well, because LobbyMenu is using them
to login to the server.

PlayerIndex is now a shared parameter.

I've shifted some code around in InWorld, however the overall logic is the
same.

This build (as well as the last) does not compile.
2014-04-26 01:05:31 +10:00
Kayne Ruse 235a05d006 Rearranged the SerialPacket and serialization code
The serialization code is now using macros to simplify each line, and to
prevent errors. It should be noted that, apart from the region content,
the serialization and deserialization code is essentially identical.
2014-04-25 23:50:19 +10:00
Kayne Ruse dabb7b3b2e Compiled a list of tasks
The list in todo.txt are a list of tasks that will be needed to complete
the login/user accounts overhaul, and will hopefully make the server a
persistent system.

Once the server is persistent (via the database) I can start on the combat
system.
2014-04-22 01:55:09 +10:00
Kayne Ruse e756289c2b Adjusted a few comments 2014-04-22 01:54:26 +10:00
Kayne Ruse c534158c2e Merge branch 'login' (read more)
This branch was originally intended to rewrite the login system, but I've discovered some serious problems that could not wait. See the previous commit for more information. Hopefully I can get back to this soon.

I believe this version deserves a new release tag.
2014-04-21 04:00:37 +10:00
Kayne Ruse b47191a0c1 Fixed a horrible region coordinate bug
Coordinates are supposed to be stored by their x & y, but the sizes of the
tile sheets were getting mixed in as well. When trying to store a region
at (0, 20), it was being stored at (0, 260).

Another visual bug inside the tile sheet's rendering function masked this
issue until now.

Another thing to note is that I've removed an incredibly complex system
for updating the client's map. The new system may seem complex at first,
but it is straight forward compared to what it replaced.

I've also fixed a few logarithmic lagging points in the code.
2014-04-21 03:56:48 +10:00
Kayne Ruse 6c6a025f2a Adjusted a few comments 2014-04-21 02:13:00 +10:00
Kayne Ruse 60edc97ea5 Added rejections for incompatible servers 2014-04-21 01:38:28 +10:00
Kayne Ruse a5b209d9e0 Merge branch 'login' (read more)
Made a few tweaks to the code, but the build still works, so I'm merging it into master.
2014-04-21 01:02:38 +10:00
Kayne Ruse fd673a415f Removed singleton pattern 2014-04-21 01:01:00 +10:00
Kayne Ruse 4270765146 Renamed NetworkPacket to SerialPacket, updated build 2014-04-20 23:54:59 +10:00
Kayne Ruse f56cb58dfb Revised SQL setup script, and the script function 2014-04-20 23:11:46 +10:00
Kayne Ruse f315f4bf35 Merge branch 'map' (read more)
After refactoring the map system, this new build uses the preprocessor macros to define the sizes of each region object. These macros, which are defined in region.hpp, were being used anyway; these modifications simply speed up the process by cutting out a lot of the fat.
2014-04-20 05:41:49 +10:00
Kayne Ruse 69765de433 Removed the TODO file; I think it's fairly stable again 2014-04-20 05:34:15 +10:00
Kayne Ruse 35d463d4ba Removed some annoying debugging messages 2014-04-20 05:30:08 +10:00
Kayne Ruse 894b46c5db Found the error in the format functor
I shouldn't automatically guess where an error is, since this project is
so complex.
2014-04-20 05:14:25 +10:00
Kayne Ruse eb0b18af6f Brought the programs into line, (BUG, read more)
It seems that the serialization code has a bug in it. I was expecting
something like this. When the server tries to send the region content, it
exits. I'll try and find the cause of the error, but I'm committing my
changes anyway.
2014-04-20 04:41:06 +10:00
Kayne Ruse fba183fa27 Brought the common/ directory up to date with the region's preprocessors
I really hope the serialization code still works.
2014-04-20 04:02:26 +10:00
Kayne Ruse c5a627004a Refactored the map system (read more)
The region's width, height and depth are all defined by preprocessor
macros. The rest of the map system has been updated to match. The
programs proper need to be updated as well. It would be a good idea to
include the macros' values as part of the initial communication protocols,
so that the clients don't connect to a server that is using the wrong
sized regions.
2014-04-20 03:41:08 +10:00
Kayne Ruse ac27fb0ca7 Found a list of TODO comments 2014-04-20 02:40:06 +10:00
Kayne Ruse be4a8311d5 Adjusted a few comments 2014-04-20 02:39:29 +10:00
Kayne Ruse 6d32d44fa3 Reverted some of the changes, stable 2014-04-15 23:23:15 +10:00
Kayne Ruse 9bacfb1424 Merge branch 'entity' (early part) (read more)
I've had some issues with the entity system I created, so I'm trying to
revert it right now, while also retaining the other few tweaks I've made.
2014-04-15 22:40:07 +10:00
Kayne Ruse c3464be589 The server is working correctly, using the entity system 2014-04-13 22:20:30 +10:00
Kayne Ruse 7fe71c60d0 This will not build; working on refactoring 2014-04-13 03:49:35 +10:00
Kayne Ruse 0c6537fb36 Began work on the server's generic entity system 2014-04-13 03:02:26 +10:00
55 changed files with 1827 additions and 2110 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. T
## 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
+5 -17
View File
@@ -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");
@@ -131,10 +119,10 @@ 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();
+7 -9
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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 {
+123 -182
View File
@@ -27,19 +27,16 @@
#include <cmath> #include <cmath>
#include <stdexcept> #include <stdexcept>
//debugging
#include <iostream>
using std::cout;
using std::endl;
//------------------------- //-------------------------
//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
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp"); buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
@@ -63,29 +60,17 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
shutDownButton.SetText("Shut Down"); shutDownButton.SetText("Shut Down");
//load the tilesheet //load the tilesheet
//TODO: add the tilesheet to the map system?
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15); tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
//setup the map object //TODO: move this into it's own function
mapPager.SetRegionWidth(REGION_WIDTH);
mapPager.SetRegionHeight(REGION_HEIGHT);
mapPager.SetRegionDepth(REGION_DEPTH);
//create the server-side player object
NetworkPacket packet;
packet.meta.type = NetworkPacket::Type::PLAYER_NEW;
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
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
//request a sync //request a sync
packet.meta.type = NetworkPacket::Type::SYNCHRONIZE; SerialPacket packet;
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); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
@@ -106,7 +91,7 @@ void InWorld::FrameStart() {
} }
void InWorld::Update(double delta) { void InWorld::Update(double delta) {
NetworkPacket packet; SerialPacket packet;
//suck in all waiting packets //suck in all waiting packets
while(network.Receive()) { while(network.Receive()) {
@@ -139,11 +124,12 @@ void InWorld::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0); // SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen()); Render(GetScreen());
SDL_Flip(GetScreen()); SDL_Flip(GetScreen());
fps.Calculate();
} }
void InWorld::Render(SDL_Surface* const screen) { void InWorld::Render(SDL_Surface* const screen) {
//draw the map //draw the map
for (auto it = mapPager.GetContainer()->begin(); it != mapPager.GetContainer()->end(); it++) { for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y); tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
} }
@@ -155,10 +141,7 @@ void InWorld::Render(SDL_Surface* const screen) {
//draw UI //draw UI
disconnectButton.DrawTo(screen); disconnectButton.DrawTo(screen);
shutDownButton.DrawTo(screen); shutDownButton.DrawTo(screen);
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0); font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
fps.Calculate();
} }
//------------------------- //-------------------------
@@ -200,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;
} }
@@ -233,28 +216,28 @@ 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;
} }
@@ -264,50 +247,76 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
//Network handlers //Network handlers
//------------------------- //-------------------------
void InWorld::HandlePacket(NetworkPacket packet) { 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 NetworkPacket::Type::PLAYER_NEW: case SerialPacket::Type::REGION_CONTENT:
HandlePlayerNew(packet);
break;
case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet);
break;
case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
case NetworkPacket::Type::REGION_CONTENT:
HandleRegionContent(packet); HandleRegionContent(packet);
break; break;
case SerialPacket::Type::CHARACTER_UPDATE:
HandleCharacterUpdate(packet);
break;
case SerialPacket::Type::CHARACTER_NEW:
HandleCharacterNew(packet);
break;
case SerialPacket::Type::CHARACTER_DELETE:
HandleCharacterDelete(packet);
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);
}
regionPager.PushRegion(packet.regionInfo.region);
packet.regionInfo.region = nullptr;
}
void InWorld::HandleCharacterUpdate(SerialPacket packet) {
if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
HandleCharacterNew(packet);
return;
} }
playerCharacters[packet.playerInfo.playerIndex].GetSprite()->LoadSurface(config["dir.sprites"] + packet.playerInfo.avatar, 4, 4); //update only if the message didn't originate from here
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position); if (packet.characterInfo.clientIndex != clientIndex) {
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion); playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
playerCharacters[packet.playerInfo.playerIndex].ResetDirection(); playerCharacters[packet.characterInfo.characterIndex].SetMotion(packet.characterInfo.motion);
}
playerCharacters[packet.characterInfo.characterIndex].ResetDirection();
}
void InWorld::HandleCharacterNew(SerialPacket packet) {
if (playerCharacters.find(packet.characterInfo.characterIndex) != playerCharacters.end()) {
throw(std::runtime_error("Cannot create duplicate characters"));
}
//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 //catch this client's player object
if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) { if (packet.characterInfo.characterIndex == characterIndex && !localCharacter) {
playerIndex = packet.playerInfo.playerIndex; localCharacter = &playerCharacters[characterIndex];
localCharacter = &playerCharacters[playerIndex];
//setup the camera //setup the camera
camera.width = GetScreen()->w; camera.width = GetScreen()->w;
camera.height = GetScreen()->h; camera.height = GetScreen()->h;
@@ -317,99 +326,74 @@ void InWorld::HandlePlayerNew(NetworkPacket packet) {
} }
} }
void InWorld::HandlePlayerDelete(NetworkPacket packet) { void InWorld::HandleCharacterDelete(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) { //TODO: authenticate
throw(std::runtime_error("Cannot delete non-existant players")); if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
throw(std::runtime_error("Cannot delete non-existant characters"));
} }
playerCharacters.erase(packet.playerInfo.playerIndex); playerCharacters.erase(packet.characterInfo.characterIndex);
//catch this client's player object //catch this client's player object
if (packet.playerInfo.clientIndex == clientIndex) { if (packet.characterInfo.characterIndex == characterIndex) {
playerIndex = -1; characterIndex = -1;
localCharacter = nullptr; localCharacter = nullptr;
} }
} }
void InWorld::HandlePlayerUpdate(NetworkPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
HandlePlayerNew(packet);
return;
}
//update only if the message didn't originate from here
if (packet.playerInfo.clientIndex != clientIndex) {
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position);
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion);
}
playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
}
void InWorld::HandleRegionContent(NetworkPacket packet) {
//replace existing regions
if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
mapPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y);
}
mapPager.PushRegion(packet.regionInfo.region);
packet.regionInfo.region = nullptr;
//debugging
cout << "Received region: " << packet.regionInfo.x << ", " << packet.regionInfo.y << endl;
if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
cout << "Success" << endl;
}
else {
cout << "Failure" << endl;
}
}
//------------------------- //-------------------------
//Server control //Server control
//------------------------- //-------------------------
void InWorld::SendState() { void InWorld::SendPlayerUpdate() {
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//pack the packet //pack the packet
packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE; packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
packet.playerInfo.clientIndex = clientIndex; packet.characterInfo.clientIndex = clientIndex;
packet.playerInfo.playerIndex = playerIndex; packet.characterInfo.accountIndex = accountIndex;
packet.playerInfo.position = localCharacter->GetPosition(); packet.characterInfo.characterIndex = characterIndex;
packet.playerInfo.motion = localCharacter->GetMotion(); packet.characterInfo.position = localCharacter->GetPosition();
packet.characterInfo.motion = localCharacter->GetMotion();
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
void InWorld::RequestDisconnect() { void InWorld::RequestDisconnect() {
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//send a disconnect request //send a disconnect request
packet.meta.type = NetworkPacket::Type::DISCONNECT; packet.meta.type = SerialPacket::Type::DISCONNECT;
packet.clientInfo.index = clientIndex; packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.accountIndex = accountIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
void InWorld::RequestShutDown() { void InWorld::RequestShutDown() {
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//send a shutdown request //send a shutdown request
packet.meta.type = NetworkPacket::Type::SHUTDOWN; packet.meta.type = SerialPacket::Type::SHUTDOWN;
packet.clientInfo.index = clientIndex; packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.accountIndex = accountIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
void InWorld::RequestRegion(int x, int y) { void InWorld::RequestRegion(int mapIndex, int x, int y) {
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//pack the region's data //pack the region's data
packet.meta.type = NetworkPacket::Type::REGION_REQUEST; packet.meta.type = SerialPacket::Type::REGION_REQUEST;
packet.regionInfo.mapIndex = mapIndex;
packet.regionInfo.x = x; packet.regionInfo.x = x;
packet.regionInfo.y = y; packet.regionInfo.y = y;
serialize(&packet, buffer); serialize(&packet, buffer);
@@ -420,79 +404,36 @@ void InWorld::RequestRegion(int x, int y) {
//Utilities //Utilities
//------------------------- //-------------------------
int InWorld::CheckBufferDistance(Region* const region) { //TODO: convert this into a more generic function?; using parameters for the bounds
/* DOCUMENTATION
* This algorithm is extremely complex and involed, but initial tests show
* that it gives the right answers. The purpose is to determine how far off screen
* a certain region is, so that it can be unloaded when necessary.
*
* If the region is actually onscreen, then there's no reason to run the rest, so
* the algorithm corrects for the camera's location, before checking the bounds of
* the screen.
*
* The next part is tricky. If X or Y is negative, then it is divided by the
* graphical size of the regions, resulting in a usable integer, representing how
* far from the screen it is in "region units". If, however, X or Y is larger than
* 0, than first, the size of the screen is subtracted from that variable, before
* it is then divided by the graphical size of a region. Finally, to compensate for
* the off by one error, 1 is added at the end.
*
* Since only the magnitude of the distance in either direction is needed, this
* method returns the largest absolute value of X or Y.
*
* The final result of this algorithm is an integer representing how far, rounded
* up, a certain region is from the screen's edges in any direction, measured in
* "region units". This algorithm may be flawed, in which case, I recommend simply
* replacing it with a boolean check, to see if the region's distance from the player
* is larger than a certain value. This algorithm lacks the advantages I initially
* expected, so that may be beneficial at some point.
*/
//locations relative to the camera
int x = region->GetX() - camera.x;
int y = region->GetY() - camera.y;
//if the region is visible, return -1
if (x >= -mapPager.GetRegionWidth() * tileSheet.GetTileW() && x < camera.width &&
y >= -mapPager.GetRegionHeight() * tileSheet.GetTileH() && y < camera.height) {
return -1;
}
//prune the screen's area from the algorithm; get the pseudo-indexes
if (x < 0) x /= (mapPager.GetRegionWidth() * tileSheet.GetTileW());
if (y < 0) y /= (mapPager.GetRegionHeight() * tileSheet.GetTileH());
if (x > 0) x = (x - camera.width) / (mapPager.GetRegionWidth() * tileSheet.GetTileW()) + 1;
if (y > 0) y = (y - camera.height) / (mapPager.GetRegionHeight() * tileSheet.GetTileH()) + 1;
//return the pseudo-index with the greatest magnitude
return std::max(abs(x), abs(y));
}
void InWorld::UpdateMap() { 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 //prune distant regions
for (auto it = mapPager.GetContainer()->begin(); it != mapPager.GetContainer()->end(); /* EMPTY */) { for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
if (CheckBufferDistance(*it) > 2) { //check if the region is outside off this area
//debugging if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) {
cout << "unloading: " << (*it)->GetX() << ", " << (*it)->GetY() << endl;
mapPager.UnloadRegion((*it)->GetX(), (*it)->GetY()); //clunky, but the alternative was time consuming
int tmpX = (*it)->GetX();
int tmpY = (*it)->GetY();
++it;
//reset regionPager.UnloadRegion(tmpX, tmpY);
it = mapPager.GetContainer()->begin();
continue; continue;
} }
++it; ++it;
} }
//TODO: make the region units official //request empty regions within this zone
int regionUnitX = mapPager.GetRegionWidth() * tileSheet.GetTileW(); for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
int regionUnitY = mapPager.GetRegionHeight() * tileSheet.GetTileH(); for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
//request empty regions, including buffers (-1 & +1 region unit) RequestRegion(0, i, j);
for (int i = snapToBase(regionUnitX, camera.x - regionUnitX); i <= snapToBase(regionUnitX, camera.x + camera.width + regionUnitX); i += regionUnitX) {
for (int j = snapToBase(regionUnitY, camera.y - regionUnitY); j <= snapToBase(regionUnitY, camera.y + camera.height + regionUnitY); j += regionUnitY) {
if (!mapPager.FindRegion(i, j)) {
RequestRegion(i, j);
} }
} }
} }
+17 -16
View File
@@ -23,13 +23,13 @@
#define INWORLD_HPP_ #define INWORLD_HPP_
//maps //maps
#include "map_generator.hpp" #include "map_allocator.hpp"
#include "map_file_format.hpp" #include "map_file_format.hpp"
#include "region_pager.hpp" #include "region_pager.hpp"
//networking //networking
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "network_packet.hpp" #include "serial_packet.hpp"
#include "serial.hpp" #include "serial.hpp"
//graphics //graphics
@@ -52,7 +52,7 @@
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:
@@ -72,28 +72,28 @@ protected:
void KeyUp(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&);
//Network handlers //Network handlers
void HandlePacket(NetworkPacket); void HandlePacket(SerialPacket);
void HandleDisconnect(NetworkPacket); void HandleDisconnect(SerialPacket);
void HandlePlayerNew(NetworkPacket); void HandleCharacterNew(SerialPacket);
void HandlePlayerDelete(NetworkPacket); void HandleCharacterDelete(SerialPacket);
void HandlePlayerUpdate(NetworkPacket); void HandleCharacterUpdate(SerialPacket);
void HandleRegionContent(NetworkPacket); void HandleRegionContent(SerialPacket);
//Server control //Server control
void SendState(); void SendPlayerUpdate();
void RequestDisconnect(); void RequestDisconnect();
void RequestShutDown(); void RequestShutDown();
void RequestRegion(int x, int y); void RequestRegion(int mapIndex, int x, int y);
//utilities //utilities
int CheckBufferDistance(Region* const);
void UpdateMap(); void UpdateMap();
//globals //shared parameters
ConfigUtility& config; ConfigUtility& config;
FrameRate fps;
UDPNetworkUtility& network; UDPNetworkUtility& network;
int& clientIndex; int& clientIndex;
int& accountIndex;
int& characterIndex;
//graphics //graphics
Image buttonImage; Image buttonImage;
@@ -101,21 +101,22 @@ protected:
TileSheet tileSheet; TileSheet tileSheet;
//map //map
RegionPager<BlankGenerator, DummyFormat> mapPager; RegionPager<BlankAllocator, DummyFormat> regionPager;
//UI //UI
Button disconnectButton; Button disconnectButton;
Button shutDownButton; Button shutDownButton;
//TODO: Fix the camera
struct { struct {
int x = 0, y = 0; int x = 0, y = 0;
int width = 0, height = 0; int width = 0, height = 0;
int marginX = 0, marginY = 0; int marginX = 0, marginY = 0;
} camera; } camera;
FrameRate fps;
//game //game
std::map<int, PlayerCharacter> playerCharacters; std::map<int, PlayerCharacter> playerCharacters;
PlayerCharacter* localCharacter = nullptr; PlayerCharacter* localCharacter = nullptr;
int playerIndex = -1;
}; };
#endif #endif
+46 -14
View File
@@ -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,7 +81,7 @@ 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()) {
deserialize(&packet, network.GetInData()); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; packet.meta.srcAddress = network.GetInPacket()->address;
@@ -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?
} }
} }
@@ -126,11 +143,11 @@ 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 //the vars
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//broadcast to the network, or a specific server //broadcast to the network, or a specific server
packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST; packet.meta.type = SerialPacket::Type::BROADCAST_REQUEST;
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE); network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE);
@@ -139,13 +156,18 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
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 //the vars
NetworkPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; 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
packet.meta.type = NetworkPacket::Type::JOIN_REQUEST;
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE); network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
selection = nullptr; selection = nullptr;
@@ -181,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;
} }
} }
+17 -8
View File
@@ -22,23 +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"
//network
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "network_packet.hpp" #include "serial_packet.hpp"
#include "serial.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:
@@ -55,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;
@@ -71,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;
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+75
View File
@@ -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
+5 -5
View File
@@ -44,17 +44,17 @@ void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t til
void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) { void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) {
Region::type_t tile = 0; Region::type_t tile = 0;
for (register int i = 0; i < region->GetWidth(); ++i) { for (register int i = 0; i < REGION_WIDTH; ++i) {
for (register int j = 0; j < region->GetHeight(); ++j) { for (register int j = 0; j < REGION_HEIGHT; ++j) {
for (register int k = 0; k < region->GetDepth(); ++k) { for (register int k = 0; k < REGION_DEPTH; ++k) {
tile = region->GetTile(i, j, k); tile = region->GetTile(i, j, k);
//0 is invisible //0 is invisible
if (tile == 0) continue; if (tile == 0) continue;
image.SetClipX((tile-1) % XCount * image.GetClipW()); image.SetClipX((tile-1) % XCount * image.GetClipW());
image.SetClipY((tile-1) / XCount * image.GetClipH()); image.SetClipY((tile-1) / XCount * image.GetClipH());
image.DrawTo(dest, image.DrawTo(dest,
region->GetX() + i * image.GetClipW() - camX, (region->GetX() + i) * image.GetClipW() - camX,
region->GetY() + j * image.GetClipH() - camY); (region->GetY() + j) * image.GetClipH() - camY);
} }
} }
} }
@@ -19,33 +19,25 @@
* 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 "map_generator.hpp" #include "map_allocator.hpp"
#include <stdexcept> #include <stdexcept>
void BlankGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) { void BlankAllocator::Create(Region** const ptr, int x, int y) {
(*ptr) = new Region(width, height, depth, x, y); (*ptr) = new Region(x, y);
} }
void BlankGenerator::Unload(Region* const ptr) { void BlankAllocator::Unload(Region* const ptr) {
delete ptr; delete ptr;
} }
/*
void PerlinGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) {
(*ptr) = new Region(width, height, depth, x, y);
}
void PerlinGenerator::Unload(Region* const ptr) { void LuaAllocator::Create(Region** const ptr, int x, int y) {
delete ptr;
}
*/
void LuaGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) {
//something to work on //something to work on
(*ptr) = new Region(width, height, depth, x, y); (*ptr) = new Region(x, y);
//API hook //API hook
lua_getglobal(state, "Region"); lua_getglobal(state, "map");
lua_getfield(state, -1, "Create"); lua_getfield(state, -1, "create");
lua_pushlightuserdata(state, *ptr); lua_pushlightuserdata(state, *ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) { if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
@@ -53,10 +45,10 @@ void LuaGenerator::Create(Region** const ptr, int width, int height, int depth,
lua_pop(state, 1); lua_pop(state, 1);
} }
void LuaGenerator::Unload(Region* const ptr) { void LuaAllocator::Unload(Region* const ptr) {
//API hook //API hook
lua_getglobal(state, "Region"); lua_getglobal(state, "map");
lua_getfield(state, -1, "Unload"); lua_getfield(state, -1, "unload");
lua_pushlightuserdata(state, ptr); lua_pushlightuserdata(state, ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) { if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) )); throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
@@ -19,32 +19,24 @@
* 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 MAPGENERATOR_HPP_ #ifndef MAPALLOCATOR_HPP_
#define MAPGENERATOR_HPP_ #define MAPALLOCATOR_HPP_
#include "region.hpp" #include "region.hpp"
#include "lua/lua.hpp" #include "lua/lua.hpp"
class BlankGenerator { class BlankAllocator {
public: public:
void Create(Region** const, int width, int height, int depth, int x, int y); void Create(Region** const, int x, int y);
void Unload(Region* const); void Unload(Region* const);
private: private:
// //
}; };
/*
class PerlinGenerator { class LuaAllocator {
public: public:
void Create(Region** const, int width, int height, int depth, int x, int y); void Create(Region** const, int x, int y);
void Unload(Region* const);
private:
//
};
*/
class LuaGenerator {
public:
void Create(Region** const, int width, int height, int depth, int x, int y);
void Unload(Region* const); void Unload(Region* const);
lua_State* SetLuaState(lua_State* L) { return state = L; } lua_State* SetLuaState(lua_State* L) { return state = L; }
+10 -23
View File
@@ -23,37 +23,24 @@
#include <stdexcept> #include <stdexcept>
void DummyFormat::Load(Region** const ptr, int width, int height, int depth, int x, int y) { void DummyFormat::Load(Region** const ptr, int x, int y) {
//EMPTY //EMPTY
} }
void DummyFormat::Save(Region* const ptr) { void DummyFormat::Save(Region* const ptr) {
//EMPTY //EMPTY
} }
/*
void VerboseFormat::Load(Region** const ptr, int x, int y) {
//TODO
}
void VerboseFormat::Save(Region* const ptr) { void LuaFormat::Load(Region** const ptr, int x, int y) {
//TODO
}
void CompactFormat::Load(Region** const ptr, int x, int y) {
//TODO
}
void CompactFormat::Save(Region* const ptr) {
//TODO
}
*/
void LuaFormat::Load(Region** const ptr, int width, int height, int depth, int x, int y) {
//something to load into //something to load into
(*ptr) = new Region(width, height, depth, x, y);
if (!(*ptr)) {
(*ptr) = new Region(x, y);
}
//API hook //API hook
lua_getglobal(state, "Region"); lua_getglobal(state, "map");
lua_getfield(state, -1, "Load"); lua_getfield(state, -1, "load");
lua_pushlightuserdata(state, *ptr); lua_pushlightuserdata(state, *ptr);
lua_pushstring(state, saveDir.c_str()); lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 1, 0) != LUA_OK) { if (lua_pcall(state, 2, 1, 0) != LUA_OK) {
@@ -68,8 +55,8 @@ void LuaFormat::Load(Region** const ptr, int width, int height, int depth, int x
void LuaFormat::Save(Region* const ptr) { void LuaFormat::Save(Region* const ptr) {
//API hook //API hook
lua_getglobal(state, "Region"); lua_getglobal(state, "map");
lua_getfield(state, -1, "Save"); lua_getfield(state, -1, "save");
lua_pushlightuserdata(state, ptr); lua_pushlightuserdata(state, ptr);
lua_pushstring(state, saveDir.c_str()); lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 0, 0) != LUA_OK) { if (lua_pcall(state, 2, 0, 0) != LUA_OK) {
+4 -23
View File
@@ -30,18 +30,7 @@
class DummyFormat { class DummyFormat {
public: public:
void Load(Region** const, int width, int height, int depth, int x, int y); void Load(Region** const, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
private:
std::string saveDir;
};
/*
class VerboseFormat {
public:
void Load(Region** const, int width, int height, int depth, int x, int y);
void Save(Region* const); void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; } std::string SetSaveDir(std::string s) { return saveDir = s; }
@@ -50,20 +39,12 @@ private:
std::string saveDir; std::string saveDir;
}; };
class CompactFormat { //TODO: verbose save file format
public: //TODO: compact save file format
void Load(Region** const, int width, int height, int depth, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
private:
std::string saveDir;
};
*/
class LuaFormat { class LuaFormat {
public: public:
void Load(Region** const, int width, int height, int depth, int x, int y); void Load(Region** const, int x, int y);
void Save(Region* const); void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; } std::string SetSaveDir(std::string s) { return saveDir = s; }
+3 -23
View File
@@ -21,35 +21,15 @@
*/ */
#include "region.hpp" #include "region.hpp"
Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY): Region::Region(int argX, int argY):
width(argWidth),
height(argHeight),
depth(argDepth),
x(argX), x(argX),
y(argY) y(argY)
{ {
tiles = new type_t**[width]; for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) {
for (register int i = 0; i < width; ++i) { *(reinterpret_cast<type_t*>(tiles) + i) = 0;
tiles[i] = new type_t*[height];
for (register int j = 0; j < height; ++j) {
tiles[i][j] = new type_t[depth];
for (register int k = 0; k < depth; ++k) {
tiles[i][j][k] = 0;
}
}
} }
} }
Region::~Region() {
for (register int i = 0; i < width; ++i) {
for (register int j = 0; j < height; j++) {
delete tiles[i][j];
}
delete tiles[i];
}
delete tiles;
}
Region::type_t Region::SetTile(int x, int y, int z, type_t v) { Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
return tiles[x][y][z] = v; return tiles[x][y][z] = v;
} }
+3 -10
View File
@@ -22,7 +22,6 @@
#ifndef REGION_HPP_ #ifndef REGION_HPP_
#define REGION_HPP_ #define REGION_HPP_
//temporary?
#define REGION_WIDTH 20 #define REGION_WIDTH 20
#define REGION_HEIGHT 20 #define REGION_HEIGHT 20
#define REGION_DEPTH 3 #define REGION_DEPTH 3
@@ -32,26 +31,20 @@ public:
typedef unsigned short type_t; typedef unsigned short type_t;
Region() = delete; Region() = delete;
Region(int width, int height, int depth, int x, int y); Region(int x, int y);
~Region(); ~Region() = default;
type_t SetTile(int x, int y, int z, type_t v); type_t SetTile(int x, int y, int z, type_t v);
type_t GetTile(int x, int y, int z); type_t GetTile(int x, int y, int z);
//accessors //accessors
int GetWidth() const { return width; }
int GetHeight() const { return height; }
int GetDepth() const { return depth; }
int GetX() const { return x; } int GetX() const { return x; }
int GetY() const { return y; } int GetY() const { return y; }
private: private:
const int width;
const int height;
const int depth;
const int x; const int x;
const int y; const int y;
type_t*** tiles = nullptr; type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH];
}; };
#endif #endif
+6 -16
View File
@@ -23,18 +23,6 @@
#include "utility.hpp" #include "utility.hpp"
RegionPagerBase::RegionPagerBase(int argWidth, int argHeight, int argDepth):
regionWidth(argWidth),
regionHeight(argHeight),
regionDepth(argDepth)
{
//EMPTY
}
RegionPagerBase::~RegionPagerBase() {
//EMPTY
}
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) { Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
Region* ptr = GetRegion(x, y); Region* ptr = GetRegion(x, y);
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v); return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
@@ -47,12 +35,10 @@ Region::type_t RegionPagerBase::GetTile(int x, int y, int z) {
Region* RegionPagerBase::GetRegion(int x, int y) { Region* RegionPagerBase::GetRegion(int x, int y) {
//snap the coords //snap the coords
x = snapToBase(regionWidth, x); x = snapToBase(REGION_WIDTH, x);
y = snapToBase(regionHeight, y); y = snapToBase(REGION_HEIGHT, y);
//get the region by various means //get the region by various means
//TODO: revert this try/catch point
Region* ptr = nullptr; Region* ptr = nullptr;
ptr = FindRegion(x, y); ptr = FindRegion(x, y);
if (ptr) return ptr; if (ptr) return ptr;
@@ -62,6 +48,10 @@ Region* RegionPagerBase::GetRegion(int x, int y) {
} }
Region* RegionPagerBase::FindRegion(int x, int y) { Region* RegionPagerBase::FindRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//find the region //find the region
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) { for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) {
if ((*it)->GetX() == x && (*it)->GetY() == y) { if ((*it)->GetX() == x && (*it)->GetY() == y) {
+29 -53
View File
@@ -29,9 +29,8 @@
class RegionPagerBase { class RegionPagerBase {
public: public:
RegionPagerBase() = default; RegionPagerBase() {};
RegionPagerBase(int regionWidth, int regionHeight, int regionDepth); virtual ~RegionPagerBase() {};
virtual ~RegionPagerBase();
//tile manipulation //tile manipulation
Region::type_t SetTile(int x, int y, int z, Region::type_t v); Region::type_t SetTile(int x, int y, int z, Region::type_t v);
@@ -47,93 +46,70 @@ public:
virtual Region* SaveRegion(int x, int y) = 0; virtual Region* SaveRegion(int x, int y) = 0;
virtual Region* CreateRegion(int x, int y) = 0; virtual Region* CreateRegion(int x, int y) = 0;
virtual void UnloadRegion(int x, int y) = 0; virtual void UnloadRegion(int x, int y) = 0;
//TODO: delete? //TODO: delete existing regions
//accessors & mutators //accessors & mutators
//NOTE: don't change the sizes mid-program, it will cause issues
int SetRegionWidth(int i) { return regionWidth = i; }
int SetRegionHeight(int i) { return regionHeight = i; }
int SetRegionDepth(int i) { return regionDepth = i; }
int GetRegionWidth() const { return regionWidth; }
int GetRegionHeight() const { return regionHeight; }
int GetRegionDepth() const { return regionDepth; }
std::list<Region*>* GetContainer() { return &regionList; } std::list<Region*>* GetContainer() { return &regionList; }
protected: protected:
int regionWidth;
int regionHeight;
int regionDepth;
std::list<Region*> regionList; std::list<Region*> regionList;
}; };
template<typename MapGenerator, typename MapFileFormat> template<typename Allocator, typename FileFormat>
class RegionPager : public RegionPagerBase { class RegionPager : public RegionPagerBase {
public: public:
RegionPager() = default; RegionPager() {};
RegionPager(int w, int h, int d):
RegionPagerBase(w, h, d)
{
//EMPTY
}
~RegionPager() { ~RegionPager() {
UnloadAll(); UnloadAll();
} }
Region* LoadRegion(int x, int y) { Region* LoadRegion(int x, int y) {
//snap the coords //snap the coords
x = snapToBase(regionWidth, x); x = snapToBase(REGION_WIDTH, x);
y = snapToBase(regionHeight, y); y = snapToBase(REGION_HEIGHT, y);
//load the region if possible //load the region if possible
Region* ptr = nullptr; Region* ptr = nullptr;
format.Load(&ptr, regionWidth, regionHeight, regionDepth, x, y); format.Load(&ptr, x, y);
if (ptr) { if (ptr) {
regionList.push_back(ptr); return PushRegion(ptr);
return ptr;
} }
return nullptr; return nullptr;
} }
Region* SaveRegion(int x, int y) { Region* SaveRegion(int x, int y) {
//snap the coords //snap the coords
x = snapToBase(regionWidth, x); x = snapToBase(REGION_WIDTH, x);
y = snapToBase(regionHeight, y); y = snapToBase(REGION_HEIGHT, y);
//find & save the region //find & save the region
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) { Region* ptr = FindRegion(x, y);
if ((*it)->GetX() == x && (*it)->GetY() == y) { if (ptr) {
format.Save(*it); format.Save(ptr);
return *it;
}
} }
return nullptr; return ptr;
} }
Region* CreateRegion(int x, int y) { Region* CreateRegion(int x, int y) {
//snap the coords //snap the coords
x = snapToBase(regionWidth, x); x = snapToBase(REGION_WIDTH, x);
y = snapToBase(regionHeight, y); y = snapToBase(REGION_HEIGHT, y);
//create and push the object //create and push the object
Region* ptr = nullptr; Region* ptr = nullptr;
generator.Create(&ptr, regionWidth, regionHeight, regionDepth, x, y); allocator.Create(&ptr, x, y);
regionList.push_back(ptr); return PushRegion(ptr);
return ptr;
} }
void UnloadRegion(int x, int y) { void UnloadRegion(int x, int y) {
//snap the coords //snap the coords
x = snapToBase(regionWidth, x); x = snapToBase(REGION_WIDTH, x);
y = snapToBase(regionHeight, y); y = snapToBase(REGION_HEIGHT, y);
//custom loop
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) { for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
if ((*it)->GetX() == x && (*it)->GetY() == y) { if ((*it)->GetX() == x && (*it)->GetY() == y) {
generator.Unload(*it); allocator.Unload(*it);
regionList.erase(it); it = regionList.erase(it);
//reset the loop, because of reasons
it = regionList.begin();
continue; continue;
} }
++it; ++it;
@@ -141,17 +117,17 @@ public:
} }
void UnloadAll() { void UnloadAll() {
for (auto& it : regionList) { for (auto& it : regionList) {
generator.Unload(it); allocator.Unload(it);
} }
regionList.clear(); regionList.clear();
} }
//accessors //accessors
MapGenerator* GetGenerator() { return &generator; } Allocator* GetAllocator() { return &allocator; }
MapFileFormat* GetFormat() { return &format; } FileFormat* GetFormat() { return &format; }
protected: protected:
MapGenerator generator; Allocator allocator;
MapFileFormat format; FileFormat format;
}; };
#endif #endif
+157 -170
View File
@@ -21,97 +21,69 @@
*/ */
#include "serial.hpp" #include "serial.hpp"
#include "map_generator.hpp" #include "map_allocator.hpp"
#include <cstring> #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 //internal serialization functions
//------------------------- //-------------------------
void serializeType(NetworkPacket* packet, char* buffer) { void serializeType(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
} }
void serializeServer(NetworkPacket* packet, char* buffer) { void serializeServer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE); //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(NetworkPacket* packet, char* buffer) { void serializeClient(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, &packet->clientInfo.index, sizeof(int));
}
void serializePlayer(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//indexes //indexes
memcpy(buffer, &packet->playerInfo.clientIndex, sizeof(int)); SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
buffer += sizeof(int); SERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
memcpy(buffer, &packet->playerInfo.playerIndex, sizeof(int)); SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
buffer += sizeof(int);
//text //texts
memcpy(buffer, packet->playerInfo.handle, PACKET_STRING_SIZE); SERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE; SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
memcpy(buffer, packet->playerInfo.avatar, PACKET_STRING_SIZE); SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
//vectors
memcpy(buffer, &packet->playerInfo.position.x, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.position.y, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.motion.x, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.motion.y, sizeof(double));
} }
void serializeRegionFormat(NetworkPacket* packet, char* buffer) { void serializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//size
memcpy(buffer, &packet->regionInfo.width, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.height, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.depth, sizeof(int));
buffer += sizeof(int);
//x & y
memcpy(buffer, &packet->regionInfo.x, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.y, sizeof(int));
}
void serializeRegionContent(NetworkPacket* packet, char* buffer) {
//format //format
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type)); SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(NetworkPacket::Type); SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
//size void serializeRegionContent(SerialPacket* packet, char* buffer) {
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetWidth(); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetHeight();
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetDepth();
buffer += sizeof(int);
//x & y //format
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetX(); SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(int); SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetY(); SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
buffer += sizeof(int);
//content //content
for (register int i = 0; i < packet->regionInfo.region->GetWidth(); i++) { for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < packet->regionInfo.region->GetHeight(); j++) { for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < packet->regionInfo.region->GetDepth(); k++) { for (register int k = 0; k < REGION_DEPTH; k++) {
*reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k); *reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k);
buffer += sizeof(Region::type_t); buffer += sizeof(Region::type_t);
} }
@@ -119,88 +91,84 @@ void serializeRegionContent(NetworkPacket* packet, char* buffer) {
} }
} }
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 //internal deserialization functions
//------------------------- //-------------------------
void deserializeType(NetworkPacket* packet, char* buffer) { void deserializeType(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
} }
void deserializeServer(NetworkPacket* packet, char* buffer) { void deserializeServer(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE); //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(NetworkPacket* packet, char* buffer) { void deserializeClient(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(&packet->clientInfo.index, buffer, sizeof(int));
}
void deserializePlayer(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//indexes //indexes
memcpy(&packet->playerInfo.clientIndex, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
buffer += sizeof(int); DESERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
memcpy(&packet->playerInfo.playerIndex, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
buffer += sizeof(int);
//text //texts
memcpy(packet->playerInfo.handle, buffer, PACKET_STRING_SIZE); DESERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE; DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
memcpy(packet->playerInfo.avatar, buffer, PACKET_STRING_SIZE); DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
//vectors
memcpy(&packet->playerInfo.position.x, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.position.y, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.motion.x, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.motion.y, buffer, sizeof(double));
} }
void deserializeRegionFormat(NetworkPacket* packet, char* buffer) { void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//size
memcpy(&packet->regionInfo.width, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.height, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.depth, buffer, sizeof(int));
buffer += sizeof(int);
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
}
void deserializeRegionContent(NetworkPacket* packet, char* buffer) {
//format //format
deserializeRegionFormat(packet, buffer); DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(int) * 5 + sizeof(NetworkPacket::Type); DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
//content void deserializeRegionContent(SerialPacket* packet, char* buffer) {
BlankGenerator().Create( 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.region,
packet->regionInfo.width,
packet->regionInfo.height,
packet->regionInfo.depth,
packet->regionInfo.x, packet->regionInfo.x,
packet->regionInfo.y packet->regionInfo.y
); );
for (register int i = 0; i < packet->regionInfo.region->GetWidth(); i++) { //content
for (register int j = 0; j < packet->regionInfo.region->GetHeight(); j++) { for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int k = 0; k < packet->regionInfo.region->GetDepth(); k++) { 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)); packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast<Region::type_t*>(buffer));
buffer += sizeof(Region::type_t); buffer += sizeof(Region::type_t);
} }
@@ -208,92 +176,111 @@ void deserializeRegionContent(NetworkPacket* packet, char* buffer) {
} }
} }
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 //the interface functions
//------------------------- //-------------------------
void serialize(NetworkPacket* packet, void* buffer) { void serialize(SerialPacket* packet, void* buffer) {
switch(packet->meta.type) { switch(packet->meta.type) {
//No extra data //No extra data
case NetworkPacket::Type::NONE: case SerialPacket::Type::NONE:
case NetworkPacket::Type::PING: case SerialPacket::Type::PING:
case NetworkPacket::Type::PONG: case SerialPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST: case SerialPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer)); serializeType(packet, reinterpret_cast<char*>(buffer));
break; break;
//Server info //Server info
case NetworkPacket::Type::BROADCAST_RESPONSE: case SerialPacket::Type::BROADCAST_RESPONSE:
serializeServer(packet, reinterpret_cast<char*>(buffer)); serializeServer(packet, reinterpret_cast<char*>(buffer));
break; break;
//Client info //Client info
case NetworkPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::DISCONNECT: case SerialPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::SHUTDOWN: case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer)); serializeClient(packet, reinterpret_cast<char*>(buffer));
break; break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
serializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info //region info
case NetworkPacket::Type::REGION_REQUEST: case SerialPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer)); serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break; break;
case NetworkPacket::Type::REGION_CONTENT: case SerialPacket::Type::REGION_CONTENT:
serializeRegionContent(packet, reinterpret_cast<char*>(buffer)); serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break; 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(NetworkPacket* packet, void* buffer) { void deserialize(SerialPacket* packet, void* buffer) {
//find the type, so that you can actually deserialize the packet! //find the type, so that you can actually deserialize the packet!
deserializeType(packet, reinterpret_cast<char*>(buffer)); deserializeType(packet, reinterpret_cast<char*>(buffer));
switch(packet->meta.type) { switch(packet->meta.type) {
//No extra data //No extra data
case NetworkPacket::Type::NONE: case SerialPacket::Type::NONE:
case NetworkPacket::Type::PING: case SerialPacket::Type::PING:
case NetworkPacket::Type::PONG: case SerialPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST: case SerialPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
//NOTHING //NOTHING
break; break;
//Server info //Server info
case NetworkPacket::Type::BROADCAST_RESPONSE: case SerialPacket::Type::BROADCAST_RESPONSE:
deserializeServer(packet, reinterpret_cast<char*>(buffer)); deserializeServer(packet, reinterpret_cast<char*>(buffer));
break; break;
//Client info //Client info
case NetworkPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::DISCONNECT: case SerialPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::SHUTDOWN: case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer)); deserializeClient(packet, reinterpret_cast<char*>(buffer));
break; break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
deserializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info //region info
case NetworkPacket::Type::REGION_REQUEST: case SerialPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer)); deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break; break;
case NetworkPacket::Type::REGION_CONTENT: case SerialPacket::Type::REGION_CONTENT:
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer)); deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break; 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;
} }
} }
+8 -7
View File
@@ -22,16 +22,17 @@
#ifndef SERIAL_HPP_ #ifndef SERIAL_HPP_
#define SERIAL_HPP_ #define SERIAL_HPP_
#include "network_packet.hpp" #include "serial_packet.hpp"
/* Sending regions are the largest type of packet /* NOTE: Keep the PACKET_BUFFER_SIZE up to date
* content: width * height * depth * sizoeof(type) * NOTE: REGION_CONTENT is currently the largest type of packet
* map format: sizeof(int) * 5 * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
* map format: sizeof(int) * 3
* metadata: sizeof(metadata) * metadata: sizeof(metadata)
*/ */
#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 5 + sizeof(NetworkPacket::Metadata) #define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacket::Metadata)
void serialize(NetworkPacket* const, void*); void serialize(SerialPacket* const, void*);
void deserialize(NetworkPacket* const, void*); void deserialize(SerialPacket* const, void*);
#endif #endif
@@ -19,19 +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 "vector2.hpp"
#include "region.hpp" #include "region.hpp"
#include "SDL/SDL_net.h" #include "SDL/SDL_net.h"
#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
@@ -41,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,
@@ -49,23 +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.
PLAYER_NEW = 10,
PLAYER_DELETE = 11,
PLAYER_UPDATE = 12,
//map data //map data
REGION_REQUEST = 13, REGION_REQUEST = 10,
REGION_CONTENT = 14, REGION_CONTENT = 11,
//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
@@ -77,38 +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;
//TODO: map format
}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];
Vector2 position; }clientInfo;
Vector2 motion;
}playerInfo;
//map data //map data
struct RegionInformation { struct RegionInformation {
Metadata meta; Metadata meta;
int width, height, depth, x, y; int mapIndex;
int x, y;
Region* region; Region* region;
}regionInfo; }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 motion;
}characterInfo;
//defaults //defaults
NetworkPacket() { SerialPacket() {
meta.type = Type::NONE; meta.type = Type::NONE;
meta.srcAddress = {0,0}; meta.srcAddress = {0,0};
} }
+2 -2
View File
@@ -20,7 +20,7 @@
#define LUA_LIB #define LUA_LIB
#include "lua/lua.hpp" #include "lua/lua.hpp"
#include "region_api.hpp" #include "map_api.hpp"
/* /*
@@ -41,7 +41,7 @@ static const luaL_Reg loadedlibs[] = {
{LUA_DBLIBNAME, luaopen_debug}, {LUA_DBLIBNAME, luaopen_debug},
/* custom libs */ /* custom libs */
{LUA_REGIONLIBNAME, luaopen_regionapi}, {LUA_MAPLIBNAME, luaopen_mapapi},
{NULL, NULL} {NULL, NULL}
}; };
+126
View File
@@ -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;
}
@@ -19,12 +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 REGIONAPI_HPP_ #ifndef MAPAPI_HPP_
#define REGIONAPI_HPP_ #define MAPAPI_HPP_
#include "lua/lua.hpp" #include "lua/lua.hpp"
#define LUA_REGIONLIBNAME "Region" #define LUA_MAPLIBNAME "map"
LUAMOD_API int luaopen_regionapi(lua_State* L); LUAMOD_API int luaopen_mapapi(lua_State* L);
#endif #endif
-91
View File
@@ -1,91 +0,0 @@
/* 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 "region_api.hpp"
#include "region.hpp"
static int setTile(lua_State* L) {
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));
return 0;
}
static int getTile(lua_State* L) {
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);
return 1;
}
static int getWidth(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetWidth());
return 1;
}
static int getHeight(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetHeight());
return 1;
}
static int getDepth(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetDepth());
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 dummy(lua_State* L) {
return 0;
}
static const luaL_Reg regionlib[] = {
{"SetTile",setTile},
{"GetTile",getTile},
{"GetWidth",getWidth},
{"GetHeight",getHeight},
{"GetDepth",getDepth},
{"GetX",getX},
{"GetY",getY},
{"Create", dummy},
{"Unload", dummy},
{"Load", dummy},
{"Save", dummy},
{nullptr, nullptr}
};
LUAMOD_API int luaopen_regionapi(lua_State* L) {
luaL_newlib(L, regionlib);
return 1;
}
+50
View File
@@ -0,0 +1,50 @@
/* 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 "sql_utility.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <fstream>
#include <cstdlib>
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;
}
std::string script;
getline(is, script, '\0');
is.close();
//run the SQL loaded from the file
char* errmsg = nullptr;
int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg);
if (ret != SQLITE_OK) {
//handle any errors received from the SQL
std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg);
free(errmsg);
throw(e);
}
return ret;
}
+8 -19
View File
@@ -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;
}
+4 -1
View File
@@ -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
-139
View File
@@ -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
}
-74
View File
@@ -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
-130
View File
@@ -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;
}
-235
View File
@@ -1,235 +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", "Close"},
{"Edit", "Set Tile", "Set Brush", "Script"},
{"Debug", "Debug On", "Debug Off", "Toggle", "Testificate"}
});
//setup the map
pager.SetRegionWidth(REGION_WIDTH);
pager.SetRegionHeight(REGION_HEIGHT);
pager.SetRegionDepth(REGION_DEPTH);
//debug
tsheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
for (int i = 0; i < REGION_WIDTH; i++) {
for (int j = 0; j < REGION_HEIGHT; j++) {
pager.SetTile(i, j, 0, 14);
}
}
pager.SetTile(5, 10, 1, 48);
}
EditorScene::~EditorScene() {
//
}
//-------------------------
//Frame loop
//-------------------------
void EditorScene::FrameStart() {
//
}
void EditorScene::Update(double delta) {
//
}
void EditorScene::FrameEnd() {
//
}
void EditorScene::Render(SDL_Surface* const screen) {
tsheet.DrawRegionTo(screen, pager.GetRegion(0, 0), camera.x, camera.y);
/* //debug
for (int i = 0; i < pager.GetRegionWidth()*2; i++) {
for (int j = 0; j < pager.GetRegionHeight()*2; j++) {
for (int k = 0; k < pager.GetRegionDepth(); k++) {
//TODO: skip the out-of-bounds regions
tsheet.DrawTo(
screen,
i*tsheet.GetTileW()-camera.x,
j*tsheet.GetTileH()-camera.y,
pager.GetTile(i,j,k)
);
}
}
}
*/
//draw a big bar across the top (hackish)
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, with a grey background
SDL_Rect clip = {
Sint16(debugInfo.GetClipW() - str.size() * font.GetCharW()),
Sint16(font.GetCharH() * line),
Uint16(str.size() * font.GetCharW()),
Uint16(font.GetCharH())
};
SDL_FillRect(debugInfo.GetSurface(), &clip, SDL_MapRGB(debugInfo.GetSurface()->format, 64, 64, 64));
font.DrawStringTo(str, debugInfo.GetSurface(), clip.x, clip.y);
}
//-------------------------
//Event handlers
//-------------------------
void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
menuBar.MouseMotion(motion);
if (motion.state & SDL_BUTTON_RMASK) {
camera.x -= motion.xrel;
camera.y -= motion.yrel;
}
}
void EditorScene::MouseButtonDown(SDL_MouseButtonEvent const& button) {
menuBar.MouseButtonDown(button);
}
void EditorScene::MouseButtonUp(SDL_MouseButtonEvent const& button) {
int entry, drop;
menuBar.MouseButtonUp(button, &entry, &drop);
HandleMenuOption(entry, drop);
}
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) {
//
}
//-------------------------
//Members
//-------------------------
void EditorScene::HandleMenuOption(int entry, int 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: CLOSE
break;
}
break;
case 1: //Edit
switch(drop) {
case 0:
//TODO: SET TILE
break;
case 1:
//TODO: SET BRUSH
break;
case 2:
//TODO: 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;
}
}
-80
View File
@@ -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 "config_utility.hpp"
#include "image.hpp"
#include "raster_font.hpp"
#include "menu_bar.hpp"
#include "region_pager.hpp"
#include "map_generator.hpp"
#include "map_file_format.hpp"
#include "tile_sheet.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&);
//members
void HandleMenuOption(int entry, int drop);
//globals
ConfigUtility& config;
//debugging tools
void DrawToDebugInfo(std::string, int line);
Image debugInfo;
bool debugOpen = true;
RasterFont font;
Image buttonImage;
MenuBar menuBar;
struct {
int x = 0, y = 0;
} camera;
RegionPager<BlankGenerator, DummyFormat> pager;
TileSheet tsheet;
};
#endif
-43
View File
@@ -1,43 +0,0 @@
#config
INCLUDES+=../common ../common/graphics ../common/map ../common/ui
LIBS+=../libcommon.a -lmingw32 -lSDLmain -lSDL -llua
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
#source
CXXSRC=$(wildcard *.cpp)
CSRC=$(wildcard *.c)
#objects
OBJDIR=obj
OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o))
OBJ+=$(addprefix $(OBJDIR)/,$(CSRC:.c=.o))
#output
OUTDIR=../out
OUT=$(addprefix $(OUTDIR)/,editor)
#targets
all: $(OBJ) $(OUT)
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(OBJ): | $(OBJDIR)
$(OUT): | $(OUTDIR)
$(OBJDIR):
mkdir $(OBJDIR)
$(OUTDIR):
mkdir $(OUTDIR)
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-91
View File
@@ -1,91 +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)
{
//
}
TestificateScene::~TestificateScene() {
//
}
//-------------------------
//Frame loop
//-------------------------
void TestificateScene::FrameStart() {
//
}
void TestificateScene::Update(double delta) {
//
}
void TestificateScene::FrameEnd() {
//
}
void TestificateScene::Render(SDL_Surface* const screen) {
//
}
//-------------------------
//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) {
//
}
-53
View File
@@ -1,53 +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 TESTIFICATESCENE_HPP_
#define TESTIFICATESCENE_HPP_
#include "base_scene.hpp"
#include "config_utility.hpp"
class TestificateScene : public BaseScene {
public:
//Public access members
TestificateScene(ConfigUtility* const);
~TestificateScene();
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;
};
#endif
+1 -1
View File
@@ -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)
+3 -2
View File
@@ -23,7 +23,8 @@ map.pager.height = 20
map.pager.depth = 3 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
+12 -14
View File
@@ -1,29 +1,27 @@
print("Lua script check OK (./rsc)") print("Lua script check OK (./rsc)")
function Region.Create(r) function map.create(region)
print("Region:Create(r", Region.GetX(r), Region.GetY(r), ")") for i = 1, map.getregionwidth() do
for i = 1, Region.GetWidth(r) do for j = 1, map.getregionheight() do
for j = 1, Region.GetHeight(r) do if math.abs(map.getx(region) + i -1) == math.abs(map.gety(region) + j -1) then
if math.abs(i) == math.abs(j) then map.settile(region, i, j, 1, 50)
Region.SetTile(r, i, j, 1, 50)
else else
Region.SetTile(r, i, j, 1, 14) map.settile(region, i, j, 1, 14)
end end
end end
end end
print("done")
end end
function Region.Unload(r) function map.unload(region)
print("Region:Unload(r", Region.GetX(r), Region.GetY(r), ")") --
end end
--return true if file loaded, otherwise return false --return true if file loaded, otherwise return false
function Region.Load(r, saveDir) function map.load(region, dir)
print("Region:Load(r,", saveDir, Region.GetX(r), Region.GetY(r), ")") --
return false return false
end end
function Region.Save(r, saveDir) function map.save(region, dir)
print("Region:Save(r,", saveDir, Region.GetX(r), Region.GetY(r), ")") --
end end
+49 -39
View File
@@ -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,35 +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 EDITORAPPLICATION_HPP_ #ifndef ACCOUNTDATA_HPP_
#define EDITORAPPLICATION_HPP_ #define ACCOUNTDATA_HPP_
#include "scene_list.hpp" #include <string>
#include "base_scene.hpp"
#include "config_utility.hpp"
class EditorApplication { struct AccountData {
private: std::string username;
EditorApplication(); //TODO: password
~EditorApplication(); bool blackListed = false;
static EditorApplication instance; bool whiteListed = true;
public: int clientIndex;
static EditorApplication* GetInstance() { return &instance; }
void Init();
void Proc();
void Quit();
private:
//Private access members
void LoadScene(SceneList sceneIndex);
void UnloadScene();
//globals
ConfigUtility config;
BaseScene* activeScene = nullptr;
}; };
#endif #endif
+192
View File
@@ -0,0 +1,192 @@
/* 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 = "INSERT OR REPLACE INTO UserAccounts VALUES (?, ?, ?, ?);";
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_text(statement, 2, account.username.c_str(), account.username.size() + 1, SQLITE_STATIC) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 3, account.blackListed) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 4, 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);
}
+59
View File
@@ -0,0 +1,59 @@
/* 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 CHARACTERDATA_HPP_
#define CHARACTERDATA_HPP_
//POD members
#include "bbox.hpp"
#include "vector2.hpp"
#include <string>
struct CharacterData {
//metadata
int owner;
std::string handle;
std::string avatar;
//world position
int mapIndex = 0;
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;
};
#endif
+229
View File
@@ -0,0 +1,229 @@
/* 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 = "INSERT OR REPLACE INTO PlayerCharacters (uid, owner, mapIndex, positionX, positionY) VALUES (?, ?, ?, ?, ?);";
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.owner) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 3, character.mapIndex) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 4, (int)character.position.x) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 5, (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,18 +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 SCENELIST_HPP_ #ifndef CLIENTDATA_HPP_
#define SCENELIST_HPP_ #define CLIENTDATA_HPP_
enum class SceneList { #include "SDL/SDL_net.h"
//these are reserved
QUIT,
CONTINUE,
FIRST,
//custom indexes struct ClientData {
TESTIFICATESCENE, IPaddress address = {0,0};
EDITORSCENE, static int uidCounter;
}; };
#endif #endif
+1 -1
View File
@@ -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) {
-361
View File
@@ -1,361 +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;
int runSQLScript(sqlite3* db, std::string fname) {
ifstream is(fname);
if (!is.is_open()) {
return -1;
}
string script;
getline(is, script, '\0');
is.close();
//TODO: flesh out this error if needed
if (sqlite3_exec(db, script.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) {
return -2;
}
return 0;
}
//-------------------------
//Define the public members
//-------------------------
void ServerApplication::Init(int argc, char** argv) {
cout << "Beginning startup" << endl;
int ret = 0;
//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 initialize SDL_net"));
}
network.Open(config.Int("server.port"), PACKET_BUFFER_SIZE);
cout << "Initialized SDL_net" << endl;
//Init SQL
ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
if (ret != SQLITE_OK || !database) {
throw(runtime_error(string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
}
cout << "Initialized SQL" << endl;
//setup the database
if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
throw(runtime_error("Failed to initialize SQL's setup script"));
}
cout << "Initialized SQL's setup script" << endl;
//lua
luaState = luaL_newstate();
if (!luaState) {
throw(runtime_error("Failed to initialize lua"));
}
luaL_openlibs(luaState);
cout << "Initialized lua" << endl;
//run the startup script
if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
throw(runtime_error(string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
}
cout << "Initialized lua's setup script" << endl;
//setup the map object
mapPager.SetRegionWidth(REGION_WIDTH);
mapPager.SetRegionHeight(REGION_HEIGHT);
mapPager.SetRegionDepth(REGION_DEPTH);
mapPager.GetGenerator()->SetLuaState(luaState);
mapPager.GetFormat()->SetLuaState(luaState);
mapPager.GetFormat()->SetSaveDir("save/mapname/");
//TODO: pass args to the generator & format as needed
//NOTE: I might need to rearrange the init process so that lua & SQL can interact
// with the map system as needed.
cout << "Initialized the map system" << endl;
cout << "\tsizeof(NetworkPacket): " << sizeof(NetworkPacket) << endl;
cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << endl;
//finalize the startup
cout << "Startup completed successfully" << endl;
//debugging
//
}
void ServerApplication::Loop() {
NetworkPacket 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);
}
//give the computer a break
SDL_Delay(10);
}
}
void ServerApplication::Quit() {
cout << "Shutting down" << endl;
//empty the members
mapPager.UnloadAll();
//TODO: player manager
//TODO: client manager
//APIs
lua_close(luaState);
sqlite3_close_v2(database);
network.Close();
SDLNet_Quit();
SDL_Quit();
cout << "Shutdown finished" << endl;
}
//-------------------------
//Define the uber switch
//-------------------------
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;
case NetworkPacket::Type::REGION_REQUEST:
HandleRegionRequest(packet);
break;
//handle errors
default:
throw(runtime_error("Unknown NetworkPacket::Type encountered"));
break;
}
}
//-------------------------
//Handle various network input
//-------------------------
void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) {
//send back the server's metadata
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE;
//TODO: version info
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
//TODO: player count
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
//register the new client
ClientEntry c;
c.address = packet.meta.srcAddress;
clientMap[clientCounter] = c;
//send the client their info
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = clientCounter;
serialize(&packet, buffer);
network.Send(&clientMap[clientCounter].address, buffer, PACKET_BUFFER_SIZE);
//finished this routine
clientCounter++;
cout << "Connect, total: " << clientMap.size() << endl;
}
void ServerApplication::HandleDisconnect(NetworkPacket packet) {
//disconnect the specified client
//TODO: authenticate who is disconnecting/kicking
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
clientMap.erase(packet.clientInfo.index);
//delete players from all clients
NetworkPacket delPacket;
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
erase_if(playerMap, [&](std::pair<int, PlayerEntry> it) -> bool {
//find the internal players to delete
if (it.second.clientIndex == packet.clientInfo.index) {
delPacket.playerInfo.playerIndex = it.first;
//send the delete player command to all clients
PumpPacket(delPacket);
return true;
}
return false;
});
//finished this routine
cout << "Disconnect, total: " << clientMap.size() << endl;
}
void ServerApplication::HandleSynchronize(NetworkPacket packet) {
//send all the server's data to this client
//TODO: compensate for large distances
NetworkPacket newPacket;
char buffer[PACKET_BUFFER_SIZE];
//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;
serialize(&newPacket, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
}
}
void ServerApplication::HandleShutdown(NetworkPacket packet) {
//end the server
running = false;
//disconnect all clients
packet.meta.type = NetworkPacket::Type::DISCONNECT;
PumpPacket(packet);
//finished this routine
cout << "Shutdown signal accepted" << endl;
}
void ServerApplication::HandlePlayerNew(NetworkPacket packet) {
//create the new player object
PlayerEntry newPlayer;
newPlayer.clientIndex = packet.playerInfo.clientIndex;
newPlayer.mapIndex = 0;
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, PlayerEntry> 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::HandleRegionRequest(NetworkPacket packet) {
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = NetworkPacket::Type::REGION_CONTENT;
packet.regionInfo.region = mapPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::PumpPacket(NetworkPacket packet) {
//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);
}
}
+50 -45
View File
@@ -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,13 +22,18 @@
#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 //maps
#include "map_generator.hpp" #include "map_allocator.hpp"
#include "map_file_format.hpp" #include "map_file_format.hpp"
#include "region_pager.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" #include "serial.hpp"
@@ -45,19 +50,6 @@
#include <map> #include <map>
#include <string> #include <string>
struct ClientEntry {
IPaddress address;
};
struct PlayerEntry {
int clientIndex;
int mapIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
//The main application class //The main application class
class ServerApplication { class ServerApplication {
public: public:
@@ -66,46 +58,59 @@ public:
~ServerApplication() = default; ~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 HandleRegionRequest(NetworkPacket);
void PumpPacket(NetworkPacket); //TODO: a function that only sends to characters in a certain proximity
void PumpPacket(SerialPacket);
void PumpCharacterUnload(int uid);
//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;
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 //maps
RegionPager<LuaGenerator, LuaFormat> mapPager; //TODO: I need to handle multiple map objects
//TODO: Unload regions that are distant from any characters
//networking RegionPager<LuaAllocator, LuaFormat> regionPager;
UDPNetworkUtility network;
//database
sqlite3* database = nullptr;
//lua
lua_State* luaState = nullptr;
//misc //misc
bool running = true; bool running = true;
ConfigUtility config; ConfigUtility config;
std::map<int, ClientEntry> clientMap;
std::map<int, PlayerEntry> playerMap;
int clientCounter = 0;
int playerCounter = 0;
}; };
#endif #endif
+196
View File
@@ -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);
}
+201
View File
@@ -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*>(&regionPager));
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;
}
}
+39
View File
@@ -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>
//...