Compare commits

...

16 Commits

Author SHA1 Message Date
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
31 changed files with 871 additions and 833 deletions
+2 -2
View File
@@ -119,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, &characterIndex);
break; break;
case SceneList::INWORLD: case SceneList::INWORLD:
activeScene = new InWorld(&config, &network, &clientIndex); activeScene = new InWorld(&config, &network, &clientIndex, &characterIndex);
break; break;
case SceneList::INCOMBAT: case SceneList::INCOMBAT:
activeScene = new InCombat(); activeScene = new InCombat();
+3 -1
View File
@@ -44,9 +44,11 @@ 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 characterIndex = -1;
}; };
#endif #endif
+78 -87
View File
@@ -31,10 +31,11 @@
//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 argCharacterIndex):
config(*argConfig), config(*argConfig),
network(*argNetwork), network(*argNetwork),
clientIndex(*argClientIndex) clientIndex(*argClientIndex),
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");
@@ -61,23 +62,12 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
//TODO: add the tilesheet to the map system? //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);
//create the server-side player object
//TODO: the login system needs an overhaul
SerialPacket packet;
packet.meta.type = SerialPacket::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
SerialPacket packet;
char buffer[PACKET_STRING_SIZE];
packet.meta.type = SerialPacket::Type::SYNCHRONIZE; packet.meta.type = SerialPacket::Type::SYNCHRONIZE;
packet.clientInfo.clientIndex = clientIndex;
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);
@@ -131,11 +121,11 @@ 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
//TODO: figure out something to fix the region container access
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.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);
} }
@@ -148,10 +138,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();
} }
//------------------------- //-------------------------
@@ -193,28 +180,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;
} }
@@ -226,28 +213,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;
} }
@@ -262,18 +249,18 @@ void InWorld::HandlePacket(SerialPacket packet) {
case SerialPacket::Type::DISCONNECT: case SerialPacket::Type::DISCONNECT:
HandleDisconnect(packet); HandleDisconnect(packet);
break; break;
case SerialPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet);
break;
case SerialPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet);
break;
case SerialPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
case SerialPacket::Type::REGION_CONTENT: case SerialPacket::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 SerialPacket::Type encountered")); throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
@@ -284,23 +271,49 @@ void InWorld::HandlePacket(SerialPacket packet) {
void InWorld::HandleDisconnect(SerialPacket packet) { void InWorld::HandleDisconnect(SerialPacket packet) {
network.Unbind(Channels::SERVER); network.Unbind(Channels::SERVER);
clientIndex = -1; clientIndex = -1;
characterIndex = -1;
SetNextScene(SceneList::MAINMENU); SetNextScene(SceneList::MAINMENU);
} }
void InWorld::HandlePlayerNew(SerialPacket 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")); //TODO: account for map index
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;
} }
playerCharacters[packet.playerInfo.playerIndex].GetSprite()->LoadSurface(config["dir.sprites"] + packet.playerInfo.avatar, 4, 4); void InWorld::HandleCharacterUpdate(SerialPacket packet) {
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position); if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion); HandleCharacterNew(packet);
playerCharacters[packet.playerInfo.playerIndex].ResetDirection(); return;
}
//update only if the message didn't originate from here
if (packet.characterInfo.clientIndex != clientIndex) {
playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
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;
@@ -310,57 +323,34 @@ void InWorld::HandlePlayerNew(SerialPacket packet) {
} }
} }
void InWorld::HandlePlayerDelete(SerialPacket packet) { void InWorld::HandleCharacterDelete(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) { if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
throw(std::runtime_error("Cannot delete non-existant players")); 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(SerialPacket 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(SerialPacket packet) {
//replace existing regions
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;
}
//------------------------- //-------------------------
//Server control //Server control
//------------------------- //-------------------------
void InWorld::SendState() { void InWorld::SendPlayerUpdate() {
SerialPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//pack the packet //pack the packet
packet.meta.type = SerialPacket::Type::PLAYER_UPDATE; packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
packet.playerInfo.clientIndex = clientIndex; packet.characterInfo.clientIndex = clientIndex;
packet.playerInfo.playerIndex = playerIndex; packet.characterInfo.characterIndex = characterIndex;
packet.playerInfo.position = localCharacter->GetPosition(); packet.characterInfo.position = localCharacter->GetPosition();
packet.playerInfo.motion = localCharacter->GetMotion(); 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);
@@ -372,7 +362,7 @@ void InWorld::RequestDisconnect() {
//send a disconnect request //send a disconnect request
packet.meta.type = SerialPacket::Type::DISCONNECT; packet.meta.type = SerialPacket::Type::DISCONNECT;
packet.clientInfo.index = clientIndex; packet.clientInfo.clientIndex = clientIndex;
serialize(&packet, buffer); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE); network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
@@ -383,17 +373,18 @@ void InWorld::RequestShutDown() {
//send a shutdown request //send a shutdown request
packet.meta.type = SerialPacket::Type::SHUTDOWN; packet.meta.type = SerialPacket::Type::SHUTDOWN;
packet.clientInfo.index = clientIndex; packet.clientInfo.clientIndex = clientIndex;
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) {
SerialPacket 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 = SerialPacket::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);
@@ -433,7 +424,7 @@ void InWorld::UpdateMap() {
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) { for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) { for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) { if (!regionPager.FindRegion(i, j)) {
RequestRegion(i, j); RequestRegion(0, i, j);
} }
} }
} }
+9 -9
View File
@@ -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);
~InWorld(); ~InWorld();
protected: protected:
@@ -74,25 +74,25 @@ protected:
//Network handlers //Network handlers
void HandlePacket(SerialPacket); void HandlePacket(SerialPacket);
void HandleDisconnect(SerialPacket); void HandleDisconnect(SerialPacket);
void HandlePlayerNew(SerialPacket); void HandleCharacterNew(SerialPacket);
void HandlePlayerDelete(SerialPacket); void HandleCharacterDelete(SerialPacket);
void HandlePlayerUpdate(SerialPacket); void HandleCharacterUpdate(SerialPacket);
void HandleRegionContent(SerialPacket); 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
void UpdateMap(); void UpdateMap();
//globals //shared parameters
ConfigUtility& config; ConfigUtility& config;
FrameRate fps;
UDPNetworkUtility& network; UDPNetworkUtility& network;
int& clientIndex; int& clientIndex;
int& characterIndex;
//graphics //graphics
Image buttonImage; Image buttonImage;
@@ -111,11 +111,11 @@ protected:
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
+14 -9
View File
@@ -30,10 +30,11 @@
//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 argCharacterIndex):
config(*argConfig), config(*argConfig),
network(*argNetwork), network(*argNetwork),
clientIndex(*argClientIndex) clientIndex(*argClientIndex),
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");
@@ -118,7 +119,7 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h); font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
} }
//TODO: ping? //ping?
} }
} }
@@ -155,13 +156,17 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
} }
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) { else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) {
//TODO: The player login information should be collected by the lobby screen
//the vars //the vars
SerialPacket packet; SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE]; char buffer[PACKET_BUFFER_SIZE];
//join the selected server //pack the packet
packet.meta.type = SerialPacket::Type::JOIN_REQUEST; 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
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;
@@ -203,20 +208,20 @@ void LobbyMenu::HandlePacket(SerialPacket packet) {
//extract the data //extract the data
ServerInformation server; ServerInformation server;
server.address = packet.meta.srcAddress; server.address = packet.meta.srcAddress;
server.networkVersion = packet.serverInfo.networkVersion;
server.name = packet.serverInfo.name; server.name = packet.serverInfo.name;
server.playerCount = packet.serverInfo.playerCount; server.playerCount = packet.serverInfo.playerCount;
//NOTE: Check compatibility here //NOTE: Check compatibility here
server.compatible = packet.serverInfo.regionWidth == REGION_WIDTH && server.compatible = server.networkVersion == NETWORK_VERSION;
packet.serverInfo.regionHeight == REGION_HEIGHT &&
packet.serverInfo.regionDepth == REGION_DEPTH;
//push //push
serverInfo.push_back(server); serverInfo.push_back(server);
} }
break; break;
case SerialPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_RESPONSE:
clientIndex = packet.clientInfo.index; clientIndex = packet.clientInfo.clientIndex;
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;
+4 -6
View File
@@ -28,9 +28,6 @@
#include "button.hpp" #include "button.hpp"
#include "config_utility.hpp" #include "config_utility.hpp"
//map
#include "region.hpp"
//network //network
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "serial_packet.hpp" #include "serial_packet.hpp"
@@ -45,7 +42,7 @@
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);
~LobbyMenu(); ~LobbyMenu();
protected: protected:
@@ -64,10 +61,11 @@ protected:
void HandlePacket(SerialPacket); void HandlePacket(SerialPacket);
//global //shared parameters
ConfigUtility& config; ConfigUtility& config;
UDPNetworkUtility& network; UDPNetworkUtility& network;
int& clientIndex; int& clientIndex;
int& characterIndex;
//members //members
Image image; Image image;
@@ -79,7 +77,7 @@ protected:
//server list //server list
struct ServerInformation { struct ServerInformation {
IPaddress address; IPaddress address;
//TODO: version info int networkVersion;
std::string name; std::string name;
int playerCount; int playerCount;
bool compatible; bool compatible;
+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
+4 -4
View File
@@ -36,8 +36,8 @@ void LuaAllocator::Create(Region** const ptr, int x, int y) {
(*ptr) = new Region(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) ));
@@ -47,8 +47,8 @@ void LuaAllocator::Create(Region** const ptr, int x, int y) {
void LuaAllocator::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) ));
+4 -4
View File
@@ -39,8 +39,8 @@ void LuaFormat::Load(Region** const ptr, int x, int 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) {
@@ -55,8 +55,8 @@ void LuaFormat::Load(Region** const ptr, int x, int y) {
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) {
+107 -128
View File
@@ -25,85 +25,59 @@
#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(SerialPacket* packet, char* buffer) { void serializeType(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
} }
void serializeServer(SerialPacket* packet, char* buffer) { void serializeServer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//server info //server info
//Note: version info serialization goes here SERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE); SERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE; SERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
memcpy(buffer, &packet->serverInfo.playerCount, sizeof(int));
buffer += sizeof(int);
//map format
memcpy(buffer, &packet->serverInfo.regionWidth, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->serverInfo.regionHeight, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->serverInfo.regionDepth, sizeof(int));
} }
void serializeClient(SerialPacket* packet, char* buffer) { void serializeClient(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
memcpy(buffer, &packet->clientInfo.index, sizeof(int));
}
void serializePlayer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//indexes //indexes
memcpy(buffer, &packet->playerInfo.clientIndex, sizeof(int)); SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
buffer += sizeof(int); SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
memcpy(buffer, &packet->playerInfo.playerIndex, 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(SerialPacket* packet, char* buffer) { void serializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type)); SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y //format
memcpy(buffer, &packet->regionInfo.x, sizeof(int)); SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(int); SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
memcpy(buffer, &packet->regionInfo.y, sizeof(int)); SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
} }
void serializeRegionContent(SerialPacket* packet, char* buffer) { void serializeRegionContent(SerialPacket* packet, char* buffer) {
//format SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//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 < REGION_WIDTH; i++) { for (register int i = 0; i < REGION_WIDTH; i++) {
@@ -116,92 +90,79 @@ void serializeRegionContent(SerialPacket* 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.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(SerialPacket* packet, char* buffer) { void deserializeType(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
} }
void deserializeServer(SerialPacket* packet, char* buffer) { void deserializeServer(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//server info //server info
//Note: version info deserialization goes here DESERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE); DESERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE; DESERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
memcpy(&packet->serverInfo.playerCount, buffer, sizeof(int));
buffer += sizeof(int);
//map format
memcpy(&packet->serverInfo.regionWidth, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->serverInfo.regionHeight, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->serverInfo.regionDepth, buffer, sizeof(int));
} }
void deserializeClient(SerialPacket* packet, char* buffer) { void deserializeClient(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
memcpy(&packet->clientInfo.index, buffer, sizeof(int));
}
void deserializePlayer(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//indexes //indexes
memcpy(&packet->playerInfo.clientIndex, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
buffer += sizeof(int); DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
memcpy(&packet->playerInfo.playerIndex, buffer, 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(SerialPacket* packet, char* buffer) { void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y //format
memcpy(&packet->regionInfo.x, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(int); DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
memcpy(&packet->regionInfo.y, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
} }
void deserializeRegionContent(SerialPacket* packet, char* buffer) { void deserializeRegionContent(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type)); DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y //format
memcpy(&packet->regionInfo.x, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
buffer += sizeof(int); DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
memcpy(&packet->regionInfo.y, buffer, sizeof(int)); DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
buffer += sizeof(int);
//content //an object to work on
BlankAllocator().Create( BlankAllocator().Create(
&packet->regionInfo.region, &packet->regionInfo.region,
packet->regionInfo.x, packet->regionInfo.x,
packet->regionInfo.y packet->regionInfo.y
); );
//content
for (register int i = 0; i < REGION_WIDTH; i++) { for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) { for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) { for (register int k = 0; k < REGION_DEPTH; k++) {
@@ -212,6 +173,24 @@ void deserializeRegionContent(SerialPacket* 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.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
//------------------------- //-------------------------
@@ -223,8 +202,6 @@ void serialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::PING: case SerialPacket::Type::PING:
case SerialPacket::Type::PONG: case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST: case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer)); serializeType(packet, reinterpret_cast<char*>(buffer));
break; break;
@@ -234,19 +211,14 @@ void serialize(SerialPacket* packet, void* buffer) {
break; break;
//Client info //Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT: case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN: case SerialPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer)); serializeClient(packet, reinterpret_cast<char*>(buffer));
break; break;
//Player info
case SerialPacket::Type::PLAYER_NEW:
case SerialPacket::Type::PLAYER_DELETE:
case SerialPacket::Type::PLAYER_UPDATE:
serializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info //region info
case SerialPacket::Type::REGION_REQUEST: case SerialPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer)); serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
@@ -255,6 +227,13 @@ void serialize(SerialPacket* packet, void* buffer) {
case SerialPacket::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;
} }
} }
@@ -267,8 +246,6 @@ void deserialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::PING: case SerialPacket::Type::PING:
case SerialPacket::Type::PONG: case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST: case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
//NOTHING //NOTHING
break; break;
@@ -278,19 +255,14 @@ void deserialize(SerialPacket* packet, void* buffer) {
break; break;
//Client info //Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT: case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN: case SerialPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer)); deserializeClient(packet, reinterpret_cast<char*>(buffer));
break; break;
//Player info
case SerialPacket::Type::PLAYER_NEW:
case SerialPacket::Type::PLAYER_DELETE:
case SerialPacket::Type::PLAYER_UPDATE:
deserializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info //region info
case SerialPacket::Type::REGION_REQUEST: case SerialPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer)); deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
@@ -299,5 +271,12 @@ void deserialize(SerialPacket* packet, void* buffer) {
case SerialPacket::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;
} }
} }
+2 -2
View File
@@ -27,10 +27,10 @@
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date /* NOTE: Keep the PACKET_BUFFER_SIZE up to date
* NOTE: REGION_CONTENT is currently the largest type of packet * NOTE: REGION_CONTENT is currently the largest type of packet
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t) * map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
* map format: sizeof(int) * 2 * 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) * 2 + sizeof(SerialPacket::Metadata) #define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacket::Metadata)
void serialize(SerialPacket* const, void*); void serialize(SerialPacket* const, void*);
void deserialize(SerialPacket* const, void*); void deserialize(SerialPacket* const, void*);
+31 -29
View File
@@ -27,6 +27,7 @@
#include "SDL/SDL_net.h" #include "SDL/SDL_net.h"
#define NETWORK_VERSION 20140428
#define PACKET_STRING_SIZE 100 #define PACKET_STRING_SIZE 100
#pragma pack(push, 0) #pragma pack(push, 0)
@@ -49,23 +50,25 @@ union SerialPacket {
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,42 +80,41 @@ union SerialPacket {
//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];
int playerCount; int playerCount;
//map format
int regionWidth;
int regionHeight;
int regionDepth;
}serverInfo; }serverInfo;
//information about the client //information about the client
//TODO: login credentials
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 characterIndex;
//TODO: should move handle/avatar into clientInfo; these might actually do better during the login system 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 mapIndex;
int x, y; int x, y;
Region* region; Region* region;
}regionInfo; }regionInfo;
//information about a character
struct CharacterInformation {
Metadata meta;
int clientIndex;
int characterIndex;
char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE];
int mapIndex;
Vector2 position;
Vector2 motion;
}characterInfo;
//defaults //defaults
SerialPacket() { SerialPacket() {
meta.type = Type::NONE; meta.type = Type::NONE;
+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
-88
View File
@@ -1,88 +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) {
lua_pushinteger(L, REGION_WIDTH);
return 1;
}
static int getHeight(lua_State* L) {
lua_pushinteger(L, REGION_HEIGHT);
return 1;
}
static int getDepth(lua_State* L) {
lua_pushinteger(L, REGION_DEPTH);
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;
}
+8 -22
View File
@@ -87,21 +87,7 @@ void EditorScene::FrameEnd() {
void EditorScene::Render(SDL_Surface* const screen) { void EditorScene::Render(SDL_Surface* const screen) {
tsheet.DrawRegionTo(screen, pager.GetRegion(0, 0), camera.x, camera.y); 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) //draw a big bar across the top (hackish)
buttonImage.SetClipY(0); buttonImage.SetClipY(0);
for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) { for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) {
@@ -184,29 +170,29 @@ void EditorScene::HandleMenuOption(int entry, int drop) {
case 0: //File case 0: //File
switch(drop) { switch(drop) {
case 0: case 0:
//TODO: NEW //NEW
break; break;
case 1: case 1:
//TODO: OPEN //OPEN
break; break;
case 2: case 2:
//TODO: SAVE //SAVE
break; break;
case 3: case 3:
//TODO: CLOSE //CLOSE
break; break;
} }
break; break;
case 1: //Edit case 1: //Edit
switch(drop) { switch(drop) {
case 0: case 0:
//TODO: SET TILE //SET TILE
break; break;
case 1: case 1:
//TODO: SET BRUSH //SET BRUSH
break; break;
case 2: case 2:
//TODO: SCRIPT //SCRIPT
break; break;
} }
break; break;
+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
+17 -14
View File
@@ -1,29 +1,32 @@
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
--debugging
print("DEBUG: Initial tile value: ", map.gettile(0, 0, 0))
map.settile(0, 0, 0, 86)
map.settile(10, 10, 1, 156)
+3 -3
View File
@@ -1,5 +1,3 @@
--TODO: The SQL startup script needs revising
------------------------- -------------------------
--Server --Server
------------------------- -------------------------
@@ -7,7 +5,8 @@
CREATE TABLE IF NOT EXISTS UserAccounts ( CREATE TABLE IF NOT EXISTS UserAccounts (
uid INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
username varchar(100) UNIQUE, username varchar(100) UNIQUE,
password varchar(100), --NOTE: DO NOT DO THIS!! --TODO: server-client security
-- password varchar(100),
blacklisted BIT DEFAULT 0, blacklisted BIT DEFAULT 0,
whitelisted BIT DEFAULT 1 whitelisted BIT DEFAULT 1
); );
@@ -50,6 +49,7 @@ CREATE TABLE IF NOT EXISTS PlayerCharacters (
uid INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
--metadata --metadata
owner INTEGER REFERENCES UserAccounts(uid),
handle varchar(100) UNIQUE, handle varchar(100) UNIQUE,
avatar varchar(100), avatar varchar(100),
birth timestamp NOT NULL DEFAULT (datetime()), birth timestamp NOT NULL DEFAULT (datetime()),
@@ -19,6 +19,6 @@
* 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 "player_entry.hpp" #include "character_data.hpp"
unsigned int PlayerEntry::uidCounter; int CharacterData::uidCounter = 0;
@@ -19,8 +19,8 @@
* 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 PLAYERENTRY_HPP_ #ifndef CHARACTERDATA_HPP_
#define PLAYERENTRY_HPP_ #define CHARACTERDATA_HPP_
//POD members //POD members
#include "bbox.hpp" #include "bbox.hpp"
@@ -28,35 +28,36 @@
#include <string> #include <string>
struct PlayerEntry { struct CharacterData {
//metadata //metadata
int clientIndex; int clientIndex;
std::string username;
std::string handle; std::string handle;
std::string avatar; std::string avatar;
//world position //world position
int mapIndex; int mapIndex = 0;
Vector2 position; Vector2 position = {0.0,0.0};
Vector2 motion; Vector2 motion = {0.0,0.0};
BBox bbox; BBox bbox = {0,0,0,0};
//statistics //statistics
int level; int level = 0;
int exp; int exp = 0;
int maxHP; int maxHP = 0;
int health; int health = 0;
int maxMP; int maxMP = 0;
int mana; int mana = 0;
int attack; int attack = 0;
int defence; int defence = 0;
int intelligence; int intelligence = 0;
int resistance; int resistance = 0;
float accuracy; float accuracy = 0.0;
float evasion; float evasion = 0.0;
float luck; float luck = 0.0;
//uid //uid
static unsigned int uidCounter; static int uidCounter;
}; };
#endif #endif
@@ -19,6 +19,6 @@
* 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 "client_entry.hpp" #include "client_data.hpp"
unsigned int ClientEntry::uidCounter; int ClientData::uidCounter = 0;
@@ -19,14 +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 CLIENTENTRY_HPP_ #ifndef CLIENTDATA_HPP_
#define CLIENTENTRY_HPP_ #define CLIENTDATA_HPP_
#include "SDL/SDL_net.h" #include "SDL/SDL_net.h"
struct ClientEntry { struct ClientData {
IPaddress address; IPaddress address = {0,0};
static unsigned int uidCounter; static int uidCounter;
}; };
#endif #endif
-373
View File
@@ -1,373 +0,0 @@
/* 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 "utility.hpp"
#include <stdexcept>
#include <iostream>
#include <string>
//-------------------------
//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
ClientEntry::uidCounter = 0;
PlayerEntry::uidCounter = 0;
config.Load("rsc\\config.cfg");
//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;
//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 << "Initialized SQL's setup script" << std::endl;
//lua
luaState = luaL_newstate();
if (!luaState) {
throw(std::runtime_error("Failed to initialize lua"));
}
luaL_openlibs(luaState);
std::cout << "Initialized lua" << std::endl;
//run the 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 << "Initialized lua's setup script" << std::endl;
//setup the map object
regionPager.GetAllocator()->SetLuaState(luaState);
regionPager.GetFormat()->SetLuaState(luaState);
//TODO: config parameter
regionPager.GetFormat()->SetSaveDir("save/mapname/");
std::cout << "Initialized the map system" << 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);
}
//give the computer a break
//TODO: remove this delay?
SDL_Delay(10);
}
}
void ServerApplication::Quit() {
std::cout << "Shutting down" << std::endl;
//empty the members
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::DISCONNECT:
HandleDisconnect(packet);
break;
case SerialPacket::Type::SYNCHRONIZE:
HandleSynchronize(packet);
break;
case SerialPacket::Type::SHUTDOWN:
HandleShutdown(packet);
break;
case SerialPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet);
break;
case SerialPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet);
break;
case SerialPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
case SerialPacket::Type::REGION_REQUEST:
HandleRegionRequest(packet);
break;
//handle errors
default:
throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
break;
}
}
//-------------------------
//Handle various network input
//-------------------------
void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
//send back the server's metadata
packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
//pack the data
//TODO: version info
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
packet.serverInfo.playerCount = playerMap.size();
packet.serverInfo.regionWidth = REGION_WIDTH;
packet.serverInfo.regionHeight = REGION_HEIGHT;
packet.serverInfo.regionDepth = REGION_DEPTH;
//send the data
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::HandleJoinRequest(SerialPacket packet) {
//register the new client
ClientEntry newClient;
newClient.address = packet.meta.srcAddress;
clientMap[ClientEntry::uidCounter] = newClient;
//send the client their index
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = ClientEntry::uidCounter;
serialize(&packet, buffer);
//bounce this packet
network.Send(&newClient.address, buffer, PACKET_BUFFER_SIZE);
//finished this routine
ClientEntry::uidCounter++;
std::cout << "Connect, total: " << clientMap.size() << std::endl;
}
void ServerApplication::HandleDisconnect(SerialPacket packet) {
//TODO: authenticate who is disconnecting/kicking
//disconnect the specified client
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
clientMap.erase(packet.clientInfo.index);
//prep the delete packet
SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
//TODO: can this use DeletePlayer() instead?
//delete server and client side players
erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
//find the internal players to delete
if (it.second.clientIndex == packet.clientInfo.index) {
//send the delete player command to all clients
delPacket.playerInfo.playerIndex = it.first;
PumpPacket(delPacket);
//delete this player object
return true;
}
//don't delete this player object
return false;
});
//finished this routine
std::cout << "Disconnect, 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];
//TODO: syncronize the map?
//players
newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
for (auto& it : playerMap) {
//TODO: update this for the expanded PlayerEntry structure
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(SerialPacket packet) {
//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::HandlePlayerNew(SerialPacket packet) {
//register the new PlayerEntry
//NOTE: assigning each field one-by-one so adding or moving a field doesn't break this code
PlayerEntry newPlayer;
//metadata
newPlayer.clientIndex = packet.playerInfo.clientIndex;
newPlayer.handle = packet.playerInfo.handle;
newPlayer.avatar = packet.playerInfo.avatar;
//position
newPlayer.mapIndex = 0;
newPlayer.position = {0,0};
newPlayer.motion = {0,0};
newPlayer.bbox = {0, 0, 0, 0};
//stats
//TODO
//push this player
playerMap[PlayerEntry::uidCounter] = newPlayer;
//send the client their info
packet.playerInfo.playerIndex = PlayerEntry::uidCounter;
packet.playerInfo.position = newPlayer.position;
packet.playerInfo.motion = newPlayer.motion;
//actually send to everyone
PumpPacket(packet);
//finish this routine
PlayerEntry::uidCounter++;
}
//TODO: differentiate between delete and unload
void ServerApplication::HandlePlayerDelete(SerialPacket packet) {
//TODO: authenticate who is deleting this player
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
throw(std::runtime_error("Cannot delete a non-existant player"));
}
//TODO: remove the deleted player from the database?
//prep the delete packet
SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
//delete the specified playerEntry
erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
//find the specified PlayerEntry
if (it.first == packet.playerInfo.playerIndex) {
//send to all
delPacket.playerInfo.playerIndex = it.first;
PumpPacket(delPacket);
//delete this player
return true;
}
//skip this player
return false;
});
}
void ServerApplication::HandlePlayerUpdate(SerialPacket packet) {
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
throw(std::runtime_error("Cannot update a non-existant player"));
}
//TODO: the server needs it's own movement system too
playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position;
playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion;
PumpPacket(packet);
}
void ServerApplication::HandleRegionRequest(SerialPacket packet) {
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = SerialPacket::Type::REGION_CONTENT;
packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::PumpPacket(SerialPacket 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);
}
}
+12 -11
View File
@@ -23,9 +23,8 @@
#define SERVERAPPLICATION_HPP_ #define SERVERAPPLICATION_HPP_
//server specific stuff //server specific stuff
#include "server_utility.hpp" #include "client_data.hpp"
#include "client_entry.hpp" #include "character_data.hpp"
#include "player_entry.hpp"
//maps //maps
#include "map_allocator.hpp" #include "map_allocator.hpp"
@@ -63,31 +62,33 @@ public:
private: private:
void HandlePacket(SerialPacket); void HandlePacket(SerialPacket);
//high cohesion utility functions //handle incoming traffic
void HandleBroadcastRequest(SerialPacket); void HandleBroadcastRequest(SerialPacket);
void HandleJoinRequest(SerialPacket); void HandleJoinRequest(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandleSynchronize(SerialPacket); void HandleSynchronize(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandleShutdown(SerialPacket); void HandleShutdown(SerialPacket);
void HandlePlayerNew(SerialPacket); void HandleCharacterUpdate(SerialPacket);
void HandlePlayerDelete(SerialPacket);
void HandlePlayerUpdate(SerialPacket);
void HandleRegionRequest(SerialPacket); void HandleRegionRequest(SerialPacket);
//TODO: a function that only sends to players in a certain proximity //TODO: a function that only sends to characters in a certain proximity
void PumpPacket(SerialPacket); void PumpPacket(SerialPacket);
//TODO: manage the database
//TODO: combat systems
//APIs //APIs
UDPNetworkUtility network; UDPNetworkUtility network;
sqlite3* database = nullptr; sqlite3* database = nullptr;
lua_State* luaState = nullptr; lua_State* luaState = nullptr;
//server tables //server tables
std::map<unsigned int, ClientEntry> clientMap; std::map<int, ClientData> clientMap;
std::map<unsigned int, PlayerEntry> playerMap; std::map<int, CharacterData> characterMap;
//maps //maps
//TODO: I need to handle multiple map objects //TODO: I need to handle multiple map objects
//TODO: Unload regions that are distant from any characters
RegionPager<LuaAllocator, LuaFormat> regionPager; RegionPager<LuaAllocator, LuaFormat> regionPager;
//misc //misc
+186
View File
@@ -0,0 +1,186 @@
/* 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;
//TODO: move this into the character management code
//create the new character
CharacterData newCharacter;
newCharacter.clientIndex = ClientData::uidCounter;
newCharacter.username = packet.clientInfo.username;
newCharacter.handle = packet.clientInfo.handle;
newCharacter.avatar = packet.clientInfo.avatar;
//send the client their info
packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
packet.clientInfo.clientIndex = ClientData::uidCounter;
packet.clientInfo.characterIndex = CharacterData::uidCounter;
//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 = CharacterData::uidCounter;
strncpy(packet.characterInfo.handle, newCharacter.handle.c_str(), PACKET_STRING_SIZE);
strncpy(packet.characterInfo.avatar, newCharacter.avatar.c_str(), PACKET_STRING_SIZE);
packet.characterInfo.position = newCharacter.position;
packet.characterInfo.motion = newCharacter.motion;
PumpPacket(packet);
//finished this routine
clientMap[ClientData::uidCounter] = newClient;
characterMap[CharacterData::uidCounter] = newCharacter;
ClientData::uidCounter++;
CharacterData::uidCounter++;
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
//TODO: define the difference between unloading and deletng a character
//disconnect the specified client
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.clientIndex].address, buffer, PACKET_BUFFER_SIZE);
clientMap.erase(packet.clientInfo.clientIndex);
//prep the delete packet
SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::CHARACTER_DELETE;
//delete server and client side characters
erase_if(characterMap, [&](std::pair<int, CharacterData> it) -> bool {
//find the internal characters to delete
if (it.second.clientIndex == packet.clientInfo.clientIndex) {
//send the delete characters command to all clients
delPacket.characterInfo.characterIndex = it.first;
PumpPacket(delPacket);
//delete this characters object
return true;
}
//don't delete this characters object
return false;
});
//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;
packet.clientInfo.clientIndex = -1;
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);
}
}
+188
View File
@@ -0,0 +1,188 @@
/* 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 "server_utility.hpp"
#include <stdexcept>
#include <iostream>
#include <string>
//-------------------------
//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
//TODO: save the existing players
//empty the members
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;
}
}
+30
View File
@@ -0,0 +1,30 @@
I need to keep the documentation up to date. Namey, the GDD is getting out of date.
--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