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);
break;
case SceneList::LOBBYMENU:
activeScene = new LobbyMenu(&config, &network, &clientIndex);
activeScene = new LobbyMenu(&config, &network, &clientIndex, &characterIndex);
break;
case SceneList::INWORLD:
activeScene = new InWorld(&config, &network, &clientIndex);
activeScene = new InWorld(&config, &network, &clientIndex, &characterIndex);
break;
case SceneList::INCOMBAT:
activeScene = new InCombat();
+3 -1
View File
@@ -44,9 +44,11 @@ private:
BaseScene* activeScene = nullptr;
//shared parameters
ConfigUtility config;
UDPNetworkUtility network;
int clientIndex = -1; //replace with a struct?
int clientIndex = -1;
int characterIndex = -1;
};
#endif
+78 -87
View File
@@ -31,10 +31,11 @@
//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),
network(*argNetwork),
clientIndex(*argClientIndex)
clientIndex(*argClientIndex),
characterIndex(*argCharacterIndex)
{
//setup the utility objects
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?
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
SerialPacket packet;
char buffer[PACKET_STRING_SIZE];
packet.meta.type = SerialPacket::Type::SYNCHRONIZE;
packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
@@ -131,11 +121,11 @@ void InWorld::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen());
SDL_Flip(GetScreen());
fps.Calculate();
}
void InWorld::Render(SDL_Surface* const screen) {
//draw the map
//TODO: figure out something to fix the region container access
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
}
@@ -148,10 +138,7 @@ void InWorld::Render(SDL_Surface* const screen) {
//draw UI
disconnectButton.DrawTo(screen);
shutDownButton.DrawTo(screen);
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:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_RIGHT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_UP:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_DOWN:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
SendState();
SendPlayerUpdate();
}
break;
}
@@ -226,28 +213,28 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
case SDLK_LEFT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_RIGHT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_UP:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
SendState();
SendPlayerUpdate();
}
break;
case SDLK_DOWN:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
SendState();
SendPlayerUpdate();
}
break;
}
@@ -262,18 +249,18 @@ void InWorld::HandlePacket(SerialPacket packet) {
case SerialPacket::Type::DISCONNECT:
HandleDisconnect(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_CONTENT:
HandleRegionContent(packet);
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
default:
throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
@@ -284,23 +271,49 @@ void InWorld::HandlePacket(SerialPacket packet) {
void InWorld::HandleDisconnect(SerialPacket packet) {
network.Unbind(Channels::SERVER);
clientIndex = -1;
characterIndex = -1;
SetNextScene(SceneList::MAINMENU);
}
void InWorld::HandlePlayerNew(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) != playerCharacters.end()) {
throw(std::runtime_error("Cannot create duplicate players"));
void InWorld::HandleRegionContent(SerialPacket packet) {
//replace existing regions
//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;
}
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);
playerCharacters[packet.playerInfo.playerIndex].SetPosition(packet.playerInfo.position);
playerCharacters[packet.playerInfo.playerIndex].SetMotion(packet.playerInfo.motion);
playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
//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
if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) {
playerIndex = packet.playerInfo.playerIndex;
localCharacter = &playerCharacters[playerIndex];
if (packet.characterInfo.characterIndex == characterIndex && !localCharacter) {
localCharacter = &playerCharacters[characterIndex];
//setup the camera
camera.width = GetScreen()->w;
camera.height = GetScreen()->h;
@@ -310,57 +323,34 @@ void InWorld::HandlePlayerNew(SerialPacket packet) {
}
}
void InWorld::HandlePlayerDelete(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
throw(std::runtime_error("Cannot delete non-existant players"));
void InWorld::HandleCharacterDelete(SerialPacket packet) {
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
if (packet.playerInfo.clientIndex == clientIndex) {
playerIndex = -1;
if (packet.characterInfo.characterIndex == characterIndex) {
characterIndex = -1;
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
//-------------------------
void InWorld::SendState() {
void InWorld::SendPlayerUpdate() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the packet
packet.meta.type = SerialPacket::Type::PLAYER_UPDATE;
packet.playerInfo.clientIndex = clientIndex;
packet.playerInfo.playerIndex = playerIndex;
packet.playerInfo.position = localCharacter->GetPosition();
packet.playerInfo.motion = localCharacter->GetMotion();
packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
packet.characterInfo.clientIndex = clientIndex;
packet.characterInfo.characterIndex = characterIndex;
packet.characterInfo.position = localCharacter->GetPosition();
packet.characterInfo.motion = localCharacter->GetMotion();
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
@@ -372,7 +362,7 @@ void InWorld::RequestDisconnect() {
//send a disconnect request
packet.meta.type = SerialPacket::Type::DISCONNECT;
packet.clientInfo.index = clientIndex;
packet.clientInfo.clientIndex = clientIndex;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
@@ -383,17 +373,18 @@ void InWorld::RequestShutDown() {
//send a shutdown request
packet.meta.type = SerialPacket::Type::SHUTDOWN;
packet.clientInfo.index = clientIndex;
packet.clientInfo.clientIndex = clientIndex;
serialize(&packet, buffer);
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;
char buffer[PACKET_BUFFER_SIZE];
//pack the region's data
packet.meta.type = SerialPacket::Type::REGION_REQUEST;
packet.regionInfo.mapIndex = mapIndex;
packet.regionInfo.x = x;
packet.regionInfo.y = y;
serialize(&packet, buffer);
@@ -433,7 +424,7 @@ void InWorld::UpdateMap() {
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
RequestRegion(i, j);
RequestRegion(0, i, j);
}
}
}
+9 -9
View File
@@ -52,7 +52,7 @@
class InWorld : public BaseScene {
public:
//Public access members
InWorld(ConfigUtility* const, UDPNetworkUtility* const, int* const);
InWorld(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const);
~InWorld();
protected:
@@ -74,25 +74,25 @@ protected:
//Network handlers
void HandlePacket(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandlePlayerNew(SerialPacket);
void HandlePlayerDelete(SerialPacket);
void HandlePlayerUpdate(SerialPacket);
void HandleCharacterNew(SerialPacket);
void HandleCharacterDelete(SerialPacket);
void HandleCharacterUpdate(SerialPacket);
void HandleRegionContent(SerialPacket);
//Server control
void SendState();
void SendPlayerUpdate();
void RequestDisconnect();
void RequestShutDown();
void RequestRegion(int x, int y);
void RequestRegion(int mapIndex, int x, int y);
//utilities
void UpdateMap();
//globals
//shared parameters
ConfigUtility& config;
FrameRate fps;
UDPNetworkUtility& network;
int& clientIndex;
int& characterIndex;
//graphics
Image buttonImage;
@@ -111,11 +111,11 @@ protected:
int width = 0, height = 0;
int marginX = 0, marginY = 0;
} camera;
FrameRate fps;
//game
std::map<int, PlayerCharacter> playerCharacters;
PlayerCharacter* localCharacter = nullptr;
int playerIndex = -1;
};
#endif
+14 -9
View File
@@ -30,10 +30,11 @@
//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),
network(*argNetwork),
clientIndex(*argClientIndex)
clientIndex(*argClientIndex),
characterIndex(*argCharacterIndex)
{
//setup the utility objects
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);
}
//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) {
//TODO: The player login information should be collected by the lobby screen
//the vars
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//join the selected server
//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
serialize(&packet, buffer);
network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
selection = nullptr;
@@ -203,20 +208,20 @@ void LobbyMenu::HandlePacket(SerialPacket packet) {
//extract the data
ServerInformation server;
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 = packet.serverInfo.regionWidth == REGION_WIDTH &&
packet.serverInfo.regionHeight == REGION_HEIGHT &&
packet.serverInfo.regionDepth == REGION_DEPTH;
server.compatible = server.networkVersion == NETWORK_VERSION;
//push
serverInfo.push_back(server);
}
break;
case SerialPacket::Type::JOIN_RESPONSE:
clientIndex = packet.clientInfo.index;
clientIndex = packet.clientInfo.clientIndex;
characterIndex = packet.clientInfo.characterIndex;
network.Bind(&packet.meta.srcAddress, Channels::SERVER);
SetNextScene(SceneList::INWORLD);
break;
+4 -6
View File
@@ -28,9 +28,6 @@
#include "button.hpp"
#include "config_utility.hpp"
//map
#include "region.hpp"
//network
#include "udp_network_utility.hpp"
#include "serial_packet.hpp"
@@ -45,7 +42,7 @@
class LobbyMenu : public BaseScene {
public:
//Public access members
LobbyMenu(ConfigUtility* const, UDPNetworkUtility* const, int* const);
LobbyMenu(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const);
~LobbyMenu();
protected:
@@ -64,10 +61,11 @@ protected:
void HandlePacket(SerialPacket);
//global
//shared parameters
ConfigUtility& config;
UDPNetworkUtility& network;
int& clientIndex;
int& characterIndex;
//members
Image image;
@@ -79,7 +77,7 @@ protected:
//server list
struct ServerInformation {
IPaddress address;
//TODO: version info
int networkVersion;
std::string name;
int playerCount;
bool compatible;
+1 -1
View File
@@ -49,7 +49,7 @@ protected:
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//globals
//shared parameters
ConfigUtility& config;
//members
+1 -1
View File
@@ -49,7 +49,7 @@ protected:
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//globals
//shared parameters
ConfigUtility& config;
//members
+1 -1
View File
@@ -40,7 +40,7 @@ protected:
void Update(double delta);
void Render(SDL_Surface* const);
//globals
//shared parameters
ConfigUtility& config;
//members
+4 -4
View File
@@ -36,8 +36,8 @@ void LuaAllocator::Create(Region** const ptr, int x, int y) {
(*ptr) = new Region(x, y);
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Create");
lua_getglobal(state, "map");
lua_getfield(state, -1, "create");
lua_pushlightuserdata(state, *ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
@@ -47,8 +47,8 @@ void LuaAllocator::Create(Region** const ptr, int x, int y) {
void LuaAllocator::Unload(Region* const ptr) {
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Unload");
lua_getglobal(state, "map");
lua_getfield(state, -1, "unload");
lua_pushlightuserdata(state, ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
+4 -4
View File
@@ -39,8 +39,8 @@ void LuaFormat::Load(Region** const ptr, int x, int y) {
}
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Load");
lua_getglobal(state, "map");
lua_getfield(state, -1, "load");
lua_pushlightuserdata(state, *ptr);
lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 1, 0) != LUA_OK) {
@@ -55,8 +55,8 @@ void LuaFormat::Load(Region** const ptr, int x, int y) {
void LuaFormat::Save(Region* const ptr) {
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Save");
lua_getglobal(state, "map");
lua_getfield(state, -1, "save");
lua_pushlightuserdata(state, ptr);
lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 0, 0) != LUA_OK) {
+107 -128
View File
@@ -25,85 +25,59 @@
#include <cstring>
//-------------------------
//Convenience Macros
//-------------------------
#define SERIALIZE(buffer, data, size) memcpy(buffer, data, size); buffer += size;
#define DESERIALIZE(buffer, data, size) memcpy(data, buffer, size); buffer += size;
//-------------------------
//internal serialization functions
//-------------------------
void serializeType(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
}
void serializeServer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//server info
//Note: version info serialization goes here
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
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));
SERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
SERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
SERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
}
void serializeClient(SerialPacket* packet, char* buffer) {
memcpy(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);
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
memcpy(buffer, &packet->playerInfo.clientIndex, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->playerInfo.playerIndex, sizeof(int));
buffer += sizeof(int);
SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
//text
memcpy(buffer, packet->playerInfo.handle, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(buffer, packet->playerInfo.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));
//texts
SERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
}
void serializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//x & y
memcpy(buffer, &packet->regionInfo.x, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.y, sizeof(int));
//format
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
void serializeRegionContent(SerialPacket* packet, char* buffer) {
//format
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//x & y
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetX();
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetY();
buffer += sizeof(int);
//format
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
//content
for (register int i = 0; i < REGION_WIDTH; i++) {
@@ -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
//-------------------------
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) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//server info
//Note: version info deserialization goes here
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
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));
DESERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
DESERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
DESERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
}
void deserializeClient(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, 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);
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
memcpy(&packet->playerInfo.clientIndex, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->playerInfo.playerIndex, buffer, sizeof(int));
buffer += sizeof(int);
DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
//text
memcpy(packet->playerInfo.handle, buffer, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(packet->playerInfo.avatar, buffer, 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));
//texts
DESERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
}
void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
//format
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
void deserializeRegionContent(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
buffer += sizeof(int);
//format
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
//content
//an object to work on
BlankAllocator().Create(
&packet->regionInfo.region,
packet->regionInfo.x,
packet->regionInfo.y
);
//content
for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) {
@@ -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
//-------------------------
@@ -223,8 +202,6 @@ void serialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer));
break;
@@ -234,19 +211,14 @@ void serialize(SerialPacket* packet, void* buffer) {
break;
//Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//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
case SerialPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
@@ -255,6 +227,13 @@ void serialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::REGION_CONTENT:
serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
//Character info
case SerialPacket::Type::CHARACTER_NEW:
case SerialPacket::Type::CHARACTER_DELETE:
case SerialPacket::Type::CHARACTER_UPDATE:
serializeCharacter(packet, reinterpret_cast<char*>(buffer));
break;
}
}
@@ -267,8 +246,6 @@ void deserialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
//NOTHING
break;
@@ -278,19 +255,14 @@ void deserialize(SerialPacket* packet, void* buffer) {
break;
//Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//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
case SerialPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
@@ -299,5 +271,12 @@ void deserialize(SerialPacket* packet, void* buffer) {
case SerialPacket::Type::REGION_CONTENT:
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
//Character info
case SerialPacket::Type::CHARACTER_NEW:
case SerialPacket::Type::CHARACTER_DELETE:
case SerialPacket::Type::CHARACTER_UPDATE:
deserializeCharacter(packet, reinterpret_cast<char*>(buffer));
break;
}
}
+2 -2
View File
@@ -27,10 +27,10 @@
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date
* NOTE: REGION_CONTENT is currently the largest type of packet
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
* map format: sizeof(int) * 2
* map format: sizeof(int) * 3
* 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 deserialize(SerialPacket* const, void*);
+31 -29
View File
@@ -27,6 +27,7 @@
#include "SDL/SDL_net.h"
#define NETWORK_VERSION 20140428
#define PACKET_STRING_SIZE 100
#pragma pack(push, 0)
@@ -49,23 +50,25 @@ union SerialPacket {
JOIN_REQUEST = 5,
JOIN_RESPONSE = 6,
//disconnect from the server
DISCONNECT = 7,
//mass update
SYNCHRONIZE = 8,
SYNCHRONIZE = 7,
//disconnect from the server
DISCONNECT = 8,
//shut down the server
SHUTDOWN = 9,
//Player movement, etc.
PLAYER_NEW = 10,
PLAYER_DELETE = 11,
PLAYER_UPDATE = 12,
//map data
REGION_REQUEST = 13,
REGION_CONTENT = 14,
REGION_REQUEST = 10,
REGION_CONTENT = 11,
//Character movement, etc.
CHARACTER_NEW = 12,
CHARACTER_DELETE = 13,
CHARACTER_UPDATE = 14,
//TODO: combat packets
};
//metadata on the packet itself
@@ -77,42 +80,41 @@ union SerialPacket {
//information about the server
struct ServerInformation {
Metadata meta;
//TODO: version info
int networkVersion;
char name[PACKET_STRING_SIZE];
int playerCount;
//map format
int regionWidth;
int regionHeight;
int regionDepth;
}serverInfo;
//information about the client
//TODO: login credentials
struct ClientInformation {
Metadata meta;
int index;
}clientInfo;
//information about a player
struct PlayerInformation {
Metadata meta;
int clientIndex;
int playerIndex;
//TODO: should move handle/avatar into clientInfo; these might actually do better during the login system
int characterIndex;
char username[PACKET_STRING_SIZE];
char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE];
Vector2 position;
Vector2 motion;
}playerInfo;
}clientInfo;
//map data
struct RegionInformation {
Metadata meta;
int mapIndex;
int x, y;
Region* region;
}regionInfo;
//information about a character
struct CharacterInformation {
Metadata meta;
int clientIndex;
int characterIndex;
char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE];
int mapIndex;
Vector2 position;
Vector2 motion;
}characterInfo;
//defaults
SerialPacket() {
meta.type = Type::NONE;
+2 -2
View File
@@ -20,7 +20,7 @@
#define LUA_LIB
#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},
/* custom libs */
{LUA_REGIONLIBNAME, luaopen_regionapi},
{LUA_MAPLIBNAME, luaopen_mapapi},
{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
* distribution.
*/
#ifndef REGIONAPI_HPP_
#define REGIONAPI_HPP_
#ifndef MAPAPI_HPP_
#define MAPAPI_HPP_
#include "lua/lua.hpp"
#define LUA_REGIONLIBNAME "Region"
LUAMOD_API int luaopen_regionapi(lua_State* L);
#define LUA_MAPLIBNAME "map"
LUAMOD_API int luaopen_mapapi(lua_State* L);
#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) {
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()) {
@@ -184,29 +170,29 @@ void EditorScene::HandleMenuOption(int entry, int drop) {
case 0: //File
switch(drop) {
case 0:
//TODO: NEW
//NEW
break;
case 1:
//TODO: OPEN
//OPEN
break;
case 2:
//TODO: SAVE
//SAVE
break;
case 3:
//TODO: CLOSE
//CLOSE
break;
}
break;
case 1: //Edit
switch(drop) {
case 0:
//TODO: SET TILE
//SET TILE
break;
case 1:
//TODO: SET BRUSH
//SET BRUSH
break;
case 2:
//TODO: SCRIPT
//SCRIPT
break;
}
break;
+3 -2
View File
@@ -23,7 +23,8 @@ map.pager.height = 20
map.pager.depth = 3
#player options
player.handle = username
player.avatar = elliot2.bmp
client.username = Kayne Ruse
client.handle = Ratstail91
client.avatar = elliot2.bmp
#debugging
+17 -14
View File
@@ -1,29 +1,32 @@
print("Lua script check OK (./rsc)")
function Region.Create(r)
-- print("Region:Create(r", Region.GetX(r), Region.GetY(r), ")")
for i = 1, Region.GetWidth(r) do
for j = 1, Region.GetHeight(r) do
if math.abs(i) == math.abs(j) then
Region.SetTile(r, i, j, 1, 50)
function map.create(region)
for i = 1, map.getregionwidth() do
for j = 1, map.getregionheight() do
if math.abs(map.getx(region) + i -1) == math.abs(map.gety(region) + j -1) then
map.settile(region, i, j, 1, 50)
else
Region.SetTile(r, i, j, 1, 14)
map.settile(region, i, j, 1, 14)
end
end
end
-- print("done")
end
function Region.Unload(r)
-- print("Region:Unload(r", Region.GetX(r), Region.GetY(r), ")")
function map.unload(region)
--
end
--return true if file loaded, otherwise return false
function Region.Load(r, saveDir)
-- print("Region:Load(r,", saveDir, Region.GetX(r), Region.GetY(r), ")")
function map.load(region, dir)
--
return false
end
function Region.Save(r, saveDir)
-- print("Region:Save(r,", saveDir, Region.GetX(r), Region.GetY(r), ")")
function map.save(region, dir)
--
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
-------------------------
@@ -7,7 +5,8 @@
CREATE TABLE IF NOT EXISTS UserAccounts (
uid INTEGER PRIMARY KEY AUTOINCREMENT,
username varchar(100) UNIQUE,
password varchar(100), --NOTE: DO NOT DO THIS!!
--TODO: server-client security
-- password varchar(100),
blacklisted BIT DEFAULT 0,
whitelisted BIT DEFAULT 1
);
@@ -50,6 +49,7 @@ CREATE TABLE IF NOT EXISTS PlayerCharacters (
uid INTEGER PRIMARY KEY AUTOINCREMENT,
--metadata
owner INTEGER REFERENCES UserAccounts(uid),
handle varchar(100) UNIQUE,
avatar varchar(100),
birth timestamp NOT NULL DEFAULT (datetime()),
@@ -19,6 +19,6 @@
* 3. This notice may not be removed or altered from any source
* 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
* distribution.
*/
#ifndef PLAYERENTRY_HPP_
#define PLAYERENTRY_HPP_
#ifndef CHARACTERDATA_HPP_
#define CHARACTERDATA_HPP_
//POD members
#include "bbox.hpp"
@@ -28,35 +28,36 @@
#include <string>
struct PlayerEntry {
struct CharacterData {
//metadata
int clientIndex;
std::string username;
std::string handle;
std::string avatar;
//world position
int mapIndex;
Vector2 position;
Vector2 motion;
BBox bbox;
int mapIndex = 0;
Vector2 position = {0.0,0.0};
Vector2 motion = {0.0,0.0};
BBox bbox = {0,0,0,0};
//statistics
int level;
int exp;
int maxHP;
int health;
int maxMP;
int mana;
int attack;
int defence;
int intelligence;
int resistance;
float accuracy;
float evasion;
float luck;
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;
//uid
static unsigned int uidCounter;
static int uidCounter;
};
#endif
@@ -19,6 +19,6 @@
* 3. This notice may not be removed or altered from any source
* 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
* distribution.
*/
#ifndef CLIENTENTRY_HPP_
#define CLIENTENTRY_HPP_
#ifndef CLIENTDATA_HPP_
#define CLIENTDATA_HPP_
#include "SDL/SDL_net.h"
struct ClientEntry {
IPaddress address;
static unsigned int uidCounter;
struct ClientData {
IPaddress address = {0,0};
static int uidCounter;
};
#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_
//server specific stuff
#include "server_utility.hpp"
#include "client_entry.hpp"
#include "player_entry.hpp"
#include "client_data.hpp"
#include "character_data.hpp"
//maps
#include "map_allocator.hpp"
@@ -63,31 +62,33 @@ public:
private:
void HandlePacket(SerialPacket);
//high cohesion utility functions
//handle incoming traffic
void HandleBroadcastRequest(SerialPacket);
void HandleJoinRequest(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandleSynchronize(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandleShutdown(SerialPacket);
void HandlePlayerNew(SerialPacket);
void HandlePlayerDelete(SerialPacket);
void HandlePlayerUpdate(SerialPacket);
void HandleCharacterUpdate(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);
//TODO: manage the database
//TODO: combat systems
//APIs
UDPNetworkUtility network;
sqlite3* database = nullptr;
lua_State* luaState = nullptr;
//server tables
std::map<unsigned int, ClientEntry> clientMap;
std::map<unsigned int, PlayerEntry> playerMap;
std::map<int, ClientData> clientMap;
std::map<int, CharacterData> characterMap;
//maps
//TODO: I need to handle multiple map objects
//TODO: Unload regions that are distant from any characters
RegionPager<LuaAllocator, LuaFormat> regionPager;
//misc
+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