diff options
Diffstat (limited to 'src/database.cc')
| -rw-r--r-- | src/database.cc | 266 |
1 files changed, 256 insertions, 10 deletions
diff --git a/src/database.cc b/src/database.cc index d9c2815..429f357 100644 --- a/src/database.cc +++ b/src/database.cc @@ -100,18 +100,46 @@ void ExitStatementCache(void){ // Queries //============================================================================== +bool LoadWorldID(const char *WorldName, int *WorldID){ + ASSERT(WorldName && WorldID); + sqlite3_stmt *Stmt = PrepareQuery( + "SELECT WorldID FROM Worlds WHERE Name = ?1"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_text(Stmt, 1, WorldName, -1, NULL) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldName: %s", sqlite3_errmsg(g_Database)); + return false; + } -bool LoadHouseOwners(const char *WorldName, DynamicArray<THouseOwner> *HouseOwners){ - ASSERT(WorldName && HouseOwners); + if(sqlite3_step(Stmt) != SQLITE_ROW){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + *WorldID = sqlite3_column_int(Stmt, 0); + return true; +} + +bool LoadHouseOwners(int WorldID, DynamicArray<THouseOwner> *HouseOwners){ + ASSERT(HouseOwners); sqlite3_stmt *Stmt = PrepareQuery( - "SELECT HouseID, OwnerID, Characters.Name, PaidUntil" - " FROM HouseOwners" - " LEFT JOIN Characters ON Characters.CharacterID = OwnerID"); + "SELECT O.HouseID, O.OwnerID, C.Name, O.PaidUntil" + " FROM HouseOwners AS O" + " LEFT JOIN Characters AS C ON C.CharacterID = O.OwnerID" + " WHERE O.WorldID = ?1"); if(Stmt == NULL){ LOG_ERR("Failed to prepare query"); return false; } + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + while(sqlite3_step(Stmt) == SQLITE_ROW){ THouseOwner Owner = {}; Owner.HouseID = sqlite3_column_int(Stmt, 0); @@ -130,19 +158,237 @@ bool LoadHouseOwners(const char *WorldName, DynamicArray<THouseOwner> *HouseOwne return true; } -bool LoadWorldConfig(const char *WorldName, TWorldConfig *WorldConfig){ - ASSERT(WorldName && WorldConfig); +bool DeleteHouses(int WorldID){ + sqlite3_stmt *Stmt = PrepareQuery( + "DELETE FROM Houses WHERE WorldID = ?1"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + return true; +} + +bool InsertHouses(int WorldID, int NumHouses, THouse *Houses){ + sqlite3_stmt *Stmt = PrepareQuery( + "INSERT INTO Houses (WorldID, HouseID, Name, Rent, Description," + " Size, PositionX, PositionY, PositionZ, Town, GuildHouse)" + " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + for(int i = 0; i < NumHouses; i += 1){ + if(sqlite3_bind_int(Stmt, 2, Houses[i].HouseID) != SQLITE_OK + || sqlite3_bind_text(Stmt, 3, Houses[i].Name, -1, NULL) != SQLITE_OK + || sqlite3_bind_int(Stmt, 4, Houses[i].Rent) != SQLITE_OK + || sqlite3_bind_text(Stmt, 5, Houses[i].Description, -1, NULL) != SQLITE_OK + || sqlite3_bind_int(Stmt, 6, Houses[i].Size) != SQLITE_OK + || sqlite3_bind_int(Stmt, 7, Houses[i].PositionX) != SQLITE_OK + || sqlite3_bind_int(Stmt, 8, Houses[i].PositionY) != SQLITE_OK + || sqlite3_bind_int(Stmt, 9, Houses[i].PositionZ) != SQLITE_OK + || sqlite3_bind_text(Stmt, 10, Houses[i].Town, -1, NULL) != SQLITE_OK + || sqlite3_bind_int(Stmt, 11, Houses[i].GuildHouse ? 1: 0) != SQLITE_OK){ + LOG_ERR("Failed to bind parameters for house %d: %s", + Houses[i].HouseID, sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to insert house %d: %s", + Houses[i].HouseID, sqlite3_errmsg(g_Database)); + return false; + } + + sqlite3_reset(Stmt); + } + + return true; +} + +bool ClearIsOnline(int WorldID, int *NumAffectedCharacters){ + sqlite3_stmt *Stmt = PrepareQuery( + "UPDATE Characters SET IsOnline = 0" + " WHERE WorldID = ?1 AND IsOnline != 0"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + *NumAffectedCharacters = sqlite3_changes(g_Database); + return true; +} + +bool DeleteOnlineCharacters(int WorldID){ + sqlite3_stmt *Stmt = PrepareQuery( + "DELETE FROM OnlineCharacters WHERE WorldID = ?1"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + return true; +} + +bool InsertOnlineCharacters(int WorldID, int NumCharacters, TOnlineCharacter *Characters){ + sqlite3_stmt *Stmt = PrepareQuery( + "INSERT INTO OnlineCharacters (WorldID, Name, Level, Profession)" + " VALUES (?1, ?2, ?3, ?4)"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + for(int i = 0; i < NumCharacters; i += 1){ + if(sqlite3_bind_text(Stmt, 2, Characters[i].Name, -1, NULL) != SQLITE_OK + || sqlite3_bind_int(Stmt, 3, Characters[i].Level) != SQLITE_OK + || sqlite3_bind_text(Stmt, 4, Characters[i].Profession, -1, NULL) != SQLITE_OK){ + LOG_ERR("Failed to bind parameters for character \"%s\": %s", + Characters[i].Name, sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to insert character \"%s\": %s", + Characters[i].Name, sqlite3_errmsg(g_Database)); + return false; + } + + sqlite3_reset(Stmt); + } + + return true; +} + +bool CheckOnlineRecord(int WorldID, int NumCharacters, bool *NewRecord){ + ASSERT(NewRecord); + sqlite3_stmt *Stmt = PrepareQuery( + "UPDATE Worlds SET OnlineRecord = ?2" + " WHERE WorldID = ?1 AND OnlineRecord < ?2"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_bind_int(Stmt, 2, NumCharacters) != SQLITE_OK){ + LOG_ERR("Failed to bind NumCharacters: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_step(Stmt) != SQLITE_DONE){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + *NewRecord = sqlite3_changes(g_Database) > 0; + return true; +} + +bool LoadCharacterIndex(int WorldID, int MinimumCharacterID, + int MaxEntries, int *NumEntries, TCharacterIndexEntry *Entries){ + ASSERT(MaxEntries > 0 && NumEntries && Entries); + sqlite3_stmt *Stmt = PrepareQuery( + "SELECT CharacterID, Name FROM Characters" + " WHERE WorldID = ?1 AND CharacterID >= ?2" + " ORDER BY CharacterID ASC LIMIT ?3"); + if(Stmt == NULL){ + LOG_ERR("Failed to prepare query"); + return false; + } + + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_bind_int(Stmt, 2, MinimumCharacterID) != SQLITE_OK){ + LOG_ERR("Failed to bind MinimumCharacterID: %s", sqlite3_errmsg(g_Database)); + return false; + } + + if(sqlite3_bind_int(Stmt, 3, MaxEntries) != SQLITE_OK){ + LOG_ERR("Failed to bind MaxEntries: %s", sqlite3_errmsg(g_Database)); + return false; + } + + // NOTE(fusion): We shouldn't get more than `MaxEntries` rows but it's + // always better to be safe. + int EntryIndex = 0; + while(sqlite3_step(Stmt) == SQLITE_ROW && EntryIndex < MaxEntries){ + Entries[EntryIndex].CharacterID = sqlite3_column_int(Stmt, 0); + StringCopy(Entries[EntryIndex].Name, + sizeof(Entries[EntryIndex].Name), + (const char *)sqlite3_column_text(Stmt, 1)); + } + + if(sqlite3_errcode(g_Database) != SQLITE_DONE){ + LOG_ERR("Failed to execute query: %s", sqlite3_errmsg(g_Database)); + return false; + } + + *NumEntries = EntryIndex; + return true; +} + +bool LoadWorldConfig(int WorldID, TWorldConfig *WorldConfig){ + ASSERT(WorldConfig); sqlite3_stmt *Stmt = PrepareQuery( "SELECT Type, RebootTime, Address, Port, MaxPlayers," " PremiumPlayerBuffer, MaxNewbies, PremiumNewbieBuffer" - " FROM Worlds WHERE Name = ?1"); + " FROM Worlds WHERE WorldID = ?1"); if(Stmt == NULL){ LOG_ERR("Failed to prepare query"); return false; } - if(sqlite3_bind_text(Stmt, 1, WorldName, -1, NULL) != SQLITE_OK){ - LOG_ERR("Failed to bind WorldName: %s", sqlite3_errmsg(g_Database)); + if(sqlite3_bind_int(Stmt, 1, WorldID) != SQLITE_OK){ + LOG_ERR("Failed to bind WorldID: %s", sqlite3_errmsg(g_Database)); return false; } |
