Merge branch 'server' (read more)

The only different between this commit and the currently stable branch is the
serialization code and a slight tweak to the server's startup sequence. I tried
to refactor the server, by moving the clientMap and playerMap into their own
wrapper classes, but that failed miserably. I need to stop getting so worked up
all the time, I've wasted way too much time already.
This commit is contained in:
Kayne Ruse
2014-03-11 19:00:32 +11:00
12 changed files with 383 additions and 154 deletions
+21 -8
View File
@@ -65,11 +65,14 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
packet.playerInfo.motion = {0,0}; packet.playerInfo.motion = {0,0};
//send it //send it
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); char buffer[sizeof(NetworkPacket)];
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, sizeof(NetworkPacket));
//request a sync //request a sync
packet.meta.type = NetworkPacket::Type::SYNCHRONIZE; packet.meta.type = NetworkPacket::Type::SYNCHRONIZE;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, sizeof(NetworkPacket));
} }
InWorld::~InWorld() { InWorld::~InWorld() {
@@ -88,7 +91,7 @@ void InWorld::Update(double delta) {
//suck in all waiting packets //suck in all waiting packets
NetworkPacket packet; NetworkPacket packet;
while(network.Receive()) { while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet); HandlePacket(packet);
} }
@@ -287,6 +290,9 @@ void InWorld::HandlePlayerUpdate(NetworkPacket packet) {
void InWorld::SendState() { void InWorld::SendState() {
NetworkPacket packet; NetworkPacket packet;
char buffer[sizeof(NetworkPacket)];
//pack the packet
packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE; packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
packet.playerInfo.clientIndex = clientIndex; packet.playerInfo.clientIndex = clientIndex;
packet.playerInfo.playerIndex = playerIndex; packet.playerInfo.playerIndex = playerIndex;
@@ -295,21 +301,28 @@ void InWorld::SendState() {
packet.playerInfo.position = localCharacter->GetPosition(); packet.playerInfo.position = localCharacter->GetPosition();
packet.playerInfo.motion = localCharacter->GetMotion(); packet.playerInfo.motion = localCharacter->GetMotion();
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, sizeof(NetworkPacket));
} }
void InWorld::RequestDisconnect() { void InWorld::RequestDisconnect() {
//send a disconnect request
NetworkPacket packet; NetworkPacket packet;
char buffer[sizeof(NetworkPacket)];
//send a disconnect request
packet.meta.type = NetworkPacket::Type::DISCONNECT; packet.meta.type = NetworkPacket::Type::DISCONNECT;
packet.clientInfo.index = clientIndex; packet.clientInfo.index = clientIndex;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, sizeof(NetworkPacket));
} }
void InWorld::RequestShutDown() { void InWorld::RequestShutDown() {
//send a shutdown request
NetworkPacket packet; NetworkPacket packet;
char buffer[sizeof(NetworkPacket)];
//send a shutdown request
packet.meta.type = NetworkPacket::Type::SHUTDOWN; packet.meta.type = NetworkPacket::Type::SHUTDOWN;
packet.clientInfo.index = clientIndex; packet.clientInfo.index = clientIndex;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, sizeof(NetworkPacket));
} }
+1
View File
@@ -27,6 +27,7 @@
#include "config_utility.hpp" #include "config_utility.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "network_packet.hpp" #include "network_packet.hpp"
#include "serial.hpp"
#include "image.hpp" #include "image.hpp"
#include "raster_font.hpp" #include "raster_font.hpp"
#include "button.hpp" #include "button.hpp"
+13 -5
View File
@@ -80,7 +80,7 @@ void LobbyMenu::Update(double delta) {
//suck in all waiting packets //suck in all waiting packets
NetworkPacket packet; NetworkPacket packet;
while(network.Receive()) { while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet); HandlePacket(packet);
} }
@@ -125,10 +125,14 @@ void LobbyMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (search.MouseButtonUp(button) == Button::State::HOVER) { if (search.MouseButtonUp(button) == Button::State::HOVER) {
//broadcast to the network, or a specific server //the vars
NetworkPacket packet; NetworkPacket packet;
char buffer[sizeof(NetworkPacket)];
//broadcast to the network, or a specific server
packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST; packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST;
network.Send(config["server.host"].c_str(), config.Int("server.port"), reinterpret_cast<void*>(&packet), sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, sizeof(NetworkPacket));
//reset the server list //reset the server list
serverInfo.clear(); serverInfo.clear();
@@ -136,10 +140,14 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
} }
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) { else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) {
//join the selected server //the vars
NetworkPacket packet; NetworkPacket packet;
char buffer[sizeof(NetworkPacket)];
//join the selected server
packet.meta.type = NetworkPacket::Type::JOIN_REQUEST; packet.meta.type = NetworkPacket::Type::JOIN_REQUEST;
network.Send(&selection->address, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(&selection->address, buffer, sizeof(NetworkPacket));
selection = nullptr; selection = nullptr;
} }
+1
View File
@@ -31,6 +31,7 @@
#include "config_utility.hpp" #include "config_utility.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "network_packet.hpp" #include "network_packet.hpp"
#include "serial.hpp"
#include <vector> #include <vector>
+3
View File
@@ -94,6 +94,9 @@ union NetworkPacket {
Vector2 motion; Vector2 motion;
}playerInfo; }playerInfo;
//map data
//...
//defaults //defaults
NetworkPacket() { NetworkPacket() {
meta.type = Type::NONE; meta.type = Type::NONE;
+207
View File
@@ -0,0 +1,207 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "serial.hpp"
#include <cstring>
//#include <iostream>
//using namespace std;
//-------------------------
//internal serialization functions
//-------------------------
void serializeType(NetworkPacket* packet, char* buffer) {
// cout << "serializeType" << endl;
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
}
void serializeServer(NetworkPacket* packet, char* buffer) {
// cout << "serializeServer" << endl;
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
}
void serializeClient(NetworkPacket* packet, char* buffer) {
// cout << "serializeClient" << endl;
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, &packet->clientInfo.index, sizeof(int));
}
void serializePlayer(NetworkPacket* packet, char* buffer) {
// cout << "serializePlayer" << endl;
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//indexes
memcpy(buffer, &packet->playerInfo.clientIndex, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->playerInfo.playerIndex, sizeof(int));
buffer += 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));
}
//-------------------------
//internal deserialization functions
//-------------------------
void deserializeType(NetworkPacket* packet, char* buffer) {
// cout << "deserializeType" << endl;
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
}
void deserializeServer(NetworkPacket* packet, char* buffer) {
// cout << "deserializeServer" << endl;
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE);
}
void deserializeClient(NetworkPacket* packet, char* buffer) {
// cout << "deserializeClient" << endl;
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(&packet->clientInfo.index, buffer, sizeof(int));
}
void deserializePlayer(NetworkPacket* packet, char* buffer) {
// cout << "deserializePlayer" << endl;
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//indexes
memcpy(&packet->playerInfo.clientIndex, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->playerInfo.playerIndex, buffer, sizeof(int));
buffer += 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));
}
//-------------------------
//the interface functions
//-------------------------
void serialize(NetworkPacket* packet, void* buffer) {
switch(packet->meta.type) {
//No extra data
case NetworkPacket::Type::NONE:
case NetworkPacket::Type::PING:
case NetworkPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer));
break;
//Server info
case NetworkPacket::Type::BROADCAST_RESPONSE:
serializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case NetworkPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::DISCONNECT:
case NetworkPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
serializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
}
// for (int i = 0; i < sizeof(NetworkPacket); i++) {
// cout << ((char*)(buffer))[i];
// }
// cout << endl;
}
void deserialize(NetworkPacket* packet, void* buffer) {
//find the type, so that you can actually deserialize the packet!
deserializeType(packet, reinterpret_cast<char*>(buffer));
switch(packet->meta.type) {
//No extra data
case NetworkPacket::Type::NONE:
case NetworkPacket::Type::PING:
case NetworkPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
//
break;
//Server info
case NetworkPacket::Type::BROADCAST_RESPONSE:
deserializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case NetworkPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::DISCONNECT:
case NetworkPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
deserializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
}
// for (int i = 0; i < sizeof(NetworkPacket); i++) {
// cout << ((char*)(buffer))[i];
// }
// cout << endl;
}
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,20 +19,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 CLIENT_HPP_ #ifndef SERIAL_HPP_
#define CLIENT_HPP_ #define SERIAL_HPP_
#include "SDL/SDL_net.h" #include "network_packet.hpp"
#include <map> void serialize(NetworkPacket* const, void*);
void deserialize(NetworkPacket* const, void*);
/* Hold the client info.
*/
struct Client {
IPaddress address;
};
typedef std::map<int, Client> ClientMap;
#endif #endif
View File
+1
View File
@@ -0,0 +1 @@
print("Lua script check OK")
-43
View File
@@ -1,43 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef PLAYER_HPP_
#define PLAYER_HPP_
#include "vector2.hpp"
#include <string>
#include <map>
/* Hold the player info.
*/
struct Player {
int clientIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
typedef std::map<int, Player> PlayerMap;
#endif
+106 -74
View File
@@ -30,20 +30,28 @@
using namespace std; using namespace std;
//------------------------- int runSQLScript(sqlite3* db, std::string fname) {
//Define the ServerApplication ifstream is(fname);
//------------------------- if (!is.is_open()) {
return -1;
ServerApplication::ServerApplication() { }
// string script;
getline(is, script, '\0');
is.close();
//TODO: flesh out this error if needed
if (sqlite3_exec(db, script.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) {
return -2;
}
return 0;
} }
ServerApplication::~ServerApplication() { //-------------------------
// //Define the public members
} //-------------------------
void ServerApplication::Init(int argc, char** argv) { void ServerApplication::Init(int argc, char** argv) {
//TODO: proper command line option parsing cout << "Beginning startup" << endl;
int ret = 0;
//load config //load config
config.Load("rsc\\config.cfg"); config.Load("rsc\\config.cfg");
@@ -52,101 +60,108 @@ void ServerApplication::Init(int argc, char** argv) {
if (SDL_Init(0)) { if (SDL_Init(0)) {
throw(runtime_error("Failed to initialize SDL")); throw(runtime_error("Failed to initialize SDL"));
} }
cout << "initialized SDL" << endl; cout << "Initialized SDL" << endl;
//Init SDL_net //Init SDL_net
if (SDLNet_Init()) { if (SDLNet_Init()) {
throw(runtime_error("Failed to init SDL_net")); throw(runtime_error("Failed to initialize SDL_net"));
} }
network.Open(config.Int("server.port"), sizeof(NetworkPacket)); network.Open(config.Int("server.port"), sizeof(NetworkPacket));
cout << "initialized SDL_net" << endl; cout << "Initialized SDL_net" << endl;
//Init SQL //Init SQL
string dbname = (config["server.dbname"].size()) ? config["server.dbname"] : std::string(argv[0]) + ".db"; //fancy and unnecessary ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
int ret = sqlite3_open_v2(dbname.c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, nullptr);
if (ret != SQLITE_OK || !database) { if (ret != SQLITE_OK || !database) {
throw(runtime_error("Failed to open the server database")); throw(runtime_error(string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
} }
cout << "initialized SQL" << endl; cout << "Initialized SQL" << endl;
cout << "Database filename: " << dbname << endl;
//TODO: move this into a function? //setup the database
//Run setup scripts if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
ifstream is("rsc\\scripts\\setup_server.sql"); throw(runtime_error("Failed to initialize SQL's setup script"));
if (!is.is_open()) {
throw(runtime_error("Failed to run database setup script"));
} }
string script; cout << "Initialized SQL's setup script" << endl;
getline(is, script, '\0');
is.close(); //lua
sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr); luaState = luaL_newstate();
if (!luaState) {
throw(runtime_error("Failed to initialize lua"));
}
luaL_openlibs(luaState);
cout << "Initialized lua" << endl;
//run the startup script
if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
throw(runtime_error(string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
}
cout << "Initialized lua's setup script" << endl;
//finalize the startup
cout << "Startup completed successfully" << endl;
} }
void ServerApplication::Loop() { void ServerApplication::Loop() {
NetworkPacket packet; NetworkPacket packet;
while(running) { while(running) {
//suck in the waiting packets & process them //suck in the waiting packets & process them
try { while(network.Receive()) {
while(network.Receive()) { //get the packet
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; //cache the source address
HandlePacket(packet); packet.meta.srcAddress = network.GetInPacket()->address;
} //we need to go deeper
HandlePacket(packet);
} }
catch(exception& e) {
cerr << "Network Error: " << e.what() << endl;
}
//give the computer a break //give the computer a break
SDL_Delay(10); SDL_Delay(10);
} }
} }
void ServerApplication::Quit() { void ServerApplication::Quit() {
//members cout << "Shutting down" << endl;
network.Close(); //empty the members
//TODO: player manager
//TODO: client manager
//APIs //APIs
lua_close(luaState);
sqlite3_close_v2(database); sqlite3_close_v2(database);
network.Close();
SDLNet_Quit(); SDLNet_Quit();
SDL_Quit(); SDL_Quit();
cout << "Shutdown finished" << endl;
} }
//-------------------------
//Define the uber switch
//-------------------------
void ServerApplication::HandlePacket(NetworkPacket packet) { void ServerApplication::HandlePacket(NetworkPacket packet) {
switch(packet.meta.type) { switch(packet.meta.type) {
case NetworkPacket::Type::BROADCAST_REQUEST: case NetworkPacket::Type::BROADCAST_REQUEST:
HandleBroadcastRequest(packet); HandleBroadcastRequest(packet);
break; break;
case NetworkPacket::Type::JOIN_REQUEST: case NetworkPacket::Type::JOIN_REQUEST:
HandleJoinRequest(packet); HandleJoinRequest(packet);
break; break;
case NetworkPacket::Type::DISCONNECT: case NetworkPacket::Type::DISCONNECT:
HandleDisconnect(packet); HandleDisconnect(packet);
break; break;
case NetworkPacket::Type::SYNCHRONIZE: case NetworkPacket::Type::SYNCHRONIZE:
HandleSynchronize(packet); HandleSynchronize(packet);
break; break;
case NetworkPacket::Type::SHUTDOWN: case NetworkPacket::Type::SHUTDOWN:
HandleShutdown(packet); HandleShutdown(packet);
break; break;
case NetworkPacket::Type::PLAYER_NEW: case NetworkPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet); HandlePlayerNew(packet);
break; break;
case NetworkPacket::Type::PLAYER_DELETE: case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet); HandlePlayerDelete(packet);
break; break;
case NetworkPacket::Type::PLAYER_UPDATE: case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet); HandlePlayerUpdate(packet);
break; break;
//handle errors //handle errors
default: default:
throw(runtime_error("Unknown NetworkPacket::Type encountered")); throw(runtime_error("Unknown NetworkPacket::Type encountered"));
@@ -154,27 +169,35 @@ void ServerApplication::HandlePacket(NetworkPacket packet) {
} }
} }
//-------------------------
//Handle various network input
//-------------------------
void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) { void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) {
//send back the server's name //send back the server's metadata
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE; packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE;
//TODO: version info
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str()); snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
network.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket)); //TODO: player count
char buffer[sizeof(NetworkPacket)];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, sizeof(NetworkPacket));
} }
void ServerApplication::HandleJoinRequest(NetworkPacket packet) { void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
//TODO: prevent duplicate logins from the same address? //register the new client
ClientEntry c;
//create the new client, filling it with the correct info c.address = packet.meta.srcAddress;
Client newClient; clientMap[clientCounter] = c;
newClient.address = packet.meta.srcAddress;
//push the new client
clientMap[clientCounter] = newClient;
//send the client their info //send the client their info
char buffer[sizeof(NetworkPacket)];
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = clientCounter; packet.clientInfo.index = clientCounter;
network.Send(&newClient.address, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(&clientMap[clientCounter].address, buffer, sizeof(NetworkPacket));
//finished this routine //finished this routine
clientCounter++; clientCounter++;
@@ -183,32 +206,36 @@ void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
void ServerApplication::HandleDisconnect(NetworkPacket packet) { void ServerApplication::HandleDisconnect(NetworkPacket packet) {
//disconnect the specified client //disconnect the specified client
network.Send(&clientMap[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket)); //TODO: authenticate who is disconnecting/kicking
char buffer[sizeof(NetworkPacket)];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, sizeof(NetworkPacket));
clientMap.erase(packet.clientInfo.index); clientMap.erase(packet.clientInfo.index);
//delete players //delete players from all clients
erase_if(playerMap, [&](pair<int, Player> it) -> bool { NetworkPacket delPacket;
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
erase_if(playerMap, [&](std::pair<int, PlayerEntry> it) -> bool {
//find the internal players to delete
if (it.second.clientIndex == packet.clientInfo.index) { if (it.second.clientIndex == packet.clientInfo.index) {
NetworkPacket delPacket;
//data to delete one specific player
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
delPacket.playerInfo.playerIndex = it.first; delPacket.playerInfo.playerIndex = it.first;
//send the delete player command to all clients
//send to all
PumpPacket(delPacket); PumpPacket(delPacket);
return true; return true;
} }
return false; return false;
}); });
//finished this routine
cout << "disconnect, total: " << clientMap.size() << endl; cout << "disconnect, total: " << clientMap.size() << endl;
} }
void ServerApplication::HandleSynchronize(NetworkPacket packet) { void ServerApplication::HandleSynchronize(NetworkPacket packet) {
//send all the server's data to this client //send all the server's data to this client
//TODO: compensate for large distances
NetworkPacket newPacket; NetworkPacket newPacket;
char buffer[sizeof(NetworkPacket)];
//players //players
newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE; newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
@@ -218,7 +245,8 @@ void ServerApplication::HandleSynchronize(NetworkPacket packet) {
snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
newPacket.playerInfo.position = it.second.position; newPacket.playerInfo.position = it.second.position;
newPacket.playerInfo.motion = it.second.motion; newPacket.playerInfo.motion = it.second.motion;
network.Send(&clientMap[packet.clientInfo.index].address, &newPacket, sizeof(NetworkPacket)); serialize(&newPacket, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, sizeof(NetworkPacket));
} }
} }
@@ -230,13 +258,15 @@ void ServerApplication::HandleShutdown(NetworkPacket packet) {
packet.meta.type = NetworkPacket::Type::DISCONNECT; packet.meta.type = NetworkPacket::Type::DISCONNECT;
PumpPacket(packet); PumpPacket(packet);
//finished this routine
cout << "shutting down" << endl; cout << "shutting down" << endl;
} }
void ServerApplication::HandlePlayerNew(NetworkPacket packet) { void ServerApplication::HandlePlayerNew(NetworkPacket packet) {
//create the new player object //create the new player object
Player newPlayer; PlayerEntry newPlayer;
newPlayer.clientIndex = packet.playerInfo.clientIndex; newPlayer.clientIndex = packet.playerInfo.clientIndex;
newPlayer.mapIndex = 0;
newPlayer.handle = packet.playerInfo.handle; newPlayer.handle = packet.playerInfo.handle;
newPlayer.avatar = packet.playerInfo.avatar; newPlayer.avatar = packet.playerInfo.avatar;
newPlayer.position = {0,0}; newPlayer.position = {0,0};
@@ -263,7 +293,7 @@ void ServerApplication::HandlePlayerDelete(NetworkPacket packet) {
} }
//delete players //delete players
erase_if(playerMap, [&](pair<int, Player> it) -> bool { erase_if(playerMap, [&](pair<int, PlayerEntry> it) -> bool {
if (it.first == packet.playerInfo.playerIndex) { if (it.first == packet.playerInfo.playerIndex) {
NetworkPacket delPacket; NetworkPacket delPacket;
@@ -293,8 +323,10 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) {
} }
void ServerApplication::PumpPacket(NetworkPacket packet) { void ServerApplication::PumpPacket(NetworkPacket packet) {
//send this packet to all clients //I don't really like this, but it'll do for now
char buffer[sizeof(NetworkPacket)];
serialize(&packet, buffer);
for (auto& it : clientMap) { for (auto& it : clientMap) {
network.Send(&it.second.address, &packet, sizeof(NetworkPacket)); network.Send(&it.second.address, buffer, sizeof(NetworkPacket));
} }
} }
+23 -9
View File
@@ -25,28 +25,40 @@
//networking //networking
#include "network_packet.hpp" #include "network_packet.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "serial.hpp"
//APIs //APIs
#include "lua/lua.hpp"
#include "sqlite3/sqlite3.h" #include "sqlite3/sqlite3.h"
#include "SDL/SDL.h" #include "SDL/SDL.h"
//misc //common
#include "config_utility.hpp" #include "config_utility.hpp"
#include "vector2.hpp" #include "vector2.hpp"
#include "client.hpp"
#include "player.hpp"
//STL //STL
#include <map> #include <map>
#include <string> #include <string>
struct ClientEntry {
IPaddress address;
};
struct PlayerEntry {
int clientIndex;
int mapIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
//The main application class //The main application class
class ServerApplication { class ServerApplication {
public: public:
//standard functions //standard functions
ServerApplication(); ServerApplication() = default;
~ServerApplication(); ~ServerApplication() = default;
void Init(int argc, char** argv); void Init(int argc, char** argv);
void Loop(); void Loop();
@@ -73,13 +85,15 @@ private:
//database //database
sqlite3* database = nullptr; sqlite3* database = nullptr;
//lua
lua_State* luaState = nullptr;
//misc //misc
bool running = true; bool running = true;
ConfigUtility config; ConfigUtility config;
//global lists std::map<int, ClientEntry> clientMap;
ClientMap clientMap; std::map<int, PlayerEntry> playerMap;
PlayerMap playerMap;
int clientCounter = 0; int clientCounter = 0;
int playerCounter = 0; int playerCounter = 0;