Merge branch 'develop', read more
This merge handles a number of backend features, including error handling and other types of messages. I think there's more I could've done in this time, but this is what I have nonetheless.
This commit is contained in:
@@ -75,7 +75,7 @@ private:
|
||||
//base statistics
|
||||
Statistics stats;
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
|
||||
//metadata
|
||||
int owner;
|
||||
|
||||
@@ -89,6 +89,7 @@ void ClientApplication::Init(int argc, char** argv) {
|
||||
|
||||
std::cout << "Internal sizes:" << std::endl;
|
||||
|
||||
DEBUG_OUTPUT_VAR(NETWORK_VERSION);
|
||||
DEBUG_OUTPUT_VAR(sizeof(Region::type_t));
|
||||
DEBUG_OUTPUT_VAR(sizeof(Region));
|
||||
DEBUG_OUTPUT_VAR(REGION_WIDTH);
|
||||
@@ -96,8 +97,10 @@ void ClientApplication::Init(int argc, char** argv) {
|
||||
DEBUG_OUTPUT_VAR(REGION_DEPTH);
|
||||
DEBUG_OUTPUT_VAR(REGION_TILE_FOOTPRINT);
|
||||
DEBUG_OUTPUT_VAR(REGION_SOLID_FOOTPRINT);
|
||||
DEBUG_OUTPUT_VAR(PACKET_STRING_SIZE);
|
||||
DEBUG_OUTPUT_VAR(PACKET_BUFFER_SIZE);
|
||||
DEBUG_OUTPUT_VAR(MAX_PACKET_SIZE);
|
||||
DEBUG_OUTPUT_VAR(static_cast<int>(SerialPacketType::LAST));
|
||||
|
||||
#undef DEBUG_OUTPUT_VAR
|
||||
|
||||
|
||||
@@ -85,13 +85,15 @@ void CleanUp::Update() {
|
||||
SetNextScene(SceneList::MAINMENU);
|
||||
}
|
||||
|
||||
//BUGFIX: Eat incoming packets
|
||||
//Eat incoming packets
|
||||
while(network.Receive());
|
||||
}
|
||||
|
||||
void CleanUp::Render(SDL_Surface* const screen) {
|
||||
ConfigUtility& config = ConfigUtility::GetSingleton();
|
||||
|
||||
backButton.DrawTo(screen);
|
||||
font.DrawStringTo("You have been disconnected.", screen, 50, 30);
|
||||
font.DrawStringTo(config["client.disconnectMessage"], screen, 50, 30);
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
|
||||
@@ -73,6 +73,14 @@ InWorld::InWorld(
|
||||
//TODO: Tile size and tile sheet should be loaded elsewhere
|
||||
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 32, 32);
|
||||
|
||||
//send this player's character info
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_NEW;
|
||||
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
||||
newPacket.accountIndex = accountIndex;
|
||||
network.SendTo(Channels::SERVER, &newPacket);
|
||||
|
||||
//request a sync
|
||||
RequestSynchronize();
|
||||
|
||||
@@ -142,9 +150,11 @@ void InWorld::Update() {
|
||||
camera.y = localCharacter->GetOrigin().y - camera.marginY;
|
||||
|
||||
//check the connection
|
||||
if (Clock::now() - lastBeat > std::chrono::seconds(5)) {
|
||||
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
|
||||
if (attemptedBeats > 2) {
|
||||
throw(std::runtime_error("Connection lost"));
|
||||
RequestDisconnect();
|
||||
SetNextScene(SceneList::CLEANUP);
|
||||
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
|
||||
}
|
||||
|
||||
ServerPacket newPacket;
|
||||
@@ -302,6 +312,9 @@ void InWorld::HandlePacket(SerialPacket* const argPacket) {
|
||||
case SerialPacketType::CHARACTER_UPDATE:
|
||||
HandleCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
HandleCharacterRejection(static_cast<TextPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::REGION_CONTENT:
|
||||
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
|
||||
break;
|
||||
@@ -330,6 +343,7 @@ void InWorld::HandlePong(ServerPacket* const argPacket) {
|
||||
void InWorld::HandleDisconnect(ClientPacket* const argPacket) {
|
||||
//TODO: More needed in the disconnection
|
||||
SetNextScene(SceneList::CLEANUP);
|
||||
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been disconnected";
|
||||
}
|
||||
|
||||
void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) {
|
||||
@@ -366,7 +380,6 @@ void InWorld::HandleCharacterNew(CharacterPacket* const argPacket) {
|
||||
localCharacter = &newCharacter;
|
||||
|
||||
//setup the camera
|
||||
//TODO: move this?
|
||||
camera.width = GetScreen()->w;
|
||||
camera.height = GetScreen()->h;
|
||||
|
||||
@@ -390,7 +403,6 @@ void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) {
|
||||
|
||||
void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) {
|
||||
if (characterMap.find(argPacket->characterIndex) == characterMap.end()) {
|
||||
std::cout << "Warning: HandleCharacterUpdate() is passing to HandleCharacterNew()" << std::endl;
|
||||
HandleCharacterNew(argPacket);
|
||||
return;
|
||||
}
|
||||
@@ -405,6 +417,14 @@ void InWorld::HandleCharacterUpdate(CharacterPacket* const argPacket) {
|
||||
}
|
||||
}
|
||||
|
||||
void InWorld::HandleCharacterRejection(TextPacket* const argPacket) {
|
||||
RequestDisconnect();
|
||||
SetNextScene(SceneList::CLEANUP);
|
||||
ConfigUtility& config = ConfigUtility::GetSingleton();
|
||||
config["client.disconnectMessage"] = "Error: ";
|
||||
config["client.disconnectMessage"] += argPacket->text;
|
||||
}
|
||||
|
||||
void InWorld::HandleRegionContent(RegionPacket* const argPacket) {
|
||||
//replace existing regions
|
||||
regionPager.UnloadRegion(argPacket->x, argPacket->y);
|
||||
|
||||
@@ -83,6 +83,7 @@ protected:
|
||||
void HandleCharacterNew(CharacterPacket* const);
|
||||
void HandleCharacterDelete(CharacterPacket* const);
|
||||
void HandleCharacterUpdate(CharacterPacket* const);
|
||||
void HandleCharacterRejection(TextPacket* const);
|
||||
void HandleRegionContent(RegionPacket* const);
|
||||
|
||||
//Server control
|
||||
@@ -113,7 +114,8 @@ protected:
|
||||
//UI
|
||||
Button disconnectButton;
|
||||
Button shutDownButton;
|
||||
//TODO: Review the camera
|
||||
|
||||
//the camera structure
|
||||
struct {
|
||||
int x = 0, y = 0;
|
||||
int width = 0, height = 0;
|
||||
@@ -125,6 +127,7 @@ protected:
|
||||
Character* localCharacter = nullptr;
|
||||
|
||||
//connections
|
||||
//TODO: This needs it's own utility, for both InWorld and InCombat
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
Clock::time_point lastBeat = Clock::now();
|
||||
int attemptedBeats = 0;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
//-------------------------
|
||||
//Public access members
|
||||
@@ -63,7 +64,7 @@ LobbyMenu::LobbyMenu(int* const argClientIndex, int* const argAccountIndex):
|
||||
//set the server list's position
|
||||
listBox = {300, 50, 200, font.GetCharH()};
|
||||
|
||||
//BUGFIX: Eat incoming packets
|
||||
//Eat incoming packets
|
||||
while(network.Receive());
|
||||
|
||||
//Initial broadcast
|
||||
@@ -192,6 +193,9 @@ void LobbyMenu::HandlePacket(SerialPacket* const argPacket) {
|
||||
case SerialPacketType::JOIN_RESPONSE:
|
||||
HandleJoinResponse(static_cast<ClientPacket*>(argPacket));
|
||||
break;
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
HandleJoinRejection(static_cast<TextPacket*>(argPacket));
|
||||
break;
|
||||
//handle errors
|
||||
default:
|
||||
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in LobbyMenu: " + to_string_custom(static_cast<int>(argPacket->type)) ));
|
||||
@@ -219,14 +223,11 @@ void LobbyMenu::HandleJoinResponse(ClientPacket* const argPacket) {
|
||||
accountIndex = argPacket->accountIndex;
|
||||
network.Bind(argPacket->srcAddress, Channels::SERVER);
|
||||
SetNextScene(SceneList::INWORLD);
|
||||
}
|
||||
|
||||
//send this player's character info
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_NEW;
|
||||
strncpy(newPacket.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
|
||||
newPacket.accountIndex = accountIndex;
|
||||
network.SendTo(Channels::SERVER, &newPacket);
|
||||
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
|
||||
//TODO: Better output
|
||||
std::cerr << "Error: " << argPacket->text << std::endl;
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
|
||||
@@ -63,6 +63,7 @@ protected:
|
||||
void HandlePacket(SerialPacket* const);
|
||||
void HandleBroadcastResponse(ServerPacket* const);
|
||||
void HandleJoinResponse(ClientPacket* const);
|
||||
void HandleJoinRejection(TextPacket* const);
|
||||
|
||||
//server control
|
||||
void SendBroadcastRequest();
|
||||
|
||||
@@ -46,7 +46,7 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) {
|
||||
//stats structure
|
||||
serializeStatistics(&buffer, &packet->stats);
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
}
|
||||
|
||||
void deserializeCharacter(void* buffer, CharacterPacket* packet) {
|
||||
@@ -70,5 +70,5 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) {
|
||||
//stats structure
|
||||
deserializeStatistics(&buffer, &packet->stats);
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ struct CharacterPacket : SerialPacketBase {
|
||||
//gameplay
|
||||
Statistics stats;
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
};
|
||||
|
||||
void serializeCharacter(void* buffer, CharacterPacket* packet);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* 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 "text_packet.hpp"
|
||||
|
||||
#include "serial_utility.hpp"
|
||||
|
||||
void serializeText(void* buffer, TextPacket* packet) {
|
||||
serialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
||||
|
||||
//content
|
||||
serialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||
serialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||
}
|
||||
|
||||
void deserializeText(void* buffer, TextPacket* packet) {
|
||||
deserialCopy(&buffer, &packet->type, sizeof(SerialPacketType));
|
||||
|
||||
//content
|
||||
deserialCopy(&buffer, packet->name, PACKET_STRING_SIZE);
|
||||
deserialCopy(&buffer, packet->text, PACKET_STRING_SIZE);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright: (c) Kayne Ruse 2013, 2014
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
#ifndef TEXTPACKET_HPP_
|
||||
#define TEXTPACKET_HPP_
|
||||
|
||||
#include "serial_packet_base.hpp"
|
||||
|
||||
struct TextPacket : SerialPacketBase {
|
||||
char name[PACKET_STRING_SIZE];
|
||||
char text[PACKET_STRING_SIZE];
|
||||
};
|
||||
|
||||
void serializeText(void* buffer, TextPacket* packet);
|
||||
void deserializeText(void* buffer, TextPacket* packet);
|
||||
|
||||
#endif
|
||||
@@ -27,18 +27,20 @@
|
||||
#include "client_packet.hpp"
|
||||
#include "region_packet.hpp"
|
||||
#include "server_packet.hpp"
|
||||
#include "text_packet.hpp"
|
||||
|
||||
//SerialPacketBase is defined in serial_packet_base.hpp
|
||||
typedef SerialPacketBase SerialPacket;
|
||||
|
||||
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients
|
||||
constexpr int NETWORK_VERSION = 20140831;
|
||||
constexpr int NETWORK_VERSION = 20140909;
|
||||
|
||||
union MaxPacket {
|
||||
CharacterPacket a;
|
||||
ClientPacket b;
|
||||
RegionPacket c;
|
||||
ServerPacket d;
|
||||
TextPacket e;
|
||||
};
|
||||
|
||||
constexpr int MAX_PACKET_SIZE = sizeof(MaxPacket);
|
||||
|
||||
@@ -52,7 +52,6 @@ enum class SerialPacketType {
|
||||
//Connecting to a server as a client
|
||||
JOIN_REQUEST,
|
||||
JOIN_RESPONSE,
|
||||
JOIN_REJECTION,
|
||||
|
||||
//client requests all information from the server
|
||||
SYNCHRONIZE,
|
||||
@@ -88,10 +87,23 @@ enum class SerialPacketType {
|
||||
CHARACTER_STATS_REQUEST,
|
||||
CHARACTER_STATS_RESPONSE,
|
||||
|
||||
//reject a character request
|
||||
//-------------------------
|
||||
//TextPacket
|
||||
// name, text
|
||||
//-------------------------
|
||||
|
||||
//general speech
|
||||
TEXT_BROADCAST,
|
||||
|
||||
//rejection/error messages
|
||||
SHUTDOWN_REJECTION,
|
||||
JOIN_REJECTION,
|
||||
CHARACTER_REJECTION,
|
||||
|
||||
//-------------------------
|
||||
//not used
|
||||
//-------------------------
|
||||
|
||||
LAST
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "client_packet.hpp"
|
||||
#include "region_packet.hpp"
|
||||
#include "server_packet.hpp"
|
||||
#include "text_packet.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -53,7 +54,6 @@ void serializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
break;
|
||||
case SerialPacketType::JOIN_REQUEST:
|
||||
case SerialPacketType::JOIN_RESPONSE:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::SYNCHRONIZE:
|
||||
case SerialPacketType::DISCONNECT:
|
||||
case SerialPacketType::SHUTDOWN:
|
||||
@@ -68,9 +68,14 @@ void serializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
case SerialPacketType::CHARACTER_UPDATE:
|
||||
case SerialPacketType::CHARACTER_STATS_REQUEST:
|
||||
case SerialPacketType::CHARACTER_STATS_RESPONSE:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::TEXT_BROADCAST:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
serializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +93,6 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
break;
|
||||
case SerialPacketType::JOIN_REQUEST:
|
||||
case SerialPacketType::JOIN_RESPONSE:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::SYNCHRONIZE:
|
||||
case SerialPacketType::DISCONNECT:
|
||||
case SerialPacketType::SHUTDOWN:
|
||||
@@ -103,8 +107,13 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
|
||||
case SerialPacketType::CHARACTER_UPDATE:
|
||||
case SerialPacketType::CHARACTER_STATS_REQUEST:
|
||||
case SerialPacketType::CHARACTER_STATS_RESPONSE:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
|
||||
break;
|
||||
case SerialPacketType::TEXT_BROADCAST:
|
||||
case SerialPacketType::JOIN_REJECTION:
|
||||
case SerialPacketType::SHUTDOWN_REJECTION:
|
||||
case SerialPacketType::CHARACTER_REJECTION:
|
||||
deserializeText(buffer, static_cast<TextPacket*>(packet));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
//BUGFIX: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
||||
//NOTE: memset() is used before sending a packet to remove old data; you don't want to send sensitive data over the network
|
||||
//NOTE: don't confuse SerialPacketBase with UDPpacket
|
||||
|
||||
void UDPNetworkUtility::Open(int port) {
|
||||
|
||||
@@ -88,7 +88,6 @@ ConfigUtility::table_t ConfigUtility::Read(std::string fname) {
|
||||
is.close();
|
||||
|
||||
//load in any subordinate config files
|
||||
//TODO: Possibility of nesting config levels?
|
||||
if (retTable.find("config.next") != retTable.end()) {
|
||||
table_t subTable = Read(retTable["config.next"]);
|
||||
retTable.insert(subTable.begin(), subTable.end());
|
||||
|
||||
@@ -17,7 +17,7 @@ tiles = {
|
||||
|
||||
--custom generation systems here
|
||||
function islandGenerator(region)
|
||||
io.write("Generating (", Region.GetX(region), ", ", Region.GetY(region), ")\n")
|
||||
-- io.write("Generating (", Region.GetX(region), ", ", Region.GetY(region), ")\n")
|
||||
for i = 1, Region.GetWidth(region) do
|
||||
for j = 1, Region.GetHeight(region) do
|
||||
local dist = math.dist(0, 0, i + Region.GetX(region) -1, j + Region.GetY(region) -1)
|
||||
|
||||
@@ -157,7 +157,7 @@ int CharacterManager::LoadCharacter(int owner, std::string handle, std::string a
|
||||
newChar.baseStats.evasion = sqlite3_column_double(statement, 20);
|
||||
newChar.baseStats.luck = sqlite3_column_double(statement, 21);
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
|
||||
//finish the routine
|
||||
sqlite3_finalize(statement);
|
||||
@@ -214,7 +214,7 @@ int CharacterManager::SaveCharacter(int uid) {
|
||||
ret |= sqlite3_bind_double(statement, 17, character.baseStats.evasion) != SQLITE_OK;
|
||||
ret |= sqlite3_bind_double(statement, 18, character.baseStats.luck) != SQLITE_OK;
|
||||
|
||||
//TODO: gameplay components: equipment, items, buffs, debuffs
|
||||
//gameplay components: equipment, items, buffs, debuffs...
|
||||
|
||||
//check for binding errors
|
||||
if (ret) {
|
||||
@@ -225,7 +225,7 @@ int CharacterManager::SaveCharacter(int uid) {
|
||||
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||
//if this fails, than something went horribly wrong
|
||||
sqlite3_finalize(statement);
|
||||
throw( std::runtime_error(std::string() + "Unknown SQL error when saving an account: " + sqlite3_errmsg(database)) );
|
||||
throw( std::runtime_error(std::string() + "Unknown SQL error when saving a character: " + sqlite3_errmsg(database)) );
|
||||
}
|
||||
|
||||
sqlite3_finalize(statement);
|
||||
@@ -258,7 +258,7 @@ void CharacterManager::DeleteCharacter(int uid) {
|
||||
if (sqlite3_step(statement) != SQLITE_DONE) {
|
||||
//if this fails, than something went horribly wrong
|
||||
sqlite3_finalize(statement);
|
||||
throw( std::runtime_error(std::string() + "Unknown SQL error when deleting an account: " + sqlite3_errmsg(database)) );
|
||||
throw( std::runtime_error(std::string() + "Unknown SQL error when deleting a character: " + sqlite3_errmsg(database)) );
|
||||
}
|
||||
|
||||
//finish the routine
|
||||
|
||||
@@ -110,6 +110,7 @@ void ServerApplication::Init(int argc, char** argv) {
|
||||
|
||||
std::cout << "Internal sizes:" << std::endl;
|
||||
|
||||
DEBUG_OUTPUT_VAR(NETWORK_VERSION);
|
||||
DEBUG_OUTPUT_VAR(sizeof(Region::type_t));
|
||||
DEBUG_OUTPUT_VAR(sizeof(Region));
|
||||
DEBUG_OUTPUT_VAR(REGION_WIDTH);
|
||||
@@ -117,8 +118,10 @@ void ServerApplication::Init(int argc, char** argv) {
|
||||
DEBUG_OUTPUT_VAR(REGION_DEPTH);
|
||||
DEBUG_OUTPUT_VAR(REGION_TILE_FOOTPRINT);
|
||||
DEBUG_OUTPUT_VAR(REGION_SOLID_FOOTPRINT);
|
||||
DEBUG_OUTPUT_VAR(PACKET_STRING_SIZE);
|
||||
DEBUG_OUTPUT_VAR(PACKET_BUFFER_SIZE);
|
||||
DEBUG_OUTPUT_VAR(MAX_PACKET_SIZE);
|
||||
DEBUG_OUTPUT_VAR(static_cast<int>(SerialPacketType::LAST));
|
||||
|
||||
#undef DEBUG_OUTPUT_VAR
|
||||
|
||||
@@ -148,7 +151,7 @@ void ServerApplication::Proc() {
|
||||
//TODO: This could be checked only every few seconds
|
||||
//Check connections
|
||||
for (auto& it : clientMap) {
|
||||
if (std::chrono::steady_clock::now() - it.second.GetLastBeat() > std::chrono::seconds(5)) {
|
||||
if (std::chrono::steady_clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
|
||||
ServerPacket newPacket;
|
||||
newPacket.type = SerialPacketType::PING;
|
||||
network.SendTo(it.second.GetAddress(), &newPacket);
|
||||
|
||||
+43
-28
@@ -35,8 +35,6 @@ void ServerApplication::HandlePing(ServerPacket* const argPacket) {
|
||||
|
||||
void ServerApplication::HandlePong(ServerPacket* const argPacket) {
|
||||
//find and update the specified client
|
||||
|
||||
//BUGFIX: running multiple clients on one computer will result in matching host values; check the ports too
|
||||
for (auto& it : clientMap) {
|
||||
if (it.second.GetAddress().host == argPacket->srcAddress.host &&
|
||||
it.second.GetAddress().port == argPacket->srcAddress.port
|
||||
@@ -60,16 +58,18 @@ void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) {
|
||||
}
|
||||
|
||||
void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
|
||||
//create the new client
|
||||
ClientData newClient;
|
||||
newClient.SetAddress(argPacket->srcAddress);
|
||||
|
||||
//load the user account
|
||||
//TODO: handle passwords
|
||||
int accountIndex = accountMgr.LoadAccount(argPacket->username, clientIndex);
|
||||
|
||||
//Cannot load
|
||||
if (accountIndex < 0) {
|
||||
//TODO: send rejection packet
|
||||
std::cerr << "Error: Account already loaded: " << accountIndex << std::endl;
|
||||
TextPacket newPacket;
|
||||
newPacket.type = SerialPacketType::JOIN_REJECTION;
|
||||
std::string msg = std::string() + "Account already loaded: " + argPacket->username;
|
||||
memset(newPacket.name, 0, PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.text, msg.c_str(), PACKET_STRING_SIZE); //BUG: If the name is too long this would truncate it
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,10 +79,14 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
|
||||
newPacket.clientIndex = clientIndex;
|
||||
newPacket.accountIndex = accountIndex;
|
||||
|
||||
network.SendTo(newClient.GetAddress(), static_cast<SerialPacket*>(&newPacket));
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
|
||||
//register the client
|
||||
ClientData newClient;
|
||||
newClient.SetAddress(argPacket->srcAddress);
|
||||
clientMap[clientIndex++] = newClient;
|
||||
|
||||
//finished this routine
|
||||
clientMap[clientIndex++] = newClient;
|
||||
std::cout << "New connection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl;
|
||||
}
|
||||
|
||||
@@ -105,9 +109,9 @@ void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) {
|
||||
);
|
||||
|
||||
//save and unload this account's characters
|
||||
//pump the unload message to all remaining clients
|
||||
characterMgr.UnloadCharacterIf([&](std::map<int, CharacterData>::iterator it) -> bool {
|
||||
if (argPacket->accountIndex == it->second.GetOwner()) {
|
||||
//pump the unload message to all remaining clients
|
||||
PumpCharacterUnload(it->first);
|
||||
return true;
|
||||
}
|
||||
@@ -167,23 +171,32 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) {
|
||||
|
||||
void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) {
|
||||
//BUG: #27 Characters can be created with an invalid account index
|
||||
//TODO: Make sure that a character's owner's account is loaded before continuing
|
||||
|
||||
//NOTE: misnomer, try to load the character first
|
||||
int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
|
||||
|
||||
if (characterIndex == -1) {
|
||||
//TODO: rejection packet
|
||||
std::cerr << "Warning: Character already loaded" << std::endl;
|
||||
//cannot load or create
|
||||
if (characterIndex < 0) {
|
||||
//build the error message
|
||||
std::string msg;
|
||||
if (characterIndex == -1) {
|
||||
msg += "Character already loaded: ";
|
||||
}
|
||||
else if (characterIndex == -2) {
|
||||
msg += "Character already exists: ";
|
||||
}
|
||||
msg += argPacket->handle;
|
||||
|
||||
//create, fill and send the packet
|
||||
TextPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_REJECTION;
|
||||
memset(newPacket.name, 0, PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.text, msg.c_str(), PACKET_STRING_SIZE);
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
return;
|
||||
}
|
||||
|
||||
if (characterIndex == -2) {
|
||||
//TODO: rejection packet
|
||||
std::cerr << "Warning: Character already exists" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Make sure that a character's owner's account is loaded before continuing
|
||||
|
||||
//send this new character to all clients
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_NEW;
|
||||
@@ -198,9 +211,13 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket)
|
||||
int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
|
||||
|
||||
//if this is not your character
|
||||
if (characterIndex == -2) {
|
||||
//TODO: rejection packet
|
||||
std::cerr << "Warning: Character cannot be deleted" << std::endl;
|
||||
if (characterIndex < 0 && characterMgr.GetCharacter(characterIndex)->GetOwner() != argPacket->accountIndex) {
|
||||
//send the rejection packet
|
||||
TextPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_REJECTION;
|
||||
memset(newPacket.name, 0, PACKET_STRING_SIZE);
|
||||
strncpy(newPacket.text, "Character cannot be deleted", PACKET_STRING_SIZE);
|
||||
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
|
||||
|
||||
//unload an unneeded character
|
||||
if (characterIndex != -1) {
|
||||
@@ -223,8 +240,6 @@ void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket)
|
||||
|
||||
//make a new character if this one doesn't exist
|
||||
if (!character) {
|
||||
//this isn't normal
|
||||
std::cerr << "Warning: HandleCharacterUpdate() is passing to HandleCharacterNew()" << std::endl;
|
||||
HandleCharacterNew(argPacket);
|
||||
return;
|
||||
}
|
||||
@@ -257,7 +272,6 @@ void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) {
|
||||
newPacket.type = SerialPacketType::CHARACTER_UPDATE;
|
||||
|
||||
for (auto& it : *characterMgr.GetContainer()) {
|
||||
newPacket.characterIndex = it.first;
|
||||
CopyCharacterToPacket(&newPacket, it.first);
|
||||
network.SendTo(client.GetAddress(), static_cast<SerialPacket*>(&newPacket));
|
||||
}
|
||||
@@ -320,6 +334,7 @@ void ServerApplication::PumpPacket(SerialPacket* const argPacket) {
|
||||
|
||||
void ServerApplication::PumpCharacterUnload(int uid) {
|
||||
//delete the client-side character(s)
|
||||
//NOTE: This is a strange function
|
||||
CharacterPacket newPacket;
|
||||
newPacket.type = SerialPacketType::CHARACTER_DELETE;
|
||||
newPacket.characterIndex = uid;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
TODO: Rejection messages
|
||||
TODO: The error handling is terrible
|
||||
TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times
|
||||
TODO: Config switch for the debug output
|
||||
TODO: A better way of handling the disconnection message
|
||||
TODO: LobbyMenu::HandleJoinRejection()
|
||||
TODO: Get the rooms working, even if only via hotkeys
|
||||
TODO: Fix shoddy movement
|
||||
TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times
|
||||
|
||||
TODO: Remove the big "Shut Down" button
|
||||
TODO: Make a way for the server owner to control the server directly
|
||||
TODO: Move the map system into it's own namespace?
|
||||
TODO: The TileSheet class should implement the surface itself
|
||||
TODO: make the whole thing more fault tolerant
|
||||
|
||||
Reference in New Issue
Block a user