aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-10-09 21:36:58 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-10-09 21:36:58 -0300
commitddcba8ef56fe122a77e890a2740489045e3dc6a0 (patch)
tree20df9dfe70d0cda1a19a337c4ecd2269fd5efe9a
parent3faece41a82befa36a7a454a2a3c2b470ed82f55 (diff)
downloadquerymanager-ddcba8ef56fe122a77e890a2740489045e3dc6a0.tar.gz
querymanager-ddcba8ef56fe122a77e890a2740489045e3dc6a0.zip
update query functions
-rw-r--r--src/query.cc2071
-rw-r--r--src/querymanager.hh82
2 files changed, 724 insertions, 1429 deletions
diff --git a/src/query.cc b/src/query.cc
index c55806d..f03a1db 100644
--- a/src/query.cc
+++ b/src/query.cc
@@ -32,7 +32,7 @@ static TQueryQueue *g_QueryQueue;
// Query Name
//==============================================================================
const char *QueryName(int QueryType){
- const char *Name = "UNKNOWN";
+ const char *Name = "";
switch(QueryType){
case QUERY_LOGIN: Name = "LOGIN"; break;
case QUERY_INTERNAL_RESOLVE_WORLD: Name = "INTERNAL_RESOLVE_WORLD"; break;
@@ -185,13 +185,12 @@ static void *WorkerThread(void *Data){
LOG("Worker#%d: ACTIVE...", Worker->WorkerID);
AtomicStore(&Worker->Status, WORKER_STATUS_ACTIVE);
while(TQuery *Query = QueryDequeue(&Worker->Stop)){
- bool (*ProcessQuery)(TDatabase*, TQuery*) = NULL;
+ void (*ProcessQuery)(TDatabase*, TQuery*) = NULL;
Query->QueryType = Query->Request.Read8();
switch(Query->QueryType){
case QUERY_INTERNAL_RESOLVE_WORLD: ProcessQuery = ProcessInternalResolveWorld; break;
-/* case QUERY_CHECK_ACCOUNT_PASSWORD: ProcessQuery = ProcessCheckAccountPassword; break;
+ case QUERY_CHECK_ACCOUNT_PASSWORD: ProcessQuery = ProcessCheckAccountPassword; break;
case QUERY_LOGIN_ACCOUNT: ProcessQuery = ProcessLoginAccount; break;
- case QUERY_LOGIN_ADMIN: ProcessQuery = ProcessLoginAdmin; break;
case QUERY_LOGIN_GAME: ProcessQuery = ProcessLoginGame; break;
case QUERY_LOGOUT_GAME: ProcessQuery = ProcessLogoutGame; break;
case QUERY_SET_NAMELOCK: ProcessQuery = ProcessSetNamelock; break;
@@ -229,17 +228,20 @@ static void *WorkerThread(void *Data){
case QUERY_GET_WORLDS: ProcessQuery = ProcessGetWorlds; break;
case QUERY_GET_ONLINE_CHARACTERS: ProcessQuery = ProcessGetOnlineCharacters; break;
case QUERY_GET_KILL_STATISTICS: ProcessQuery = ProcessGetKillStatistics; break;
-*/
}
+ Query->QueryStatus = QUERY_STATUS_PENDING;
if(ProcessQuery != NULL && DatabaseCheckpoint(Database)){
// NOTE(fusion): A minimum of 1 attempt is ASSUMED.
int Attempts = g_Config.QueryMaxAttempts;
- while(!ProcessQuery(Database, Query)){
- if(Attempts <= 0 || !DatabaseCheckpoint(Database)){
- QueryFailed(Query);
+ while(true){
+ ProcessQuery(Database, Query);
+ if(Query->QueryStatus != QUERY_STATUS_PENDING
+ || Attempts <= 0
+ || !DatabaseCheckpoint(Database)){
break;
}
+
Attempts -= 1;
// NOTE(fusion): This one is important because we want to know
@@ -248,7 +250,9 @@ static void *WorkerThread(void *Data){
LOG_WARN("Worker#%d: Query %s failed, retrying...",
Worker->WorkerID, QueryName(Query->QueryType));
}
- }else{
+ }
+
+ if(Query->QueryStatus == QUERY_STATUS_PENDING){
QueryFailed(Query);
}
@@ -398,6 +402,7 @@ bool QueryInternalResolveWorld(TQuery *Query, const char *World){
// Query Response
//==============================================================================
TWriteBuffer *QueryBeginResponse(TQuery *Query, int Status){
+ ASSERT(Status != QUERY_STATUS_PENDING);
Query->QueryStatus = Status;
Query->Response = TWriteBuffer(Query->Buffer, Query->BufferSize);
Query->Response.Write16(0);
@@ -439,130 +444,9 @@ void QueryFailed(TQuery *Query){
QueryFinishResponse(Query);
}
-// Query Processing
-//==============================================================================
-// IMPORTANT(fusion): Query functions will return TRUE when they executed normally,
-// and FALSE when they were interrupted by some unexpected error such as a database
-// failure. The query response should only be written at the very end, when we know
-// it has SUCCEEDED, so that request data is kept intact (because they share the
-// query buffer) if the caller decides to retry the operation.
-
-// NOTE(fusion): These should be used with query functions to reduce clutter.
-#define QUERY_STOP_IF(Cond) \
- do{ \
- if(Cond){ \
- return false; \
- } \
- }while(0)
-
-#define QUERY_ERROR_IF(Cond, ErrorCode) \
- do{ \
- if(Cond){ \
- QueryError(Query, ErrorCode); \
- return true; \
- } \
- }while(0)
-
-#define QUERY_FAIL_IF(Cond) \
- do{ \
- if(Cond){ \
- QueryFailed(Query); \
- return true; \
- } \
- }while(0)
-
-bool ProcessInternalResolveWorld(TDatabase *Database, TQuery *Query){
- char World[30];
- TReadBuffer Request = Query->Request;
- Request.ReadString(World, sizeof(World));
-
- int WorldID;
- QUERY_STOP_IF(!GetWorldID(Database, World, &WorldID));
- QUERY_FAIL_IF(WorldID <= 0);
-
- Query->WorldID = WorldID;
- QueryOk(Query);
- return true;
-}
-
-bool ProcessCheckAccountPassword(TDatabase *Database, TQuery *Query);
-bool ProcessLoginAccount(TDatabase *Database, TQuery *Query);
-bool ProcessLoginAdmin(TDatabase *Database, TQuery *Query);
-bool ProcessLoginGame(TDatabase *Database, TQuery *Query);
-bool ProcessLogoutGame(TDatabase *Database, TQuery *Query);
-bool ProcessSetNamelock(TDatabase *Database, TQuery *Query);
-bool ProcessBanishAccount(TDatabase *Database, TQuery *Query);
-bool ProcessSetNotation(TDatabase *Database, TQuery *Query);
-bool ProcessReportStatement(TDatabase *Database, TQuery *Query);
-bool ProcessBanishIpAddress(TDatabase *Database, TQuery *Query);
-bool ProcessLogCharacterDeath(TDatabase *Database, TQuery *Query);
-bool ProcessAddBuddy(TDatabase *Database, TQuery *Query);
-bool ProcessRemoveBuddy(TDatabase *Database, TQuery *Query);
-bool ProcessDecrementIsOnline(TDatabase *Database, TQuery *Query);
-bool ProcessFinishAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessTransferHouses(TDatabase *Database, TQuery *Query);
-bool ProcessEvictFreeAccounts(TDatabase *Database, TQuery *Query);
-bool ProcessEvictDeletedCharacters(TDatabase *Database, TQuery *Query);
-bool ProcessEvictExGuildleaders(TDatabase *Database, TQuery *Query);
-bool ProcessInsertHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessUpdateHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessDeleteHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessGetHouseOwners(TDatabase *Database, TQuery *Query);
-bool ProcessGetAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessStartAuction(TDatabase *Database, TQuery *Query);
-bool ProcessInsertHouses(TDatabase *Database, TQuery *Query);
-bool ProcessClearIsOnline(TDatabase *Database, TQuery *Query);
-bool ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query);
-bool ProcessLogKilledCreatures(TDatabase *Database, TQuery *Query);
-bool ProcessLoadPlayers(TDatabase *Database, TQuery *Query);
-bool ProcessExcludeFromAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessCancelHouseTransfer(TDatabase *Database, TQuery *Query);
-bool ProcessLoadWorldConfig(TDatabase *Database, TQuery *Query);
-bool ProcessCreateAccount(TDatabase *Database, TQuery *Query);
-bool ProcessCreateCharacter(TDatabase *Database, TQuery *Query);
-bool ProcessGetAccountSummary(TDatabase *Database, TQuery *Query);
-bool ProcessGetCharacterProfile(TDatabase *Database, TQuery *Query);
-bool ProcessGetWorlds(TDatabase *Database, TQuery *Query);
-bool ProcessGetOnlineCharacters(TDatabase *Database, TQuery *Query);
-bool ProcessGetKillStatistics(TDatabase *Database, TQuery *Query);
-
-
-// TODO(fusion): These are the old query processing functions. The new ones will
-// be very similar, except that we want a way to tell whether there was a database
-// failure, such as a connection reset, so we can automatically retry them up to
-// a certain amount of times before failing.
-// bool ProcessX(Database, Query){
-// // Execute database queries, returning false on failure. The
-// // response should only be written at the very end when we know
-// // the query SUCCEEDED, to keep the request data intact if a retry
-// // is needed (because they share the query buffer).
-// }
-//
-// ...
-//
-// void DatabaseCheckpoint(Database){
-// // Check whether there was a database error or if the database is
-// // still connected and make sure it is ready for processing a query.
-// }
-//
-// ...
-//
-// int NumAttempts = MaxAttempts;
-// DatabaseCheckpoint(Database);
-// while(!ProcessX(Database, Query)){
-// if(Attempts <= 0){
-// QueryFailed(Query);
-// break;
-// }
-// DatabaseCheckpoint(Database);
-// NumAttempts -= 1;
-// }
-
-
-#if 0
-// Connection Queries
+// Query Helpers
//==============================================================================
-void CompoundBanishment(TBanishmentStatus Status, int *Days, bool *FinalWarning){
+static void CompoundBanishment(TBanishmentStatus Status, int *Days, bool *FinalWarning){
// TODO(fusion): We might want to add all these constants as config values.
ASSERT(Days != NULL && FinalWarning != NULL);
if(Status.FinalWarning){
@@ -578,666 +462,480 @@ void CompoundBanishment(TBanishmentStatus Status, int *Days, bool *FinalWarning)
}
}
+// Query Processing
+//==============================================================================
+// IMPORTANT(fusion): Query processing functions are expected to signal their status
+// by updating `Query->QueryStatus`. A query that is still `PENDING` at the end of
+// processing is considered unfinished and may be retried.
+// The query response should only be written at the very end, when we know it has
+// SUCCEEDED, so that request data is kept intact (because they share the same query
+// buffer) if the caller decides to retry it.
+// Since using `QueryBeginResponse` automatically sets `Query->QueryStatus`, it
+// should be unlikely that the request data is modified while keeping a `PENDING`
+// status.
-void ProcessLoginQuery(TConnection *Connection, TReadBuffer *Buffer){
- char Password[30];
- char LoginData[30];
- int ApplicationType = Buffer->Read8();
- Buffer->ReadString(Password, sizeof(Password));
- if(ApplicationType == APPLICATION_TYPE_GAME){
- Buffer->ReadString(LoginData, sizeof(LoginData));
- }
-
- // TODO(fusion): Probably just disconnect on failed login attempt? Implement
- // write then disconnect?
- if(!StringEq(g_QueryManagerPassword, Password)){
- LOG_WARN("Invalid login attempt from %s", Connection->RemoteAddress);
- SendQueryStatusFailed(Connection);
- return;
- }
+// NOTE(fusion): These should be used with query functions to reduce clutter.
+#define QUERY_STOP_IF(Cond) \
+ do{ \
+ if(Cond){ \
+ Query->QueryStatus = QUERY_STATUS_PENDING; \
+ return; \
+ } \
+ }while(0)
- int WorldID = 0;
- if(ApplicationType == APPLICATION_TYPE_GAME){
- WorldID = GetWorldID(LoginData);
- if(WorldID == 0){
- LOG_WARN("Rejecting connection %s from unknown game server \"%s\"",
- Connection->RemoteAddress, LoginData);
- SendQueryStatusFailed(Connection);
- return;
- }
- LOG("Connection %s AUTHORIZED to game server \"%s\" (%d)",
- Connection->RemoteAddress, LoginData, WorldID);
- }else if(ApplicationType == APPLICATION_TYPE_LOGIN){
- LOG("Connection %s AUTHORIZED to login server", Connection->RemoteAddress);
- }else if(ApplicationType == APPLICATION_TYPE_WEB){
- LOG("Connection %s AUTHORIZED to web server", Connection->RemoteAddress);
- }else{
- LOG_WARN("Rejecting connection %s from unknown application type %d",
- Connection->RemoteAddress, ApplicationType);
- SendQueryStatusFailed(Connection);
- return;
- }
+#define QUERY_ERROR_IF(Cond, ErrorCode) \
+ do{ \
+ if(Cond){ \
+ QueryError(Query, ErrorCode); \
+ return; \
+ } \
+ }while(0)
- Connection->Authorized = true;
- Connection->ApplicationType = ApplicationType;
- Connection->WorldID = WorldID;
- SendQueryStatusOk(Connection);
-}
+#define QUERY_FAIL_IF(Cond) \
+ do{ \
+ if(Cond){ \
+ QueryFailed(Query); \
+ return; \
+ } \
+ }while(0)
-static int CheckAccountPasswordTransaction(int AccountID, const char *Password, int IPAddress){
- TransactionScope Tx("CheckAccountPassword");
- if(!Tx.Begin()){
- return -1;
- }
+void ProcessInternalResolveWorld(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
- TAccount Account;
- if(!GetAccountData(AccountID, &Account)){
- return -1;
- }
+ char World[30];
+ Request.ReadString(World, sizeof(World));
- if(Account.AccountID == 0){
- return 1;
- }
+ int WorldID;
+ QUERY_STOP_IF(!GetWorldID(Database, World, &WorldID));
+ QUERY_FAIL_IF(WorldID <= 0);
- if(!TestPassword(Account.Auth, sizeof(Account.Auth), Password)){
- return 2;
- }
+ Query->WorldID = WorldID;
+ QueryOk(Query);
+}
- if(GetAccountFailedLoginAttempts(Account.AccountID, 5 * 60) > 10){
- return 3;
- }
+static void CheckAccountPasswordTx(TDatabase *Database, TQuery *Query,
+ int AccountID, const char *Password, int IPAddress){
+ TransactionScope Tx("CheckAccountPassword");
+ QUERY_STOP_IF(!Tx.Begin(Database));
- if(GetIPAddressFailedLoginAttempts(IPAddress, 30 * 60) > 20){
- return 4;
- }
+ TAccount Account;
+ QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
+ QUERY_ERROR_IF(Account.AccountID == 0, 1);
+ QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
- if(!Tx.Commit()){
- return -1;
- }
+ int FailedLoginAttempts;
+ QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
+ QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
- return 0;
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessCheckAccountPasswordQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessCheckAccountPassword(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+
char Password[30];
char IPString[16];
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(Password, sizeof(Password));
- Buffer->ReadString(IPString, sizeof(IPString));
+ int AccountID = (int)Request.Read32();
+ Request.ReadString(Password, sizeof(Password));
+ Request.ReadString(IPString, sizeof(IPString));
int IPAddress = 0;
- if(!ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(!ParseIPAddress(IPString, &IPAddress));
- // NOTE(fusion): Similar to `ProcessLoginAccountQuery`.
- int Result = CheckAccountPasswordTransaction(AccountID, Password, IPAddress);
- InsertLoginAttempt(AccountID, IPAddress, (Result != 0));
- if(Result == -1){
- SendQueryStatusFailed(Connection);
- }else if(Result != 0){
- SendQueryStatusError(Connection, Result);
- }else{
- SendQueryStatusOk(Connection);
+ // NOTE(fusion): Same as `ProcessLoginGame`.
+ CheckAccountPasswordTx(Database, Query, AccountID, Password, IPAddress);
+ if(Query->QueryStatus != QUERY_STATUS_PENDING){
+ InsertLoginAttempt(Database, AccountID, IPAddress,
+ (Query->QueryStatus != QUERY_STATUS_OK));
}
}
-int LoginAccountTransaction(int AccountID, const char *Password, int IPAddress,
- DynamicArray<TCharacterEndpoint> *Characters, int *PremiumDays){
+static void LoginAccountTx(TDatabase *Database, TQuery *Query,
+ int AccountID, const char *Password, int IPAddress){
TransactionScope Tx("LoginAccount");
- if(!Tx.Begin()){
- return -1;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
TAccount Account;
- if(!GetAccountData(AccountID, &Account)){
- return -1;
- }
+ QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
+ QUERY_ERROR_IF(Account.AccountID == 0, 1);
+ QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
+
+ int FailedLoginAttempts;
+ QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
+ QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
+
+ bool IsBanished;
+ QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
+ QUERY_ERROR_IF(IsBanished, 5);
+ QUERY_STOP_IF(!IsIPBanished(Database, IPAddress, &IsBanished));
+ QUERY_ERROR_IF(IsBanished, 6);
- if(Account.AccountID == 0){
- return 1;
- }
-
- if(!TestPassword(Account.Auth, sizeof(Account.Auth), Password)){
- return 2;
- }
-
- if(GetAccountFailedLoginAttempts(Account.AccountID, 5 * 60) > 10){
- return 3;
- }
-
- if(GetIPAddressFailedLoginAttempts(IPAddress, 30 * 60) > 20){
- return 4;
- }
-
- if(IsAccountBanished(Account.AccountID)){
- return 5;
- }
-
- if(IsIPBanished(IPAddress)){
- return 6;
- }
-
- if(!GetCharacterEndpoints(Account.AccountID, Characters)){
- return -1;
- }
+ DynamicArray<TCharacterEndpoint> Characters;
+ QUERY_STOP_IF(!GetCharacterEndpoints(Database, Account.AccountID, &Characters));
+ QUERY_STOP_IF(!Tx.Commit());
- if(!Tx.Commit()){
- return -1;
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ int NumCharacters = std::min<int>(Characters.Length(), UINT8_MAX);
+ Response->Write8((uint8)NumCharacters);
+ for(int i = 0; i < NumCharacters; i += 1){
+ Response->WriteString(Characters[i].Name);
+ Response->WriteString(Characters[i].WorldName);
+ Response->Write32BE((uint32)Characters[i].WorldAddress);
+ Response->Write16((uint16)Characters[i].WorldPort);
}
-
- *PremiumDays = Account.PremiumDays + Account.PendingPremiumDays;
- return 0;
+ Response->Write16((uint16)(Account.PremiumDays + Account.PendingPremiumDays));
+ QueryFinishResponse(Query);
}
-void ProcessLoginAccountQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessLoginAccount(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+
char Password[30];
char IPString[16];
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(Password, sizeof(Password));
- Buffer->ReadString(IPString, sizeof(IPString));
+ int AccountID = (int)Request.Read32();
+ Request.ReadString(Password, sizeof(Password));
+ Request.ReadString(IPString, sizeof(IPString));
int IPAddress = 0;
- if(!ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int PremiumDays = 0;
- DynamicArray<TCharacterEndpoint> Characters;
- int Result = LoginAccountTransaction(AccountID, Password,
- IPAddress, &Characters, &PremiumDays);
-
- // NOTE(fusion): Similar to `ProcessLoginGameQuery` except we don't modify
- // any tables inside the login transaction.
- // TODO(fusion): Maybe have different login attempt tables or types?
- InsertLoginAttempt(AccountID, IPAddress, (Result != 0));
-
- if(Result == -1){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(!ParseIPAddress(IPString, &IPAddress));
- if(Result != 0){
- SendQueryStatusError(Connection, Result);
- return;
+ // NOTE(fusion): Same as `ProcessLoginGame`.
+ LoginAccountTx(Database, Query, AccountID, Password, IPAddress);
+ if(Query->QueryStatus != QUERY_STATUS_PENDING){
+ InsertLoginAttempt(Database, AccountID, IPAddress,
+ (Query->QueryStatus != QUERY_STATUS_OK));
}
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- int NumCharacters = std::min<int>(Characters.Length(), UINT8_MAX);
- WriteBuffer.Write8((uint8)NumCharacters);
- for(int i = 0; i < NumCharacters; i += 1){
- WriteBuffer.WriteString(Characters[i].Name);
- WriteBuffer.WriteString(Characters[i].WorldName);
- WriteBuffer.Write32BE((uint32)Characters[i].WorldAddress);
- WriteBuffer.Write16((uint16)Characters[i].WorldPort);
- }
- WriteBuffer.Write16((uint16)PremiumDays);
- SendResponse(Connection, &WriteBuffer);
-}
-
-void ProcessLoginAdminQuery(TConnection *Connection, TReadBuffer *Buffer){
- // TODO(fusion): I thought for a second this could be the query used with
- // the login server but it doesn't take a password or ip address for basic
- // checks. Even if it's used in combination with `CheckAccountPassword`,
- // it doesn't make sense to split what should have been a single query which
- // is what the new `LoginAccount` query does.
- SendQueryStatusFailed(Connection);
}
-static int LoginGameTransaction(int WorldID, int AccountID, const char *CharacterName,
- const char *Password, int IPAddress, bool PrivateWorld, bool GamemasterRequired,
- TCharacterLoginData *Character, DynamicArray<TAccountBuddy> *Buddies,
- DynamicArray<TCharacterRight> *Rights, bool *PremiumAccountActivated){
+static void LoginGameTx(TDatabase *Database, TQuery *Query,
+ int AccountID, const char *CharacterName, const char *Password,
+ int IPAddress, bool PrivateWorld, bool GamemasterRequired){
TransactionScope Tx("LoginGame");
- if(!Tx.Begin()){
- return -1;
- }
-
- if(!GetCharacterLoginData(CharacterName, Character)){
- return -1;
- }
-
- if(Character->CharacterID == 0){
- return 1;
- }
-
- if(Character->Deleted){
- return 2;
- }
-
- if(Character->WorldID != WorldID){
- return 3;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
+ TCharacterLoginData Character;
+ QUERY_STOP_IF(!GetCharacterLoginData(Database, CharacterName, &Character));
+ QUERY_ERROR_IF(Character.CharacterID == 0, 1);
+ QUERY_ERROR_IF(Character.Deleted, 2);
+ QUERY_ERROR_IF(Character.WorldID != Query->WorldID, 3);
if(PrivateWorld){
- if(!GetWorldInvitation(WorldID, Character->CharacterID)){
- return 4;
- }
+ bool Invited;
+ QUERY_STOP_IF(!GetWorldInvitation(Database, Query->WorldID, Character.CharacterID, &Invited));
+ QUERY_ERROR_IF(!Invited, 4);
}
TAccount Account;
- if(!GetAccountData(AccountID, &Account)){
- return -1;
- }
-
- if(Account.AccountID == 0 || Account.AccountID != Character->AccountID){
- // NOTE(fusion): This is correct, there is no error code 5.
- return 15;
- }
-
- if(Account.Deleted){
- return 8;
- }
-
- if(!TestPassword(Account.Auth, sizeof(Account.Auth), Password)){
- return 6;
- }
-
- if(GetAccountFailedLoginAttempts(Account.AccountID, 5 * 60) > 10){
- return 7;
- }
-
- if(GetIPAddressFailedLoginAttempts(IPAddress, 30 * 60) > 20){
- return 9;
- }
-
- if(IsAccountBanished(Account.AccountID)){
- return 10;
- }
-
- if(IsCharacterNamelocked(Character->CharacterID)){
- return 11;
- }
-
- if(IsIPBanished(IPAddress)){
- return 12;
- }
+ QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
+ // NOTE(fusion): This is correct, there is no error code 5.
+ QUERY_ERROR_IF(Account.AccountID == 0 || Account.AccountID != Character.AccountID, 15);
+ QUERY_ERROR_IF(Account.Deleted, 8);
+ QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 6);
+
+ int FailedLoginAttempts;
+ QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 10, 7);
+ QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
+ QUERY_ERROR_IF(FailedLoginAttempts > 20, 9);
+
+ bool IsBanished;
+ QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
+ QUERY_ERROR_IF(IsBanished, 10);
+ QUERY_STOP_IF(!IsCharacterNamelocked(Database, Character.CharacterID, &IsBanished));
+ QUERY_ERROR_IF(IsBanished, 11);
+ QUERY_STOP_IF(!IsIPBanished(Database, IPAddress, &IsBanished));
+ QUERY_ERROR_IF(IsBanished, 12);
// TODO(fusion): Probably merge these into a single operation?
- if(!GetCharacterRight(Character->CharacterID, "ALLOW_MULTICLIENT")
- && GetAccountOnlineCharacters(Account.AccountID) > 0
- && !IsCharacterOnline(Character->CharacterID)){
- return 13;
+ bool MultiClient;
+ QUERY_STOP_IF(!GetCharacterRight(Database, Character.CharacterID, "ALLOW_MULTICLIENT", &MultiClient));
+ if(!MultiClient){
+ int OnlineCharacters;
+ QUERY_STOP_IF(!GetAccountOnlineCharacters(Database, Account.AccountID, &OnlineCharacters));
+ if(OnlineCharacters > 0){
+ bool IsOnline;
+ QUERY_STOP_IF(!IsCharacterOnline(Database, Character.CharacterID, &IsOnline));
+ QUERY_ERROR_IF(!IsOnline, 13);
+ }
}
if(GamemasterRequired){
- if(!GetCharacterRight(Character->CharacterID, "GAMEMASTER_OUTFIT")){
- return 14;
- }
+ bool GamemasterOutfit;
+ QUERY_STOP_IF(!GetCharacterRight(Database, Character.CharacterID, "GAMEMASTER_OUTFIT", &GamemasterOutfit));
+ QUERY_ERROR_IF(!GamemasterOutfit, 14);
}
- if(!GetBuddies(WorldID, Account.AccountID, Buddies)){
- return -1;
- }
+ DynamicArray<TAccountBuddy> Buddies;
+ QUERY_STOP_IF(!GetBuddies(Database, Query->WorldID, Account.AccountID, &Buddies));
- if(!GetCharacterRights(Character->CharacterID, Rights)){
- return -1;
- }
+ DynamicArray<TCharacterRight> Rights;
+ QUERY_STOP_IF(!GetCharacterRights(Database, Character.CharacterID, &Rights));
+ bool PremiumAccountActivated = false;
if(Account.PremiumDays == 0 && Account.PendingPremiumDays > 0){
- if(!ActivatePendingPremiumDays(Account.AccountID)){
- return -1;
- }
-
+ QUERY_STOP_IF(!ActivatePendingPremiumDays(Database, Account.AccountID));
Account.PremiumDays += Account.PendingPremiumDays;
Account.PendingPremiumDays = 0;
- *PremiumAccountActivated = true;
+ PremiumAccountActivated = true;
}
if(Account.PremiumDays > 0){
- Rights->Push(TCharacterRight{"PREMIUM_ACCOUNT"});
+ Rights.Push(TCharacterRight{"PREMIUM_ACCOUNT"});
}
- if(!IncrementIsOnline(WorldID, Character->CharacterID)){
- return -1;
+ QUERY_STOP_IF(!IncrementIsOnline(Database, Query->WorldID, Character.CharacterID));
+ QUERY_STOP_IF(!Tx.Commit());
+
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write32((uint32)Character.CharacterID);
+ Response->WriteString(Character.Name);
+ Response->Write8((uint8)Character.Sex);
+ Response->WriteString(Character.Guild);
+ Response->WriteString(Character.Rank);
+ Response->WriteString(Character.Title);
+
+ int NumBuddies = std::min<int>(Buddies.Length(), UINT8_MAX);
+ Response->Write8((uint8)NumBuddies);
+ for(int i = 0; i < NumBuddies; i += 1){
+ Response->Write32((uint32)Buddies[i].CharacterID);
+ Response->WriteString(Buddies[i].Name);
}
- if(!Tx.Commit()){
- return -1;
+ int NumRights = std::min<int>(Rights.Length(), UINT8_MAX);
+ Response->Write8((uint8)NumRights);
+ for(int i = 0; i < NumRights; i += 1){
+ Response->WriteString(Rights[i].Name);
}
- return 0;
+ Response->WriteFlag(PremiumAccountActivated);
+ QueryFinishResponse(Query);
}
-void ProcessLoginGameQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessLoginGame(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char Password[30];
char IPString[16];
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(Password, sizeof(Password));
- Buffer->ReadString(IPString, sizeof(IPString));
- bool PrivateWorld = Buffer->ReadFlag();
- Buffer->ReadFlag(); // "PremiumAccountRequired" unused
- bool GamemasterRequired = Buffer->ReadFlag();
+ int AccountID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(Password, sizeof(Password));
+ Request.ReadString(IPString, sizeof(IPString));
+ bool PrivateWorld = Request.ReadFlag();
+ Request.ReadFlag(); // "PremiumAccountRequired" unused
+ bool GamemasterRequired = Request.ReadFlag();
- int IPAddress = 0;
- if(!ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- TCharacterLoginData Character;
- DynamicArray<TAccountBuddy> Buddies;
- DynamicArray<TCharacterRight> Rights;
- bool PremiumAccountActivated = false;
- int Result = LoginGameTransaction(Connection->WorldID, AccountID,
- CharacterName, Password, IPAddress, PrivateWorld,
- GamemasterRequired, &Character, &Buddies, &Rights,
- &PremiumAccountActivated);
+ int IPAddress;
+ QUERY_FAIL_IF(!ParseIPAddress(IPString, &IPAddress));
// IMPORTANT(fusion): We need to insert login attempts outside the login game
// transaction or we could end up not having it recorded at all due to rollbacks.
// It is also the reason the whole transaction had to be pulled to its own function.
// IMPORTANT(fusion): Don't return if we fail to insert the login attempt as the
// result of the whole operation was already determined by the transaction function.
- InsertLoginAttempt(AccountID, IPAddress, (Result != 0));
-
- if(Result == -1){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(Result != 0){
- SendQueryStatusError(Connection, Result);
- return;
- }
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write32((uint32)Character.CharacterID);
- WriteBuffer.WriteString(Character.Name);
- WriteBuffer.Write8((uint8)Character.Sex);
- WriteBuffer.WriteString(Character.Guild);
- WriteBuffer.WriteString(Character.Rank);
- WriteBuffer.WriteString(Character.Title);
-
- int NumBuddies = std::min<int>(Buddies.Length(), UINT8_MAX);
- WriteBuffer.Write8((uint8)NumBuddies);
- for(int i = 0; i < NumBuddies; i += 1){
- WriteBuffer.Write32((uint32)Buddies[i].CharacterID);
- WriteBuffer.WriteString(Buddies[i].Name);
+ LoginGameTx(Database, Query, AccountID, CharacterName,
+ Password, IPAddress, PrivateWorld, GamemasterRequired);
+ if(Query->QueryStatus != QUERY_STATUS_PENDING){
+ InsertLoginAttempt(Database, AccountID, IPAddress,
+ (Query->QueryStatus != QUERY_STATUS_OK));
}
-
- int NumRights = std::min<int>(Rights.Length(), UINT8_MAX);
- WriteBuffer.Write8((uint8)NumRights);
- for(int i = 0; i < NumRights; i += 1){
- WriteBuffer.WriteString(Rights[i].Name);
- }
-
- WriteBuffer.WriteFlag(PremiumAccountActivated);
-
- SendResponse(Connection, &WriteBuffer);
}
-void ProcessLogoutGameQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessLogoutGame(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char Profession[30];
char Residence[30];
- int CharacterID = (int)Buffer->Read32();
- int Level = Buffer->Read16();
- Buffer->ReadString(Profession, sizeof(Profession));
- Buffer->ReadString(Residence, sizeof(Residence));
- int LastLoginTime = (int)Buffer->Read32();
- int TutorActivities = Buffer->Read16();
-
- if(!LogoutCharacter(Connection->WorldID, CharacterID, Level,
- Profession, Residence, LastLoginTime, TutorActivities)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+ int CharacterID = (int)Request.Read32();
+ int Level = Request.Read16();
+ Request.ReadString(Profession, sizeof(Profession));
+ Request.ReadString(Residence, sizeof(Residence));
+ int LastLoginTime = (int)Request.Read32();
+ int TutorActivities = Request.Read16();
+
+ QUERY_STOP_IF(!LogoutCharacter(Database, Query->WorldID, CharacterID,
+ Level, Profession, Residence, LastLoginTime, TutorActivities));
+ QueryOk(Query);
}
-void ProcessSetNamelockQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessSetNamelock(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char IPString[16];
char Reason[200];
char Comment[200];
- int GamemasterID = (int)Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(IPString, sizeof(IPString));
- Buffer->ReadString(Reason, sizeof(Reason));
- Buffer->ReadString(Comment, sizeof(Comment));
+ int GamemasterID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(IPString, sizeof(IPString));
+ Request.ReadString(Reason, sizeof(Reason));
+ Request.ReadString(Comment, sizeof(Comment));
int IPAddress = 0;
- if(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress));
TransactionScope Tx("SetNamelock");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = GetCharacterID(Connection->WorldID, CharacterName);
- if(CharacterID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }
+ int CharacterID;
+ QUERY_STOP_IF(!GetCharacterID(Database, Query->WorldID, CharacterName, &CharacterID));
+ QUERY_ERROR_IF(CharacterID == 0, 1);
// TODO(fusion): Might be `NO_BANISHMENT`.
- if(GetCharacterRight(CharacterID, "NAMELOCK")){
- SendQueryStatusError(Connection, 2);
- return;
- }
+ bool Namelock;
+ QUERY_STOP_IF(!GetCharacterRight(Database, CharacterID, "NAMELOCK", &Namelock));
+ QUERY_ERROR_IF(Namelock, 2);
- TNamelockStatus Status = GetNamelockStatus(CharacterID);
- if(Status.Namelocked){
- SendQueryStatusError(Connection, (Status.Approved ? 4 : 3));
- return;
- }
+ TNamelockStatus Status;
+ QUERY_STOP_IF(!GetNamelockStatus(Database, CharacterID, &Status));
+ QUERY_ERROR_IF(Status.Namelocked, (Status.Approved ? 4 : 3));
- if(!InsertNamelock(CharacterID, IPAddress, GamemasterID, Reason, Comment)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!InsertNamelock(Database, CharacterID, IPAddress, GamemasterID, Reason, Comment));
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessBanishAccountQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessBanishAccount(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char IPString[16];
char Reason[200];
char Comment[200];
- int GamemasterID = (int)Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(IPString, sizeof(IPString));
- Buffer->ReadString(Reason, sizeof(Reason));
- Buffer->ReadString(Comment, sizeof(Comment));
- bool FinalWarning = Buffer->ReadFlag();
+ int GamemasterID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(IPString, sizeof(IPString));
+ Request.ReadString(Reason, sizeof(Reason));
+ Request.ReadString(Comment, sizeof(Comment));
+ bool FinalWarning = Request.ReadFlag();
int IPAddress = 0;
- if(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress));
TransactionScope Tx("BanishAccount");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = GetCharacterID(Connection->WorldID, CharacterName);
- if(CharacterID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }
+ int CharacterID;
+ QUERY_STOP_IF(!GetCharacterID(Database, Query->WorldID, CharacterName, &CharacterID));
+ QUERY_ERROR_IF(CharacterID == 0, 1);
// TODO(fusion): Might be `NO_BANISHMENT`.
- if(GetCharacterRight(CharacterID, "BANISHMENT")){
- SendQueryStatusError(Connection, 2);
- return;
- }
+ bool Banishment;
+ QUERY_STOP_IF(!GetCharacterRight(Database, CharacterID, "BANISHMENT", &Banishment));
+ QUERY_ERROR_IF(Banishment, 2);
- TBanishmentStatus Status = GetBanishmentStatus(CharacterID);
- if(Status.Banished){
- SendQueryStatusError(Connection, 3);
- return;
- }
+ TBanishmentStatus Status;
+ QUERY_STOP_IF(!GetBanishmentStatus(Database, CharacterID, &Status));
+ QUERY_ERROR_IF(Status.Banished, 3);
- int BanishmentID = 0;
int Days = 7;
+ int BanishmentID = 0;
CompoundBanishment(Status, &Days, &FinalWarning);
- if(!InsertBanishment(CharacterID, IPAddress, GamemasterID,
- Reason, Comment, FinalWarning, Days * 86400, &BanishmentID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write32((uint32)BanishmentID);
- WriteBuffer.Write8(Days > 0 ? Days : 0xFF);
- WriteBuffer.WriteFlag(FinalWarning);
- SendResponse(Connection, &WriteBuffer);
+ QUERY_STOP_IF(!InsertBanishment(Database, CharacterID, IPAddress,
+ GamemasterID, Reason, Comment, FinalWarning, Days * 86400,
+ &BanishmentID));
+ QUERY_STOP_IF(!Tx.Commit());
+
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write32((uint32)BanishmentID);
+ Response->Write8(Days > 0 ? Days : 0xFF);
+ Response->WriteFlag(FinalWarning);
+ QueryFinishResponse(Query);
}
-void ProcessSetNotationQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessSetNotation(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char IPString[16];
char Reason[200];
char Comment[200];
- int GamemasterID = Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(IPString, sizeof(IPString));
- Buffer->ReadString(Reason, sizeof(Reason));
- Buffer->ReadString(Comment, sizeof(Comment));
+ int GamemasterID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(IPString, sizeof(IPString));
+ Request.ReadString(Reason, sizeof(Reason));
+ Request.ReadString(Comment, sizeof(Comment));
int IPAddress = 0;
- if(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(!StringEmpty(IPString) && !ParseIPAddress(IPString, &IPAddress));
TransactionScope Tx("SetNotation");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = GetCharacterID(Connection->WorldID, CharacterName);
- if(CharacterID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }
+ int CharacterID;
+ QUERY_STOP_IF(!GetCharacterID(Database, Query->WorldID, CharacterName, &CharacterID));
+ QUERY_ERROR_IF(CharacterID == 0, 1);
// TODO(fusion): Might be `NO_BANISHMENT`.
- if(GetCharacterRight(CharacterID, "NOTATION")){
- SendQueryStatusError(Connection, 2);
- return;
- }
+ bool Notation;
+ QUERY_STOP_IF(!GetCharacterRight(Database, CharacterID, "NOTATION", &Notation));
+ QUERY_ERROR_IF(Notation, 2);
+ int Notations = 0;
int BanishmentID = 0;
- if(GetNotationCount(CharacterID) >= 5){
+ QUERY_STOP_IF(!GetNotationCount(Database, CharacterID, &Notations));
+ if(Notations >= 5){
int BanishmentDays = 7;
bool FinalWarning = false;
- TBanishmentStatus Status = GetBanishmentStatus(CharacterID);
+ TBanishmentStatus Status = {};
+ QUERY_STOP_IF(!GetBanishmentStatus(Database, CharacterID, &Status));
CompoundBanishment(Status, &BanishmentDays, &FinalWarning);
- if(!InsertBanishment(CharacterID, IPAddress, 0, "Excessive Notations",
- "", FinalWarning, BanishmentDays, &BanishmentID)){
- SendQueryStatusFailed(Connection);
- return;
- }
- }
-
- if(!InsertNotation(CharacterID, IPAddress, GamemasterID, Reason, Comment)){
- SendQueryStatusFailed(Connection);
- return;
+ QUERY_STOP_IF(!InsertBanishment(Database, CharacterID, IPAddress,
+ 0, "Excessive Notations", "", FinalWarning, BanishmentDays,
+ &BanishmentID));
}
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!InsertNotation(Database, CharacterID, IPAddress, GamemasterID, Reason, Comment));
+ QUERY_STOP_IF(!Tx.Commit());
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write32((uint32)BanishmentID);
- SendResponse(Connection, &WriteBuffer);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write32((uint32)BanishmentID);
+ QueryFinishResponse(Query);
}
-void ProcessReportStatementQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessReportStatement(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char Reason[200];
char Comment[200];
- int ReporterID = Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(Reason, sizeof(Reason));
- Buffer->ReadString(Comment, sizeof(Comment));
- int BanishmentID = Buffer->Read32();
- int StatementID = Buffer->Read32();
- int NumStatements = Buffer->Read16();
+ int ReporterID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(Reason, sizeof(Reason));
+ Request.ReadString(Comment, sizeof(Comment));
+ int BanishmentID = (int)Request.Read32();
+ int StatementID = (int)Request.Read32();
+ int NumStatements = (int)Request.Read16();
if(StatementID == 0){
- LOG_ERR("Missing reported statement id");
- SendQueryStatusFailed(Connection);
+ LOG_ERR("Missing statement id");
+ QueryFailed(Query);
return;
}
if(NumStatements == 0){
- LOG_ERR("Missing report statements");
- SendQueryStatusFailed(Connection);
+ LOG_ERR("Missing statement context");
+ QueryFailed(Query);
return;
}
TStatement *ReportedStatement = NULL;
TStatement *Statements = (TStatement*)alloca(NumStatements * sizeof(TStatement));
for(int i = 0; i < NumStatements; i += 1){
- Statements[i].StatementID = (int)Buffer->Read32();
- Statements[i].Timestamp = (int)Buffer->Read32();
- Statements[i].CharacterID = (int)Buffer->Read32();
- Buffer->ReadString(Statements[i].Channel, sizeof(Statements[i].Channel));
- Buffer->ReadString(Statements[i].Text, sizeof(Statements[i].Text));
+ Statements[i].StatementID = (int)Request.Read32();
+ Statements[i].Timestamp = (int)Request.Read32();
+ Statements[i].CharacterID = (int)Request.Read32();
+ Request.ReadString(Statements[i].Channel, sizeof(Statements[i].Channel));
+ Request.ReadString(Statements[i].Text, sizeof(Statements[i].Text));
if(Statements[i].StatementID == StatementID){
if(ReportedStatement != NULL){
LOG_WARN("Reported statement (%d, %d, %d) appears multiple times",
- Connection->WorldID, Statements[i].Timestamp,
- Statements[i].StatementID);
+ Query->WorldID, Statements[i].Timestamp, Statements[i].StatementID);
}
ReportedStatement = &Statements[i];
}
@@ -1245,723 +943,429 @@ void ProcessReportStatementQuery(TConnection *Connection, TReadBuffer *Buffer){
if(ReportedStatement == NULL){
LOG_ERR("Missing reported statement");
- SendQueryStatusFailed(Connection);
+ QueryFailed(Query);
return;
}
TransactionScope Tx("ReportStatement");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = GetCharacterID(Connection->WorldID, CharacterName);
- if(CharacterID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }else if(ReportedStatement->CharacterID != CharacterID){
- LOG_ERR("Reported statement character mismatch");
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(IsStatementReported(Connection->WorldID, ReportedStatement)){
- SendQueryStatusError(Connection, 2);
- return;
- }
-
- if(!InsertStatements(Connection->WorldID, NumStatements, Statements)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ int CharacterID;
+ QUERY_STOP_IF(!GetCharacterID(Database, Query->WorldID, CharacterName, &CharacterID));
+ QUERY_ERROR_IF(CharacterID == 0, 1);
- if(!InsertReportedStatement(Connection->WorldID, ReportedStatement,
- BanishmentID, ReporterID, Reason, Comment)){
- SendQueryStatusFailed(Connection);
+ if(ReportedStatement->CharacterID != CharacterID){
+ LOG_ERR("Reported statement character mismatch");
+ QueryFailed(Query);
return;
}
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ bool IsReported;
+ QUERY_STOP_IF(!IsStatementReported(Database, Query->WorldID, ReportedStatement, &IsReported));
+ QUERY_ERROR_IF(IsReported, 2);
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!InsertStatements(Database, Query->WorldID, NumStatements, Statements));
+ QUERY_STOP_IF(!InsertReportedStatement(Database, Query->WorldID, ReportedStatement,
+ BanishmentID, ReporterID, Reason, Comment));
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessBanishIPAddressQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
+void ProcessBanishIpAddress(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char CharacterName[30];
char IPString[16];
char Reason[200];
char Comment[200];
- int GamemasterID = Buffer->Read16();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- Buffer->ReadString(IPString, sizeof(IPString));
- Buffer->ReadString(Reason, sizeof(Reason));
- Buffer->ReadString(Comment, sizeof(Comment));
+ int GamemasterID = (int)Request.Read16();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ Request.ReadString(IPString, sizeof(IPString));
+ Request.ReadString(Reason, sizeof(Reason));
+ Request.ReadString(Comment, sizeof(Comment));
- int IPAddress = 0;
- if(!ParseIPAddress(IPString, &IPAddress)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ int IPAddress;
+ QUERY_FAIL_IF(!ParseIPAddress(IPString, &IPAddress));
TransactionScope Tx("BanishIP");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = GetCharacterID(Connection->WorldID, CharacterName);
- if(CharacterID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }
+ int CharacterID;
+ QUERY_STOP_IF(!GetCharacterID(Database, Query->WorldID, CharacterName, &CharacterID));
+ QUERY_ERROR_IF(CharacterID == 0, 1);
// TODO(fusion): Might be `NO_BANISHMENT`.
- if(GetCharacterRight(CharacterID, "IP_BANISHMENT")){
- SendQueryStatusError(Connection, 2);
- return;
- }
+ bool IPBanishment;
+ QUERY_STOP_IF(!GetCharacterRight(Database, CharacterID, "IP_BANISHMENT", &IPBanishment));
+ QUERY_ERROR_IF(IPBanishment, 2);
- // IMPORTANT(fusion): It is not a good idea to ban an IP address, specially
- // V4 addresses, as they may be dynamically assigned or represent the address
- // of a public ISP router that manages multiple clients.
+ // IMPORTANT(fusion): It is not a good idea to ban IP addresses, specially V4,
+ // as they may be dynamically assigned or represent the address of a public ISP
+ // router that manages multiple clients.
int BanishmentDays = 3;
- if(!InsertIPBanishment(CharacterID, IPAddress, GamemasterID,
- Reason, Comment, BanishmentDays * 86400)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!InsertIPBanishment(Database, CharacterID, IPAddress,
+ GamemasterID, Reason, Comment, BanishmentDays * 86400));
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessLogCharacterDeathQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessLogCharacterDeath(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
char Remark[30];
- int CharacterID = (int)Buffer->Read32();
- int Level = Buffer->Read16();
- int OffenderID = (int)Buffer->Read32();
- Buffer->ReadString(Remark, sizeof(Remark));
- bool Unjustified = Buffer->ReadFlag();
- int Timestamp = (int)Buffer->Read32();
- if(!InsertCharacterDeath(Connection->WorldID, CharacterID, Level,
- OffenderID, Remark, Unjustified, Timestamp)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ int CharacterID = (int)Request.Read32();
+ int Level = (int)Request.Read16();
+ int OffenderID = (int)Request.Read32();
+ Request.ReadString(Remark, sizeof(Remark));
+ bool Unjustified = Request.ReadFlag();
+ int Timestamp = (int)Request.Read32();
+ QUERY_STOP_IF(!InsertCharacterDeath(Database, Query->WorldID, CharacterID,
+ Level, OffenderID, Remark, Unjustified, Timestamp));
+ QueryOk(Query);
- SendQueryStatusOk(Connection);
}
-void ProcessAddBuddyQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int AccountID = (int)Buffer->Read32();
- int BuddyID = (int)Buffer->Read32();
- if(!InsertBuddy(Connection->WorldID, AccountID, BuddyID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessAddBuddy(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int AccountID = (int)Request.Read32();
+ int BuddyID = (int)Request.Read32();
+ QUERY_STOP_IF(!InsertBuddy(Database, Query->WorldID, AccountID, BuddyID));
+ QueryOk(Query);
}
-void ProcessRemoveBuddyQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int AccountID = (int)Buffer->Read32();
- int BuddyID = (int)Buffer->Read32();
- if(!DeleteBuddy(Connection->WorldID, AccountID, BuddyID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessRemoveBuddy(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int AccountID = (int)Request.Read32();
+ int BuddyID = (int)Request.Read32();
+ QUERY_STOP_IF(!DeleteBuddy(Database, Query->WorldID, AccountID, BuddyID));
+ QueryOk(Query);
}
-void ProcessDecrementIsOnlineQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int CharacterID = (int)Buffer->Read32();
- if(!DecrementIsOnline(Connection->WorldID, CharacterID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessDecrementIsOnline(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int CharacterID = (int)Request.Read32();
+ QUERY_STOP_IF(!DecrementIsOnline(Database, Query->WorldID, CharacterID));
+ QueryOk(Query);
}
-void ProcessFinishAuctionsQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessFinishAuctions(TDatabase *Database, TQuery *Query){
DynamicArray<THouseAuction> Auctions;
- if(!FinishHouseAuctions(Connection->WorldID, &Auctions)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!FinishHouseAuctions(Database, Query->WorldID, &Auctions));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumAuctions = std::min<int>(Auctions.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumAuctions);
+ Response->Write16((uint16)NumAuctions);
for(int i = 0; i < NumAuctions; i += 1){
- WriteBuffer.Write16((uint16)Auctions[i].HouseID);
- WriteBuffer.Write32((uint32)Auctions[i].BidderID);
- WriteBuffer.WriteString(Auctions[i].BidderName);
- WriteBuffer.Write32((uint32)Auctions[i].BidAmount);
+ Response->Write16((uint16)Auctions[i].HouseID);
+ Response->Write32((uint32)Auctions[i].BidderID);
+ Response->WriteString(Auctions[i].BidderName);
+ Response->Write32((uint32)Auctions[i].BidAmount);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessTransferHousesQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessTransferHouses(TDatabase *Database, TQuery *Query){
DynamicArray<THouseTransfer> Transfers;
- if(!FinishHouseTransfers(Connection->WorldID, &Transfers)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!FinishHouseTransfers(Database, Query->WorldID, &Transfers));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumTransfers = std::min<int>(Transfers.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumTransfers);
+ Response->Write16((uint16)NumTransfers);
for(int i = 0; i < NumTransfers; i += 1){
- WriteBuffer.Write16((uint16)Transfers[i].HouseID);
- WriteBuffer.Write32((uint32)Transfers[i].NewOwnerID);
- WriteBuffer.WriteString(Transfers[i].NewOwnerName);
- WriteBuffer.Write32((uint32)Transfers[i].Price);
+ Response->Write16((uint16)Transfers[i].HouseID);
+ Response->Write32((uint32)Transfers[i].NewOwnerID);
+ Response->WriteString(Transfers[i].NewOwnerName);
+ Response->Write32((uint32)Transfers[i].Price);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessEvictFreeAccountsQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessEvictFreeAccounts(TDatabase *Database, TQuery *Query){
DynamicArray<THouseEviction> Evictions;
- if(!GetFreeAccountEvictions(Connection->WorldID, &Evictions)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetFreeAccountEvictions(Database, Query->WorldID, &Evictions));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumEvictions = std::min<int>(Evictions.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumEvictions);
+ Response->Write16((uint16)NumEvictions);
for(int i = 0; i < NumEvictions; i += 1){
- WriteBuffer.Write16((uint16)Evictions[i].HouseID);
- WriteBuffer.Write32((uint32)Evictions[i].OwnerID);
+ Response->Write16((uint16)Evictions[i].HouseID);
+ Response->Write32((uint32)Evictions[i].OwnerID);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessEvictDeletedCharactersQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessEvictDeletedCharacters(TDatabase *Database, TQuery *Query){
DynamicArray<THouseEviction> Evictions;
- if(!GetDeletedCharacterEvictions(Connection->WorldID, &Evictions)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetDeletedCharacterEvictions(Database, Query->WorldID, &Evictions));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumEvictions = std::min<int>(Evictions.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumEvictions);
+ Response->Write16((uint16)NumEvictions);
for(int i = 0; i < NumEvictions; i += 1){
- WriteBuffer.Write16((uint16)Evictions[i].HouseID);
+ Response->Write16((uint16)Evictions[i].HouseID);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessEvictExGuildleadersQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessEvictExGuildleaders(TDatabase *Database, TQuery *Query){
// NOTE(fusion): This is a bit different from the other eviction functions.
// The server doesn't maintain guild information for characters so it will
// send a list of guild houses with their owners and we're supposed to check
// whether the owner is still a guild leader. I don't think we should check
// any other information as the server is authoritative on house information.
DynamicArray<int> Evictions;
- int NumGuildHouses = Buffer->Read16();
+ TReadBuffer Request = Query->Request;
+ int NumGuildHouses = (int)Request.Read16();
for(int i = 0; i < NumGuildHouses; i += 1){
- int HouseID = Buffer->Read16();
- int OwnerID = (int)Buffer->Read32();
- if(!GetGuildLeaderStatus(Connection->WorldID, OwnerID)){
+ int HouseID = (int)Request.Read16();
+ int OwnerID = (int)Request.Read32();
+
+ bool IsGuildLeader;
+ QUERY_STOP_IF(!GetGuildLeaderStatus(Database, Query->WorldID, OwnerID, &IsGuildLeader));
+ if(IsGuildLeader){
Evictions.Push(HouseID);
}
}
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumEvictions = std::min<int>(Evictions.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumEvictions);
+ Response->Write16((uint16)NumEvictions);
for(int i = 0; i < NumEvictions; i += 1){
- WriteBuffer.Write16((uint16)Evictions[i]);
+ Response->Write16((uint16)Evictions[i]);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessInsertHouseOwnerQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int HouseID = Buffer->Read16();
- int OwnerID = (int)Buffer->Read32();
- int PaidUntil = (int)Buffer->Read32();
- if(!InsertHouseOwner(Connection->WorldID, HouseID, OwnerID, PaidUntil)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessInsertHouseOwner(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int HouseID = (int)Request.Read16();
+ int OwnerID = (int)Request.Read32();
+ int PaidUntil = (int)Request.Read32();
+ QUERY_STOP_IF(!InsertHouseOwner(Database, Query->WorldID, HouseID, OwnerID, PaidUntil));
+ QueryOk(Query);
}
-void ProcessUpdateHouseOwnerQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int HouseID = Buffer->Read16();
- int OwnerID = (int)Buffer->Read32();
- int PaidUntil = (int)Buffer->Read32();
- if(!UpdateHouseOwner(Connection->WorldID, HouseID, OwnerID, PaidUntil)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessUpdateHouseOwner(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int HouseID = (int)Request.Read16();
+ int OwnerID = (int)Request.Read32();
+ int PaidUntil = (int)Request.Read32();
+ QUERY_STOP_IF(!UpdateHouseOwner(Database, Query->WorldID, HouseID, OwnerID, PaidUntil));
+ QueryOk(Query);
}
-void ProcessDeleteHouseOwnerQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int HouseID = Buffer->Read16();
- if(!DeleteHouseOwner(Connection->WorldID, HouseID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessDeleteHouseOwner(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int HouseID = (int)Request.Read16();
+ QUERY_STOP_IF(!DeleteHouseOwner(Database, Query->WorldID, HouseID));
+ QueryOk(Query);
}
-void ProcessGetHouseOwnersQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessGetHouseOwners(TDatabase *Database, TQuery *Query){
DynamicArray<THouseOwner> Owners;
- if(!GetHouseOwners(Connection->WorldID, &Owners)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetHouseOwners(Database, Query->WorldID, &Owners));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumOwners = std::min<int>(Owners.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumOwners);
+ Response->Write16((uint16)NumOwners);
for(int i = 0; i < NumOwners; i += 1){
- WriteBuffer.Write16((uint16)Owners[i].HouseID);
- WriteBuffer.Write32((uint32)Owners[i].OwnerID);
- WriteBuffer.WriteString(Owners[i].OwnerName);
- WriteBuffer.Write32((uint32)Owners[i].PaidUntil);
+ Response->Write16((uint16)Owners[i].HouseID);
+ Response->Write32((uint32)Owners[i].OwnerID);
+ Response->WriteString(Owners[i].OwnerName);
+ Response->Write32((uint32)Owners[i].PaidUntil);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessGetAuctionsQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessGetAuctions(TDatabase *Database, TQuery *Query){
DynamicArray<int> Auctions;
- if(!GetHouseAuctions(Connection->WorldID, &Auctions)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetHouseAuctions(Database, Query->WorldID, &Auctions));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumAuctions = std::min<int>(Auctions.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumAuctions);
+ Response->Write16((uint16)NumAuctions);
for(int i = 0; i < NumAuctions; i += 1){
- WriteBuffer.Write16((uint16)Auctions[i]);
+ Response->Write16((uint16)Auctions[i]);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessStartAuctionQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int HouseID = Buffer->Read16();
- if(!StartHouseAuction(Connection->WorldID, HouseID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+void ProcessStartAuction(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int HouseID = (int)Request.Read16();
+ QUERY_STOP_IF(!StartHouseAuction(Database, Query->WorldID, HouseID));
+ QueryOk(Query);
}
-void ProcessInsertHousesQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessInsertHouses(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
TransactionScope Tx("InsertHouses");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!DeleteHouses(Connection->WorldID)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
+ QUERY_STOP_IF(!DeleteHouses(Database, Query->WorldID));
- int NumHouses = Buffer->Read16();
+ int NumHouses = (int)Request.Read16();
if(NumHouses > 0){
-G THouse *Houses = (THouse*)alloca(NumHouses * sizeof(THouse));
+ THouse *Houses = (THouse*)alloca(NumHouses * sizeof(THouse));
for(int i = 0; i < NumHouses; i += 1){
- Houses[i].HouseID = Buffer->Read16();
- Buffer->ReadString(Houses[i].Name, sizeof(Houses[i].Name));
- Houses[i].Rent = (int)Buffer->Read32();
- Buffer->ReadString(Houses[i].Description, sizeof(Houses[i].Description));
- Houses[i].Size = Buffer->Read16();
- Houses[i].PositionX = Buffer->Read16();
- Houses[i].PositionY = Buffer->Read16();
- Houses[i].PositionZ = Buffer->Read8();
- Buffer->ReadString(Houses[i].Town, sizeof(Houses[i].Town));
- Houses[i].GuildHouse = Buffer->ReadFlag();
+ Houses[i].HouseID = (int)Request.Read16();
+ Request.ReadString(Houses[i].Name, sizeof(Houses[i].Name));
+ Houses[i].Rent = (int)Request.Read32();
+ Request.ReadString(Houses[i].Description, sizeof(Houses[i].Description));
+ Houses[i].Size = (int)Request.Read16();
+ Houses[i].PositionX = (int)Request.Read16();
+ Houses[i].PositionY = (int)Request.Read16();
+ Houses[i].PositionZ = (int)Request.Read8();
+ Request.ReadString(Houses[i].Town, sizeof(Houses[i].Town));
+ Houses[i].GuildHouse = Request.ReadFlag();
}
- if(!InsertHouses(Connection->WorldID, NumHouses, Houses)){
- SendQueryStatusFailed(Connection);
- return;
- }
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
+ QUERY_STOP_IF(!InsertHouses(Database, Query->WorldID, NumHouses, Houses));
}
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessClearIsOnlineQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessClearIsOnline(TDatabase *Database, TQuery *Query){
int NumAffectedCharacters;
- if(!ClearIsOnline(Connection->WorldID, &NumAffectedCharacters)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write16((uint16)NumAffectedCharacters);
- SendResponse(Connection, &WriteBuffer);
+ QUERY_STOP_IF(!ClearIsOnline(Database, Query->WorldID, &NumAffectedCharacters));
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write16((uint16)NumAffectedCharacters);
+ QueryFinishResponse(Query);
}
-void ProcessCreatePlayerlistQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
TransactionScope Tx("OnlineList");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!DeleteOnlineCharacters(Connection->WorldID)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
+ QUERY_STOP_IF(!DeleteOnlineCharacters(Database, Query->WorldID));
// TODO(fusion): I think `NumCharacters` may be used to signal that the
// server is going OFFLINE, in which case we'd have to add an `Online`
// column to `Worlds` and update it here.
bool NewRecord = false;
- int NumCharacters = Buffer->Read16();
+ int NumCharacters = (int)Request.Read16();
if(NumCharacters != 0xFFFF && NumCharacters > 0){
TOnlineCharacter *Characters = (TOnlineCharacter*)alloca(NumCharacters * sizeof(TOnlineCharacter));
for(int i = 0; i < NumCharacters; i += 1){
- Buffer->ReadString(Characters[i].Name, sizeof(Characters[i].Name));
- Characters[i].Level = Buffer->Read16();
- Buffer->ReadString(Characters[i].Profession, sizeof(Characters[i].Profession));
+ Request.ReadString(Characters[i].Name, sizeof(Characters[i].Name));
+ Characters[i].Level = (int)Request.Read16();
+ Request.ReadString(Characters[i].Profession, sizeof(Characters[i].Profession));
}
- if(!InsertOnlineCharacters(Connection->WorldID, NumCharacters, Characters)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!CheckOnlineRecord(Connection->WorldID, NumCharacters, &NewRecord)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!InsertOnlineCharacters(Database, Query->WorldID, NumCharacters, Characters));
+ QUERY_STOP_IF(!CheckOnlineRecord(Database, Query->WorldID, NumCharacters, &NewRecord));
}
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Commit());
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.WriteFlag(NewRecord);
- SendResponse(Connection, &WriteBuffer);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->WriteFlag(NewRecord);
+ QueryFinishResponse(Query);
}
-void ProcessLogKilledCreaturesQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- int NumStats = Buffer->Read16();
+void ProcessLogKilledCreatures(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int NumStats = (int)Request.Read16();
TKillStatistics *Stats = (TKillStatistics*)alloca(NumStats * sizeof(TKillStatistics));
for(int i = 0; i < NumStats; i += 1){
- Buffer->ReadString(Stats[i].RaceName, sizeof(Stats[i].RaceName));
- Stats[i].PlayersKilled = (int)Buffer->Read32();
- Stats[i].TimesKilled = (int)Buffer->Read32();
+ Request.ReadString(Stats[i].RaceName, sizeof(Stats[i].RaceName));
+ Stats[i].PlayersKilled = (int)Request.Read32();
+ Stats[i].TimesKilled = (int)Request.Read32();
}
if(NumStats > 0){
TransactionScope Tx("LogKilledCreatures");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!MergeKillStatistics(Connection->WorldID, NumStats, Stats)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
+ QUERY_STOP_IF(!MergeKillStatistics(Database, Query->WorldID, NumStats, Stats));
+ QUERY_STOP_IF(!Tx.Commit());
}
- SendQueryStatusOk(Connection);
+ QueryOk(Query);
}
-void ProcessLoadPlayersQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessLoadPlayers(TDatabase *Database, TQuery *Query){
// IMPORTANT(fusion): The server expect 10K entries at most. It is probably
// some shared hard coded constant.
int NumEntries;
TCharacterIndexEntry Entries[10000];
- int MinimumCharacterID = (int)Buffer->Read32();
- if(!GetCharacterIndexEntries(Connection->WorldID,
- MinimumCharacterID, NARRAY(Entries), &NumEntries, Entries)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ TReadBuffer Request = Query->Request;
+ int MinimumCharacterID = (int)Request.Read32();
+ QUERY_STOP_IF(!GetCharacterIndexEntries(Database, Query->WorldID,
+ MinimumCharacterID, NARRAY(Entries), &NumEntries, Entries));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write32((uint32)NumEntries);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write32((uint32)NumEntries);
for(int i = 0; i < NumEntries; i += 1){
- WriteBuffer.WriteString(Entries[i].Name);
- WriteBuffer.Write32((uint32)Entries[i].CharacterID);
+ Response->WriteString(Entries[i].Name);
+ Response->Write32((uint32)Entries[i].CharacterID);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessExcludeFromAuctionsQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessExcludeFromAuctions(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
TransactionScope Tx("ExcludeFromAuctions");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int CharacterID = (int)Buffer->Read32();
- bool Banish = Buffer->ReadFlag();
+ int CharacterID = (int)Request.Read32();
+ bool Banish = Request.ReadFlag();
int ExclusionDays = 7;
int BanishmentID = 0;
if(Banish){
int BanishmentDays = 7;
bool FinalWarning = false;
- TBanishmentStatus Status = GetBanishmentStatus(CharacterID);
+ TBanishmentStatus Status;
+ QUERY_STOP_IF(!GetBanishmentStatus(Database, CharacterID, &Status));
CompoundBanishment(Status, &BanishmentDays, &FinalWarning);
- if(!InsertBanishment(CharacterID, 0, 0, "Spoiling Auction",
- "", FinalWarning, BanishmentDays * 86400, &BanishmentID)){
- SendQueryStatusFailed(Connection);
- return;
- }
- }
-
- if(!ExcludeFromAuctions(Connection->WorldID,
- CharacterID, ExclusionDays * 86400, BanishmentID)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
+ QUERY_STOP_IF(!InsertBanishment(Database, CharacterID, 0,
+ 0, "Spoiling Auction", "", FinalWarning, BanishmentDays * 86400,
+ &BanishmentID));
}
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!ExcludeFromAuctions(Database, Query->WorldID,
+ CharacterID, ExclusionDays * 86400, BanishmentID));
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessCancelHouseTransferQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessCancelHouseTransfer(TDatabase *Database, TQuery *Query){
// TODO(fusion): Not sure what this is used for. Maybe house transfer rows
// are kept permanently and this query is used to delete/flag it, in case
// the it didn't complete. We might need to refine `FinishHouseTransfers`.
//int HouseID = Buffer->Read16();
- SendQueryStatusOk(Connection);
+ QueryOk(Query);
}
-void ProcessLoadWorldConfigQuery(TConnection *Connection, TReadBuffer *Buffer){
- if(Connection->ApplicationType != APPLICATION_TYPE_GAME){
- SendQueryStatusFailed(Connection);
- return;
- }
-
+void ProcessLoadWorldConfig(TDatabase *Database, TQuery *Query){
TWorldConfig WorldConfig = {};
- if(!GetWorldConfig(Connection->WorldID, &WorldConfig)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.Write8((uint8)WorldConfig.Type);
- WriteBuffer.Write8((uint8)WorldConfig.RebootTime);
- WriteBuffer.Write32BE((uint32)WorldConfig.IPAddress);
- WriteBuffer.Write16((uint16)WorldConfig.Port);
- WriteBuffer.Write16((uint16)WorldConfig.MaxPlayers);
- WriteBuffer.Write16((uint16)WorldConfig.PremiumPlayerBuffer);
- WriteBuffer.Write16((uint16)WorldConfig.MaxNewbies);
- WriteBuffer.Write16((uint16)WorldConfig.PremiumNewbieBuffer);
- SendResponse(Connection, &WriteBuffer);
-}
-
-void ProcessCreateAccountQuery(TConnection *Connection, TReadBuffer *Buffer){
- // TODO(fusion): We'd ideally want to automatically generate an account number
- // and return it in case of success but that would also require a more robust
- // website infrastructure with verification e-mails, etc...
- char Email[100];
- char Password[30];
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(Email, sizeof(Email));
- Buffer->ReadString(Password, sizeof(Password));
-
- // NOTE(fusion): Inputs should be checked before hand.
- if(AccountID <= 0 || StringEmpty(Email) || StringEmpty(Password)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- uint8 Auth[64];
- if(!GenerateAuth(Password, Auth, sizeof(Auth))){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- TransactionScope Tx("CreateAccount");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(AccountNumberExists(AccountID)){
- SendQueryStatusError(Connection, 1);
- return;
- }
-
- if(AccountEmailExists(Email)){
- SendQueryStatusError(Connection, 2);
- return;
- }
-
- if(!CreateAccount(AccountID, Email, Auth, sizeof(Auth))){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!GetWorldConfig(Database, Query->WorldID, &WorldConfig));
+
+ int IPAddress;
+ QUERY_FAIL_IF(!ResolveHostName(WorldConfig.HostName, &IPAddress));
+
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->Write8((uint8)WorldConfig.Type);
+ Response->Write8((uint8)WorldConfig.RebootTime);
+ Response->Write32BE((uint32)IPAddress);
+ Response->Write16((uint16)WorldConfig.Port);
+ Response->Write16((uint16)WorldConfig.MaxPlayers);
+ Response->Write16((uint16)WorldConfig.PremiumPlayerBuffer);
+ Response->Write16((uint16)WorldConfig.MaxNewbies);
+ Response->Write16((uint16)WorldConfig.PremiumNewbieBuffer);
+ QueryFinishResponse(Query);
}
-bool ProcessCreateAccountQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessCreateAccount(TDatabase *Database, TQuery *Query){
// TODO(fusion): We'd ideally want to automatically generate an account number
// and return it in case of success but that would also require a more robust
// website infrastructure with verification e-mails, etc...
char Email[100];
char Password[30];
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(Email, sizeof(Email));
- Buffer->ReadString(Password, sizeof(Password));
+ TReadBuffer Request = Query->Request;
+ int AccountID = (int)Request.Read32();
+ Request.ReadString(Email, sizeof(Email));
+ Request.ReadString(Password, sizeof(Password));
// NOTE(fusion): Inputs should be checked before hand.
QUERY_FAIL_IF(AccountID <= 0);
@@ -1972,283 +1376,174 @@ bool ProcessCreateAccountQuery(TConnection *Connection, TReadBuffer *Buffer){
QUERY_FAIL_IF(!GenerateAuth(Password, Auth, sizeof(Auth)));
TransactionScope Tx("CreateAccount");
- QUERY_RETRY_IF(!Tx.Begin(Database));
- QUERY_RETRY_IF(!AccountNumberExists(Database, AccountID, &AccountExists));
+ QUERY_STOP_IF(!Tx.Begin(Database));
+
+ bool AccountExists;
+ QUERY_STOP_IF(!AccountNumberExists(Database, AccountID, &AccountExists));
QUERY_ERROR_IF(AccountExists, 1);
- QUERY_RETRY_IF(!AccountEmailExists(Database, Email, &AccountExists));
+ QUERY_STOP_IF(!AccountEmailExists(Database, Email, &AccountExists));
QUERY_ERROR_IF(AccountExists, 2);
- QUERY_FAIL_IF(!CreateAccount(AccountID, Email, Auth, sizeof(Auth)));
- QUERY_RETRY_IF(!Tx.Commit());
+ QUERY_STOP_IF(!CreateAccount(Database, AccountID, Email, Auth, sizeof(Auth)));
+ QUERY_STOP_IF(!Tx.Commit());
QueryOk(Query);
- return true;
}
-void ProcessCreateCharacterQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessCreateCharacter(TDatabase *Database, TQuery *Query){
char WorldName[30];
char CharacterName[30];
- Buffer->ReadString(WorldName, sizeof(WorldName));
- int AccountID = (int)Buffer->Read32();
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
- int Sex = Buffer->Read8();
+ TReadBuffer Request = Query->Request;
+ Request.ReadString(WorldName, sizeof(WorldName));
+ int AccountID = (int)Request.Read32();
+ Request.ReadString(CharacterName, sizeof(CharacterName));
+ int Sex = (int)Request.Read8();
// NOTE(fusion): Inputs should be checked before hand.
- if(AccountID <= 0 || (Sex != 1 && Sex != 2)
- || StringEmpty(WorldName)
- || StringEmpty(CharacterName)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(AccountID <= 0);
+ QUERY_FAIL_IF(Sex != 1 && Sex != 2);
+ QUERY_FAIL_IF(StringEmpty(WorldName));
+ QUERY_FAIL_IF(StringEmpty(CharacterName));
TransactionScope Tx("CreateCharacter");
- if(!Tx.Begin()){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!Tx.Begin(Database));
- int WorldID = GetWorldID(WorldName);
- if(WorldID == 0){
- SendQueryStatusError(Connection, 1);
- return;
- }
+ int WorldID;
+ QUERY_STOP_IF(!GetWorldID(Database, WorldName, &WorldID));
+ QUERY_ERROR_IF(WorldID == 0, 1);
- if(!AccountNumberExists(AccountID)){
- SendQueryStatusError(Connection, 2);
- return;
- }
+ bool AccountExists;
+ QUERY_STOP_IF(!AccountNumberExists(Database, AccountID, &AccountExists));
+ QUERY_ERROR_IF(!AccountExists, 2);
- if(CharacterNameExists(CharacterName)){
- SendQueryStatusError(Connection, 3);
- return;
- }
+ bool CharacterExists;
+ QUERY_STOP_IF(!CharacterNameExists(Database, CharacterName, &CharacterExists));
+ QUERY_ERROR_IF(CharacterExists, 3);
- if(!CreateCharacter(WorldID, AccountID, CharacterName, Sex)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!Tx.Commit()){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- SendQueryStatusOk(Connection);
+ QUERY_STOP_IF(!CreateCharacter(Database, WorldID, AccountID, CharacterName, Sex));
+ QUERY_STOP_IF(!Tx.Commit());
+ QueryOk(Query);
}
-void ProcessGetAccountSummaryQuery(TConnection *Connection, TReadBuffer *Buffer){
- int AccountID = (int)Buffer->Read32();
+void ProcessGetAccountSummary(TDatabase *Database, TQuery *Query){
+ TReadBuffer Request = Query->Request;
+ int AccountID = (int)Request.Read32();
- if(AccountID <= 0){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(AccountID <= 0);
TAccount Account;
- if(!GetAccountData(AccountID, &Account)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(Account.AccountID != AccountID){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
+ QUERY_FAIL_IF(Account.AccountID == 0 || Account.AccountID != AccountID);
DynamicArray<TCharacterSummary> Characters;
- if(!GetCharacterSummaries(AccountID, &Characters)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetCharacterSummaries(Database, AccountID, &Characters));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.WriteString(Account.Email);
- WriteBuffer.Write16((uint16)Account.PremiumDays);
- WriteBuffer.Write16((uint16)Account.PendingPremiumDays);
- WriteBuffer.WriteFlag(Account.Deleted);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->WriteString(Account.Email);
+ Response->Write16((uint16)Account.PremiumDays);
+ Response->Write16((uint16)Account.PendingPremiumDays);
+ Response->WriteFlag(Account.Deleted);
int NumCharacters = std::min<int>(Characters.Length(), UINT8_MAX);
- WriteBuffer.Write8((uint8)NumCharacters);
+ Response->Write8((uint8)NumCharacters);
for(int i = 0; i < NumCharacters; i += 1){
- WriteBuffer.WriteString(Characters[i].Name);
- WriteBuffer.WriteString(Characters[i].World);
- WriteBuffer.Write16((uint16)Characters[i].Level);
- WriteBuffer.WriteString(Characters[i].Profession);
- WriteBuffer.WriteFlag(Characters[i].Online);
- WriteBuffer.WriteFlag(Characters[i].Deleted);
+ Response->WriteString(Characters[i].Name);
+ Response->WriteString(Characters[i].World);
+ Response->Write16((uint16)Characters[i].Level);
+ Response->WriteString(Characters[i].Profession);
+ Response->WriteFlag(Characters[i].Online);
+ Response->WriteFlag(Characters[i].Deleted);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessGetCharacterProfileQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessGetCharacterProfile(TDatabase *Database, TQuery *Query){
char CharacterName[30];
- Buffer->ReadString(CharacterName, sizeof(CharacterName));
+ TReadBuffer Request = Query->Request;
+ Request.ReadString(CharacterName, sizeof(CharacterName));
- if(StringEmpty(CharacterName)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_FAIL_IF(StringEmpty(CharacterName));
TCharacterProfile Character;
- if(!GetCharacterProfile(CharacterName, &Character)){
- SendQueryStatusFailed(Connection);
- return;
- }
-
- if(!StringEqCI(Character.Name, CharacterName)){
- SendQueryStatusError(Connection, 1);
- return;
- }
-
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
- WriteBuffer.WriteString(Character.Name);
- WriteBuffer.WriteString(Character.World);
- WriteBuffer.Write8((uint8)Character.Sex);
- WriteBuffer.WriteString(Character.Guild);
- WriteBuffer.WriteString(Character.Rank);
- WriteBuffer.WriteString(Character.Title);
- WriteBuffer.Write16((uint16)Character.Level);
- WriteBuffer.WriteString(Character.Profession);
- WriteBuffer.WriteString(Character.Residence);
- WriteBuffer.Write32((uint32)Character.LastLogin);
- WriteBuffer.Write16((uint16)Character.PremiumDays);
- WriteBuffer.WriteFlag(Character.Online);
- WriteBuffer.WriteFlag(Character.Deleted);
- SendResponse(Connection, &WriteBuffer);
+ QUERY_STOP_IF(!GetCharacterProfile(Database, CharacterName, &Character));
+ QUERY_ERROR_IF(!StringEqCI(Character.Name, CharacterName), 1);
+
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
+ Response->WriteString(Character.Name);
+ Response->WriteString(Character.World);
+ Response->Write8((uint8)Character.Sex);
+ Response->WriteString(Character.Guild);
+ Response->WriteString(Character.Rank);
+ Response->WriteString(Character.Title);
+ Response->Write16((uint16)Character.Level);
+ Response->WriteString(Character.Profession);
+ Response->WriteString(Character.Residence);
+ Response->Write32((uint32)Character.LastLogin);
+ Response->Write16((uint16)Character.PremiumDays);
+ Response->WriteFlag(Character.Online);
+ Response->WriteFlag(Character.Deleted);
+ QueryFinishResponse(Query);
}
-void ProcessGetWorldsQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessGetWorlds(TDatabase *Database, TQuery *Query){
DynamicArray<TWorld> Worlds;
- if(!GetWorlds(&Worlds)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetWorlds(Database, &Worlds));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumWorlds = std::min<int>(Worlds.Length(), UINT8_MAX);
- WriteBuffer.Write8((uint8)NumWorlds);
+ Response->Write8((uint8)NumWorlds);
for(int i = 0; i < NumWorlds; i += 1){
- WriteBuffer.WriteString(Worlds[i].Name);
- WriteBuffer.Write8((uint8)Worlds[i].Type);
- WriteBuffer.Write16((uint16)Worlds[i].NumPlayers);
- WriteBuffer.Write16((uint16)Worlds[i].MaxPlayers);
- WriteBuffer.Write16((uint16)Worlds[i].OnlineRecord);
- WriteBuffer.Write32((uint32)Worlds[i].OnlineRecordTimestamp);
+ Response->WriteString(Worlds[i].Name);
+ Response->Write8((uint8)Worlds[i].Type);
+ Response->Write16((uint16)Worlds[i].NumPlayers);
+ Response->Write16((uint16)Worlds[i].MaxPlayers);
+ Response->Write16((uint16)Worlds[i].OnlineRecord);
+ Response->Write32((uint32)Worlds[i].OnlineRecordTimestamp);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessGetOnlineCharactersQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessGetOnlineCharacters(TDatabase *Database, TQuery *Query){
char WorldName[30];
- Buffer->ReadString(WorldName, sizeof(WorldName));
+ TReadBuffer Request = Query->Request;
+ Request.ReadString(WorldName, sizeof(WorldName));
- int WorldID = GetWorldID(WorldName);
- if(WorldID == 0){
- SendQueryStatusFailed(Connection);
- return;
- }
+ int WorldID;
+ QUERY_STOP_IF(!GetWorldID(Database, WorldName, &WorldID));
+ QUERY_FAIL_IF(WorldID == 0);
DynamicArray<TOnlineCharacter> Characters;
- if(!GetOnlineCharacters(WorldID, &Characters)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetOnlineCharacters(Database, WorldID, &Characters));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumCharacters = std::min<int>(Characters.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumCharacters);
+ Response->Write16((uint16)NumCharacters);
for(int i = 0; i < NumCharacters; i += 1){
- WriteBuffer.WriteString(Characters[i].Name);
- WriteBuffer.Write16((uint16)Characters[i].Level);
- WriteBuffer.WriteString(Characters[i].Profession);
+ Response->WriteString(Characters[i].Name);
+ Response->Write16((uint16)Characters[i].Level);
+ Response->WriteString(Characters[i].Profession);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessGetKillStatisticsQuery(TConnection *Connection, TReadBuffer *Buffer){
+void ProcessGetKillStatistics(TDatabase *Database, TQuery *Query){
char WorldName[30];
- Buffer->ReadString(WorldName, sizeof(WorldName));
+ TReadBuffer Request = Query->Request;
+ Request.ReadString(WorldName, sizeof(WorldName));
- int WorldID = GetWorldID(WorldName);
- if(WorldID == 0){
- SendQueryStatusFailed(Connection);
- return;
- }
+ int WorldID;
+ QUERY_STOP_IF(!GetWorldID(Database, WorldName, &WorldID));
+ QUERY_FAIL_IF(WorldID == 0);
DynamicArray<TKillStatistics> Stats;
- if(!GetKillStatistics(WorldID, &Stats)){
- SendQueryStatusFailed(Connection);
- return;
- }
+ QUERY_STOP_IF(!GetKillStatistics(Database, WorldID, &Stats));
- TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
+ TWriteBuffer *Response = QueryBeginResponse(Query, QUERY_STATUS_OK);
int NumStats = std::min<int>(Stats.Length(), UINT16_MAX);
- WriteBuffer.Write16((uint16)NumStats);
+ Response->Write16((uint16)NumStats);
for(int i = 0; i < NumStats; i += 1){
- WriteBuffer.WriteString(Stats[i].RaceName);
- WriteBuffer.Write32((uint32)Stats[i].PlayersKilled);
- WriteBuffer.Write32((uint32)Stats[i].TimesKilled);
+ Response->WriteString(Stats[i].RaceName);
+ Response->Write32((uint32)Stats[i].PlayersKilled);
+ Response->Write32((uint32)Stats[i].TimesKilled);
}
- SendResponse(Connection, &WriteBuffer);
+ QueryFinishResponse(Query);
}
-void ProcessConnectionQuery(TConnection *Connection){
- TReadBuffer Buffer(Connection->Buffer, Connection->RWSize);
- int Query = Buffer.Read8();
- if(!Connection->Authorized){
- if(Query == QUERY_LOGIN){
- ProcessLoginQuery(Connection, &Buffer);
- }else{
- LOG_ERR("Unauthorized query %d from %s", QueryType, Connection->RemoteAddress);
- CloseConnection(Connection);
- }
- return;
- }
-
- switch(Query){
- case QUERY_CHECK_ACCOUNT_PASSWORD: ProcessCheckAccountPasswordQuery(Connection, &Buffer); break;
- case QUERY_LOGIN_ACCOUNT: ProcessLoginAccountQuery(Connection, &Buffer); break;
- case QUERY_LOGIN_ADMIN: ProcessLoginAdminQuery(Connection, &Buffer); break;
- case QUERY_LOGIN_GAME: ProcessLoginGameQuery(Connection, &Buffer); break;
- case QUERY_LOGOUT_GAME: ProcessLogoutGameQuery(Connection, &Buffer); break;
- case QUERY_SET_NAMELOCK: ProcessSetNamelockQuery(Connection, &Buffer); break;
- case QUERY_BANISH_ACCOUNT: ProcessBanishAccountQuery(Connection, &Buffer); break;
- case QUERY_SET_NOTATION: ProcessSetNotationQuery(Connection, &Buffer); break;
- case QUERY_REPORT_STATEMENT: ProcessReportStatementQuery(Connection, &Buffer); break;
- case QUERY_BANISH_IP_ADDRESS: ProcessBanishIPAddressQuery(Connection, &Buffer); break;
- case QUERY_LOG_CHARACTER_DEATH: ProcessLogCharacterDeathQuery(Connection, &Buffer); break;
- case QUERY_ADD_BUDDY: ProcessAddBuddyQuery(Connection, &Buffer); break;
- case QUERY_REMOVE_BUDDY: ProcessRemoveBuddyQuery(Connection, &Buffer); break;
- case QUERY_DECREMENT_IS_ONLINE: ProcessDecrementIsOnlineQuery(Connection, &Buffer); break;
- case QUERY_FINISH_AUCTIONS: ProcessFinishAuctionsQuery(Connection, &Buffer); break;
- case QUERY_TRANSFER_HOUSES: ProcessTransferHousesQuery(Connection, &Buffer); break;
- case QUERY_EVICT_FREE_ACCOUNTS: ProcessEvictFreeAccountsQuery(Connection, &Buffer); break;
- case QUERY_EVICT_DELETED_CHARACTERS: ProcessEvictDeletedCharactersQuery(Connection, &Buffer); break;
- case QUERY_EVICT_EX_GUILDLEADERS: ProcessEvictExGuildleadersQuery(Connection, &Buffer); break;
- case QUERY_INSERT_HOUSE_OWNER: ProcessInsertHouseOwnerQuery(Connection, &Buffer); break;
- case QUERY_UPDATE_HOUSE_OWNER: ProcessUpdateHouseOwnerQuery(Connection, &Buffer); break;
- case QUERY_DELETE_HOUSE_OWNER: ProcessDeleteHouseOwnerQuery(Connection, &Buffer); break;
- case QUERY_GET_HOUSE_OWNERS: ProcessGetHouseOwnersQuery(Connection, &Buffer); break;
- case QUERY_GET_AUCTIONS: ProcessGetAuctionsQuery(Connection, &Buffer); break;
- case QUERY_START_AUCTION: ProcessStartAuctionQuery(Connection, &Buffer); break;
- case QUERY_INSERT_HOUSES: ProcessInsertHousesQuery(Connection, &Buffer); break;
- case QUERY_CLEAR_IS_ONLINE: ProcessClearIsOnlineQuery(Connection, &Buffer); break;
- case QUERY_CREATE_PLAYERLIST: ProcessCreatePlayerlistQuery(Connection, &Buffer); break;
- case QUERY_LOG_KILLED_CREATURES: ProcessLogKilledCreaturesQuery(Connection, &Buffer); break;
- case QUERY_LOAD_PLAYERS: ProcessLoadPlayersQuery(Connection, &Buffer); break;
- case QUERY_EXCLUDE_FROM_AUCTIONS: ProcessExcludeFromAuctionsQuery(Connection, &Buffer); break;
- case QUERY_CANCEL_HOUSE_TRANSFER: ProcessCancelHouseTransferQuery(Connection, &Buffer); break;
- case QUERY_LOAD_WORLD_CONFIG: ProcessLoadWorldConfigQuery(Connection, &Buffer); break;
- case QUERY_CREATE_ACCOUNT: ProcessCreateAccountQuery(Connection, &Buffer); break;
- case QUERY_CREATE_CHARACTER: ProcessCreateCharacterQuery(Connection, &Buffer); break;
- case QUERY_GET_ACCOUNT_SUMMARY: ProcessGetAccountSummaryQuery(Connection, &Buffer); break;
- case QUERY_GET_CHARACTER_PROFILE: ProcessGetCharacterProfileQuery(Connection, &Buffer); break;
- case QUERY_GET_WORLDS: ProcessGetWorldsQuery(Connection, &Buffer); break;
- case QUERY_GET_ONLINE_CHARACTERS: ProcessGetOnlineCharactersQuery(Connection, &Buffer); break;
- case QUERY_GET_KILL_STATISTICS: ProcessGetKillStatisticsQuery(Connection, &Buffer); break;
- default:{
- LOG_ERR("Unknown query %d from %s", Query, Connection->RemoteAddress);
- SendQueryStatusFailed(Connection);
- break;
- }
- }
-}
-#endif
diff --git a/src/querymanager.hh b/src/querymanager.hh
index 5bf8286..84ce9e5 100644
--- a/src/querymanager.hh
+++ b/src/querymanager.hh
@@ -863,6 +863,7 @@ enum : int {
QUERY_STATUS_OK = 0,
QUERY_STATUS_ERROR = 1,
QUERY_STATUS_FAILED = 3,
+ QUERY_STATUS_PENDING = 4,
};
enum : int {
@@ -941,47 +942,46 @@ void QueryOk(TQuery *Query);
void QueryError(TQuery *Query, int ErrorCode);
void QueryFailed(TQuery *Query);
-bool ProcessInternalResolveWorld(TDatabase *Database, TQuery *Query);
-bool ProcessCheckAccountPassword(TDatabase *Database, TQuery *Query);
-bool ProcessLoginAccount(TDatabase *Database, TQuery *Query);
-bool ProcessLoginAdmin(TDatabase *Database, TQuery *Query);
-bool ProcessLoginGame(TDatabase *Database, TQuery *Query);
-bool ProcessLogoutGame(TDatabase *Database, TQuery *Query);
-bool ProcessSetNamelock(TDatabase *Database, TQuery *Query);
-bool ProcessBanishAccount(TDatabase *Database, TQuery *Query);
-bool ProcessSetNotation(TDatabase *Database, TQuery *Query);
-bool ProcessReportStatement(TDatabase *Database, TQuery *Query);
-bool ProcessBanishIpAddress(TDatabase *Database, TQuery *Query);
-bool ProcessLogCharacterDeath(TDatabase *Database, TQuery *Query);
-bool ProcessAddBuddy(TDatabase *Database, TQuery *Query);
-bool ProcessRemoveBuddy(TDatabase *Database, TQuery *Query);
-bool ProcessDecrementIsOnline(TDatabase *Database, TQuery *Query);
-bool ProcessFinishAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessTransferHouses(TDatabase *Database, TQuery *Query);
-bool ProcessEvictFreeAccounts(TDatabase *Database, TQuery *Query);
-bool ProcessEvictDeletedCharacters(TDatabase *Database, TQuery *Query);
-bool ProcessEvictExGuildleaders(TDatabase *Database, TQuery *Query);
-bool ProcessInsertHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessUpdateHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessDeleteHouseOwner(TDatabase *Database, TQuery *Query);
-bool ProcessGetHouseOwners(TDatabase *Database, TQuery *Query);
-bool ProcessGetAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessStartAuction(TDatabase *Database, TQuery *Query);
-bool ProcessInsertHouses(TDatabase *Database, TQuery *Query);
-bool ProcessClearIsOnline(TDatabase *Database, TQuery *Query);
-bool ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query);
-bool ProcessLogKilledCreatures(TDatabase *Database, TQuery *Query);
-bool ProcessLoadPlayers(TDatabase *Database, TQuery *Query);
-bool ProcessExcludeFromAuctions(TDatabase *Database, TQuery *Query);
-bool ProcessCancelHouseTransfer(TDatabase *Database, TQuery *Query);
-bool ProcessLoadWorldConfig(TDatabase *Database, TQuery *Query);
-bool ProcessCreateAccount(TDatabase *Database, TQuery *Query);
-bool ProcessCreateCharacter(TDatabase *Database, TQuery *Query);
-bool ProcessGetAccountSummary(TDatabase *Database, TQuery *Query);
-bool ProcessGetCharacterProfile(TDatabase *Database, TQuery *Query);
-bool ProcessGetWorlds(TDatabase *Database, TQuery *Query);
-bool ProcessGetOnlineCharacters(TDatabase *Database, TQuery *Query);
-bool ProcessGetKillStatistics(TDatabase *Database, TQuery *Query);
+void ProcessInternalResolveWorld(TDatabase *Database, TQuery *Query);
+void ProcessCheckAccountPassword(TDatabase *Database, TQuery *Query);
+void ProcessLoginAccount(TDatabase *Database, TQuery *Query);
+void ProcessLoginGame(TDatabase *Database, TQuery *Query);
+void ProcessLogoutGame(TDatabase *Database, TQuery *Query);
+void ProcessSetNamelock(TDatabase *Database, TQuery *Query);
+void ProcessBanishAccount(TDatabase *Database, TQuery *Query);
+void ProcessSetNotation(TDatabase *Database, TQuery *Query);
+void ProcessReportStatement(TDatabase *Database, TQuery *Query);
+void ProcessBanishIpAddress(TDatabase *Database, TQuery *Query);
+void ProcessLogCharacterDeath(TDatabase *Database, TQuery *Query);
+void ProcessAddBuddy(TDatabase *Database, TQuery *Query);
+void ProcessRemoveBuddy(TDatabase *Database, TQuery *Query);
+void ProcessDecrementIsOnline(TDatabase *Database, TQuery *Query);
+void ProcessFinishAuctions(TDatabase *Database, TQuery *Query);
+void ProcessTransferHouses(TDatabase *Database, TQuery *Query);
+void ProcessEvictFreeAccounts(TDatabase *Database, TQuery *Query);
+void ProcessEvictDeletedCharacters(TDatabase *Database, TQuery *Query);
+void ProcessEvictExGuildleaders(TDatabase *Database, TQuery *Query);
+void ProcessInsertHouseOwner(TDatabase *Database, TQuery *Query);
+void ProcessUpdateHouseOwner(TDatabase *Database, TQuery *Query);
+void ProcessDeleteHouseOwner(TDatabase *Database, TQuery *Query);
+void ProcessGetHouseOwners(TDatabase *Database, TQuery *Query);
+void ProcessGetAuctions(TDatabase *Database, TQuery *Query);
+void ProcessStartAuction(TDatabase *Database, TQuery *Query);
+void ProcessInsertHouses(TDatabase *Database, TQuery *Query);
+void ProcessClearIsOnline(TDatabase *Database, TQuery *Query);
+void ProcessCreatePlayerlist(TDatabase *Database, TQuery *Query);
+void ProcessLogKilledCreatures(TDatabase *Database, TQuery *Query);
+void ProcessLoadPlayers(TDatabase *Database, TQuery *Query);
+void ProcessExcludeFromAuctions(TDatabase *Database, TQuery *Query);
+void ProcessCancelHouseTransfer(TDatabase *Database, TQuery *Query);
+void ProcessLoadWorldConfig(TDatabase *Database, TQuery *Query);
+void ProcessCreateAccount(TDatabase *Database, TQuery *Query);
+void ProcessCreateCharacter(TDatabase *Database, TQuery *Query);
+void ProcessGetAccountSummary(TDatabase *Database, TQuery *Query);
+void ProcessGetCharacterProfile(TDatabase *Database, TQuery *Query);
+void ProcessGetWorlds(TDatabase *Database, TQuery *Query);
+void ProcessGetOnlineCharacters(TDatabase *Database, TQuery *Query);
+void ProcessGetKillStatistics(TDatabase *Database, TQuery *Query);
// connections.cc
//==============================================================================