Merge branch 'develop', reviewed the managers' layout

This commit is contained in:
Kayne Ruse
2014-10-01 02:23:13 +10:00
11 changed files with 157 additions and 89 deletions
+6 -6
View File
@@ -33,22 +33,22 @@ using namespace std;
int main(int argc, char* argv[]) {
try {
//create the singletons
ConfigUtility::Create();
UDPNetworkUtility::Create();
ConfigUtility::CreateSingleton();
UDPNetworkUtility::CreateSingleton();
//call the server's routines
ClientApplication::Create();
ClientApplication::CreateSingleton();
ClientApplication& app = ClientApplication::GetSingleton();
app.Init(argc, argv);
app.Proc();
app.Quit();
ClientApplication::Delete();
ClientApplication::DeleteSingleton();
//delete the singletons
ConfigUtility::Delete();
UDPNetworkUtility::Delete();
ConfigUtility::DeleteSingleton();
UDPNetworkUtility::DeleteSingleton();
}
catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl;
+2 -2
View File
@@ -33,13 +33,13 @@ public:
}
return *ptr;
}
static void Create() {
static void CreateSingleton() {
if (ptr) {
throw(std::logic_error("This singleton has already been created"));
}
ptr = new T();
}
static void Delete() {
static void DeleteSingleton() {
if (!ptr) {
throw(std::logic_error("A non-existant singleton cannot be deleted"));
}
+46 -10
View File
@@ -31,12 +31,13 @@ static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM Accounts WHERE username = ?;";
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted = ?2, whitelisted = ?3, mod = ?4, admin = ?5 WHERE uid = ?1;";
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;";
//-------------------------
//Define the public methods
//-------------------------
int AccountManager::CreateAccount(std::string username, int clientIndex) {
int AccountManager::Create(std::string username, int clientIndex) {
//create this user account, failing if it exists, leave this account in memory
sqlite3_stmt* statement = nullptr;
@@ -60,10 +61,10 @@ int AccountManager::CreateAccount(std::string username, int clientIndex) {
sqlite3_finalize(statement);
//load this account into memory
return LoadAccount(username, clientIndex);
return Load(username, clientIndex);
}
int AccountManager::LoadAccount(std::string username, int clientIndex) {
int AccountManager::Load(std::string username, int clientIndex) {
//load this user account, failing if it is in memory, creating it if it doesn't exist
sqlite3_stmt* statement = nullptr;
@@ -109,13 +110,13 @@ int AccountManager::LoadAccount(std::string username, int clientIndex) {
if (ret == SQLITE_DONE) {
//create the non-existant account instead
return CreateAccount(username, clientIndex);
return Create(username, clientIndex);
}
throw(std::runtime_error(std::string() + "Unknown SQL error in LoadAccount: " + sqlite3_errmsg(database) ));
}
int AccountManager::SaveAccount(int uid) {
int AccountManager::Save(int uid) {
//save this user account from memory, replacing it if it exists in the database
//DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID.
@@ -158,14 +159,14 @@ int AccountManager::SaveAccount(int uid) {
return 0;
}
void AccountManager::UnloadAccount(int uid) {
void AccountManager::Unload(int uid) {
//save this user account, and then unload it
//NOTE: the associated characters are unloaded externally
SaveAccount(uid);
Save(uid);
accountMap.erase(uid);
}
void AccountManager::DeleteAccount(int uid) {
void AccountManager::Delete(int uid) {
//delete a user account from the database, and remove it from memory
//NOTE: the associated characters should be deleted externally
sqlite3_stmt* statement = nullptr;
@@ -194,16 +195,29 @@ void AccountManager::DeleteAccount(int uid) {
void AccountManager::UnloadAll() {
for (auto& it : accountMap) {
SaveAccount(it.first);
Save(it.first);
}
accountMap.clear();
}
void AccountManager::UnloadIf(std::function<bool(std::pair<int, AccountData>)> fn) {
//replicate std::remove_if, using custom code
for (std::map<int, AccountData>::iterator it = accountMap.begin(); it != accountMap.end(); /* empty */) {
if (fn(*it)) {
Save(it->first);
it = accountMap.erase(it);
continue;
}
++it;
}
}
//-------------------------
//Define the accessors and mutators
//-------------------------
AccountData* AccountManager::GetAccount(int uid) {
AccountData* AccountManager::Get(int uid) {
//TODO: could this load an account first?
std::map<int, AccountData>::iterator it = accountMap.find(uid);
if (it == accountMap.end()) {
@@ -213,6 +227,28 @@ AccountData* AccountManager::GetAccount(int uid) {
return &it->second;
}
int AccountManager::GetLoadedCount() {
return accountMap.size();
}
int AccountManager::GetTotalCount() {
//a lot just to count something.
sqlite3_stmt* statement = nullptr;
//prep
if (sqlite3_prepare_v2(database, COUNT_USER_ACCOUNT_RECORDS, -1, &statement, nullptr) != SQLITE_OK) {
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
}
//execute & retrieve the result
sqlite3_step(statement);
int ret = sqlite3_column_int(statement, 0);
//finish the routine
sqlite3_finalize(statement);
return ret;
}
std::map<int, AccountData>* AccountManager::GetContainer() {
return &accountMap;
}
+10 -6
View File
@@ -27,21 +27,25 @@
#include "sqlite3/sqlite3.h"
#include <functional>
#include <map>
class AccountManager : public Singleton<AccountManager> {
public:
//public access methods
int CreateAccount(std::string username, int clientIndex);
int LoadAccount(std::string username, int clientIndex);
int SaveAccount(int uid);
void UnloadAccount(int uid);
void DeleteAccount(int uid);
int Create(std::string username, int clientIndex);
int Load(std::string username, int clientIndex);
int Save(int uid);
void Unload(int uid);
void Delete(int uid);
void UnloadAll();
void UnloadIf(std::function<bool(std::pair<int, AccountData>)> fn);
//accessors and mutators
AccountData* GetAccount(int uid);
AccountData* Get(int uid);
int GetLoadedCount();
int GetTotalCount();
std::map<int, AccountData>* GetContainer();
sqlite3* SetDatabase(sqlite3* db);
+46 -22
View File
@@ -23,6 +23,7 @@
#include "sqlite3/sqlite3.h"
#include <algorithm>
#include <stdexcept>
//-------------------------
@@ -33,13 +34,14 @@ static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, av
static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;";
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET roomIndex = ?2, originX = ?3, originY = ?4 WHERE uid = ?1;";
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;";
//-------------------------
//Define the methods
//-------------------------
//NOTE: default baseStats as a parameter would be good for different beggining states or multiple classes
int CharacterManager::CreateCharacter(int owner, std::string handle, std::string avatar) {
int CharacterManager::Create(int owner, std::string handle, std::string avatar) {
//Create the character, failing if it exists
sqlite3_stmt* statement = nullptr;
@@ -69,10 +71,10 @@ int CharacterManager::CreateCharacter(int owner, std::string handle, std::string
sqlite3_finalize(statement);
//load this character into memory
return LoadCharacter(owner, handle, avatar);
return Load(owner, handle, avatar);
}
int CharacterManager::LoadCharacter(int owner, std::string handle, std::string avatar) {
int CharacterManager::Load(int owner, std::string handle, std::string avatar) {
//load the specified character, creating it if it doesn't exist
//fail if it is already loaded, or does not belong to this account
sqlite3_stmt* statement = nullptr;
@@ -132,13 +134,13 @@ int CharacterManager::LoadCharacter(int owner, std::string handle, std::string a
if (ret == SQLITE_DONE) {
//create the non-existant character instead
return CreateCharacter(owner, handle, avatar);
return Create(owner, handle, avatar);
}
throw(std::runtime_error(std::string() + "Unknown SQL error in LoadCharacter: " + sqlite3_errmsg(database) ));
}
int CharacterManager::SaveCharacter(int uid) {
int CharacterManager::Save(int uid) {
//save this character from memory, replacing it if it exists in the database
//DOCS: To use this method, change the in-memory copy, and then call this function using that object's UID.
@@ -182,13 +184,13 @@ int CharacterManager::SaveCharacter(int uid) {
return 0;
}
void CharacterManager::UnloadCharacter(int uid) {
void CharacterManager::Unload(int uid) {
//save this character, then unload it
SaveCharacter(uid);
Save(uid);
characterMap.erase(uid);
}
void CharacterManager::DeleteCharacter(int uid) {
void CharacterManager::Delete(int uid) {
//delete this character from the database, then remove it from memory
sqlite3_stmt* statement = nullptr;
@@ -214,30 +216,30 @@ void CharacterManager::DeleteCharacter(int uid) {
characterMap.erase(uid);
}
void CharacterManager::UnloadCharacterIf(std::function<bool(std::map<int, CharacterData>::iterator)> f) {
//save this character, then unload it if the parameter returns true
for (std::map<int, CharacterData>::iterator it = characterMap.begin(); it != characterMap.end(); /* EMPTY */ ) {
if (f(it)) {
SaveCharacter(it->first);
void CharacterManager::UnloadAll() {
for (auto& it : characterMap) {
Save(it.first);
}
characterMap.clear();
}
void CharacterManager::UnloadIf(std::function<bool(std::pair<int, CharacterData>)> fn) {
//replicate std::remove_if, using custom code
for (std::map<int, CharacterData>::iterator it = characterMap.begin(); it != characterMap.end(); /* empty */) {
if (fn(*it)) {
Save(it->first);
it = characterMap.erase(it);
continue;
}
it++;
++it;
}
}
void CharacterManager::UnloadAll() {
for (auto& it : characterMap) {
SaveCharacter(it.first);
}
characterMap.clear();
}
//-------------------------
//Define the accessors and mutators
//-------------------------
CharacterData* CharacterManager::GetCharacter(int uid) {
CharacterData* CharacterManager::Get(int uid) {
std::map<int, CharacterData>::iterator it = characterMap.find(uid);
if (it == characterMap.end()) {
@@ -247,6 +249,28 @@ CharacterData* CharacterManager::GetCharacter(int uid) {
return &it->second;
}
int CharacterManager::GetLoadedCount() {
return characterMap.size();
}
int CharacterManager::GetTotalCount() {
//a lot just to count something.
sqlite3_stmt* statement = nullptr;
//prep
if (sqlite3_prepare_v2(database, COUNT_CHARACTER_RECORDS, -1, &statement, nullptr) != SQLITE_OK) {
throw( std::runtime_error(std::string() + "Failed to prepare an SQL statement: " + sqlite3_errmsg(database)) );
}
//execute & retrieve the result
sqlite3_step(statement);
int ret = sqlite3_column_int(statement, 0);
//finish the routine
sqlite3_finalize(statement);
return ret;
}
std::map<int, CharacterData>* CharacterManager::GetContainer() {
return &characterMap;
}
+10 -9
View File
@@ -27,24 +27,25 @@
#include "sqlite3/sqlite3.h"
#include <map>
#include <functional>
#include <map>
class CharacterManager : public Singleton<CharacterManager> {
public:
//public access methods
int CreateCharacter(int owner, std::string handle, std::string avatar);
int LoadCharacter(int owner, std::string handle, std::string avatar);
int SaveCharacter(int uid);
void UnloadCharacter(int uid);
void DeleteCharacter(int uid);
void UnloadCharacterIf(std::function<bool(std::map<int, CharacterData>::iterator)> f);
int Create(int owner, std::string handle, std::string avatar);
int Load(int owner, std::string handle, std::string avatar);
int Save(int uid);
void Unload(int uid);
void Delete(int uid);
void UnloadAll();
void UnloadIf(std::function<bool(std::pair<int, CharacterData>)> fn);
//accessors and mutators
CharacterData* GetCharacter(int uid);
CharacterData* Get(int uid);
int GetLoadedCount();
int GetTotalCount();
std::map<int, CharacterData>* GetContainer();
sqlite3* SetDatabase(sqlite3* db);
+15 -12
View File
@@ -22,7 +22,10 @@
#include "server_application.hpp"
//singletons
#include "account_manager.hpp"
#include "character_manager.hpp"
#include "config_utility.hpp"
#include "room_manager.hpp"
#include "udp_network_utility.hpp"
#include <stdexcept>
@@ -33,28 +36,28 @@ using namespace std;
int main(int argc, char* argv[]) {
try {
//create the singletons
AccountManager::Create();
CharacterManager::Create();
ConfigUtility::Create();
RoomManager::Create();
UDPNetworkUtility::Create();
AccountManager::CreateSingleton();
CharacterManager::CreateSingleton();
ConfigUtility::CreateSingleton();
RoomManager::CreateSingleton();
UDPNetworkUtility::CreateSingleton();
//call the server's routines
ServerApplication::Create();
ServerApplication::CreateSingleton();
ServerApplication& app = ServerApplication::GetSingleton();
app.Init(argc, argv);
app.Proc();
app.Quit();
ServerApplication::Delete();
ServerApplication::DeleteSingleton();
//delete the singletons
AccountManager::Delete();
CharacterManager::Delete();
ConfigUtility::Delete();
RoomManager::Delete();
UDPNetworkUtility::Delete();
AccountManager::DeleteSingleton();
CharacterManager::DeleteSingleton();
ConfigUtility::DeleteSingleton();
RoomManager::DeleteSingleton();
UDPNetworkUtility::DeleteSingleton();
}
catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl;
+1 -1
View File
@@ -22,7 +22,7 @@
#include "server_application.hpp"
//utility functions
#include "sql_utility.hpp"
#include "sql_tools.hpp"
#include "utility.hpp"
#include <stdexcept>
+20 -20
View File
@@ -52,7 +52,7 @@ void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) {
newPacket.type = SerialPacketType::BROADCAST_RESPONSE;
strncpy(newPacket.name, config["server.name"].c_str(), PACKET_STRING_SIZE);
newPacket.playerCount = characterMgr.GetContainer()->size();
newPacket.playerCount = characterMgr.GetLoadedCount();
newPacket.version = NETWORK_VERSION;
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
@@ -61,7 +61,7 @@ void ServerApplication::HandleBroadcastRequest(ServerPacket* const argPacket) {
void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
//load the user account
//TODO: handle passwords
int accountIndex = accountMgr.LoadAccount(argPacket->username, clientIndex);
int accountIndex = accountMgr.Load(argPacket->username, clientIndex);
//Cannot load
if (accountIndex < 0) {
@@ -88,7 +88,7 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
clientMap[clientIndex++] = newClient;
//finished this routine
std::cout << "New connection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl;
std::cout << "New connection, " << clientMap.size() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) {
@@ -105,26 +105,26 @@ void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) {
//forward to the specified client
network.SendTo(
clientMap[ accountMgr.GetAccount(argPacket->accountIndex)->GetClientIndex() ].GetAddress(),
clientMap[ accountMgr.Get(argPacket->accountIndex)->GetClientIndex() ].GetAddress(),
static_cast<SerialPacket*>(argPacket)
);
//save and unload this account's characters
characterMgr.UnloadCharacterIf([&](std::map<int, CharacterData>::iterator it) -> bool {
if (argPacket->accountIndex == it->second.GetOwner()) {
characterMgr.UnloadIf([&](std::pair<int, CharacterData> it) -> bool {
if (argPacket->accountIndex == it.second.GetOwner()) {
//pump the unload message to all remaining clients
PumpCharacterUnload(it->first);
PumpCharacterUnload(it.first);
return true;
}
return false;
});
//erase the in-memory stuff
clientMap.erase(accountMgr.GetAccount(argPacket->accountIndex)->GetClientIndex());
accountMgr.UnloadAccount(argPacket->accountIndex);
clientMap.erase(accountMgr.Get(argPacket->accountIndex)->GetClientIndex());
accountMgr.Unload(argPacket->accountIndex);
//finished this routine
std::cout << "Disconnection, " << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl;
std::cout << "Disconnection, " << clientMap.size() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
void ServerApplication::HandleShutdown(ClientPacket* const argPacket) {
@@ -173,7 +173,7 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) {
void ServerApplication::HandleCharacterNew(CharacterPacket* const argPacket) {
//NOTE: misnomer, try to load the character first
int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
int characterIndex = characterMgr.Load(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
//cannot load or create
if (characterIndex < 0) {
@@ -207,10 +207,10 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket)
//NOTE: Disconnecting only unloads a character, this explicitly deletes it
//Authenticate the owner is doing this
int characterIndex = characterMgr.LoadCharacter(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
int characterIndex = characterMgr.Load(argPacket->accountIndex, argPacket->handle, argPacket->avatar);
//if this is not your character
if (characterIndex < 0 && characterMgr.GetCharacter(characterIndex)->GetOwner() != argPacket->accountIndex) {
if (characterIndex < 0 && characterMgr.Get(characterIndex)->GetOwner() != argPacket->accountIndex) {
//send the rejection packet
TextPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_REJECTION;
@@ -220,13 +220,13 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket)
//unload an unneeded character
if (characterIndex != -1) {
characterMgr.UnloadCharacter(characterIndex);
characterMgr.Unload(characterIndex);
}
return;
}
//delete it
characterMgr.DeleteCharacter(characterIndex);
characterMgr.Delete(characterIndex);
//TODO: success packet
@@ -235,7 +235,7 @@ void ServerApplication::HandleCharacterDelete(CharacterPacket* const argPacket)
}
void ServerApplication::HandleCharacterUpdate(CharacterPacket* const argPacket) {
CharacterData* character = characterMgr.GetCharacter(argPacket->characterIndex);
CharacterData* character = characterMgr.Get(argPacket->characterIndex);
//make a new character if this one doesn't exist
if (!character) {
@@ -327,8 +327,8 @@ void ServerApplication::CleanupLostConnection(int clientIndex) {
network.SendTo(clientMap[clientIndex].GetAddress(), &newPacket);
//clean up this mess
characterMgr.UnloadCharacter(characterIndex);
accountMgr.UnloadAccount(accountIndex);
characterMgr.Unload(characterIndex);
accountMgr.Unload(accountIndex);
clientMap.erase(clientIndex);
PumpCharacterUnload(characterIndex);
@@ -338,7 +338,7 @@ void ServerApplication::CleanupLostConnection(int clientIndex) {
std::cerr << "\tClient: " << clientIndex << std::endl;
std::cerr << "\tAccount: " << accountIndex << std::endl;
std::cerr << "\tCharacter: " << characterIndex << std::endl;
std::cout << clientMap.size() << " clients and " << accountMgr.GetContainer()->size() << " accounts total" << std::endl;
std::cout << clientMap.size() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
}
//TODO: a function that only sends to characters in a certain proximity
@@ -359,7 +359,7 @@ void ServerApplication::PumpCharacterUnload(int uid) {
}
void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
CharacterData* character = characterMgr.GetCharacter(characterIndex);
CharacterData* character = characterMgr.Get(characterIndex);
if (!character) {
throw(std::runtime_error("Failed to copy a character to a packet"));
}
@@ -19,7 +19,7 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "sql_utility.hpp"
#include "sql_tools.hpp"
#include "utility.hpp"