From 4b27350bdf720b2a4ab7de5f3355d79bd5ef93d9 Mon Sep 17 00:00:00 2001 From: David Markowitz Date: Wed, 8 Nov 2023 01:47:55 -0800 Subject: [PATCH] Update CDComponentsRegistryTable.h Database: Rename and add further comments Datavbase: Add comments Add some comments Build: Fix PCH directories Database: Fix time thanks apple Database: Fix compiler warnings Overload destructor Define specialty for time_t Use string instead of string_view for temp empty string Update CDTable.h Property: Update queries to use mapId Database: Reorganize Reorganize into CDClient folder and GameDatabase folder for clearer meanings and file structure Folders: Rename to GameDatabase MySQL: Remove MySQL Specifier from table Database: Move Tables to Interfaces Database: Reorder functions in header Database: Simplify property queries Database: Remove unused queries Remove extra query definitions as well Database: Consolidate User getters Database: Comment logs Update MySQLDatabase.cpp Database: Use generic code Playkey: Fix bad optional access Database: Move stuff around WorldServer: Update queries Ugc reduced by many scopes use new queries very fast tested that ugc still loads Database: Add auth queries I tested that only the correct password can sign into an account. Tested that disabled playkeys do not allow the user to play the game Database: Add donation query Database: add objectId queries Database: Add master queries Database: Fix mis-named function Database: Add slash command queries Mail: Fix itemId type CharFilter: Use new query ObjectID: Remove duplicate code SlashCommand: Update query with function Database: Add mail queries Ugc: Fix issues with saving models Resolve large scope blocks as well --- CMakeLists.txt | 13 +- dChatFilter/dChatFilter.cpp | 3 +- dChatServer/ChatPacketHandler.cpp | 58 +- dCommon/BrickByBrickFix.cpp | 4 +- .../CDClientDatabase.cpp | 0 .../{ => CDClientDatabase}/CDClientDatabase.h | 0 .../CDClientManager.cpp | 0 .../{ => CDClientDatabase}/CDClientManager.h | 0 .../CDClientTables}/CDActivitiesTable.cpp | 0 .../CDClientTables}/CDActivitiesTable.h | 0 .../CDActivityRewardsTable.cpp | 0 .../CDClientTables}/CDActivityRewardsTable.h | 0 .../CDClientTables}/CDAnimationsTable.cpp | 0 .../CDClientTables}/CDAnimationsTable.h | 0 .../CDBehaviorParameterTable.cpp | 0 .../CDBehaviorParameterTable.h | 0 .../CDBehaviorTemplateTable.cpp | 0 .../CDClientTables}/CDBehaviorTemplateTable.h | 0 .../CDClientTables}/CDBrickIDTableTable.cpp | 0 .../CDClientTables}/CDBrickIDTableTable.h | 0 .../CDComponentsRegistryTable.cpp | 0 .../CDComponentsRegistryTable.h | 2 + .../CDClientTables}/CDCurrencyTableTable.cpp | 0 .../CDClientTables}/CDCurrencyTableTable.h | 0 .../CDDestructibleComponentTable.cpp | 0 .../CDDestructibleComponentTable.h | 0 .../CDClientTables}/CDEmoteTable.cpp | 0 .../CDClientTables}/CDEmoteTable.h | 0 .../CDClientTables}/CDFeatureGatingTable.cpp | 0 .../CDClientTables}/CDFeatureGatingTable.h | 0 .../CDInventoryComponentTable.cpp | 0 .../CDInventoryComponentTable.h | 0 .../CDClientTables}/CDItemComponentTable.cpp | 0 .../CDClientTables}/CDItemComponentTable.h | 0 .../CDClientTables}/CDItemSetSkillsTable.cpp | 0 .../CDClientTables}/CDItemSetSkillsTable.h | 0 .../CDClientTables}/CDItemSetsTable.cpp | 0 .../CDClientTables}/CDItemSetsTable.h | 0 .../CDLevelProgressionLookupTable.cpp | 0 .../CDLevelProgressionLookupTable.h | 0 .../CDClientTables}/CDLootMatrixTable.cpp | 0 .../CDClientTables}/CDLootMatrixTable.h | 0 .../CDClientTables}/CDLootTableTable.cpp | 0 .../CDClientTables}/CDLootTableTable.h | 0 .../CDClientTables}/CDMissionEmailTable.cpp | 0 .../CDClientTables}/CDMissionEmailTable.h | 0 .../CDMissionNPCComponentTable.cpp | 0 .../CDMissionNPCComponentTable.h | 0 .../CDClientTables}/CDMissionTasksTable.cpp | 0 .../CDClientTables}/CDMissionTasksTable.h | 0 .../CDClientTables}/CDMissionsTable.cpp | 0 .../CDClientTables}/CDMissionsTable.h | 0 .../CDMovementAIComponentTable.cpp | 0 .../CDMovementAIComponentTable.h | 0 .../CDClientTables}/CDObjectSkillsTable.cpp | 0 .../CDClientTables}/CDObjectSkillsTable.h | 0 .../CDClientTables}/CDObjectsTable.cpp | 0 .../CDClientTables}/CDObjectsTable.h | 0 .../CDPackageComponentTable.cpp | 0 .../CDClientTables}/CDPackageComponentTable.h | 0 .../CDPhysicsComponentTable.cpp | 0 .../CDClientTables}/CDPhysicsComponentTable.h | 0 .../CDPropertyEntranceComponentTable.cpp | 0 .../CDPropertyEntranceComponentTable.h | 0 .../CDPropertyTemplateTable.cpp | 0 .../CDClientTables}/CDPropertyTemplateTable.h | 0 .../CDProximityMonitorComponentTable.cpp | 0 .../CDProximityMonitorComponentTable.h | 0 .../CDRailActivatorComponent.cpp | 0 .../CDRailActivatorComponent.h | 0 .../CDClientTables}/CDRarityTableTable.cpp | 0 .../CDClientTables}/CDRarityTableTable.h | 0 .../CDRebuildComponentTable.cpp | 0 .../CDClientTables}/CDRebuildComponentTable.h | 0 .../CDClientTables}/CDRewardsTable.cpp | 0 .../CDClientTables}/CDRewardsTable.h | 0 .../CDScriptComponentTable.cpp | 0 .../CDClientTables}/CDScriptComponentTable.h | 0 .../CDClientTables}/CDSkillBehaviorTable.cpp | 0 .../CDClientTables}/CDSkillBehaviorTable.h | 0 .../CDClientTables}/CDTable.h | 0 .../CDVendorComponentTable.cpp | 0 .../CDClientTables}/CDVendorComponentTable.h | 0 .../CDClientTables}/CDZoneTableTable.cpp | 0 .../CDClientTables}/CDZoneTableTable.h | 0 .../CDClientTables}/CMakeLists.txt | 2 +- dDatabase/CDClientDatabase/CMakeLists.txt | 12 + dDatabase/CMakeLists.txt | 17 +- dDatabase/Databases/CMakeLists.txt | 4 - dDatabase/Databases/DatabaseStructs.h | 104 --- dDatabase/Databases/GameDatabase.h | 89 -- dDatabase/Databases/MySQLDatabase.cpp | 786 ------------------ dDatabase/Databases/MySQLDatabase.h | 98 --- dDatabase/GameDatabase/CMakeLists.txt | 12 + dDatabase/{ => GameDatabase}/Database.cpp | 4 +- dDatabase/{ => GameDatabase}/Database.h | 2 +- dDatabase/GameDatabase/GameDatabase.h | 49 ++ dDatabase/GameDatabase/ITables/IAccounts.h | 37 + dDatabase/GameDatabase/ITables/IActivityLog.h | 19 + dDatabase/GameDatabase/ITables/IBugReports.h | 20 + dDatabase/GameDatabase/ITables/ICharInfo.h | 49 ++ dDatabase/GameDatabase/ITables/ICharXml.h | 20 + dDatabase/GameDatabase/ITables/ICommandLog.h | 14 + dDatabase/GameDatabase/ITables/IFriends.h | 32 + dDatabase/GameDatabase/ITables/ILeaderboard.h | 14 + dDatabase/GameDatabase/ITables/IMail.h | 54 ++ .../GameDatabase/ITables/IMigrationHistory.h | 17 + .../GameDatabase/ITables/IObjectIdTracker.h | 19 + dDatabase/GameDatabase/ITables/IPetNames.h | 21 + dDatabase/GameDatabase/ITables/IPlayKeys.h | 15 + .../ITables/IPlayerCheatDetections.h | 20 + dDatabase/GameDatabase/ITables/IProperty.h | 38 + .../GameDatabase/ITables/IPropertyContents.h | 40 + dDatabase/GameDatabase/ITables/IServers.h | 21 + dDatabase/GameDatabase/ITables/IUgc.h | 32 + .../{ => GameDatabase}/MigrationRunner.cpp | 3 +- .../{ => GameDatabase}/MigrationRunner.h | 0 dDatabase/GameDatabase/MySQL/CMakeLists.txt | 11 + .../GameDatabase/MySQL/MySQLDatabase.cpp | 113 +++ dDatabase/GameDatabase/MySQL/MySQLDatabase.h | 245 ++++++ .../GameDatabase/MySQL/Tables/Accounts.cpp | 37 + .../GameDatabase/MySQL/Tables/ActivityLog.cpp | 6 + .../GameDatabase/MySQL/Tables/BugReports.cpp | 6 + .../GameDatabase/MySQL/Tables/CMakeLists.txt | 22 + .../GameDatabase/MySQL/Tables/CharInfo.cpp | 78 ++ .../GameDatabase/MySQL/Tables/CharXml.cpp | 19 + .../GameDatabase/MySQL/Tables/CommandLog.cpp | 5 + .../GameDatabase/MySQL/Tables/Friends.cpp | 73 ++ .../GameDatabase/MySQL/Tables/Leaderboard.cpp | 11 + dDatabase/GameDatabase/MySQL/Tables/Mail.cpp | 84 ++ .../MySQL/Tables/MigrationHistory.cpp | 13 + .../MySQL/Tables/ObjectIdTracker.cpp | 17 + .../GameDatabase/MySQL/Tables/PetNames.cpp | 26 + .../GameDatabase/MySQL/Tables/PlayKeys.cpp | 11 + .../MySQL/Tables/PlayerCheatDetections.cpp | 7 + .../GameDatabase/MySQL/Tables/Property.cpp | 57 ++ .../MySQL/Tables/PropertyContents.cpp | 54 ++ .../GameDatabase/MySQL/Tables/Servers.cpp | 23 + dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp | 71 ++ dGame/User.cpp | 15 +- dGame/UserManager.cpp | 22 +- dGame/dComponents/DonationVendorComponent.cpp | 6 +- dGame/dComponents/PetComponent.cpp | 2 +- .../PropertyManagementComponent.cpp | 64 +- dGame/dGameMessages/GameMessageHandler.h | 2 +- dGame/dGameMessages/GameMessages.cpp | 52 +- dGame/dUtilities/CheatDetection.cpp | 11 +- dGame/dUtilities/Mail.cpp | 103 +-- dGame/dUtilities/SlashCommandHandler.cpp | 83 +- dMasterServer/MasterServer.cpp | 41 +- dMasterServer/ObjectIDManager.cpp | 49 +- dMasterServer/ObjectIDManager.h | 2 +- dNet/AuthPackets.cpp | 90 +- dNet/ClientPackets.cpp | 19 +- dWorldServer/WorldServer.cpp | 141 ++-- 155 files changed, 1829 insertions(+), 1606 deletions(-) rename dDatabase/{ => CDClientDatabase}/CDClientDatabase.cpp (100%) rename dDatabase/{ => CDClientDatabase}/CDClientDatabase.h (100%) rename dDatabase/{ => CDClientDatabase}/CDClientManager.cpp (100%) rename dDatabase/{ => CDClientDatabase}/CDClientManager.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDActivitiesTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDActivitiesTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDActivityRewardsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDActivityRewardsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDAnimationsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDAnimationsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBehaviorParameterTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBehaviorParameterTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBehaviorTemplateTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBehaviorTemplateTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBrickIDTableTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDBrickIDTableTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDComponentsRegistryTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDComponentsRegistryTable.h (96%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDCurrencyTableTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDCurrencyTableTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDDestructibleComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDDestructibleComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDEmoteTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDEmoteTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDFeatureGatingTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDFeatureGatingTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDInventoryComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDInventoryComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemSetSkillsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemSetSkillsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemSetsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDItemSetsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLevelProgressionLookupTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLevelProgressionLookupTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLootMatrixTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLootMatrixTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLootTableTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDLootTableTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionEmailTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionEmailTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionNPCComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionNPCComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionTasksTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionTasksTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMissionsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMovementAIComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDMovementAIComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDObjectSkillsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDObjectSkillsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDObjectsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDObjectsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPackageComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPackageComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPhysicsComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPhysicsComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPropertyEntranceComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPropertyEntranceComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPropertyTemplateTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDPropertyTemplateTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDProximityMonitorComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDProximityMonitorComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRailActivatorComponent.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRailActivatorComponent.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRarityTableTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRarityTableTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRebuildComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRebuildComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRewardsTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDRewardsTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDScriptComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDScriptComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDSkillBehaviorTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDSkillBehaviorTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDVendorComponentTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDVendorComponentTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDZoneTableTable.cpp (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CDZoneTableTable.h (100%) rename dDatabase/{Tables => CDClientDatabase/CDClientTables}/CMakeLists.txt (93%) create mode 100644 dDatabase/CDClientDatabase/CMakeLists.txt delete mode 100644 dDatabase/Databases/CMakeLists.txt delete mode 100644 dDatabase/Databases/DatabaseStructs.h delete mode 100644 dDatabase/Databases/GameDatabase.h delete mode 100644 dDatabase/Databases/MySQLDatabase.cpp delete mode 100644 dDatabase/Databases/MySQLDatabase.h create mode 100644 dDatabase/GameDatabase/CMakeLists.txt rename dDatabase/{ => GameDatabase}/Database.cpp (88%) rename dDatabase/{ => GameDatabase}/Database.h (71%) create mode 100644 dDatabase/GameDatabase/GameDatabase.h create mode 100644 dDatabase/GameDatabase/ITables/IAccounts.h create mode 100644 dDatabase/GameDatabase/ITables/IActivityLog.h create mode 100644 dDatabase/GameDatabase/ITables/IBugReports.h create mode 100644 dDatabase/GameDatabase/ITables/ICharInfo.h create mode 100644 dDatabase/GameDatabase/ITables/ICharXml.h create mode 100644 dDatabase/GameDatabase/ITables/ICommandLog.h create mode 100644 dDatabase/GameDatabase/ITables/IFriends.h create mode 100644 dDatabase/GameDatabase/ITables/ILeaderboard.h create mode 100644 dDatabase/GameDatabase/ITables/IMail.h create mode 100644 dDatabase/GameDatabase/ITables/IMigrationHistory.h create mode 100644 dDatabase/GameDatabase/ITables/IObjectIdTracker.h create mode 100644 dDatabase/GameDatabase/ITables/IPetNames.h create mode 100644 dDatabase/GameDatabase/ITables/IPlayKeys.h create mode 100644 dDatabase/GameDatabase/ITables/IPlayerCheatDetections.h create mode 100644 dDatabase/GameDatabase/ITables/IProperty.h create mode 100644 dDatabase/GameDatabase/ITables/IPropertyContents.h create mode 100644 dDatabase/GameDatabase/ITables/IServers.h create mode 100644 dDatabase/GameDatabase/ITables/IUgc.h rename dDatabase/{ => GameDatabase}/MigrationRunner.cpp (97%) rename dDatabase/{ => GameDatabase}/MigrationRunner.h (100%) create mode 100644 dDatabase/GameDatabase/MySQL/CMakeLists.txt create mode 100644 dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp create mode 100644 dDatabase/GameDatabase/MySQL/MySQLDatabase.h create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/ActivityLog.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/BugReports.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt create mode 100644 dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/CharXml.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/CommandLog.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Friends.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Leaderboard.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Mail.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/MigrationHistory.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/ObjectIdTracker.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/PetNames.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/PlayKeys.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/PlayerCheatDetections.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Property.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Servers.cpp create mode 100644 dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c251e728..635f5f446 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,8 +214,12 @@ set(INCLUDED_DIRECTORIES "dNavigation/dTerrain" "dZoneManager" "dDatabase" - "dDatabase/Tables" - "dDatabase/Databases" + "dDatabase/CDClientDatabase" + "dDatabase/CDClientDatabase/CDClientTables" + "dDatabase/GameDatabase" + "dDatabase/GameDatabase/ITables" + "dDatabase/GameDatabase/MySQL" + "dDatabase/GameDatabase/MySQL/Tables" "dNet" "dScripts" "dScripts/02_server" @@ -330,8 +334,9 @@ add_subdirectory(thirdparty) file( GLOB HEADERS_DDATABASE LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dDatabase/*.h - ${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h + ${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h + ${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h + ${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h ) diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index cec849321..6e81db3b8 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -33,8 +33,7 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { //Read player names that are ok as well: auto approvedNames = Database::Get()->GetApprovedCharacterNames(); - if (!approvedNames) return; - for (auto& name : approvedNames->names) { + for (auto& name : approvedNames) { std::transform(name.begin(), name.end(), name.begin(), ::tolower); //Transform to lowercase m_ApprovedWords.push_back(CalculateHash(name)); } diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index e4e147216..982521d86 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -31,34 +31,32 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { if (!player) return; auto friendsList = Database::Get()->GetFriendsList(playerID); - if (friendsList) { - for (const auto& friendData : friendsList->friends) { - FriendData fd; - fd.isFTP = false; // not a thing in DLU - fd.friendID = friendData.friendID; - GeneralUtils::SetBit(fd.friendID, eObjectBits::PERSISTENT); - GeneralUtils::SetBit(fd.friendID, eObjectBits::CHARACTER); - - fd.isBestFriend = friendData.isBestFriend; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs - if (fd.isBestFriend) player->countOfBestFriends += 1; - fd.friendName = friendData.friendName; - - //Now check if they're online: - auto fr = playerContainer.GetPlayerData(fd.friendID); - - if (fr) { - fd.isOnline = true; - fd.zoneID = fr->zoneID; - - //Since this friend is online, we need to update them on the fact that we've just logged in: - SendFriendUpdate(fr, player, 1, fd.isBestFriend); - } else { - fd.isOnline = false; - fd.zoneID = LWOZONEID(); - } - - player->friends.push_back(fd); + for (const auto& friendData : friendsList) { + FriendData fd; + fd.isFTP = false; // not a thing in DLU + fd.friendID = friendData.friendID; + GeneralUtils::SetBit(fd.friendID, eObjectBits::PERSISTENT); + GeneralUtils::SetBit(fd.friendID, eObjectBits::CHARACTER); + + fd.isBestFriend = friendData.isBestFriend; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs + if (fd.isBestFriend) player->countOfBestFriends += 1; + fd.friendName = friendData.friendName; + + //Now check if they're online: + auto fr = playerContainer.GetPlayerData(fd.friendID); + + if (fr) { + fd.isOnline = true; + fd.zoneID = fr->zoneID; + + //Since this friend is online, we need to update them on the fact that we've just logged in: + SendFriendUpdate(fr, player, 1, fd.isBestFriend); + } else { + fd.isOnline = false; + fd.zoneID = LWOZONEID(); } + + player->friends.push_back(fd); } //Now, we need to send the friendlist to the server they came from: @@ -142,7 +140,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { if (!requestee) { requestee.reset(new PlayerData()); requestee->playerName = playerName; - auto responseType = Database::Get()->DoesCharacterExist(playerName) + auto responseType = Database::Get()->GetCharacterInfo(playerName) ? eAddFriendResponseType::NOTONLINE : eAddFriendResponseType::INVALIDCHARACTER; @@ -300,9 +298,9 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { //we'll have to query the db here to find the user, since you can delete them while they're offline. //First, we need to find their ID: LWOOBJID friendID = 0; - auto friendIdResult = Database::Get()->GetAccountIdFromCharacterName(friendName); + auto friendIdResult = Database::Get()->GetCharacterInfo(friendName); if (friendIdResult) { - friendID = friendIdResult.value(); + friendID = friendIdResult->id; } // Convert friendID to LWOOBJID diff --git a/dCommon/BrickByBrickFix.cpp b/dCommon/BrickByBrickFix.cpp index 9669cdbc8..f8a9e0220 100644 --- a/dCommon/BrickByBrickFix.cpp +++ b/dCommon/BrickByBrickFix.cpp @@ -23,7 +23,7 @@ bool CheckSd0Magic(std::istream& streamToCheck); */ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() { uint32_t modelsTruncated{}; - auto modelsToTruncate = Database::Get()->GetUgcModels(); + auto modelsToTruncate = Database::Get()->GetAllUgcModels(); bool previousCommitValue = Database::Get()->GetAutoCommit(); Database::Get()->SetAutoCommit(false); for (auto& model : modelsToTruncate) { @@ -95,7 +95,7 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() { */ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() { uint32_t updatedModels = 0; - auto modelsToUpdate = Database::Get()->GetUgcModels(); + auto modelsToUpdate = Database::Get()->GetAllUgcModels(); auto previousAutoCommitState = Database::Get()->GetAutoCommit(); Database::Get()->SetAutoCommit(false); for (auto& model : modelsToUpdate) { diff --git a/dDatabase/CDClientDatabase.cpp b/dDatabase/CDClientDatabase/CDClientDatabase.cpp similarity index 100% rename from dDatabase/CDClientDatabase.cpp rename to dDatabase/CDClientDatabase/CDClientDatabase.cpp diff --git a/dDatabase/CDClientDatabase.h b/dDatabase/CDClientDatabase/CDClientDatabase.h similarity index 100% rename from dDatabase/CDClientDatabase.h rename to dDatabase/CDClientDatabase/CDClientDatabase.h diff --git a/dDatabase/CDClientManager.cpp b/dDatabase/CDClientDatabase/CDClientManager.cpp similarity index 100% rename from dDatabase/CDClientManager.cpp rename to dDatabase/CDClientDatabase/CDClientManager.cpp diff --git a/dDatabase/CDClientManager.h b/dDatabase/CDClientDatabase/CDClientManager.h similarity index 100% rename from dDatabase/CDClientManager.h rename to dDatabase/CDClientDatabase/CDClientManager.h diff --git a/dDatabase/Tables/CDActivitiesTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDActivitiesTable.cpp similarity index 100% rename from dDatabase/Tables/CDActivitiesTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDActivitiesTable.cpp diff --git a/dDatabase/Tables/CDActivitiesTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDActivitiesTable.h similarity index 100% rename from dDatabase/Tables/CDActivitiesTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDActivitiesTable.h diff --git a/dDatabase/Tables/CDActivityRewardsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDActivityRewardsTable.cpp similarity index 100% rename from dDatabase/Tables/CDActivityRewardsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDActivityRewardsTable.cpp diff --git a/dDatabase/Tables/CDActivityRewardsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDActivityRewardsTable.h similarity index 100% rename from dDatabase/Tables/CDActivityRewardsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDActivityRewardsTable.h diff --git a/dDatabase/Tables/CDAnimationsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDAnimationsTable.cpp similarity index 100% rename from dDatabase/Tables/CDAnimationsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDAnimationsTable.cpp diff --git a/dDatabase/Tables/CDAnimationsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDAnimationsTable.h similarity index 100% rename from dDatabase/Tables/CDAnimationsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDAnimationsTable.h diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDBehaviorParameterTable.cpp similarity index 100% rename from dDatabase/Tables/CDBehaviorParameterTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDBehaviorParameterTable.cpp diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDBehaviorParameterTable.h similarity index 100% rename from dDatabase/Tables/CDBehaviorParameterTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDBehaviorParameterTable.h diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDBehaviorTemplateTable.cpp similarity index 100% rename from dDatabase/Tables/CDBehaviorTemplateTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDBehaviorTemplateTable.cpp diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDBehaviorTemplateTable.h similarity index 100% rename from dDatabase/Tables/CDBehaviorTemplateTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDBehaviorTemplateTable.h diff --git a/dDatabase/Tables/CDBrickIDTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDBrickIDTableTable.cpp similarity index 100% rename from dDatabase/Tables/CDBrickIDTableTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDBrickIDTableTable.cpp diff --git a/dDatabase/Tables/CDBrickIDTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDBrickIDTableTable.h similarity index 100% rename from dDatabase/Tables/CDBrickIDTableTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDBrickIDTableTable.h diff --git a/dDatabase/Tables/CDComponentsRegistryTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDComponentsRegistryTable.cpp similarity index 100% rename from dDatabase/Tables/CDComponentsRegistryTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDComponentsRegistryTable.cpp diff --git a/dDatabase/Tables/CDComponentsRegistryTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDComponentsRegistryTable.h similarity index 96% rename from dDatabase/Tables/CDComponentsRegistryTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDComponentsRegistryTable.h index fc4619890..fce4f6aaf 100644 --- a/dDatabase/Tables/CDComponentsRegistryTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDComponentsRegistryTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + enum class eReplicaComponentType : uint32_t; struct CDComponentsRegistry { unsigned int id; //!< The LOT is used as the ID diff --git a/dDatabase/Tables/CDCurrencyTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDCurrencyTableTable.cpp similarity index 100% rename from dDatabase/Tables/CDCurrencyTableTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDCurrencyTableTable.cpp diff --git a/dDatabase/Tables/CDCurrencyTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDCurrencyTableTable.h similarity index 100% rename from dDatabase/Tables/CDCurrencyTableTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDCurrencyTableTable.h diff --git a/dDatabase/Tables/CDDestructibleComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDDestructibleComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDDestructibleComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDDestructibleComponentTable.cpp diff --git a/dDatabase/Tables/CDDestructibleComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDDestructibleComponentTable.h similarity index 100% rename from dDatabase/Tables/CDDestructibleComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDDestructibleComponentTable.h diff --git a/dDatabase/Tables/CDEmoteTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDEmoteTable.cpp similarity index 100% rename from dDatabase/Tables/CDEmoteTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDEmoteTable.cpp diff --git a/dDatabase/Tables/CDEmoteTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDEmoteTable.h similarity index 100% rename from dDatabase/Tables/CDEmoteTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDEmoteTable.h diff --git a/dDatabase/Tables/CDFeatureGatingTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp similarity index 100% rename from dDatabase/Tables/CDFeatureGatingTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp diff --git a/dDatabase/Tables/CDFeatureGatingTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h similarity index 100% rename from dDatabase/Tables/CDFeatureGatingTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h diff --git a/dDatabase/Tables/CDInventoryComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDInventoryComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDInventoryComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDInventoryComponentTable.cpp diff --git a/dDatabase/Tables/CDInventoryComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDInventoryComponentTable.h similarity index 100% rename from dDatabase/Tables/CDInventoryComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDInventoryComponentTable.h diff --git a/dDatabase/Tables/CDItemComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDItemComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDItemComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDItemComponentTable.cpp diff --git a/dDatabase/Tables/CDItemComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDItemComponentTable.h similarity index 100% rename from dDatabase/Tables/CDItemComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDItemComponentTable.h diff --git a/dDatabase/Tables/CDItemSetSkillsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDItemSetSkillsTable.cpp similarity index 100% rename from dDatabase/Tables/CDItemSetSkillsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDItemSetSkillsTable.cpp diff --git a/dDatabase/Tables/CDItemSetSkillsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDItemSetSkillsTable.h similarity index 100% rename from dDatabase/Tables/CDItemSetSkillsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDItemSetSkillsTable.h diff --git a/dDatabase/Tables/CDItemSetsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.cpp similarity index 100% rename from dDatabase/Tables/CDItemSetsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.cpp diff --git a/dDatabase/Tables/CDItemSetsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.h similarity index 100% rename from dDatabase/Tables/CDItemSetsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDItemSetsTable.h diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDLevelProgressionLookupTable.cpp similarity index 100% rename from dDatabase/Tables/CDLevelProgressionLookupTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDLevelProgressionLookupTable.cpp diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDLevelProgressionLookupTable.h similarity index 100% rename from dDatabase/Tables/CDLevelProgressionLookupTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDLevelProgressionLookupTable.h diff --git a/dDatabase/Tables/CDLootMatrixTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDLootMatrixTable.cpp similarity index 100% rename from dDatabase/Tables/CDLootMatrixTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDLootMatrixTable.cpp diff --git a/dDatabase/Tables/CDLootMatrixTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDLootMatrixTable.h similarity index 100% rename from dDatabase/Tables/CDLootMatrixTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDLootMatrixTable.h diff --git a/dDatabase/Tables/CDLootTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp similarity index 100% rename from dDatabase/Tables/CDLootTableTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp diff --git a/dDatabase/Tables/CDLootTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h similarity index 100% rename from dDatabase/Tables/CDLootTableTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h diff --git a/dDatabase/Tables/CDMissionEmailTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionEmailTable.cpp similarity index 100% rename from dDatabase/Tables/CDMissionEmailTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionEmailTable.cpp diff --git a/dDatabase/Tables/CDMissionEmailTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionEmailTable.h similarity index 100% rename from dDatabase/Tables/CDMissionEmailTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionEmailTable.h diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDMissionNPCComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h similarity index 100% rename from dDatabase/Tables/CDMissionNPCComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h diff --git a/dDatabase/Tables/CDMissionTasksTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp similarity index 100% rename from dDatabase/Tables/CDMissionTasksTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp diff --git a/dDatabase/Tables/CDMissionTasksTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h similarity index 100% rename from dDatabase/Tables/CDMissionTasksTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h diff --git a/dDatabase/Tables/CDMissionsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp similarity index 100% rename from dDatabase/Tables/CDMissionsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp diff --git a/dDatabase/Tables/CDMissionsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h similarity index 100% rename from dDatabase/Tables/CDMissionsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h diff --git a/dDatabase/Tables/CDMovementAIComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDMovementAIComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp diff --git a/dDatabase/Tables/CDMovementAIComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h similarity index 100% rename from dDatabase/Tables/CDMovementAIComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h diff --git a/dDatabase/Tables/CDObjectSkillsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp similarity index 100% rename from dDatabase/Tables/CDObjectSkillsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp diff --git a/dDatabase/Tables/CDObjectSkillsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h similarity index 100% rename from dDatabase/Tables/CDObjectSkillsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h diff --git a/dDatabase/Tables/CDObjectsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp similarity index 100% rename from dDatabase/Tables/CDObjectsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp diff --git a/dDatabase/Tables/CDObjectsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h similarity index 100% rename from dDatabase/Tables/CDObjectsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h diff --git a/dDatabase/Tables/CDPackageComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPackageComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDPackageComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDPackageComponentTable.cpp diff --git a/dDatabase/Tables/CDPackageComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPackageComponentTable.h similarity index 100% rename from dDatabase/Tables/CDPackageComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDPackageComponentTable.h diff --git a/dDatabase/Tables/CDPhysicsComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDPhysicsComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp diff --git a/dDatabase/Tables/CDPhysicsComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h similarity index 100% rename from dDatabase/Tables/CDPhysicsComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPropertyEntranceComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDPropertyEntranceComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDPropertyEntranceComponentTable.cpp diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPropertyEntranceComponentTable.h similarity index 100% rename from dDatabase/Tables/CDPropertyEntranceComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDPropertyEntranceComponentTable.h diff --git a/dDatabase/Tables/CDPropertyTemplateTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPropertyTemplateTable.cpp similarity index 100% rename from dDatabase/Tables/CDPropertyTemplateTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDPropertyTemplateTable.cpp diff --git a/dDatabase/Tables/CDPropertyTemplateTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPropertyTemplateTable.h similarity index 100% rename from dDatabase/Tables/CDPropertyTemplateTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDPropertyTemplateTable.h diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDProximityMonitorComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDProximityMonitorComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDProximityMonitorComponentTable.cpp diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDProximityMonitorComponentTable.h similarity index 100% rename from dDatabase/Tables/CDProximityMonitorComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDProximityMonitorComponentTable.h diff --git a/dDatabase/Tables/CDRailActivatorComponent.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDRailActivatorComponent.cpp similarity index 100% rename from dDatabase/Tables/CDRailActivatorComponent.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDRailActivatorComponent.cpp diff --git a/dDatabase/Tables/CDRailActivatorComponent.h b/dDatabase/CDClientDatabase/CDClientTables/CDRailActivatorComponent.h similarity index 100% rename from dDatabase/Tables/CDRailActivatorComponent.h rename to dDatabase/CDClientDatabase/CDClientTables/CDRailActivatorComponent.h diff --git a/dDatabase/Tables/CDRarityTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDRarityTableTable.cpp similarity index 100% rename from dDatabase/Tables/CDRarityTableTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDRarityTableTable.cpp diff --git a/dDatabase/Tables/CDRarityTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDRarityTableTable.h similarity index 100% rename from dDatabase/Tables/CDRarityTableTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDRarityTableTable.h diff --git a/dDatabase/Tables/CDRebuildComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDRebuildComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDRebuildComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDRebuildComponentTable.cpp diff --git a/dDatabase/Tables/CDRebuildComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDRebuildComponentTable.h similarity index 100% rename from dDatabase/Tables/CDRebuildComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDRebuildComponentTable.h diff --git a/dDatabase/Tables/CDRewardsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDRewardsTable.cpp similarity index 100% rename from dDatabase/Tables/CDRewardsTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDRewardsTable.cpp diff --git a/dDatabase/Tables/CDRewardsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDRewardsTable.h similarity index 100% rename from dDatabase/Tables/CDRewardsTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDRewardsTable.h diff --git a/dDatabase/Tables/CDScriptComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDScriptComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDScriptComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDScriptComponentTable.cpp diff --git a/dDatabase/Tables/CDScriptComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDScriptComponentTable.h similarity index 100% rename from dDatabase/Tables/CDScriptComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDScriptComponentTable.h diff --git a/dDatabase/Tables/CDSkillBehaviorTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDSkillBehaviorTable.cpp similarity index 100% rename from dDatabase/Tables/CDSkillBehaviorTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDSkillBehaviorTable.cpp diff --git a/dDatabase/Tables/CDSkillBehaviorTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDSkillBehaviorTable.h similarity index 100% rename from dDatabase/Tables/CDSkillBehaviorTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDSkillBehaviorTable.h diff --git a/dDatabase/Tables/CDTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDTable.h similarity index 100% rename from dDatabase/Tables/CDTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDTable.h diff --git a/dDatabase/Tables/CDVendorComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDVendorComponentTable.cpp similarity index 100% rename from dDatabase/Tables/CDVendorComponentTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDVendorComponentTable.cpp diff --git a/dDatabase/Tables/CDVendorComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDVendorComponentTable.h similarity index 100% rename from dDatabase/Tables/CDVendorComponentTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDVendorComponentTable.h diff --git a/dDatabase/Tables/CDZoneTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp similarity index 100% rename from dDatabase/Tables/CDZoneTableTable.cpp rename to dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp diff --git a/dDatabase/Tables/CDZoneTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h similarity index 100% rename from dDatabase/Tables/CDZoneTableTable.h rename to dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h diff --git a/dDatabase/Tables/CMakeLists.txt b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt similarity index 93% rename from dDatabase/Tables/CMakeLists.txt rename to dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt index b6a02b02d..43ff52b21 100644 --- a/dDatabase/Tables/CMakeLists.txt +++ b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt @@ -1,4 +1,4 @@ -set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp" +set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp" "CDActivityRewardsTable.cpp" "CDAnimationsTable.cpp" "CDBehaviorParameterTable.cpp" diff --git a/dDatabase/CDClientDatabase/CMakeLists.txt b/dDatabase/CDClientDatabase/CMakeLists.txt new file mode 100644 index 000000000..2645c2155 --- /dev/null +++ b/dDatabase/CDClientDatabase/CMakeLists.txt @@ -0,0 +1,12 @@ +set(DDATABASE_CDCLIENTDATABASE_SOURCES + "CDClientDatabase.cpp" + "CDClientManager.cpp" +) + +add_subdirectory(CDClientTables) + +foreach(file ${DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES}) + set(DDATABASE_CDCLIENTDATABASE_SOURCES ${DDATABASE_CDCLIENTDATABASE_SOURCES} "CDClientTables/${file}") +endforeach() + +set(DDATABASE_CDCLIENTDATABASE_SOURCES ${DDATABASE_CDCLIENTDATABASE_SOURCES} PARENT_SCOPE) diff --git a/dDatabase/CMakeLists.txt b/dDatabase/CMakeLists.txt index 610738d20..20f37becf 100644 --- a/dDatabase/CMakeLists.txt +++ b/dDatabase/CMakeLists.txt @@ -1,18 +1,15 @@ -set(DDATABASE_SOURCES "CDClientDatabase.cpp" - "CDClientManager.cpp" - "Database.cpp" - "MigrationRunner.cpp") +set(DDATABASE_SOURCES) -add_subdirectory(Tables) +add_subdirectory(CDClientDatabase) -foreach(file ${DDATABASE_TABLES_SOURCES}) - set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Tables/${file}") +foreach(file ${DDATABASE_CDCLIENTDATABASE_SOURCES}) + set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "CDClientDatabase/${file}") endforeach() -add_subdirectory(Databases) +add_subdirectory(GameDatabase) -foreach(file ${DDATABASE_DATABASES_SOURCES}) - set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Databases/${file}") +foreach(file ${DDATABASE_GAMEDATABASE_SOURCES}) + set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "GameDatabase/${file}") endforeach() add_library(dDatabase STATIC ${DDATABASE_SOURCES}) diff --git a/dDatabase/Databases/CMakeLists.txt b/dDatabase/Databases/CMakeLists.txt deleted file mode 100644 index aacee82fe..000000000 --- a/dDatabase/Databases/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(DDATABASE_DATABASES_SOURCES - "MySQLDatabase.cpp" - PARENT_SCOPE -) diff --git a/dDatabase/Databases/DatabaseStructs.h b/dDatabase/Databases/DatabaseStructs.h deleted file mode 100644 index f67463768..000000000 --- a/dDatabase/Databases/DatabaseStructs.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __DATABASESTRUCTS__H__ -#define __DATABASESTRUCTS__H__ - -#include -#include -#include -#include - -#include "dCommonVars.h" -#include "eGameMasterLevel.h" -#include "ePermissionMap.h" -#include "NiQuaternion.h" - -enum class eActivityType : uint32_t { - PlayerLoggedIn, - PlayerLoggedOut, -}; - -// Contains various structures used as return values from database queries. -namespace DatabaseStructs { - struct MasterInfo { - std::string ip; - uint32_t port; - }; - - struct ApprovedNames { - std::vector names; - }; - - struct FriendsList { - std::vector friends; - }; - - struct BestFriendStatus { - uint32_t playerAccountId; - uint32_t friendAccountId; - uint32_t bestFriendStatus; - }; - - struct UgcModel { - LWOOBJID id; - std::stringstream lxfmlData; - }; - - struct CharacterInfo { - std::string name; - std::string pendingName; - bool needsRename; - LWOCLONEID cloneId; - ePermissionMap permissionMap; - }; - - struct UserInfo { - uint32_t accountId; - eGameMasterLevel maxGMLevel; - }; - - struct PetNameInfo { - std::string petName; - int32_t approvalStatus; - }; - - struct PropertyInfo { - LWOOBJID id; - LWOOBJID ownerId; - LWOCLONEID cloneId; - std::string name; - std::string description; - int32_t privacyOption; - std::string rejectionReason; - uint32_t modApproved; - uint32_t lastUpdatedTime; - uint32_t claimedTime; - uint32_t reputation; - }; - - struct DatabaseModel { - LWOOBJID id; - LOT lot; - NiPoint3 position; - NiQuaternion rotation; - LWOOBJID ugcId; - }; - - struct PropertyModerationInfo { - std::string rejectionReason; - uint32_t modApproved; - }; - - struct MailInsert { - std::string senderUsername; - std::string recipient; - std::string subject; - std::string body; - uint32_t senderId{}; - uint32_t receiverId{}; - int32_t attachmentCount{}; - uint32_t itemID{}; - LOT itemLOT{}; - LWOOBJID subkey{}; - }; -}; - -#endif //!__DATABASESTRUCTS__H__ diff --git a/dDatabase/Databases/GameDatabase.h b/dDatabase/Databases/GameDatabase.h deleted file mode 100644 index c398bcd4a..000000000 --- a/dDatabase/Databases/GameDatabase.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __GAMEDATABASE__H__ -#define __GAMEDATABASE__H__ - -#include "DatabaseStructs.h" -#include - -namespace sql { - class Statement; - class PreparedStatement; -}; - -class GameDatabase { -public: - virtual void Connect() = 0; - virtual void Destroy(std::string source = "", bool log = true) = 0; - virtual sql::Statement* CreateStmt() = 0; - virtual sql::PreparedStatement* CreatePreppedStmt(const std::string& query) = 0; - virtual void Commit() = 0; - virtual bool GetAutoCommit() = 0; - virtual void SetAutoCommit(bool value) = 0; - - virtual std::optional GetMasterInfo() = 0; - virtual std::optional GetApprovedCharacterNames() = 0; - virtual std::optional GetFriendsList(const uint32_t charID) = 0; - virtual std::optional DoesCharacterExist(const std::string& name) = 0; - virtual std::optional GetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId) = 0; - virtual void SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) = 0; - virtual void AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) = 0; - virtual std::optional GetAccountIdFromCharacterName(const std::string& name) = 0; - virtual void RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) = 0; - virtual void UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) = 0; - virtual void DeleteUgcModelData(const LWOOBJID& modelId) = 0; - virtual void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) = 0; - virtual std::vector GetUgcModels() = 0; - virtual void CreateMigrationHistoryTable() = 0; - virtual bool IsMigrationRun(const std::string_view str) = 0; - virtual void InsertMigration(const std::string_view str) = 0; - virtual std::optional GetCharacterInfo(const uint32_t charId) = 0; - virtual std::string GetCharacterXml(const uint32_t charId) = 0; - virtual void UpdateCharacterXml(const uint32_t charId, const std::string_view lxfml) = 0; - virtual std::optional GetUserInfo(const std::string_view username) = 0; - virtual std::optional GetLastUsedCharacterId(const uint32_t accountId) = 0; - virtual bool IsUsernameAvailable(const std::string_view username) = 0; - virtual void InsertNewCharacter(const uint32_t accountId, const uint32_t characterId, const std::string_view name, const std::string_view pendingName) = 0; - virtual void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) = 0; - virtual std::vector GetCharacterIds(uint32_t accountId) = 0; - virtual bool IsCharacterIdInUse(const uint32_t characterId) = 0; - virtual void DeleteCharacter(const uint32_t characterId) = 0; - virtual void SetCharacterName(const uint32_t characterId, const std::string_view name) = 0; - virtual void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) = 0; - virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0; - virtual void SetPetNameModerationStatus(const LWOOBJID& petId, const std::string_view name, const int32_t approvalStatus) = 0; - virtual std::optional GetPetNameInfo(const LWOOBJID& petId) = 0; - virtual std::optional GetPropertyInfo(const uint32_t templateId, const uint32_t cloneId) = 0; - virtual void UpdatePropertyModerationInfo(const LWOOBJID& id, const uint32_t privacyOption, const std::string_view rejectionReason, const uint32_t modApproved) = 0; - virtual void UpdatePropertyDetails(const LWOOBJID& id, const std::string_view name, const std::string_view description) = 0; - virtual void InsertNewProperty( - const LWOOBJID& propertyId, - const uint32_t characterId, - const uint32_t templateId, - const uint32_t cloneId, - const std::string_view name, - const std::string_view description, - const uint32_t zoneId) = 0; - - virtual std::vector GetPropertyModels(const LWOOBJID& propertyId) = 0; - virtual void RemoveUnreferencedUgcModels() = 0; - virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const DatabaseStructs::DatabaseModel& model, const std::string_view name) = 0; - virtual void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) = 0; - virtual void RemoveModel(const LWOOBJID& modelId) = 0; - virtual std::vector GetPropertyModelIds(const LWOOBJID& propertyId) = 0; - virtual std::string GetCharacterNameForCloneId(const uint32_t cloneId) = 0; - virtual std::optional GetPropertyModerationInfo(const LWOOBJID& propertyId) = 0; - virtual void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) = 0; - virtual void InsertNewBugReport( - const std::string_view body, - const std::string_view clientVersion, - const std::string_view otherPlayer, - const std::string_view selection, - const uint32_t characterId) = 0; - virtual void InsertCheatDetection( - std::optional userId, - const std::string_view username, - const std::string_view systemAddress, - const std::string_view extraMessage) = 0; - virtual void InsertNewMail(const DatabaseStructs::MailInsert& mail) = 0; -}; - -#endif //!__GAMEDATABASE__H__ diff --git a/dDatabase/Databases/MySQLDatabase.cpp b/dDatabase/Databases/MySQLDatabase.cpp deleted file mode 100644 index aeeec4fea..000000000 --- a/dDatabase/Databases/MySQLDatabase.cpp +++ /dev/null @@ -1,786 +0,0 @@ -#include "MySQLDatabase.h" - -#include "Database.h" -#include "Game.h" -#include "dConfig.h" -#include "Logger.h" - -using namespace DatabaseStructs; - -namespace { - sql::Driver* driver; - sql::Connection* con; - sql::Properties properties; - std::string databaseName; -}; - -void MySQLDatabase::Connect() { - driver = sql::mariadb::get_driver_instance(); - - // The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where - // 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the - // presence of a / - // 2) even avoiding that, the connector still assumes you're connecting with a tcp socket - // So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost, - // which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate - // property manually (which the URL parsing fails to do) - const std::string UNIX_PROTO = "unix://"; - const std::string PIPE_PROTO = "pipe://"; - std::string mysql_host = Game::config->GetValue("mysql_host"); - if (mysql_host.find(UNIX_PROTO) == 0) { - properties["hostName"] = "unix://localhost"; - properties["localSocket"] = mysql_host.substr(UNIX_PROTO.length()).c_str(); - } else if (mysql_host.find(PIPE_PROTO) == 0) { - properties["hostName"] = "pipe://localhost"; - properties["pipe"] = mysql_host.substr(PIPE_PROTO.length()).c_str(); - } else { - properties["hostName"] = mysql_host.c_str(); - } - properties["user"] = Game::config->GetValue("mysql_username").c_str(); - properties["password"] = Game::config->GetValue("mysql_password").c_str(); - properties["autoReconnect"] = "true"; - - databaseName = Game::config->GetValue("mysql_database").c_str(); - - // `connect(const Properties& props)` segfaults in windows debug, but - // `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly - if (properties.find("localSocket") != properties.end() || properties.find("pipe") != properties.end()) { - con = driver->connect(properties); - } else { - con = driver->connect(properties["hostName"].c_str(), properties["user"].c_str(), properties["password"].c_str()); - } - con->setSchema(databaseName.c_str()); -} - -void MySQLDatabase::Destroy(std::string source, bool log) { - if (!con) return; - - if (log) { - if (source != "") LOG("Destroying MySQL connection from %s!", source.c_str()); - else LOG("Destroying MySQL connection!"); - } - - con->close(); - delete con; -} - -sql::Statement* MySQLDatabase::CreateStmt() { - sql::Statement* toReturn = con->createStatement(); - return toReturn; -} - -std::unique_ptr MySQLDatabase::CreatePreppedStmtUnique(const std::string& query) { - auto* stmt = CreatePreppedStmt(query); - return std::unique_ptr(stmt); -} - -sql::PreparedStatement* MySQLDatabase::CreatePreppedStmt(const std::string& query) { - const char* test = query.c_str(); - size_t size = query.length(); - sql::SQLString str(test, size); - - if (!con) { - Connect(); - LOG("Trying to reconnect to MySQL"); - } - - if (!con->isValid() || con->isClosed()) { - delete con; - - con = nullptr; - - Connect(); - LOG("Trying to reconnect to MySQL from invalid or closed connection"); - } - - auto* stmt = con->prepareStatement(str); - - return stmt; -} - -void MySQLDatabase::Commit() { - con->commit(); -} - -bool MySQLDatabase::GetAutoCommit() { - // TODO This should not just access a pointer. A future PR should update this - // to check for null and throw an error if the connection is not valid. - return con->getAutoCommit(); -} - -void MySQLDatabase::SetAutoCommit(bool value) { - // TODO This should not just access a pointer. A future PR should update this - // to check for null and throw an error if the connection is not valid. - con->setAutoCommit(value); -} - -std::unique_ptr MySQLDatabase::ExecuteQueryUnique(const std::string& query) { - auto* result = CreatePreppedStmtUnique(query)->executeQuery(); - return std::unique_ptr(result); -} - -std::unique_ptr MySQLDatabase::ExecuteQueryUnique(const std::unique_ptr& query) { - auto* result = query->executeQuery(); - return std::unique_ptr(result); -} - -// queries -std::optional MySQLDatabase::GetMasterInfo() { - - auto result = ExecuteQueryUnique("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;"); - - if (!result->next()) { - return std::nullopt; - } - - MasterInfo toReturn; - - toReturn.ip = result->getString("ip").c_str(); - toReturn.port = result->getInt("port"); - - return toReturn; -} - -std::optional MySQLDatabase::GetApprovedCharacterNames() { - auto result = ExecuteQueryUnique("SELECT name FROM charinfo;"); - - ApprovedNames toReturn; - if (!result->next()) return std::nullopt; - - do { - toReturn.names.push_back(result->getString("name").c_str()); - } while (result->next()); - - return toReturn; -} - -std::optional MySQLDatabase::GetFriendsList(const uint32_t charId) { - auto stmt = CreatePreppedStmtUnique( - R"QUERY( - SELECT fr.requested_player, best_friend, ci.name FROM - ( - SELECT CASE - WHEN player_id = ? THEN friend_id - WHEN friend_id = ? THEN player_id - END AS requested_player, best_friend FROM friends - ) AS fr - JOIN charinfo AS ci ON ci.id = fr.requested_player - WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?; - )QUERY"); - stmt->setUInt(1, charId); - stmt->setUInt(2, charId); - stmt->setUInt(3, charId); - - FriendsList toReturn; - - auto friendsList = ExecuteQueryUnique(stmt); - - if (!friendsList->next()) { - return std::nullopt; - } - - toReturn.friends.reserve(friendsList->rowsCount()); - - do { - FriendData fd; - fd.friendID = friendsList->getUInt(1); - fd.isBestFriend = friendsList->getInt(2) == 3; // 0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs - fd.friendName = friendsList->getString(3).c_str(); - - toReturn.friends.push_back(fd); - } while (friendsList->next()); - return toReturn; -} - -std::optional MySQLDatabase::DoesCharacterExist(const std::string& name) { - auto nameQuery(CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE name = ? LIMIT 1;")); - nameQuery->setString(1, name); - auto result(nameQuery->executeQuery()); - if (!result->next()) { - return std::nullopt; - } - return result->getUInt("id"); -} - -std::optional MySQLDatabase::GetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId) { - auto friendUpdate = CreatePreppedStmtUnique("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); - friendUpdate->setUInt(1, playerAccountId); - friendUpdate->setUInt(2, friendAccountId); - friendUpdate->setUInt(3, friendAccountId); - friendUpdate->setUInt(4, playerAccountId); - auto result(ExecuteQueryUnique(friendUpdate)); - - if (!result->next()) { - return std::nullopt; - } - - BestFriendStatus toReturn; - toReturn.playerAccountId = result->getUInt("player_id"); - toReturn.friendAccountId = result->getUInt("friend_id"); - toReturn.bestFriendStatus = result->getUInt("best_friend"); - - return toReturn; -} - -void MySQLDatabase::SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) { - auto updateQuery = CreatePreppedStmtUnique("UPDATE friends SET best_friend = ? WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); - updateQuery->setUInt(1, bestFriendStatus); - updateQuery->setUInt(2, playerAccountId); - updateQuery->setUInt(3, friendAccountId); - updateQuery->setUInt(4, friendAccountId); - updateQuery->setUInt(5, playerAccountId); - updateQuery->executeUpdate(); -} - -void MySQLDatabase::AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) { - auto friendUpdate = CreatePreppedStmtUnique("INSERT IGNORE INTO friends (player_id, friend_id, best_friend) VALUES (?, ?, 0);"); - friendUpdate->setUInt(1, playerAccountId); - friendUpdate->setUInt(2, friendAccountId); - friendUpdate->execute(); -} - -std::optional MySQLDatabase::GetAccountIdFromCharacterName(const std::string& name) { - auto nameQuery(CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE name = ? LIMIT 1;")); - nameQuery->setString(1, name); - auto result(nameQuery->executeQuery()); - - if (!result->next()) { - return std::nullopt; - } - - return result->getUInt(1); -} - -void MySQLDatabase::RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) { - auto friendUpdate = CreatePreppedStmtUnique("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); - friendUpdate->setUInt(1, playerAccountId); - friendUpdate->setUInt(2, friendAccountId); - friendUpdate->setUInt(3, friendAccountId); - friendUpdate->setUInt(4, playerAccountId); - friendUpdate->execute(); -} - -void MySQLDatabase::UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) { - auto activityUpdate = CreatePreppedStmtUnique("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);"); - activityUpdate->setUInt(1, accountId); - activityUpdate->setUInt(2, static_cast(activityType)); - activityUpdate->setUInt(3, static_cast(time(NULL))); // UNIX_TIMESTAMP() - activityUpdate->setUInt(4, mapId); - activityUpdate->execute(); -} - -void MySQLDatabase::DeleteUgcModelData(const LWOOBJID& modelId) { - { - auto deleteQuery = CreatePreppedStmtUnique("DELETE FROM ugc WHERE id = ?;"); - deleteQuery->setUInt64(1, modelId); - deleteQuery->execute(); - } - { - auto deleteQuery = CreatePreppedStmtUnique("DELETE FROM properties_contents WHERE ugc_id = ?;"); - deleteQuery->setUInt64(1, modelId); - deleteQuery->execute(); - } -} - -void MySQLDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) { - auto update = CreatePreppedStmtUnique("UPDATE ugc SET lxfml = ? WHERE id = ?;"); - update->setBlob(1, &lxfml); - update->setUInt64(2, modelId); - update->executeUpdate(); -} - -std::vector MySQLDatabase::GetUgcModels() { - auto result = ExecuteQueryUnique("SELECT id, lxfml FROM ugc;"); - - std::vector models; - models.reserve(result->rowsCount()); - while (result->next()) { - UgcModel model; - model.id = result->getInt64("id"); - - // shoutouts mariadb - auto blob = result->getBlob("lxfml"); - model.lxfmlData << blob->rdbuf(); - delete blob; - models.push_back(std::move(model)); - } - return std::move(models); -} - -void MySQLDatabase::CreateMigrationHistoryTable() { - ExecuteQueryUnique("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); -} - -bool MySQLDatabase::IsMigrationRun(const std::string_view str) { - auto stmt = CreatePreppedStmtUnique("SELECT name FROM migration_history WHERE name = ?;"); - stmt->setString(1, str.data()); - return ExecuteQueryUnique(stmt)->next(); -} - -void MySQLDatabase::InsertMigration(const std::string_view str) { - auto stmt = CreatePreppedStmtUnique("INSERT INTO migration_history (name) VALUES (?);"); - stmt->setString(1, str.data()); - stmt->execute(); -} - -std::optional MySQLDatabase::GetCharacterInfo(const uint32_t charId) { - auto stmt = CreatePreppedStmtUnique("SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id = ? LIMIT 1;"); - stmt->setUInt(1, charId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return std::nullopt; - } - - CharacterInfo toReturn; - toReturn.name = result->getString("name").c_str(); - toReturn.pendingName = result->getString("pending_name").c_str(); - toReturn.needsRename = result->getBoolean("needs_rename"); - toReturn.cloneId = result->getUInt64("prop_clone_id"); - toReturn.permissionMap = static_cast(result->getUInt("permission_map")); - - return toReturn; -} - -std::string MySQLDatabase::GetCharacterXml(const uint32_t charId) { - auto stmt = CreatePreppedStmtUnique("SELECT xml_data FROM charxml WHERE id = ? LIMIT 1;"); - stmt->setUInt(1, charId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return ""; - } - - return result->getString("xml_data").c_str(); -} - -void MySQLDatabase::UpdateCharacterXml(const uint32_t charId, const std::string_view lxfml) { - auto stmt = CreatePreppedStmtUnique("UPDATE charxml SET xml_data = ? WHERE id = ?;"); - stmt->setString(1, lxfml.data()); - stmt->setUInt(2, charId); - stmt->executeUpdate(); -} - -std::optional MySQLDatabase::GetUserInfo(const std::string_view username) { - auto stmt = CreatePreppedStmtUnique("SELECT id, gm_level FROM accounts WHERE name = ? LIMIT 1;"); - stmt->setString(1, username.data()); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return std::nullopt; - } - - UserInfo toReturn; - toReturn.accountId = result->getUInt("id"); - toReturn.maxGMLevel = static_cast(result->getInt("gm_level")); - - return toReturn; -} - -std::optional MySQLDatabase::GetLastUsedCharacterId(const uint32_t accountId) { - auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE account_id = ? ORDER BY last_login DESC LIMIT 1;"); - stmt->setUInt(1, accountId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return std::nullopt; - } - - return result->getUInt("id"); -} - -bool MySQLDatabase::IsUsernameAvailable(const std::string_view username) { - auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE name = ? OR pending_name = ? LIMIT 1;"); - stmt->setString(1, username.data()); - stmt->setString(2, username.data()); - auto result = ExecuteQueryUnique(stmt); - - return !result->next(); -} - -void MySQLDatabase::InsertNewCharacter(const uint32_t accountId, const uint32_t characterId, const std::string_view name, const std::string_view pendingName) { - auto stmt = CreatePreppedStmtUnique("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); - stmt->setUInt(1, characterId); - stmt->setUInt(2, accountId); - stmt->setString(3, name.data()); - stmt->setString(4, pendingName.data()); - stmt->setBoolean(5, false); - stmt->setUInt64(6, time(NULL)); // UNIX_TIMESTAMP() - stmt->execute(); -} - -void MySQLDatabase::InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) { - auto stmt = CreatePreppedStmtUnique("INSERT INTO `charxml` (`id`, `xml_data`) VALUES (?,?)"); - stmt->setUInt(1, accountId); - stmt->setString(2, lxfml.data()); - stmt->execute(); -} - -std::vector MySQLDatabase::GetCharacterIds(const uint32_t accountId) { - auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE account_id = ? ORDER BY last_login DESC LIMIT 4;"); - stmt->setUInt(1, accountId); - auto result = ExecuteQueryUnique(stmt); - - std::vector toReturn; - toReturn.reserve(result->rowsCount()); - while (result->next()) { - toReturn.push_back(result->getUInt("id")); - } - return toReturn; -} - -bool MySQLDatabase::IsCharacterIdInUse(const uint32_t characterId) { - auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE id = ?;"); - stmt->setUInt(1, characterId); - auto result = ExecuteQueryUnique(stmt); - - return result->next(); -} - -void MySQLDatabase::DeleteCharacter(const uint32_t characterId) { - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM charxml WHERE id=? LIMIT 1;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM command_log WHERE character_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM friends WHERE player_id=? OR friend_id=?;"); - stmt->setUInt(1, characterId); - stmt->setUInt(2, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM leaderboard WHERE character_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM properties_contents WHERE property_id IN (SELECT id FROM properties WHERE owner_id=?);"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM properties WHERE owner_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM ugc WHERE character_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM activity_log WHERE character_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM mail WHERE receiver_id=?;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } - { - auto stmt = CreatePreppedStmtUnique("DELETE FROM charinfo WHERE id=? LIMIT 1;"); - stmt->setUInt(1, characterId); - stmt->execute(); - } -} - -void MySQLDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) { - auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET name = ?, pending_name = '', needs_rename = 0, last_login = ? WHERE id = ? LIMIT 1;"); - stmt->setString(1, name.data()); - stmt->setUInt64(2, time(NULL)); // UNIX_TIMESTAMP() - stmt->setUInt(3, characterId); - stmt->executeUpdate(); -} - -void MySQLDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) { - auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET pending_name = ?, needs_rename = 0, last_login = ? WHERE id = ? LIMIT 1"); - - stmt->setString(1, name.data()); - stmt->setUInt64(2, time(NULL)); // UNIX_TIMESTAMP() - stmt->setUInt(3, characterId); - - stmt->executeUpdate(); -} - -void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { - auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1"); - stmt->setUInt64(1, time(NULL)); // UNIX_TIMESTAMP() - stmt->setUInt(2, characterId); - stmt->executeUpdate(); -} - -void MySQLDatabase::SetPetNameModerationStatus(const LWOOBJID& petId, const std::string_view name, const int32_t approvalStatus) { - auto stmt = CreatePreppedStmtUnique("INSERT INTO `pet_names` (`id`, `pet_name`, `approved`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE pet_name = ?, approved = ?;"); - stmt->setUInt64(1, petId); - stmt->setString(2, name.data()); - stmt->setInt(3, approvalStatus); - stmt->setString(4, name.data()); - stmt->setInt(5, approvalStatus); - stmt->execute(); -} - -std::optional MySQLDatabase::GetPetNameInfo(const LWOOBJID& petId) { - auto stmt = CreatePreppedStmtUnique("SELECT pet_name, approved FROM pet_names WHERE id = ? LIMIT 1;"); - stmt->setUInt64(1, petId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return std::nullopt; - } - - PetNameInfo toReturn; - toReturn.petName = result->getString("pet_name").c_str(); - toReturn.approvalStatus = result->getInt("approved"); - - return toReturn; -} - -std::optional MySQLDatabase::GetPropertyInfo(const uint32_t templateId, const uint32_t cloneId) { - auto propertyLookup = CreatePreppedStmtUnique( - "SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved FROM properties WHERE template_id = ? AND clone_id = ?;"); - - propertyLookup->setUInt(1, templateId); - propertyLookup->setUInt(2, cloneId); - - auto propertyEntry = ExecuteQueryUnique(propertyLookup); - - if (!propertyEntry->next()) { - return std::nullopt; - } - - PropertyInfo toReturn; - toReturn.id = propertyEntry->getUInt64("id"); - toReturn.ownerId = propertyEntry->getUInt64("owner_id"); - toReturn.cloneId = propertyEntry->getUInt64("clone_id"); - toReturn.name = propertyEntry->getString("name").c_str(); - toReturn.description = propertyEntry->getString("description").c_str(); - toReturn.privacyOption = propertyEntry->getInt("privacy_option"); - toReturn.rejectionReason = propertyEntry->getString("rejection_reason").c_str(); - toReturn.lastUpdatedTime = propertyEntry->getUInt("last_updated"); - toReturn.claimedTime = propertyEntry->getUInt("time_claimed"); - toReturn.reputation = propertyEntry->getUInt("reputation"); - toReturn.modApproved = propertyEntry->getUInt("mod_approved"); - - return toReturn; -} - -void MySQLDatabase::UpdatePropertyModerationInfo(const LWOOBJID& id, const uint32_t privacyOption, const std::string_view rejectionReason, const uint32_t modApproved) { - auto stmt = CreatePreppedStmtUnique("UPDATE properties SET privacy_option = ?, rejection_reason = ?, mod_approved = ? WHERE id = ? LIMIT 1;"); - stmt->setUInt(1, privacyOption); - stmt->setString(2, rejectionReason.data()); - stmt->setUInt(3, modApproved); - stmt->setUInt64(4, id); - stmt->executeUpdate(); -} - -void MySQLDatabase::UpdatePropertyDetails(const LWOOBJID& id, const std::string_view name, const std::string_view description) { - auto stmt = CreatePreppedStmtUnique("UPDATE properties SET name = ?, description = ? WHERE id = ? LIMIT 1;"); - stmt->setString(1, name.data()); - stmt->setString(2, description.data()); - stmt->setUInt64(3, id); - stmt->executeUpdate(); -} -void MySQLDatabase::InsertNewProperty( - const LWOOBJID& propertyId, - const uint32_t characterId, - const uint32_t templateId, - const uint32_t cloneId, - const std::string_view name, - const std::string_view description, - const uint32_t zoneId) { - auto insertion = CreatePreppedStmtUnique( - "INSERT INTO properties" - "(id, owner_id, template_id, clone_id, name, description, zone_id, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, performance_cost)" - "VALUES (?, ?, ?, ?, ?, ?, ?, 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, 0.0)" - ); - - insertion->setUInt64(1, propertyId); - insertion->setUInt(2, characterId); - insertion->setUInt(3, templateId); - insertion->setUInt(4, cloneId); - insertion->setString(5, name.data()); - insertion->setString(6, description.data()); - insertion->setUInt(7, zoneId); - insertion->execute(); -} - -std::vector MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) { - auto stmt = CreatePreppedStmtUnique("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;"); - stmt->setUInt64(1, propertyId); - auto result = ExecuteQueryUnique(stmt); - - std::vector toReturn; - toReturn.reserve(result->rowsCount()); - while (result->next()) { - DatabaseModel model; - model.id = result->getUInt64("id"); - model.lot = static_cast(result->getUInt("lot")); - model.position.x = result->getFloat("x"); - model.position.y = result->getFloat("y"); - model.position.z = result->getFloat("z"); - model.rotation.w = result->getFloat("rw"); - model.rotation.x = result->getFloat("rx"); - model.rotation.y = result->getFloat("ry"); - model.rotation.z = result->getFloat("rz"); - model.ugcId = result->getUInt64("ugc_id"); - toReturn.push_back(std::move(model)); - } - return toReturn; // RVO; allow compiler to elide the return. -} - -void MySQLDatabase::RemoveUnreferencedUgcModels() { - auto stmt = ExecuteQueryUnique("DELETE FROM ugc WHERE id NOT IN (SELECT ugc_id FROM properties_contents WHERE ugc_id IS NOT NULL);"); -} - -void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const DatabaseStructs::DatabaseModel& model, const std::string_view name) { - auto stmt = CreatePreppedStmtUnique( - "INSERT INTO properties_contents" - "(id, property_id, ugc_id, lot, x, y, z, rx, ry, rz, rw, model_name, model_description, behavior_1, behavior_2, behavior_3, behavior_4, behavior_5)" - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 18 - ); - - stmt->setUInt64(1, model.id); - stmt->setUInt64(2, propertyId); - stmt->setNull(3, sql::DataType::BIGINT); - stmt->setUInt(4, static_cast(model.lot)); - stmt->setFloat(5, model.position.x); - stmt->setFloat(6, model.position.y); - stmt->setFloat(7, model.position.z); - stmt->setFloat(8, model.rotation.x); - stmt->setFloat(9, model.rotation.y); - stmt->setFloat(10, model.rotation.z); - stmt->setFloat(11, model.rotation.w); - stmt->setString(12, name.data()); - stmt->setString(13, ""); // Model description. TODO implement this. - stmt->setInt(14, 0); // behavior 1. TODO implement this. - stmt->setInt(15, 0); // behavior 2. TODO implement this. - stmt->setInt(16, 0); // behavior 3. TODO implement this. - stmt->setInt(17, 0); // behavior 4. TODO implement this. - stmt->setInt(18, 0); // behavior 5. TODO implement this. - try { - stmt->execute(); - } catch (sql::SQLException& e) { - LOG("Error inserting new property model: %s", e.what()); - } -} - -void MySQLDatabase::UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) { - auto stmt = CreatePreppedStmtUnique("UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;"); - stmt->setFloat(1, position.x); - stmt->setFloat(2, position.y); - stmt->setFloat(3, position.z); - stmt->setFloat(4, rotation.x); - stmt->setFloat(5, rotation.y); - stmt->setFloat(6, rotation.z); - stmt->setFloat(7, rotation.w); - stmt->setUInt64(8, propertyId); - stmt->executeUpdate(); -} - -void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) { - auto stmt = CreatePreppedStmtUnique("DELETE FROM properties_contents WHERE id = ?;"); - stmt->setUInt(1, modelId); - stmt->execute(); -} - -std::vector MySQLDatabase::GetPropertyModelIds(const LWOOBJID& propertyId) { - auto stmt = CreatePreppedStmtUnique("SELECT id FROM properties_contents WHERE property_id = ?;"); - stmt->setUInt64(1, propertyId); - auto result = ExecuteQueryUnique(stmt); - - std::vector toReturn; - toReturn.reserve(result->rowsCount()); - while (result->next()) { - toReturn.push_back(result->getUInt64("id")); - } - return toReturn; // RVO; allow compiler to elide the return. -} - -std::string MySQLDatabase::GetCharacterNameForCloneId(const uint32_t cloneId) { - auto stmt = CreatePreppedStmtUnique("SELECT name FROM charinfo WHERE prop_clone_id = ? LIMIT 1;"); - stmt->setUInt(1, cloneId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return ""; - } - - return result->getString("name").c_str(); -} - -std::optional MySQLDatabase::GetPropertyModerationInfo(const LWOOBJID& propertyId) { - auto stmt = CreatePreppedStmtUnique("SELECT rejection_reason, mod_approved FROM properties WHERE id = ? LIMIT 1;"); - stmt->setUInt64(1, propertyId); - auto result = ExecuteQueryUnique(stmt); - - if (!result->next()) { - return std::nullopt; - } - - PropertyModerationInfo toReturn; - toReturn.rejectionReason = result->getString("rejection_reason").c_str(); - toReturn.modApproved = result->getUInt("mod_approved"); - - return toReturn; -} - -void MySQLDatabase::UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) { - auto stmt = CreatePreppedStmtUnique("UPDATE properties SET performance_cost = ? WHERE zone_id = ? AND clone_id = ? LIMIT 1;"); - stmt->setFloat(1, performanceCost); - stmt->setUInt(2, zoneId.GetMapID()); - stmt->setUInt(3, zoneId.GetCloneID()); - stmt->executeUpdate(); -} - -void MySQLDatabase::InsertNewBugReport( - const std::string_view body, - const std::string_view clientVersion, - const std::string_view otherPlayer, - const std::string_view selection, - const uint32_t characterId) { - auto insertBug = CreatePreppedStmtUnique("INSERT INTO `bug_reports`(body, client_version, other_player_id, selection, reporter_id) VALUES (?, ?, ?, ?, ?)"); - insertBug->setString(1, body.data()); - insertBug->setString(2, clientVersion.data()); - insertBug->setString(3, otherPlayer.data()); - insertBug->setString(4, selection.data()); - insertBug->setInt(5, characterId); - insertBug->execute(); -} - -void MySQLDatabase::InsertCheatDetection( - std::optional userId, - const std::string_view username, - const std::string_view systemAddress, - const std::string_view extraMessage) { - auto stmt = CreatePreppedStmtUnique("INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)"); - userId ? stmt->setInt(1, userId.value()) : stmt->setNull(1, sql::DataType::INTEGER); - stmt->setString(2, username.data()); - stmt->setString(3, extraMessage.data()); - stmt->setString(4, systemAddress.data()); - stmt->execute(); -} - -void MySQLDatabase::InsertNewMail(const DatabaseStructs::MailInsert& mail) { - auto stmt = CreatePreppedStmtUnique( - "INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)"); - stmt->setUInt(1, mail.senderId); - stmt->setString(2, mail.senderUsername.c_str()); - stmt->setUInt(3, mail.receiverId); - stmt->setString(4, mail.recipient.c_str()); - stmt->setUInt64(5, time(NULL)); - stmt->setString(6, mail.subject); - stmt->setString(7, mail.body); - stmt->setUInt(8, mail.itemID); - stmt->setInt(9, mail.itemLOT); - stmt->setInt(10, 0); - stmt->setInt(11, mail.attachmentCount); - stmt->execute(); -} diff --git a/dDatabase/Databases/MySQLDatabase.h b/dDatabase/Databases/MySQLDatabase.h deleted file mode 100644 index fd00aca42..000000000 --- a/dDatabase/Databases/MySQLDatabase.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef __MYSQLDATABASE__H__ -#define __MYSQLDATABASE__H__ - -#include -#include - -#include "GameDatabase.h" - -class MySQLDatabase : public GameDatabase { -public: - void Connect() override; - void Destroy(std::string source = "", bool log = true) override; - - sql::Statement* CreateStmt() override; - sql::PreparedStatement* CreatePreppedStmt(const std::string& query) override; - void Commit() override; - bool GetAutoCommit() override; - void SetAutoCommit(bool value) override; - - // Overloaded queries - std::optional GetMasterInfo() override; - - std::optional GetApprovedCharacterNames() override; - - std::optional GetFriendsList(uint32_t charID) override; - - // No optional needed here, since if we did that, we'd return a bool of a bool in essenece. - // Just return true if and only if the character name exists. - std::optional DoesCharacterExist(const std::string& name) override; - std::optional GetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId) override; - void SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) override; - void AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; - std::optional GetAccountIdFromCharacterName(const std::string& name) override; - void RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; - void UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) override; - void DeleteUgcModelData(const LWOOBJID& modelId) override; - void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) override; - std::vector GetUgcModels() override; - void CreateMigrationHistoryTable() override; - bool IsMigrationRun(const std::string_view str) override; - void InsertMigration(const std::string_view str) override; - std::optional GetCharacterInfo(const uint32_t accountId) override; - std::string GetCharacterXml(const uint32_t accountId) override; - void UpdateCharacterXml(const uint32_t accountId, const std::string_view lxfml) override; - std::optional GetUserInfo(const std::string_view username) override; - std::optional GetLastUsedCharacterId(uint32_t accountId) override; - bool IsUsernameAvailable(const std::string_view username) override; - void InsertNewCharacter(const uint32_t accountId, const uint32_t characterId, const std::string_view name, const std::string_view pendingName) override; - void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override; - std::vector GetCharacterIds(uint32_t accountId) override; - bool IsCharacterIdInUse(const uint32_t characterId) override; - void DeleteCharacter(const uint32_t characterId) override; - void SetCharacterName(const uint32_t characterId, const std::string_view name) override; - void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) override; - void UpdateLastLoggedInCharacter(const uint32_t characterId) override; - void SetPetNameModerationStatus(const LWOOBJID& petId, const std::string_view name, const int32_t approvalStatus) override; - std::optional GetPetNameInfo(const LWOOBJID& petId) override; - std::optional GetPropertyInfo(const uint32_t templateId, const uint32_t cloneId) override; - void UpdatePropertyModerationInfo(const LWOOBJID& id, const uint32_t privacyOption, const std::string_view rejectionReason, const uint32_t modApproved) override; - void UpdatePropertyDetails(const LWOOBJID& id, const std::string_view name, const std::string_view description) override; - void InsertNewProperty( - const LWOOBJID& propertyId, - const uint32_t characterId, - const uint32_t templateId, - const uint32_t cloneId, - const std::string_view name, - const std::string_view description, - const uint32_t zoneId) override; - std::vector GetPropertyModels(const LWOOBJID& propertyId) override; - void RemoveUnreferencedUgcModels() override; - void InsertNewPropertyModel(const LWOOBJID& propertyId, const DatabaseStructs::DatabaseModel& model, const std::string_view name) override; - void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) override; - void RemoveModel(const LWOOBJID& modelId) override; - std::vector GetPropertyModelIds(const LWOOBJID& propertyId) override; - std::string GetCharacterNameForCloneId(const uint32_t cloneId) override; - std::optional GetPropertyModerationInfo(const LWOOBJID& propertyId) override; - void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; - void InsertNewBugReport( - const std::string_view body, - const std::string_view clientVersion, - const std::string_view otherPlayer, - const std::string_view selection, - const uint32_t characterId) override; - void InsertCheatDetection( - std::optional userId, - const std::string_view username, - const std::string_view systemAddress, - const std::string_view extraMessage) override; - void InsertNewMail(const DatabaseStructs::MailInsert& mail) override; -private: - std::unique_ptr CreatePreppedStmtUnique(const std::string& query); - - std::unique_ptr ExecuteQueryUnique(const std::string& query); - std::unique_ptr ExecuteQueryUnique(const std::unique_ptr& query); - -}; - -#endif //!__MYSQLDATABASE__H__ diff --git a/dDatabase/GameDatabase/CMakeLists.txt b/dDatabase/GameDatabase/CMakeLists.txt new file mode 100644 index 000000000..c32007bb7 --- /dev/null +++ b/dDatabase/GameDatabase/CMakeLists.txt @@ -0,0 +1,12 @@ +set(DDATABASE_GAMEDATABASE_SOURCES + "Database.cpp" + "MigrationRunner.cpp" +) + +add_subdirectory(MySQL) + +foreach(file ${DDATABSE_DATABSES_MYSQL_SOURCES}) + set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "MySQL/${file}") +endforeach() + +set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} PARENT_SCOPE) diff --git a/dDatabase/Database.cpp b/dDatabase/GameDatabase/Database.cpp similarity index 88% rename from dDatabase/Database.cpp rename to dDatabase/GameDatabase/Database.cpp index 82b83b083..cb4f989a3 100644 --- a/dDatabase/Database.cpp +++ b/dDatabase/GameDatabase/Database.cpp @@ -29,9 +29,9 @@ GameDatabase* Database::Get() { return database; } -void Database::Destroy(std::string source, bool log) { +void Database::Destroy(std::string source) { if (database) { - database->Destroy(source, log); + database->Destroy(source); delete database; database = nullptr; } else { diff --git a/dDatabase/Database.h b/dDatabase/GameDatabase/Database.h similarity index 71% rename from dDatabase/Database.h rename to dDatabase/GameDatabase/Database.h index b75bfe7ca..3eb292d16 100644 --- a/dDatabase/Database.h +++ b/dDatabase/GameDatabase/Database.h @@ -8,5 +8,5 @@ namespace Database { void Connect(); GameDatabase* Get(); - void Destroy(std::string source = "", bool log = true); + void Destroy(std::string source = ""); }; diff --git a/dDatabase/GameDatabase/GameDatabase.h b/dDatabase/GameDatabase/GameDatabase.h new file mode 100644 index 000000000..c31e86dfd --- /dev/null +++ b/dDatabase/GameDatabase/GameDatabase.h @@ -0,0 +1,49 @@ +#ifndef __GAMEDATABASE__H__ +#define __GAMEDATABASE__H__ + +#include + +#include "ILeaderboard.h" +#include "IPlayerCheatDetections.h" +#include "ICommandLog.h" +#include "IMail.h" +#include "IObjectIdTracker.h" +#include "IPlayKeys.h" +#include "IServers.h" +#include "IBugReports.h" +#include "IPropertyContents.h" +#include "IProperty.h" +#include "IPetNames.h" +#include "ICharXml.h" +#include "IMigrationHistory.h" +#include "IUgc.h" +#include "IFriends.h" +#include "ICharInfo.h" +#include "IAccounts.h" +#include "IActivityLog.h" + +namespace sql { + class Statement; + class PreparedStatement; +}; + +class GameDatabase : + public IPlayKeys, public ILeaderboard, public IObjectIdTracker, public IServers, + public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports, + public IPropertyContents, public IProperty, public IPetNames, public ICharXml, + public IMigrationHistory, public IUgc, public IFriends, public ICharInfo, + public IAccounts, public IActivityLog { +public: + virtual ~GameDatabase() = default; + // TODO: These should be made private. + virtual void Connect() = 0; + virtual void Destroy(std::string source = "") = 0; + virtual void ExecuteCustomQuery(const std::string_view query) = 0; + virtual sql::PreparedStatement* CreatePreppedStmt(const std::string& query) = 0; + virtual void Commit() = 0; + virtual bool GetAutoCommit() = 0; + virtual void SetAutoCommit(bool value) = 0; + virtual void DeleteCharacter(const uint32_t characterId) = 0; +}; + +#endif //!__GAMEDATABASE__H__ diff --git a/dDatabase/GameDatabase/ITables/IAccounts.h b/dDatabase/GameDatabase/ITables/IAccounts.h new file mode 100644 index 000000000..1b1f85a74 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IAccounts.h @@ -0,0 +1,37 @@ +#ifndef __IACCOUNTS__H__ +#define __IACCOUNTS__H__ + +#include +#include +#include + +enum class eGameMasterLevel : uint8_t; + +class IAccounts { +public: + struct Info { + std::string bcryptPassword; + uint32_t id{}; + uint32_t playKeyId{}; + bool banned{}; + bool locked{}; + eGameMasterLevel maxGmLevel{}; + }; + + // Get the account info for the given username. + virtual std::optional GetAccountInfo(const std::string_view username) = 0; + + // Update the account's unmute time. + virtual void UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) = 0; + + // Update the account's ban status. + virtual void UpdateAccountBan(const uint32_t accountId, const bool banned) = 0; + + // Update the account's password. + virtual void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) = 0; + + // Add a new account to the database. + virtual void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) = 0; +}; + +#endif //!__IACCOUNTS__H__ diff --git a/dDatabase/GameDatabase/ITables/IActivityLog.h b/dDatabase/GameDatabase/ITables/IActivityLog.h new file mode 100644 index 000000000..11e6e998b --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IActivityLog.h @@ -0,0 +1,19 @@ +#ifndef __IACTIVITYLOG__H__ +#define __IACTIVITYLOG__H__ + +#include + +#include "dCommonVars.h" + +enum class eActivityType : uint32_t { + PlayerLoggedOut, + PlayerLoggedIn, +}; + +class IActivityLog { +public: + // Update the activity log for the given account. + virtual void UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) = 0; +}; + +#endif //!__IACTIVITYLOG__H__ diff --git a/dDatabase/GameDatabase/ITables/IBugReports.h b/dDatabase/GameDatabase/ITables/IBugReports.h new file mode 100644 index 000000000..29a6180fd --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IBugReports.h @@ -0,0 +1,20 @@ +#ifndef __IBUGREPORTS__H__ +#define __IBUGREPORTS__H__ + +#include +#include + +class IBugReports { +public: + struct Info { + std::string body; + std::string clientVersion; + std::string otherPlayer; + std::string selection; + uint32_t characterId{}; + }; + + // Add a new bug report to the database. + virtual void InsertNewBugReport(const Info& info) = 0; +}; +#endif //!__IBUGREPORTS__H__ diff --git a/dDatabase/GameDatabase/ITables/ICharInfo.h b/dDatabase/GameDatabase/ITables/ICharInfo.h new file mode 100644 index 000000000..416dad2c7 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/ICharInfo.h @@ -0,0 +1,49 @@ +#ifndef __ICHARINFO__H__ +#define __ICHARINFO__H__ + +#include +#include +#include +#include +#include + +#include "ePermissionMap.h" + +class ICharInfo { +public: + struct Info { + std::string name; + std::string pendingName; + uint32_t id{}; + uint32_t accountId{}; + bool needsRename{}; + LWOCLONEID cloneId{}; + ePermissionMap permissionMap{}; + }; + + // Get the approved names of all characters. + virtual std::vector GetApprovedCharacterNames() = 0; + + // Get the character info for the given character id. + virtual std::optional GetCharacterInfo(const uint32_t charId) = 0; + + // Get the character info for the given character name. + virtual std::optional GetCharacterInfo(const std::string_view name) = 0; + + // Get the character ids for the given account. + virtual std::vector GetAccountCharacterIds(const uint32_t accountId) = 0; + + // Insert a new character into the database. + virtual void InsertNewCharacter(const ICharInfo::Info info) = 0; + + // Set the name of the given character. + virtual void SetCharacterName(const uint32_t characterId, const std::string_view name) = 0; + + // Set the pending name of the given character. + virtual void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) = 0; + + // Updates the given character ids last login to be right now. + virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0; +}; + +#endif //!__ICHARINFO__H__ diff --git a/dDatabase/GameDatabase/ITables/ICharXml.h b/dDatabase/GameDatabase/ITables/ICharXml.h new file mode 100644 index 000000000..f6e73387d --- /dev/null +++ b/dDatabase/GameDatabase/ITables/ICharXml.h @@ -0,0 +1,20 @@ +#ifndef __ICHARXML__H__ +#define __ICHARXML__H__ + +#include +#include +#include + +class ICharXml { +public: + // Get the character xml for the given character id. + virtual std::string GetCharacterXml(const uint32_t charId) = 0; + + // Update the character xml for the given character id. + virtual void UpdateCharacterXml(const uint32_t charId, const std::string_view lxfml) = 0; + + // Insert the character xml for the given character id. + virtual void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) = 0; +}; + +#endif //!__ICHARXML__H__ diff --git a/dDatabase/GameDatabase/ITables/ICommandLog.h b/dDatabase/GameDatabase/ITables/ICommandLog.h new file mode 100644 index 000000000..63595360d --- /dev/null +++ b/dDatabase/GameDatabase/ITables/ICommandLog.h @@ -0,0 +1,14 @@ +#ifndef __ICOMMANDLOG__H__ +#define __ICOMMANDLOG__H__ + +#include +#include + +class ICommandLog { +public: + + // Insert a new slash command log entry. + virtual void InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) = 0; +}; + +#endif //!__ICOMMANDLOG__H__ diff --git a/dDatabase/GameDatabase/ITables/IFriends.h b/dDatabase/GameDatabase/ITables/IFriends.h new file mode 100644 index 000000000..e0cd1690d --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IFriends.h @@ -0,0 +1,32 @@ +#ifndef __IFRIENDS__H__ +#define __IFRIENDS__H__ + +#include +#include +#include + +class IFriends { +public: + struct BestFriendStatus { + uint32_t playerAccountId{}; + uint32_t friendAccountId{}; + uint32_t bestFriendStatus{}; + }; + + // Get the friends list for the given character id. + virtual std::vector GetFriendsList(const uint32_t charId) = 0; + + // Get the best friend status for the given player and friend character ids. + virtual std::optional GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) = 0; + + // Set the best friend status for the given player and friend character ids. + virtual void SetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId, const uint32_t bestFriendStatus) = 0; + + // Add a friend to the given character id. + virtual void AddFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) = 0; + + // Remove a friend from the given character id. + virtual void RemoveFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) = 0; +}; + +#endif //!__IFRIENDS__H__ diff --git a/dDatabase/GameDatabase/ITables/ILeaderboard.h b/dDatabase/GameDatabase/ITables/ILeaderboard.h new file mode 100644 index 000000000..84d44eb2b --- /dev/null +++ b/dDatabase/GameDatabase/ITables/ILeaderboard.h @@ -0,0 +1,14 @@ +#ifndef __ILEADERBOARD__H__ +#define __ILEADERBOARD__H__ + +#include +#include + +class ILeaderboard { +public: + + // Get the donation total for the given activity id. + virtual std::optional GetDonationTotal(const uint32_t activityId) = 0; +}; + +#endif //!__ILEADERBOARD__H__ diff --git a/dDatabase/GameDatabase/ITables/IMail.h b/dDatabase/GameDatabase/ITables/IMail.h new file mode 100644 index 000000000..7fbc8230d --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IMail.h @@ -0,0 +1,54 @@ +#ifndef __IMAIL__H__ +#define __IMAIL__H__ + +#include +#include +#include + +#include "dCommonVars.h" +#include "NiQuaternion.h" +#include "NiPoint3.h" + +class IMail { +public: + struct MailInfo { + std::string senderUsername; + std::string recipient; + std::string subject; + std::string body; + uint64_t id{}; + uint32_t senderId{}; + uint32_t receiverId{}; + uint64_t timeSent{}; + bool wasRead{}; + struct { + LWOOBJID itemID{}; + int32_t itemCount{}; + LOT itemLOT{}; + LWOOBJID itemSubkey{}; + }; + }; + + // Insert a new mail into the database. + virtual void InsertNewMail(const MailInfo& mail) = 0; + + // Get the mail for the given character id. + virtual std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) = 0; + + // Get the mail for the given mail id. + virtual std::optional GetMail(const uint64_t mailId) = 0; + + // Get the number of unread mail for the given character id. + virtual uint32_t GetUnreadMailCount(const uint32_t characterId) = 0; + + // Mark the given mail as read. + virtual void MarkMailRead(const uint64_t mailId) = 0; + + // Claim the item from the given mail. + virtual void ClaimMailItem(const uint64_t mailId) = 0; + + // Delete the given mail. + virtual void DeleteMail(const uint64_t mailId) = 0; +}; + +#endif //!__IMAIL__H__ diff --git a/dDatabase/GameDatabase/ITables/IMigrationHistory.h b/dDatabase/GameDatabase/ITables/IMigrationHistory.h new file mode 100644 index 000000000..21f27b4a5 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IMigrationHistory.h @@ -0,0 +1,17 @@ +#ifndef __IMIGRATIONHISTORY__H__ +#define __IMIGRATIONHISTORY__H__ + +#include + +class IMigrationHistory { +public: + // Create the migration history table. + virtual void CreateMigrationHistoryTable() = 0; + + // Check if the given migration has been run. + virtual bool IsMigrationRun(const std::string_view str) = 0; + + // Insert the given migration into the migration history table. + virtual void InsertMigration(const std::string_view str) = 0; +}; +#endif //!__IMIGRATIONHISTORY__H__ diff --git a/dDatabase/GameDatabase/ITables/IObjectIdTracker.h b/dDatabase/GameDatabase/ITables/IObjectIdTracker.h new file mode 100644 index 000000000..cbe34b6d9 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IObjectIdTracker.h @@ -0,0 +1,19 @@ +#ifndef __IOBJECTIDTRACKER__H__ +#define __IOBJECTIDTRACKER__H__ + +#include +#include + +class IObjectIdTracker { +public: + // Get the current persistent id. + virtual std::optional GetCurrentPersistentId() = 0; + + // Insert the default persistent id. + virtual void InsertDefaultPersistentId() = 0; + + // Update the persistent id. + virtual void UpdatePersistentId(const uint32_t newId) = 0; +}; + +#endif //!__IOBJECTIDTRACKER__H__ diff --git a/dDatabase/GameDatabase/ITables/IPetNames.h b/dDatabase/GameDatabase/ITables/IPetNames.h new file mode 100644 index 000000000..e82f49056 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IPetNames.h @@ -0,0 +1,21 @@ +#ifndef __IPETNAMES__H__ +#define __IPETNAMES__H__ + +#include +#include + +class IPetNames { +public: + struct Info { + std::string petName; + int32_t approvalStatus{}; + }; + + // Set the pet name moderation status for the given pet id. + virtual void SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) = 0; + + // Get pet info for the given pet id. + virtual std::optional GetPetNameInfo(const LWOOBJID& petId) = 0; +}; + +#endif //!__IPETNAMES__H__ diff --git a/dDatabase/GameDatabase/ITables/IPlayKeys.h b/dDatabase/GameDatabase/ITables/IPlayKeys.h new file mode 100644 index 000000000..841029b25 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IPlayKeys.h @@ -0,0 +1,15 @@ +#ifndef __IPLAYKEYS__H__ +#define __IPLAYKEYS__H__ + +#include +#include + +class IPlayKeys { +public: + // Get the playkey id for the given playkey. + // Optional of bool may seem pointless, however the optional indicates if the playkey exists + // and the bool indicates if the playkey is active. + virtual std::optional IsPlaykeyActive(const uint32_t playkeyId) = 0; +}; + +#endif //!__IPLAYKEYS__H__ diff --git a/dDatabase/GameDatabase/ITables/IPlayerCheatDetections.h b/dDatabase/GameDatabase/ITables/IPlayerCheatDetections.h new file mode 100644 index 000000000..939f51189 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IPlayerCheatDetections.h @@ -0,0 +1,20 @@ +#ifndef __IPLAYERCHEATDETECTIONS__H__ +#define __IPLAYERCHEATDETECTIONS__H__ + +#include +#include + +class IPlayerCheatDetections { +public: + struct Info { + std::optional userId = std::nullopt; + std::string username; + std::string systemAddress; + std::string extraMessage; + }; + + // Insert a new cheat detection. + virtual void InsertCheatDetection(const IPlayerCheatDetections::Info& info) = 0; +}; + +#endif //!__IPLAYERCHEATDETECTIONS__H__ diff --git a/dDatabase/GameDatabase/ITables/IProperty.h b/dDatabase/GameDatabase/ITables/IProperty.h new file mode 100644 index 000000000..a9bc0b8c1 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IProperty.h @@ -0,0 +1,38 @@ +#ifndef __IPROPERTY__H__ +#define __IPROPERTY__H__ + +#include +#include + +class IProperty { +public: + struct Info { + std::string name; + std::string description; + std::string rejectionReason; + LWOOBJID id{}; + LWOOBJID ownerId{}; + LWOCLONEID cloneId{}; + int32_t privacyOption{}; + uint32_t modApproved{}; + uint32_t lastUpdatedTime{}; + uint32_t claimedTime{}; + uint32_t reputation{}; + }; + + // Get the property info for the given property id. + virtual std::optional GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) = 0; + + // Update the property moderation info for the given property id. + virtual void UpdatePropertyModerationInfo(const IProperty::Info& info) = 0; + + // Update the property details for the given property id. + virtual void UpdatePropertyDetails(const IProperty::Info& info) = 0; + + // Update the property performance cost for the given property id. + virtual void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) = 0; + + // Insert a new property into the database. + virtual void InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) = 0; +}; +#endif //!__IPROPERTY__H__ diff --git a/dDatabase/GameDatabase/ITables/IPropertyContents.h b/dDatabase/GameDatabase/ITables/IPropertyContents.h new file mode 100644 index 000000000..c862ca943 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IPropertyContents.h @@ -0,0 +1,40 @@ +#ifndef __IPROPERTIESCONTENTS__H__ +#define __IPROPERTIESCONTENTS__H__ + +#include +#include + +class IPropertyContents { +public: + struct Model { + inline bool operator==(const LWOOBJID& other) const noexcept { + return id == other; + } + + NiPoint3 position; + NiQuaternion rotation; + LWOOBJID id{}; + LOT lot{}; + uint32_t ugcId{}; + }; + + // Inserts a new UGC model into the database. + virtual void InsertNewUgcModel( + std::istringstream& sd0Data, + const uint32_t blueprintId, + const uint32_t accountId, + const uint32_t characterId) = 0; + + // Get the property models for the given property id. + virtual std::vector GetPropertyModels(const LWOOBJID& propertyId) = 0; + + // Insert a new property model into the database. + virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) = 0; + + // Update the model position and rotation for the given property id. + virtual void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) = 0; + + // Remove the model for the given property id. + virtual void RemoveModel(const LWOOBJID& modelId) = 0; +}; +#endif //!__IPROPERTIESCONTENTS__H__ diff --git a/dDatabase/GameDatabase/ITables/IServers.h b/dDatabase/GameDatabase/ITables/IServers.h new file mode 100644 index 000000000..ee74bbb81 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IServers.h @@ -0,0 +1,21 @@ +#ifndef __ISERVERS__H__ +#define __ISERVERS__H__ + +#include +#include + +class IServers { +public: + struct MasterInfo { + std::string ip; + uint32_t port{}; + }; + + // Set the master server ip and port. + virtual void SetMasterIp(const std::string_view ip, const uint32_t port) = 0; + + // Get the master server info. + virtual std::optional GetMasterInfo() = 0; +}; + +#endif //!__ISERVERS__H__ diff --git a/dDatabase/GameDatabase/ITables/IUgc.h b/dDatabase/GameDatabase/ITables/IUgc.h new file mode 100644 index 000000000..024636ac5 --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IUgc.h @@ -0,0 +1,32 @@ +#ifndef __IUGC__H__ +#define __IUGC__H__ + +#include +#include +#include +#include +#include + +class IUgc { +public: + struct Model { + std::stringstream lxfmlData; + LWOOBJID id{}; + }; + + // Gets all UGC models for the given property id. + virtual std::vector GetUgcModels(const LWOOBJID& propertyId) = 0; + + // Gets all Ugcs models. + virtual std::vector GetAllUgcModels() = 0; + + // Removes ugc models that are not referenced by any property. + virtual void RemoveUnreferencedUgcModels() = 0; + + // Deletes the ugc model for the given model id. + virtual void DeleteUgcModelData(const LWOOBJID& modelId) = 0; + + // Inserts a new UGC model into the database. + virtual void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) = 0; +}; +#endif //!__IUGC__H__ diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/GameDatabase/MigrationRunner.cpp similarity index 97% rename from dDatabase/MigrationRunner.cpp rename to dDatabase/GameDatabase/MigrationRunner.cpp index 8eeac5cb3..6bc3954da 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/GameDatabase/MigrationRunner.cpp @@ -62,11 +62,10 @@ void MigrationRunner::RunMigrations() { if (!finalSQL.empty()) { auto migration = GeneralUtils::SplitString(static_cast(finalSQL), ';'); - std::unique_ptr simpleStatement(Database::Get()->CreateStmt()); for (auto& query : migration) { try { if (query.empty()) continue; - simpleStatement->execute(query.c_str()); + Database::Get()->ExecuteCustomQuery(query.c_str()); } catch (sql::SQLException& e) { LOG("Encountered error running migration: %s", e.what()); } diff --git a/dDatabase/MigrationRunner.h b/dDatabase/GameDatabase/MigrationRunner.h similarity index 100% rename from dDatabase/MigrationRunner.h rename to dDatabase/GameDatabase/MigrationRunner.h diff --git a/dDatabase/GameDatabase/MySQL/CMakeLists.txt b/dDatabase/GameDatabase/MySQL/CMakeLists.txt new file mode 100644 index 000000000..9114445d5 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/CMakeLists.txt @@ -0,0 +1,11 @@ +SET(DDATABSE_DATABSES_MYSQL_SOURCES + "MySQLDatabase.cpp" +) + +add_subdirectory(Tables) + +foreach(file ${DDATABASES_DATABASES_MYSQL_TABLES_SOURCES}) + set(DDATABSE_DATABSES_MYSQL_SOURCES ${DDATABSE_DATABSES_MYSQL_SOURCES} "Tables/${file}") +endforeach() + +set(DDATABSE_DATABSES_MYSQL_SOURCES ${DDATABSE_DATABSES_MYSQL_SOURCES} PARENT_SCOPE) diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp b/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp new file mode 100644 index 000000000..259c3866e --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp @@ -0,0 +1,113 @@ +#include "MySQLDatabase.h" + +#include "Database.h" +#include "Game.h" +#include "dConfig.h" +#include "Logger.h" + +namespace { + std::string databaseName; + sql::Properties properties; + sql::Driver* driver = nullptr; + sql::Connection* con = nullptr; +}; + +void MySQLDatabase::Connect() { + driver = sql::mariadb::get_driver_instance(); + + // The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where + // 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the + // presence of a / + // 2) even avoiding that, the connector still assumes you're connecting with a tcp socket + // So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost, + // which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate + // property manually (which the URL parsing fails to do) + const std::string UNIX_PROTO = "unix://"; + const std::string PIPE_PROTO = "pipe://"; + std::string mysql_host = Game::config->GetValue("mysql_host"); + if (mysql_host.find(UNIX_PROTO) == 0) { + properties["hostName"] = "unix://localhost"; + properties["localSocket"] = mysql_host.substr(UNIX_PROTO.length()).c_str(); + } else if (mysql_host.find(PIPE_PROTO) == 0) { + properties["hostName"] = "pipe://localhost"; + properties["pipe"] = mysql_host.substr(PIPE_PROTO.length()).c_str(); + } else { + properties["hostName"] = mysql_host.c_str(); + } + properties["user"] = Game::config->GetValue("mysql_username").c_str(); + properties["password"] = Game::config->GetValue("mysql_password").c_str(); + properties["autoReconnect"] = "true"; + + databaseName = Game::config->GetValue("mysql_database").c_str(); + + // `connect(const Properties& props)` segfaults in windows debug, but + // `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly + if (properties.find("localSocket") != properties.end() || properties.find("pipe") != properties.end()) { + con = driver->connect(properties); + } else { + con = driver->connect(properties["hostName"].c_str(), properties["user"].c_str(), properties["password"].c_str()); + } + con->setSchema(databaseName.c_str()); +} + +void MySQLDatabase::Destroy(std::string source) { + if (!con) return; + + if (source.empty()) LOG("Destroying MySQL connection!"); + else LOG("Destroying MySQL connection from %s!", source.c_str()); + + con->close(); + delete con; + con = nullptr; +} + +void MySQLDatabase::ExecuteCustomQuery(const std::string_view query) { + std::unique_ptr(con->createStatement())->execute(query.data()); +} + +sql::PreparedStatement* MySQLDatabase::CreatePreppedStmt(const std::string& query) { + if (!con) { + Connect(); + LOG("Trying to reconnect to MySQL"); + } + + if (!con->isValid() || con->isClosed()) { + delete con; + + con = nullptr; + + Connect(); + LOG("Trying to reconnect to MySQL from invalid or closed connection"); + } + + return con->prepareStatement(sql::SQLString(query.c_str(), query.length())); +} + +void MySQLDatabase::Commit() { + con->commit(); +} + +bool MySQLDatabase::GetAutoCommit() { + // TODO This should not just access a pointer. A future PR should update this + // to check for null and throw an error if the connection is not valid. + return con->getAutoCommit(); +} + +void MySQLDatabase::SetAutoCommit(bool value) { + // TODO This should not just access a pointer. A future PR should update this + // to check for null and throw an error if the connection is not valid. + con->setAutoCommit(value); +} + +void MySQLDatabase::DeleteCharacter(const uint32_t characterId) { + ExecuteDelete("DELETE FROM charxml WHERE id=? LIMIT 1;", characterId); + ExecuteDelete("DELETE FROM command_log WHERE character_id=?;", characterId); + ExecuteDelete("DELETE FROM friends WHERE player_id=? OR friend_id=?;", characterId, characterId); + ExecuteDelete("DELETE FROM leaderboard WHERE character_id=?;", characterId); + ExecuteDelete("DELETE FROM properties_contents WHERE property_id IN (SELECT id FROM properties WHERE owner_id=?);", characterId); + ExecuteDelete("DELETE FROM properties WHERE owner_id=?;", characterId); + ExecuteDelete("DELETE FROM ugc WHERE character_id=?;", characterId); + ExecuteDelete("DELETE FROM activity_log WHERE character_id=?;", characterId); + ExecuteDelete("DELETE FROM mail WHERE receiver_id=?;", characterId); + ExecuteDelete("DELETE FROM charinfo WHERE id=? LIMIT 1;", characterId); +} diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h new file mode 100644 index 000000000..3a4963787 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -0,0 +1,245 @@ +#ifndef __MYSQLDATABASE__H__ +#define __MYSQLDATABASE__H__ + +#include +#include + +#include "GameDatabase.h" + +typedef std::unique_ptr& UniquePreppedStmtRef; + +// Purposefully no definition for this to provide linker errors in the case someone tries to +// bind a parameter to a type that isn't defined. +template +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const ParamType param); + +// This is a function to set each parameter in a prepared statement. +// This is accomplished with a combination of parameter packing and Fold Expressions. +// The constexpr if statement is used to prevent the compiler from trying to call SetParam with 0 arguments. +template +void SetParams(UniquePreppedStmtRef stmt, Args&&... args) { + if constexpr (sizeof...(args) != 0) { + int i = 1; + (SetParam(stmt, i++, args), ...); + } +} + +class MySQLDatabase : public GameDatabase { +public: + void Connect() override; + void Destroy(std::string source = "") override; + + sql::PreparedStatement* CreatePreppedStmt(const std::string& query) override; + void Commit() override; + bool GetAutoCommit() override; + void SetAutoCommit(bool value) override; + void ExecuteCustomQuery(const std::string_view query) override; + + // Overloaded queries + std::optional GetMasterInfo() override; + + std::vector GetApprovedCharacterNames() override; + + std::vector GetFriendsList(uint32_t charID) override; + + std::optional GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) override; + void SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) override; + void AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; + void RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; + void UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) override; + void DeleteUgcModelData(const LWOOBJID& modelId) override; + void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) override; + std::vector GetAllUgcModels() override; + void CreateMigrationHistoryTable() override; + bool IsMigrationRun(const std::string_view str) override; + void InsertMigration(const std::string_view str) override; + std::optional GetCharacterInfo(const uint32_t charId) override; + std::optional GetCharacterInfo(const std::string_view charId) override; + std::string GetCharacterXml(const uint32_t accountId) override; + void UpdateCharacterXml(const uint32_t accountId, const std::string_view lxfml) override; + std::optional GetAccountInfo(const std::string_view username) override; + void InsertNewCharacter(const ICharInfo::Info info) override; + void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override; + std::vector GetAccountCharacterIds(uint32_t accountId) override; + void DeleteCharacter(const uint32_t characterId) override; + void SetCharacterName(const uint32_t characterId, const std::string_view name) override; + void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) override; + void UpdateLastLoggedInCharacter(const uint32_t characterId) override; + void SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) override; + std::optional GetPetNameInfo(const LWOOBJID& petId) override; + std::optional GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override; + void UpdatePropertyModerationInfo(const IProperty::Info& info) override; + void UpdatePropertyDetails(const IProperty::Info& info) override; + void InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) override; + std::vector GetPropertyModels(const LWOOBJID& propertyId) override; + void RemoveUnreferencedUgcModels() override; + void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override; + void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) override; + void RemoveModel(const LWOOBJID& modelId) override; + void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; + void InsertNewBugReport(const IBugReports::Info& info) override; + void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override; + void InsertNewMail(const IMail::MailInfo& mail) override; + void InsertNewUgcModel( + std::istringstream& sd0Data, + const uint32_t blueprintId, + const uint32_t accountId, + const uint32_t characterId) override; + std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; + std::optional GetMail(const uint64_t mailId) override; + uint32_t GetUnreadMailCount(const uint32_t characterId) override; + void MarkMailRead(const uint64_t mailId) override; + void DeleteMail(const uint64_t mailId) override; + void ClaimMailItem(const uint64_t mailId) override; + void InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) override; + void UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) override; + void UpdateAccountBan(const uint32_t accountId, const bool banned) override; + void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override; + void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override; + void SetMasterIp(const std::string_view ip, const uint32_t port) override; + std::optional GetCurrentPersistentId() override; + void InsertDefaultPersistentId() override; + void UpdatePersistentId(const uint32_t id) override; + std::optional GetDonationTotal(const uint32_t activityId) override; + std::optional IsPlaykeyActive(const uint32_t playkeyId) override; + std::vector GetUgcModels(const LWOOBJID& propertyId) override; +private: + + // Generic query functions that can be used for any query. + // Return type may be different depending on the query, so it is up to the caller to check the return type. + // The first argument is the query string, and the rest are the parameters to bind to the query. + // The return type is a unique_ptr to the result set, which is deleted automatically when it goes out of scope + template + inline std::unique_ptr ExecuteSelect(const std::string& query, Args&&... args) { + std::unique_ptr preppedStmt(CreatePreppedStmt(query)); + SetParams(preppedStmt, std::forward(args)...); + return std::unique_ptr(preppedStmt->executeQuery()); + } + + template + inline void ExecuteDelete(const std::string& query, Args&&... args) { + std::unique_ptr preppedStmt(CreatePreppedStmt(query)); + SetParams(preppedStmt, std::forward(args)...); + preppedStmt->execute(); + } + + template + inline int32_t ExecuteUpdate(const std::string& query, Args&&... args) { + std::unique_ptr preppedStmt(CreatePreppedStmt(query)); + SetParams(preppedStmt, std::forward(args)...); + return preppedStmt->executeUpdate(); + } + + template + inline bool ExecuteInsert(const std::string& query, Args&&... args) { + std::unique_ptr preppedStmt(CreatePreppedStmt(query)); + SetParams(preppedStmt, std::forward(args)...); + return preppedStmt->execute(); + } +}; + +// Below are each of the definitions of SetParam for each supported type. + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::string_view param) { + // LOG("%s", param.data()); + stmt->setString(index, param.data()); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const char* param) { + // LOG("%s", param); + stmt->setString(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::string param) { + // LOG("%s", param.c_str()); + stmt->setString(index, param.c_str()); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int8_t param) { + // LOG("%u", param); + stmt->setByte(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint8_t param) { + // LOG("%d", param); + stmt->setByte(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int16_t param) { + // LOG("%u", param); + stmt->setShort(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint16_t param) { + // LOG("%d", param); + stmt->setShort(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint32_t param) { + // LOG("%u", param); + stmt->setUInt(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int32_t param) { + // LOG("%d", param); + stmt->setInt(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int64_t param) { + // LOG("%llu", param); + stmt->setInt64(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint64_t param) { + // LOG("%llu", param); + stmt->setUInt64(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const float param) { + // LOG("%f", param); + stmt->setFloat(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const double param) { + // LOG("%f", param); + stmt->setDouble(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const bool param) { + // LOG("%d", param); + stmt->setBoolean(index, param); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::istream* param) { + // LOG("Blob"); + // This is the one time you will ever see me use const_cast. + stmt->setBlob(index, const_cast(param)); +} + +template<> +inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::optional param) { + if (param) { + // LOG("%d", param.value()); + stmt->setInt(index, param.value()); + } else { + // LOG("Null"); + stmt->setNull(index, sql::DataType::SQLNULL); + } +} + +#endif //!__MYSQLDATABASE__H__ diff --git a/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp b/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp new file mode 100644 index 000000000..801f444db --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp @@ -0,0 +1,37 @@ +#include "MySQLDatabase.h" + +#include "eGameMasterLevel.h" + +std::optional MySQLDatabase::GetAccountInfo(const std::string_view username) { + auto result = ExecuteSelect("SELECT id, password, banned, locked, play_key_id, gm_level FROM accounts WHERE name = ? LIMIT 1;", username); + + if (!result->next()) { + return std::nullopt; + } + + IAccounts::Info toReturn; + toReturn.id = result->getUInt("id"); + toReturn.maxGmLevel = static_cast(result->getInt("gm_level")); + toReturn.bcryptPassword = result->getString("password").c_str(); + toReturn.banned = result->getBoolean("banned"); + toReturn.locked = result->getBoolean("locked"); + toReturn.playKeyId = result->getUInt("play_key_id"); + + return toReturn; +} + +void MySQLDatabase::UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) { + ExecuteUpdate("UPDATE accounts SET mute_expire = ? WHERE id = ?;", timeToUnmute, accountId); +} + +void MySQLDatabase::UpdateAccountBan(const uint32_t accountId, const bool banned) { + ExecuteUpdate("UPDATE accounts SET banned = ? WHERE id = ?;", banned, accountId); +} + +void MySQLDatabase::UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) { + ExecuteUpdate("UPDATE accounts SET password = ? WHERE id = ?;", bcryptpassword, accountId); +} + +void MySQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) { + ExecuteInsert("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);", username, bcryptpassword, static_cast(eGameMasterLevel::OPERATOR)); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/ActivityLog.cpp b/dDatabase/GameDatabase/MySQL/Tables/ActivityLog.cpp new file mode 100644 index 000000000..abcbc9177 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/ActivityLog.cpp @@ -0,0 +1,6 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::UpdateActivityLog(const uint32_t accountId, const eActivityType activityType, const LWOMAPID mapId) { + ExecuteInsert("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);", + accountId, static_cast(activityType), static_cast(time(NULL)), mapId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/BugReports.cpp b/dDatabase/GameDatabase/MySQL/Tables/BugReports.cpp new file mode 100644 index 000000000..4f23941df --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/BugReports.cpp @@ -0,0 +1,6 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::InsertNewBugReport(const IBugReports::Info& info) { + ExecuteInsert("INSERT INTO `bug_reports`(body, client_version, other_player_id, selection, reporter_id) VALUES (?, ?, ?, ?, ?)", + info.body, info.clientVersion, info.otherPlayer, info.selection, info.characterId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt b/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt new file mode 100644 index 000000000..e9593ba98 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt @@ -0,0 +1,22 @@ +set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES + "Accounts.cpp" + "ActivityLog.cpp" + "BugReports.cpp" + "CharInfo.cpp" + "CharXml.cpp" + "CommandLog.cpp" + "Friends.cpp" + "Leaderboard.cpp" + "Mail.cpp" + "MigrationHistory.cpp" + "ObjectIdTracker.cpp" + "PetNames.cpp" + "PlayerCheatDetections.cpp" + "PlayKeys.cpp" + "Property.cpp" + "PropertyContents.cpp" + "Servers.cpp" + "Ugc.cpp" + PARENT_SCOPE +) + diff --git a/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp new file mode 100644 index 000000000..7406e69b0 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp @@ -0,0 +1,78 @@ +#include "MySQLDatabase.h" + +std::vector MySQLDatabase::GetApprovedCharacterNames() { + auto result = ExecuteSelect("SELECT name FROM charinfo;"); + + std::vector toReturn; + + while (result->next()) { + toReturn.push_back(result->getString("name").c_str()); + } + + return toReturn; +} + +std::optional CharInfoFromQueryResult(std::unique_ptr stmt) { + if (!stmt->next()) { + return std::nullopt; + } + + ICharInfo::Info toReturn; + + toReturn.id = stmt->getUInt("id"); + toReturn.name = stmt->getString("name").c_str(); + toReturn.pendingName = stmt->getString("pending_name").c_str(); + toReturn.needsRename = stmt->getBoolean("needs_rename"); + toReturn.cloneId = stmt->getUInt64("prop_clone_id"); + toReturn.accountId = stmt->getUInt("account_id"); + toReturn.permissionMap = static_cast(stmt->getUInt("permission_map")); + + return toReturn; +} + +std::optional MySQLDatabase::GetCharacterInfo(const uint32_t charId) { + return CharInfoFromQueryResult( + ExecuteSelect("SELECT name, pending_name, needs_rename, prop_clone_id, permission_map, id, account_id FROM charinfo WHERE id = ? LIMIT 1;", charId) + ); +} + +std::optional MySQLDatabase::GetCharacterInfo(const std::string_view name) { + return CharInfoFromQueryResult( + ExecuteSelect("SELECT name, pending_name, needs_rename, prop_clone_id, permission_map, id, account_id FROM charinfo WHERE name = ? LIMIT 1;", name) + ); +} + +std::vector MySQLDatabase::GetAccountCharacterIds(const uint32_t accountId) { + auto result = ExecuteSelect("SELECT id FROM charinfo WHERE account_id = ? ORDER BY last_login DESC LIMIT 4;", accountId); + + std::vector toReturn; + toReturn.reserve(result->rowsCount()); + while (result->next()) { + toReturn.push_back(result->getUInt("id")); + } + + return toReturn; +} + +void MySQLDatabase::InsertNewCharacter(const ICharInfo::Info info) { + ExecuteInsert( + "INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)", + info.id, + info.accountId, + info.name, + info.pendingName, + false, + static_cast(time(NULL))); +} + +void MySQLDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) { + ExecuteUpdate("UPDATE charinfo SET name = ?, pending_name = '', needs_rename = 0, last_login = ? WHERE id = ? LIMIT 1;", name, static_cast(time(NULL)), characterId); +} + +void MySQLDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) { + ExecuteUpdate("UPDATE charinfo SET pending_name = ?, needs_rename = 0, last_login = ? WHERE id = ? LIMIT 1", name, static_cast(time(NULL)), characterId); +} + +void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { + ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1", static_cast(time(NULL)), characterId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/CharXml.cpp b/dDatabase/GameDatabase/MySQL/Tables/CharXml.cpp new file mode 100644 index 000000000..3cbdeb27f --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/CharXml.cpp @@ -0,0 +1,19 @@ +#include "MySQLDatabase.h" + +std::string MySQLDatabase::GetCharacterXml(const uint32_t charId) { + auto result = ExecuteSelect("SELECT xml_data FROM charxml WHERE id = ? LIMIT 1;", charId); + + if (!result->next()) { + return ""; + } + + return result->getString("xml_data").c_str(); +} + +void MySQLDatabase::UpdateCharacterXml(const uint32_t charId, const std::string_view lxfml) { + ExecuteUpdate("UPDATE charxml SET xml_data = ? WHERE id = ?;", lxfml, charId); +} + +void MySQLDatabase::InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) { + ExecuteInsert("INSERT INTO `charxml` (`id`, `xml_data`) VALUES (?,?)", accountId, lxfml); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/CommandLog.cpp b/dDatabase/GameDatabase/MySQL/Tables/CommandLog.cpp new file mode 100644 index 000000000..c8ae365ab --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/CommandLog.cpp @@ -0,0 +1,5 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) { + ExecuteInsert("INSERT INTO command_log (character_id, command) VALUES (?, ?);", characterId, command); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Friends.cpp b/dDatabase/GameDatabase/MySQL/Tables/Friends.cpp new file mode 100644 index 000000000..69ca6b172 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Friends.cpp @@ -0,0 +1,73 @@ +#include "MySQLDatabase.h" + +std::vector MySQLDatabase::GetFriendsList(const uint32_t charId) { + auto friendsList = ExecuteSelect( + R"QUERY( + SELECT fr.requested_player AS player, best_friend AS bff, ci.name AS name FROM + ( + SELECT CASE + WHEN player_id = ? THEN friend_id + WHEN friend_id = ? THEN player_id + END AS requested_player, best_friend FROM friends + ) AS fr + JOIN charinfo AS ci ON ci.id = fr.requested_player + WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?; + )QUERY", charId, charId, charId); + + std::vector toReturn; + toReturn.reserve(friendsList->rowsCount()); + + while (friendsList->next()) { + FriendData fd; + fd.friendID = friendsList->getUInt("player"); + fd.isBestFriend = friendsList->getInt("bff") == 3; // 0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs + fd.friendName = friendsList->getString("name").c_str(); + + toReturn.push_back(fd); + } + + return toReturn; +} + +std::optional MySQLDatabase::GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) { + auto result = ExecuteSelect("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;", + playerCharacterId, + friendCharacterId, + friendCharacterId, + playerCharacterId + ); + + if (!result->next()) { + return std::nullopt; + } + + IFriends::BestFriendStatus toReturn; + toReturn.playerAccountId = result->getUInt("player_id"); + toReturn.friendAccountId = result->getUInt("friend_id"); + toReturn.bestFriendStatus = result->getUInt("best_friend"); + + return toReturn; +} + +void MySQLDatabase::SetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId, const uint32_t bestFriendStatus) { + ExecuteUpdate("UPDATE friends SET best_friend = ? WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;", + bestFriendStatus, + playerCharacterId, + friendCharacterId, + friendCharacterId, + playerCharacterId + ); +} + +void MySQLDatabase::AddFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) { + ExecuteInsert("INSERT IGNORE INTO friends (player_id, friend_id, best_friend) VALUES (?, ?, 0);", playerCharacterId, friendCharacterId); +} + +void MySQLDatabase::RemoveFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) { + ExecuteDelete("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;", + playerCharacterId, + friendCharacterId, + friendCharacterId, + playerCharacterId + ); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Leaderboard.cpp b/dDatabase/GameDatabase/MySQL/Tables/Leaderboard.cpp new file mode 100644 index 000000000..22403abb0 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Leaderboard.cpp @@ -0,0 +1,11 @@ +#include "MySQLDatabase.h" + +std::optional MySQLDatabase::GetDonationTotal(const uint32_t activityId) { + auto donation_total = ExecuteSelect("SELECT SUM(primaryScore) as donation_total FROM leaderboard WHERE game_id = ?;", activityId); + + if (!donation_total->next()) { + return std::nullopt; + } + + return donation_total->getUInt("donation_total"); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp new file mode 100644 index 000000000..22c2fce11 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp @@ -0,0 +1,84 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::InsertNewMail(const IMail::MailInfo& mail) { + ExecuteInsert( + "INSERT INTO `mail` " + "(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,0)", + mail.senderId, + mail.senderUsername, + mail.receiverId, + mail.recipient, + static_cast(time(NULL)), + mail.subject, + mail.body, + mail.itemID, + mail.itemLOT, + 0, + mail.itemCount); +} + +std::vector MySQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { + auto res = ExecuteSelect( + "SELECT id, subject, body, sender_name, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read, time_sent" + " FROM mail WHERE receiver_id=? limit ?;", + characterId, numberOfMail); + + std::vector toReturn; + toReturn.reserve(res->rowsCount()); + + while (res->next()) { + IMail::MailInfo mail; + mail.id = res->getUInt64("id"); + mail.subject = res->getString("subject").c_str(); + mail.body = res->getString("body").c_str(); + mail.senderUsername = res->getString("sender_name").c_str(); + mail.itemID = res->getUInt("attachment_id"); + mail.itemLOT = res->getInt("attachment_lot"); + mail.itemSubkey = res->getInt("attachment_subkey"); + mail.itemCount = res->getInt("attachment_count"); + mail.timeSent = res->getUInt64("time_sent"); + mail.wasRead = res->getBoolean("was_read"); + + toReturn.push_back(std::move(mail)); + } + + return toReturn; +} + +std::optional MySQLDatabase::GetMail(const uint64_t mailId) { + auto res = ExecuteSelect("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;", mailId); + + if (!res->next()) { + return std::nullopt; + } + + IMail::MailInfo toReturn; + toReturn.itemLOT = res->getInt("attachment_lot"); + toReturn.itemCount = res->getInt("attachment_count"); + + return toReturn; +} + +uint32_t MySQLDatabase::GetUnreadMailCount(const uint32_t characterId) { + auto res = ExecuteSelect("SELECT COUNT(*) as number_unread FROM mail WHERE receiver_id=? AND was_read=0;", characterId); + + if (!res->next()) { + return 0; + } + + return res->getInt("number_unread"); +} + +void MySQLDatabase::MarkMailRead(const uint64_t mailId) { + ExecuteUpdate("UPDATE mail SET was_read=1 WHERE id=? LIMIT 1;", mailId); +} + +void MySQLDatabase::ClaimMailItem(const uint64_t mailId) { + ExecuteUpdate("UPDATE mail SET attachment_lot=0 WHERE id=? LIMIT 1;", mailId); +} + +void MySQLDatabase::DeleteMail(const uint64_t mailId) { + LOG("Deleting mail with id %llu", mailId); + ExecuteDelete("DELETE FROM mail WHERE id=? LIMIT 1;", mailId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/MigrationHistory.cpp b/dDatabase/GameDatabase/MySQL/Tables/MigrationHistory.cpp new file mode 100644 index 000000000..a0afc3414 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/MigrationHistory.cpp @@ -0,0 +1,13 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::CreateMigrationHistoryTable() { + ExecuteInsert("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); +} + +bool MySQLDatabase::IsMigrationRun(const std::string_view str) { + return ExecuteSelect("SELECT name FROM migration_history WHERE name = ?;", str)->next(); +} + +void MySQLDatabase::InsertMigration(const std::string_view str) { + ExecuteInsert("INSERT INTO migration_history (name) VALUES (?);", str); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/ObjectIdTracker.cpp b/dDatabase/GameDatabase/MySQL/Tables/ObjectIdTracker.cpp new file mode 100644 index 000000000..f22cd855f --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/ObjectIdTracker.cpp @@ -0,0 +1,17 @@ +#include "MySQLDatabase.h" + +std::optional MySQLDatabase::GetCurrentPersistentId() { + auto result = ExecuteSelect("SELECT last_object_id FROM object_id_tracker"); + if (!result->next()) { + return std::nullopt; + } + return result->getUInt("last_object_id"); +} + +void MySQLDatabase::InsertDefaultPersistentId() { + ExecuteInsert("INSERT INTO object_id_tracker VALUES (1);"); +} + +void MySQLDatabase::UpdatePersistentId(const uint32_t newId) { + ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = ?;", newId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/PetNames.cpp b/dDatabase/GameDatabase/MySQL/Tables/PetNames.cpp new file mode 100644 index 000000000..dd2a3a6cd --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/PetNames.cpp @@ -0,0 +1,26 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) { + ExecuteInsert( + "INSERT INTO `pet_names` (`id`, `pet_name`, `approved`) VALUES (?, ?, ?) " + "ON DUPLICATE KEY UPDATE pet_name = ?, approved = ?;", + petId, + info.petName, + info.approvalStatus, + info.petName, + info.approvalStatus); +} + +std::optional MySQLDatabase::GetPetNameInfo(const LWOOBJID& petId) { + auto result = ExecuteSelect("SELECT pet_name, approved FROM pet_names WHERE id = ? LIMIT 1;", petId); + + if (!result->next()) { + return std::nullopt; + } + + IPetNames::Info toReturn; + toReturn.petName = result->getString("pet_name").c_str(); + toReturn.approvalStatus = result->getInt("approved"); + + return toReturn; +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/PlayKeys.cpp b/dDatabase/GameDatabase/MySQL/Tables/PlayKeys.cpp new file mode 100644 index 000000000..5a4f3d9ac --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/PlayKeys.cpp @@ -0,0 +1,11 @@ +#include "MySQLDatabase.h" + +std::optional MySQLDatabase::IsPlaykeyActive(const uint32_t playkeyId) { + auto keyCheckRes = ExecuteSelect("SELECT active FROM `play_keys` WHERE id=?", playkeyId); + + if (!keyCheckRes->next()) { + return std::nullopt; + } + + return keyCheckRes->getBoolean("active"); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/PlayerCheatDetections.cpp b/dDatabase/GameDatabase/MySQL/Tables/PlayerCheatDetections.cpp new file mode 100644 index 000000000..753630c32 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/PlayerCheatDetections.cpp @@ -0,0 +1,7 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::InsertCheatDetection(const IPlayerCheatDetections::Info& info) { + ExecuteInsert( + "INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)", + info.userId, info.username, info.extraMessage, info.systemAddress); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Property.cpp b/dDatabase/GameDatabase/MySQL/Tables/Property.cpp new file mode 100644 index 000000000..5d72a3b59 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Property.cpp @@ -0,0 +1,57 @@ +#include "MySQLDatabase.h" + +std::optional MySQLDatabase::GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) { + auto propertyEntry = ExecuteSelect( + "SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved " + "FROM properties WHERE zone_id = ? AND clone_id = ?;", mapId, cloneId); + + if (!propertyEntry->next()) { + return std::nullopt; + } + + IProperty::Info toReturn; + toReturn.id = propertyEntry->getUInt64("id"); + toReturn.ownerId = propertyEntry->getUInt64("owner_id"); + toReturn.cloneId = propertyEntry->getUInt64("clone_id"); + toReturn.name = propertyEntry->getString("name").c_str(); + toReturn.description = propertyEntry->getString("description").c_str(); + toReturn.privacyOption = propertyEntry->getInt("privacy_option"); + toReturn.rejectionReason = propertyEntry->getString("rejection_reason").c_str(); + toReturn.lastUpdatedTime = propertyEntry->getUInt("last_updated"); + toReturn.claimedTime = propertyEntry->getUInt("time_claimed"); + toReturn.reputation = propertyEntry->getUInt("reputation"); + toReturn.modApproved = propertyEntry->getUInt("mod_approved"); + + return toReturn; +} + +void MySQLDatabase::UpdatePropertyModerationInfo(const IProperty::Info& info) { + ExecuteUpdate("UPDATE properties SET privacy_option = ?, rejection_reason = ?, mod_approved = ? WHERE id = ? LIMIT 1;", + info.privacyOption, + info.rejectionReason, + info.modApproved, + info.id); +} + +void MySQLDatabase::UpdatePropertyDetails(const IProperty::Info& info) { + ExecuteUpdate("UPDATE properties SET name = ?, description = ? WHERE id = ? LIMIT 1;", info.name, info.description, info.id); +} + +void MySQLDatabase::UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) { + ExecuteUpdate("UPDATE properties SET performance_cost = ? WHERE zone_id = ? AND clone_id = ? LIMIT 1;", performanceCost, zoneId.GetMapID(), zoneId.GetCloneID()); +} + +void MySQLDatabase::InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) { + auto insertion = ExecuteInsert( + "INSERT INTO properties" + "(id, owner_id, template_id, clone_id, name, description, zone_id, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, performance_cost)" + "VALUES (?, ?, ?, ?, ?, ?, ?, 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, 0.0)", + info.id, + info.ownerId, + templateId, + zoneId.GetCloneID(), + info.name, + info.description, + zoneId.GetMapID() + ); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp b/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp new file mode 100644 index 000000000..b605cd09d --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp @@ -0,0 +1,54 @@ +#include "MySQLDatabase.h" + +std::vector MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) { + auto result = ExecuteSelect("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;", propertyId); + + std::vector toReturn; + toReturn.reserve(result->rowsCount()); + while (result->next()) { + IPropertyContents::Model model; + model.id = result->getUInt64("id"); + model.lot = static_cast(result->getUInt("lot")); + model.position.x = result->getFloat("x"); + model.position.y = result->getFloat("y"); + model.position.z = result->getFloat("z"); + model.rotation.w = result->getFloat("rw"); + model.rotation.x = result->getFloat("rx"); + model.rotation.y = result->getFloat("ry"); + model.rotation.z = result->getFloat("rz"); + model.ugcId = result->getUInt64("ugc_id"); + toReturn.push_back(std::move(model)); + } + return toReturn; // RVO; allow compiler to elide the return. +} + +void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) { + try { + ExecuteInsert( + "INSERT INTO properties_contents" + "(id, property_id, ugc_id, lot, x, y, z, rx, ry, rz, rw, model_name, model_description, behavior_1, behavior_2, behavior_3, behavior_4, behavior_5)" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 18 + model.id, propertyId, model.ugcId == 0 ? std::nullopt : std::optional(model.ugcId), static_cast(model.lot), + model.position.x, model.position.y, model.position.z, model.rotation.x, model.rotation.y, model.rotation.z, model.rotation.w, + name, "", // Model description. TODO implement this. + 0, // behavior 1. TODO implement this. + 0, // behavior 2. TODO implement this. + 0, // behavior 3. TODO implement this. + 0, // behavior 4. TODO implement this. + 0 // behavior 5. TODO implement this. + ); + } catch (sql::SQLException& e) { + LOG("Error inserting new property model: %s", e.what()); + } +} + +void MySQLDatabase::UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) { + ExecuteUpdate( + "UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;", + position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w, propertyId); +} + +void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) { + ExecuteDelete("DELETE FROM properties_contents WHERE id = ?;", modelId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Servers.cpp b/dDatabase/GameDatabase/MySQL/Tables/Servers.cpp new file mode 100644 index 000000000..4411ad21d --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Servers.cpp @@ -0,0 +1,23 @@ +#include "MySQLDatabase.h" + +void MySQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) { + // We only want our 1 entry anyways, so we can just delete all and reinsert the one we want + // since it would be two queries anyways. + ExecuteDelete("TRUNCATE TABLE servers;"); + ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171022)", ip, port); +} + +std::optional MySQLDatabase::GetMasterInfo() { + auto result = ExecuteSelect("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;"); + + if (!result->next()) { + return std::nullopt; + } + + MasterInfo toReturn; + + toReturn.ip = result->getString("ip").c_str(); + toReturn.port = result->getInt("port"); + + return toReturn; +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp b/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp new file mode 100644 index 000000000..a17fbf870 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Ugc.cpp @@ -0,0 +1,71 @@ +#include "MySQLDatabase.h" + +std::vector MySQLDatabase::GetUgcModels(const LWOOBJID& propertyId) { + auto result = ExecuteSelect( + "SELECT lxfml, u.id FROM ugc AS u JOIN properties_contents AS pc ON u.id = pc.ugc_id WHERE lot = 14 AND property_id = ? AND pc.ugc_id IS NOT NULL;", + propertyId); + + std::vector toReturn; + + while (result->next()) { + IUgc::Model model; + + // blob is owned by the query, so we need to do a deep copy :/ + std::unique_ptr blob(result->getBlob("lxfml")); + model.lxfmlData << blob->rdbuf(); + model.id = result->getUInt64("id"); + toReturn.push_back(std::move(model)); + } + + return toReturn; // move elision +} + +std::vector MySQLDatabase::GetAllUgcModels() { + auto result = ExecuteSelect("SELECT id, lxfml FROM ugc;"); + + std::vector models; + models.reserve(result->rowsCount()); + while (result->next()) { + IUgc::Model model; + model.id = result->getInt64("id"); + + // blob is owned by the query, so we need to do a deep copy :/ + std::unique_ptr blob(result->getBlob("lxfml")); + model.lxfmlData << blob->rdbuf(); + models.push_back(std::move(model)); + } + + return models; +} + +void MySQLDatabase::RemoveUnreferencedUgcModels() { + ExecuteDelete("DELETE FROM ugc WHERE id NOT IN (SELECT ugc_id FROM properties_contents WHERE ugc_id IS NOT NULL);"); +} + +void MySQLDatabase::InsertNewUgcModel( + std::istringstream& sd0Data, // cant be const sad + const uint32_t blueprintId, + const uint32_t accountId, + const uint32_t characterId) { + const std::istream stream(sd0Data.rdbuf()); + ExecuteInsert( + "INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)", + blueprintId, + accountId, + characterId, + 0, + &stream, + false, + "weedeater.lxfml" + ); +} + +void MySQLDatabase::DeleteUgcModelData(const LWOOBJID& modelId) { + ExecuteDelete("DELETE FROM ugc WHERE id = ?;", modelId); + ExecuteDelete("DELETE FROM properties_contents WHERE ugc_id = ?;", modelId); +} + +void MySQLDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) { + const std::istream stream(lxfml.rdbuf()); + ExecuteUpdate("UPDATE ugc SET lxfml = ? WHERE id = ?;", &stream, modelId); +} diff --git a/dGame/User.cpp b/dGame/User.cpp index 07bc1d8e1..ce440bd71 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -23,21 +23,22 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std: m_IsBestFriendMap = std::unordered_map(); - auto userInfo = Database::Get()->GetUserInfo(username); + auto userInfo = Database::Get()->GetAccountInfo(username); if (userInfo) { - m_AccountID = userInfo->accountId; - m_MaxGMLevel = userInfo->maxGMLevel; + m_AccountID = userInfo->id; + m_MaxGMLevel = userInfo->maxGmLevel; m_MuteExpire = 0; //res->getUInt64(3); } //If we're loading a zone, we'll load the last used (aka current) character: if (Game::server->GetZoneID() != 0) { - auto lastUsedCharacter = Database::Get()->GetLastUsedCharacterId(m_AccountID); - if (lastUsedCharacter) { - Character* character = new Character(lastUsedCharacter.value(), this); + auto characterList = Database::Get()->GetAccountCharacterIds(m_AccountID); + if (!characterList.empty()) { + const uint32_t lastUsedCharacterId = characterList.front(); + Character* character = new Character(lastUsedCharacterId, this); character->UpdateFromDatabase(); m_Characters.push_back(character); - LOG("Loaded %i as it is the last used char", lastUsedCharacter.value()); + LOG("Loaded %i as it is the last used char", lastUsedCharacterId); } } } diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 9afaf87ec..f82a60feb 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -213,7 +213,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) { chars.clear(); - for (const auto& characterId : Database::Get()->GetCharacterIds(u->GetAccountID())) { + for (const auto& characterId : Database::Get()->GetAccountCharacterIds(u->GetAccountID())) { Character* character = new Character(characterId, u); character->UpdateFromDatabase(); character->SetIsNewLogin(); @@ -248,13 +248,13 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle); LOT pantsLOT = FindCharPantsID(pantsColor); - if (!name.empty() && !Database::Get()->IsUsernameAvailable(name)) { + if (!name.empty() && Database::Get()->GetCharacterInfo(name)) { LOG("AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str()); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE); return; } - if (!Database::Get()->IsUsernameAvailable(predefinedName)) { + if (Database::Get()->GetCharacterInfo(predefinedName)) { LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str()); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE); return; @@ -268,8 +268,8 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) //Now that the name is ok, we can get an objectID from Master: ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) { - if (Database::Get()->IsCharacterIdInUse(objectID)) { - LOG("Character object id unavailable, check objectidtracker!"); + if (Database::Get()->GetCharacterInfo(objectID)) { + LOG("Character object id unavailable, check object_id_tracker!"); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE); return; } @@ -311,9 +311,15 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true; std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName; - std::string_view pendingName = !name.empty() && !nameOk ? name : ""; + std::string pendingName = !name.empty() && !nameOk ? name : ""; - Database::Get()->InsertNewCharacter(u->GetAccountID(), objectID, nameToAssign, pendingName); + ICharInfo::Info info; + info.name = nameToAssign; + info.pendingName = pendingName; + info.id = objectID; + info.accountId = u->GetAccountID(); + + Database::Get()->InsertNewCharacter(info); //Now finally insert our character xml: Database::Get()->InsertCharacterXml(objectID, xml3.str()); @@ -401,7 +407,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet) return; } - if (Database::Get()->IsUsernameAvailable(newName)) { + if (Database::Get()->GetCharacterInfo(newName)) { if (IsNamePreapproved(newName)) { Database::Get()->SetCharacterName(charID, newName); LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str()); diff --git a/dGame/dComponents/DonationVendorComponent.cpp b/dGame/dComponents/DonationVendorComponent.cpp index a94a7af74..6abc959ac 100644 --- a/dGame/dComponents/DonationVendorComponent.cpp +++ b/dGame/dComponents/DonationVendorComponent.cpp @@ -22,10 +22,8 @@ DonationVendorComponent::DonationVendorComponent(Entity* parent) : VendorCompone return; } - std::unique_ptr query(Database::Get()->CreatePreppedStmt("SELECT SUM(primaryScore) as donation_total FROM leaderboard WHERE game_id = ?;")); - query->setInt(1, m_ActivityId); - std::unique_ptr donation_total(query->executeQuery()); - if (donation_total->next()) m_TotalDonated = donation_total->getInt("donation_total"); + auto donationTotal = Database::Get()->GetDonationTotal(m_ActivityId); + if (donationTotal) m_TotalDonated = donationTotal.value(); m_TotalRemaining = m_Goal - m_TotalDonated; m_PercentComplete = m_TotalDonated/static_cast(m_Goal); } diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 91d6fcab9..65b770c4c 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -1091,7 +1091,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) { } //Save to db: - Database::Get()->SetPetNameModerationStatus(m_DatabaseId, petName, approved); + Database::Get()->SetPetNameModerationStatus(m_DatabaseId, IPetNames::Info{petName, approved}); } void PetComponent::LoadPetNameFromModeration() { diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index 364ad7b28..f26d16d69 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -39,13 +39,12 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo instance = this; const auto& worldId = Game::zoneManager->GetZone()->GetZoneID(); - const auto zoneId = worldId.GetMapID(); const auto cloneId = worldId.GetCloneID(); - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int)zoneId); + auto query = CDClientDatabase::CreatePreppedStmt("SELECT id FROM PropertyTemplate WHERE mapID = ?;"); + + query.bind(1, static_cast(zoneId)); auto result = query.execQuery(); @@ -55,9 +54,7 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo templateId = result.getIntField(0); - result.finalize(); - - auto propertyInfo = Database::Get()->GetPropertyInfo(templateId, cloneId); + auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId); if (propertyInfo) { this->propertyId = propertyInfo->id; @@ -145,7 +142,13 @@ void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value) } privacyOption = value; - Database::Get()->UpdatePropertyModerationInfo(propertyId, static_cast(privacyOption), "", 0); + IProperty::Info info; + info.id = propertyId; + info.privacyOption = static_cast(privacyOption); + info.rejectionReason = rejectionReason; + info.modApproved = 0; + + Database::Get()->UpdatePropertyModerationInfo(info); } void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::string description) { @@ -155,7 +158,12 @@ void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::s propertyDescription = description; - Database::Get()->UpdatePropertyDetails(propertyId, propertyName, propertyDescription); + IProperty::Info info; + info.id = propertyId; + info.name = propertyName; + info.description = propertyDescription; + + Database::Get()->UpdatePropertyDetails(info); OnQueryPropertyData(GetOwner(), UNASSIGNED_SYSTEM_ADDRESS); } @@ -197,7 +205,14 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { propertyId = ObjectIDManager::GenerateRandomObjectID(); - Database::Get()->InsertNewProperty(propertyId, playerId, templateId, playerCloneId, name, description, propertyZoneId); + IProperty::Info info; + info.id = propertyId; + info.ownerId = playerId; + info.cloneId = playerCloneId; + info.name = name; + info.description = description; + + Database::Get()->InsertNewProperty(info, templateId, worldId); auto* zoneControlObject = Game::zoneManager->GetZoneControlObject(); for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) { @@ -517,7 +532,13 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet void PropertyManagementComponent::UpdateApprovedStatus(const bool value) { if (owner == LWOOBJID_EMPTY) return; - Database::Get()->UpdatePropertyModerationInfo(propertyId, static_cast(privacyOption), "", value); + IProperty::Info info; + info.id = propertyId; + info.modApproved = value; + info.privacyOption = static_cast(privacyOption); + info.rejectionReason = ""; + + Database::Get()->UpdatePropertyModerationInfo(info); } void PropertyManagementComponent::Load() { @@ -597,7 +618,7 @@ void PropertyManagementComponent::Save() { return; } - std::vector present = Database::Get()->GetPropertyModelIds(propertyId); + auto present = Database::Get()->GetPropertyModels(propertyId); std::vector modelIds; @@ -616,7 +637,7 @@ void PropertyManagementComponent::Save() { const auto rotation = entity->GetRotation(); if (std::find(present.begin(), present.end(), id) == present.end()) { - DatabaseStructs::DatabaseModel model; + IPropertyContents::Model model; model.id = id; model.lot = entity->GetLOT(); model.position = position; @@ -629,12 +650,12 @@ void PropertyManagementComponent::Save() { } } - for (auto id : present) { - if (std::find(modelIds.begin(), modelIds.end(), id) != modelIds.end()) { + for (auto model : present) { + if (std::find(modelIds.begin(), modelIds.end(), model.id) != modelIds.end()) { continue; } - Database::Get()->RemoveModel(id); + Database::Get()->RemoveModel(model.id); } } @@ -653,6 +674,7 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const const auto& worldId = Game::zoneManager->GetZone()->GetZoneID(); const auto zoneId = worldId.GetMapID(); + const auto cloneId = worldId.GetCloneID(); LOG("Getting property info for %d", zoneId); GameMessages::PropertyDataMessage message = GameMessages::PropertyDataMessage(zoneId); @@ -660,23 +682,21 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const const auto isClaimed = GetOwnerId() != LWOOBJID_EMPTY; LWOOBJID ownerId = GetOwnerId(); - std::string ownerName = ""; + std::string ownerName; + auto charInfo = Database::Get()->GetCharacterInfo(ownerId); + if (charInfo) ownerName = charInfo->name; std::string name = ""; std::string description = ""; uint64_t claimed = 0; char privacy = 0; if (isClaimed) { - const auto cloneId = worldId.GetCloneID(); - - ownerName = Database::Get()->GetCharacterNameForCloneId(cloneId); - name = propertyName; description = propertyDescription; claimed = claimedTime; privacy = static_cast(this->privacyOption); if (moderatorRequested) { - auto moderationInfo = Database::Get()->GetPropertyModerationInfo(propertyId); + auto moderationInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId); if (moderationInfo->rejectionReason != "") { moderatorRequested = false; rejectionReason = moderationInfo->rejectionReason; diff --git a/dGame/dGameMessages/GameMessageHandler.h b/dGame/dGameMessages/GameMessageHandler.h index 821d80be9..61378f80d 100644 --- a/dGame/dGameMessages/GameMessageHandler.h +++ b/dGame/dGameMessages/GameMessageHandler.h @@ -18,7 +18,7 @@ #include "Game.h" #include "Logger.h" #include "GameMessages.h" -#include "../dDatabase/CDClientDatabase.h" +#include "CDClientDatabase.h" enum class eGameMessageType : uint16_t; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 9247bce34..08cbc3e5c 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -2577,39 +2577,17 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent const auto zoneId = worldId.GetMapID(); const auto cloneId = worldId.GetCloneID(); - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int)zoneId); - - auto result = query.execQuery(); - - if (result.eof() || result.fieldIsNull(0)) return; - - int templateId = result.getIntField(0); - - auto propertyInfo = Database::Get()->GetPropertyInfo(templateId, cloneId); + auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId); LWOOBJID propertyId = LWOOBJID_EMPTY; if (propertyInfo) propertyId = propertyInfo->id; //Insert into ugc: - auto ugcs = Database::Get()->CreatePreppedStmt("INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)"); - ugcs->setUInt(1, blueprintIDSmall); - ugcs->setInt(2, entity->GetParentUser()->GetAccountID()); - ugcs->setInt(3, entity->GetCharacter()->GetID()); - ugcs->setInt(4, 0); - - //whacky stream biz - std::string s(sd0Data.get(), sd0Size); - std::istringstream iss(s); - - ugcs->setBlob(5, &iss); - ugcs->setBoolean(6, false); - ugcs->setString(7, "weedeater.lxfml"); - ugcs->execute(); - delete ugcs; + std::string str(sd0Data.get(), sd0Size); + std::istringstream sd0DataStream(str); + Database::Get()->InsertNewUgcModel(sd0DataStream, blueprintIDSmall, entity->GetParentUser()->GetAccountID(), entity->GetCharacter()->GetID()); //Insert into the db as a BBB model: - DatabaseStructs::DatabaseModel model; + IPropertyContents::Model model; model.id = newIDL; model.ugcId = blueprintIDSmall; model.position = NiPoint3::ZERO; @@ -5932,31 +5910,27 @@ void GameMessages::SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* e void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) { //Definitely not stolen from autogenerated code, no sir: - std::string body; - std::string clientVersion; - std::string nOtherPlayerID; - std::string selection; - uint32_t messageLength; - int32_t reporterID = 0; + IBugReports::Info reportInfo; //Reading: + uint32_t messageLength; inStream->Read(messageLength); for (uint32_t i = 0; i < (messageLength); ++i) { uint16_t character; inStream->Read(character); - body.push_back(static_cast(character)); + reportInfo.body.push_back(static_cast(character)); } auto character = entity->GetCharacter(); - if (character) reporterID = character->GetID(); + if (character) reportInfo.characterId = character->GetID(); uint32_t clientVersionLength; inStream->Read(clientVersionLength); for (unsigned int k = 0; k < clientVersionLength; k++) { unsigned char character; inStream->Read(character); - clientVersion.push_back(character); + reportInfo.clientVersion.push_back(character); } uint32_t nOtherPlayerIDLength; @@ -5964,7 +5938,7 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) for (unsigned int k = 0; k < nOtherPlayerIDLength; k++) { unsigned char character; inStream->Read(character); - nOtherPlayerID.push_back(character); + reportInfo.otherPlayer.push_back(character); } uint32_t selectionLength; @@ -5972,10 +5946,10 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) for (unsigned int k = 0; k < selectionLength; k++) { unsigned char character; inStream->Read(character); - selection.push_back(character); + reportInfo.selection.push_back(character); } - Database::Get()->InsertNewBugReport(body, clientVersion, nOtherPlayerID, selection, reporterID); + Database::Get()->InsertNewBugReport(reportInfo); } void diff --git a/dGame/dUtilities/CheatDetection.cpp b/dGame/dUtilities/CheatDetection.cpp index 172febeb7..a43cdaeb1 100644 --- a/dGame/dUtilities/CheatDetection.cpp +++ b/dGame/dUtilities/CheatDetection.cpp @@ -28,18 +28,19 @@ void ReportCheat(User* user, const SystemAddress& sysAddr, const char* messageIf LOG("WARNING: User is null, using defaults."); } - std::optional userId = std::nullopt; - if (user) userId = user->GetAccountID(); - const std::string_view username = user ? user->GetUsername().c_str() : "User is null."; + IPlayerCheatDetections::Info info; + if (user) info.userId = user->GetAccountID(); + info.username = user ? user->GetUsername().c_str() : "User is null."; // user string here because ToString is static and may change. - const std::string systemAddress = sysAddr.ToString(); + info.systemAddress = sysAddr.ToString(); constexpr int32_t bufSize = 4096; char extraMsg[bufSize]; vsnprintf(extraMsg, bufSize, messageIfNotSender, args); + info.extraMessage = extraMsg; - Database::Get()->InsertCheatDetection(userId, username, systemAddress, extraMsg); + Database::Get()->InsertCheatDetection(info); LOG("Anti-cheat message: %s", extraMsg); } diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 51113bc99..b13fd835a 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -76,17 +76,17 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, const void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJID recipient, const std::string& recipientName, const std::string& subject, const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) { - DatabaseStructs::MailInsert mailInsert; + IMail::MailInfo mailInsert; mailInsert.senderUsername = senderName; mailInsert.recipient = recipientName; mailInsert.subject = subject; mailInsert.body = body; mailInsert.senderId = sender; mailInsert.receiverId = recipient; - mailInsert.attachmentCount = attachmentCount; - mailInsert.itemID = 0; + mailInsert.itemCount = attachmentCount; + mailInsert.itemID = LWOOBJID_EMPTY; mailInsert.itemLOT = attachment; - mailInsert.subkey = LWOOBJID_EMPTY; + mailInsert.itemSubkey = LWOOBJID_EMPTY; Database::Get()->InsertNewMail(mailInsert); @@ -217,7 +217,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd } //Get the receiver's id: - auto receiverID = Database::Get()->DoesCharacterExist(recipient); + auto receiverID = Database::Get()->GetCharacterInfo(recipient); if (!receiverID) { Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound); @@ -225,21 +225,21 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd } //Check if we have a valid receiver: - if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID == character->GetObjectID()) { + if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID->id == character->GetID()) { Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf); return; } else { - DatabaseStructs::MailInsert mailInsert; + IMail::MailInfo mailInsert; mailInsert.senderUsername = character->GetName(); mailInsert.recipient = recipient; mailInsert.subject = subject; mailInsert.body = body; mailInsert.senderId = character->GetID(); - mailInsert.receiverId = receiverID.value(); - mailInsert.attachmentCount = attachmentCount; + mailInsert.receiverId = receiverID->id; + mailInsert.itemCount = attachmentCount; mailInsert.itemID = itemID; mailInsert.itemLOT = itemLOT; - mailInsert.subkey = LWOOBJID_EMPTY; + mailInsert.itemSubkey = LWOOBJID_EMPTY; Database::Get()->InsertNewMail(mailInsert); } @@ -263,52 +263,42 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd } void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT * FROM mail WHERE receiver_id=? limit 20;"); - stmt->setUInt(1, player->GetCharacter()->GetObjectID()); - sql::ResultSet* res = stmt->executeQuery(); + auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20); RakNet::BitStream bitStream; BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::MailData)); bitStream.Write(int(0)); - bitStream.Write(uint16_t(res->rowsCount())); - bitStream.Write(uint16_t(0)); + bitStream.Write(playerMail.size()); + bitStream.Write(0); - if (res->rowsCount() > 0) { - while (res->next()) { - bitStream.Write(res->getUInt64(1)); //MailID + if (!playerMail.empty()) { + for (const auto& mail : playerMail) { + bitStream.Write(mail.id); //MailID - /*std::u16string subject = GeneralUtils::UTF8ToUTF16(res->getString(7)); - std::u16string body = GeneralUtils::UTF8ToUTF16(res->getString(8)); - std::u16string sender = GeneralUtils::UTF8ToUTF16(res->getString(3)); - - WriteToPacket(&bitStream, subject, 50); - WriteToPacket(&bitStream, body, 400); - WriteToPacket(&bitStream, sender, 32);*/ - - WriteStringAsWString(&bitStream, res->getString(7).c_str(), 50); //subject - WriteStringAsWString(&bitStream, res->getString(8).c_str(), 400); //body - WriteStringAsWString(&bitStream, res->getString(3).c_str(), 32); //sender + WriteStringAsWString(&bitStream, mail.subject.c_str(), 50); //subject + WriteStringAsWString(&bitStream, mail.body.c_str(), 400); //body + WriteStringAsWString(&bitStream, mail.senderUsername.c_str(), 32); //sender bitStream.Write(uint32_t(0)); bitStream.Write(uint64_t(0)); - bitStream.Write(res->getUInt64(9)); //Attachment ID - LOT lot = res->getInt(10); + bitStream.Write(mail.itemID); //Attachment ID + LOT lot = mail.itemLOT; if (lot <= 0) bitStream.Write(LOT(-1)); else bitStream.Write(lot); bitStream.Write(uint32_t(0)); - bitStream.Write(res->getInt64(11)); //Attachment subKey - bitStream.Write(uint16_t(res->getInt(12))); //Attachment count + bitStream.Write(mail.itemSubkey); //Attachment subKey + bitStream.Write(mail.itemCount); //Attachment count bitStream.Write(uint32_t(0)); bitStream.Write(uint16_t(0)); - bitStream.Write(uint64_t(res->getUInt64(6))); //time sent (twice?) - bitStream.Write(uint64_t(res->getUInt64(6))); - bitStream.Write(uint8_t(res->getBoolean(13))); //was read + bitStream.Write(mail.timeSent); //time sent (twice?) + bitStream.Write(mail.timeSent); + bitStream.Write(mail.wasRead); //was read bitStream.Write(uint8_t(0)); bitStream.Write(uint16_t(0)); @@ -329,31 +319,24 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres packet->Read(playerID); if (mailID > 0 && playerID == player->GetObjectID()) { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;"); - stmt->setUInt64(1, mailID); - sql::ResultSet* res = stmt->executeQuery(); + auto playerMail = Database::Get()->GetMail(mailID); LOT attachmentLOT = 0; uint32_t attachmentCount = 0; - while (res->next()) { - attachmentLOT = res->getInt(1); - attachmentCount = res->getInt(2); + if (playerMail) { + attachmentLOT = playerMail->itemLOT; + attachmentCount = playerMail->itemCount; } - auto inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); + auto inv = player->GetComponent(); if (!inv) return; inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL); Mail::SendAttachmentRemoveConfirm(sysAddr, mailID); - sql::PreparedStatement* up = Database::Get()->CreatePreppedStmt("UPDATE mail SET attachment_lot=0 WHERE id=?;"); - up->setUInt64(1, mailID); - up->execute(); - delete up; - delete res; - delete stmt; + Database::Get()->ClaimMailItem(mailID); } } @@ -378,15 +361,9 @@ void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAdd } void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) { - auto returnVal = std::async(std::launch::async, [&]() { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT id FROM mail WHERE receiver_id=? AND was_read=0"); - stmt->setUInt(1, objectID); - sql::ResultSet* res = stmt->executeQuery(); - - if (res->rowsCount() > 0) Mail::SendNotification(sysAddr, res->rowsCount()); - delete res; - delete stmt; - }); + auto unreadMailCount = Database::Get()->GetUnreadMailCount(objectID); + + if (unreadMailCount > 0) Mail::SendNotification(sysAddr, unreadMailCount); } void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) { @@ -433,10 +410,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO bitStream.Write(mailID); Game::server->Send(&bitStream, sysAddr, false); - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("DELETE FROM mail WHERE id=? LIMIT 1;"); - stmt->setUInt64(1, mailID); - stmt->execute(); - delete stmt; + Database::Get()->DeleteMail(mailID); } void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { @@ -447,8 +421,5 @@ void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { bitStream.Write(mailID); Game::server->Send(&bitStream, sysAddr, false); - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("UPDATE mail SET was_read=1 WHERE id=?"); - stmt->setUInt64(1, mailID); - stmt->execute(); - delete stmt; + Database::Get()->MarkMailRead(static_cast(mailID)); } diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index c35a33e48..e554a28a8 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -360,11 +360,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } // Log command to database - auto stmt = Database::Get()->CreatePreppedStmt("INSERT INTO command_log (character_id, command) VALUES (?, ?);"); - stmt->setInt(1, entity->GetCharacter()->GetID()); - stmt->setString(2, GeneralUtils::UTF16ToWTF8(command).c_str()); - stmt->execute(); - delete stmt; + Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), chatCommand); if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 int32_t minifigItemId; @@ -817,33 +813,25 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { const auto& playerName = args[0]; - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;"); - stmt->setString(1, playerName); - sql::ResultSet* res = stmt->executeQuery(); - uint32_t receiverID = 0; - - if (res->rowsCount() > 0) { - while (res->next()) receiverID = res->getUInt(1); - } + auto playerInfo = Database::Get()->GetCharacterInfo(playerName); - delete stmt; - delete res; - - if (receiverID == 0) { + uint32_t receiverID = 0; + if (!playerInfo) { ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); return; } - uint32_t lot; + receiverID = playerInfo->id; + + LOT lot; if (!GeneralUtils::TryParse(args[1], lot)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); return; } - uint64_t currentTime = time(NULL); - DatabaseStructs::MailInsert mailInsert; + IMail::MailInfo mailInsert; mailInsert.senderId = entity->GetObjectID(); mailInsert.senderUsername = "Darkflame Universe"; mailInsert.receiverId = receiverID; @@ -852,8 +840,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit mailInsert.body = "This is a replacement item for one you lost."; mailInsert.itemID = LWOOBJID_EMPTY; mailInsert.itemLOT = lot; - mailInsert.subkey = LWOOBJID_EMPTY; - mailInsert.attachmentCount = 1; + mailInsert.itemSubkey = LWOOBJID_EMPTY; + mailInsert.itemCount = 1; Database::Get()->InsertNewMail(mailInsert); ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); @@ -1014,25 +1002,16 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit LWOOBJID characterId = 0; if (player == nullptr) { - auto* accountQuery = Database::Get()->CreatePreppedStmt("SELECT account_id, id FROM charinfo WHERE name=? LIMIT 1;"); - - accountQuery->setString(1, args[0]); + auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - auto result = accountQuery->executeQuery(); + if (characterInfo) { + accountId = characterInfo->accountId; + characterId = characterInfo->id; - if (result->rowsCount() > 0) { - while (result->next()) { - accountId = result->getUInt(1); - characterId = result->getUInt64(2); - - GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); - GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); - } + GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); + GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); } - delete accountQuery; - delete result; - if (accountId == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); @@ -1043,8 +1022,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit characterId = player->GetCharacter()->GetID(); } - auto* userUpdate = Database::Get()->CreatePreppedStmt("UPDATE accounts SET mute_expire = ? WHERE id = ?;"); - time_t expire = 1; // Default to indefinate mute if (args.size() >= 2) { @@ -1069,12 +1046,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit expire += 60 * 60 * hours; } - userUpdate->setUInt64(1, expire); - userUpdate->setInt(2, accountId); - - userUpdate->executeUpdate(); - - delete userUpdate; + Database::Get()->UpdateAccountUnmuteTime(accountId, expire); char buffer[32] = "brought up for review.\0"; @@ -1126,19 +1098,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit uint32_t accountId = 0; if (player == nullptr) { - auto* accountQuery = Database::Get()->CreatePreppedStmt("SELECT account_id FROM charinfo WHERE name=? LIMIT 1;"); - - accountQuery->setString(1, args[0]); + auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - auto result = accountQuery->executeQuery(); - - if (result->rowsCount() > 0) { - while (result->next()) accountId = result->getUInt(1); + if (characterInfo) { + accountId = characterInfo->accountId; } - delete accountQuery; - delete result; - if (accountId == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); @@ -1148,13 +1113,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit accountId = player->GetParentUser()->GetAccountID(); } - auto* userUpdate = Database::Get()->CreatePreppedStmt("UPDATE accounts SET banned = true WHERE id = ?;"); - - userUpdate->setInt(1, accountId); - - userUpdate->executeUpdate(); - - delete userUpdate; + Database::Get()->UpdateAccountBan(accountId, true); if (player != nullptr) { Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 71430faa1..8ed9cf900 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -220,19 +220,14 @@ int main(int argc, char** argv) { std::cout << "Enter a username: "; std::cin >> username; - std::unique_ptr userLookupStatement(Database::Get()->CreatePreppedStmt("SELECT id FROM accounts WHERE name=? LIMIT 1;")); - userLookupStatement->setString(1, username.c_str()); - std::unique_ptr res(userLookupStatement->executeQuery()); - if (res->rowsCount() > 0) { + auto accountId = Database::Get()->GetAccountInfo(username); + if (accountId) { LOG("Account with name \"%s\" already exists", username.c_str()); std::cout << "Do you want to change the password of that account? [y/n]?"; std::string prompt = ""; std::cin >> prompt; if (prompt == "y" || prompt == "yes") { - uint32_t accountId = 0; - res->next(); - accountId = res->getUInt(1); - if (accountId == 0) return EXIT_FAILURE; + if (accountId->id == 0) return EXIT_FAILURE; //Read the password from the console without echoing it. #ifdef __linux__ @@ -252,10 +247,7 @@ int main(int argc, char** argv) { bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); assert(bcryptState == 0); - std::unique_ptr userUpdateStatement(Database::Get()->CreatePreppedStmt("UPDATE accounts SET password = ? WHERE id = ?;")); - userUpdateStatement->setString(1, std::string(hash, BCRYPT_HASHSIZE).c_str()); - userUpdateStatement->setUInt(2, accountId); - userUpdateStatement->execute(); + Database::Get()->UpdateAccountPassword(accountId->id, std::string(hash, BCRYPT_HASHSIZE)); LOG("Account \"%s\" password updated successfully!", username.c_str()); } else { @@ -284,11 +276,7 @@ int main(int argc, char** argv) { //Create account try { - std::unique_ptr statement(Database::Get()->CreatePreppedStmt("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);")); - statement->setString(1, username.c_str()); - statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); - statement->setInt(3, 9); - statement->execute(); + Database::Get()->InsertNewAccount(username, std::string(hash, BCRYPT_HASHSIZE)); } catch(sql::SQLException& e) { LOG("A SQL error occurred!:\n %s", e.what()); return EXIT_FAILURE; @@ -307,8 +295,6 @@ int main(int argc, char** argv) { Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::shouldShutdown); //Query for the database for a server labeled "master" - auto* masterLookupStatement = Database::Get()->CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); - auto* result = masterLookupStatement->executeQuery(); auto master_server_ip = Game::config->GetValue("master_ip"); @@ -316,22 +302,7 @@ int main(int argc, char** argv) { master_server_ip = Game::server->GetIP(); } - //If we found a server, update it's IP and port to the current one. - if (result->next()) { - auto* updateStatement = Database::Get()->CreatePreppedStmt("UPDATE `servers` SET `ip` = ?, `port` = ? WHERE `id` = ?"); - updateStatement->setString(1, master_server_ip.c_str()); - updateStatement->setInt(2, Game::server->GetPort()); - updateStatement->setInt(3, result->getInt("id")); - updateStatement->execute(); - delete updateStatement; - } else { - //If we didn't find a server, create one. - auto* insertStatement = Database::Get()->CreatePreppedStmt("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171023)"); - insertStatement->setString(1, master_server_ip.c_str()); - insertStatement->setInt(2, Game::server->GetPort()); - insertStatement->execute(); - delete insertStatement; - } + Database::Get()->SetMasterIp(master_server_ip, Game::server->GetPort()); //Create additional objects here: ObjectIDManager::Instance()->Initialize(Game::logger); diff --git a/dMasterServer/ObjectIDManager.cpp b/dMasterServer/ObjectIDManager.cpp index 19ae77eca..4739addff 100644 --- a/dMasterServer/ObjectIDManager.cpp +++ b/dMasterServer/ObjectIDManager.cpp @@ -14,58 +14,35 @@ void ObjectIDManager::Initialize(Logger* logger) { this->currentPersistentID = 1; try { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt( - "SELECT last_object_id FROM object_id_tracker"); - - sql::ResultSet* result = stmt->executeQuery(); - auto next = result->next(); - - if (!next) { - sql::PreparedStatement* insertStmt = Database::Get()->CreatePreppedStmt( - "INSERT INTO object_id_tracker VALUES (1)"); - - insertStmt->execute(); - - delete insertStmt; + auto lastObjectId = Database::Get()->GetCurrentPersistentId(); + if (!lastObjectId) { + Database::Get()->InsertDefaultPersistentId(); return; + } else { + this->currentPersistentID = lastObjectId.value(); } - while (next) { - this->currentPersistentID = - result->getInt(1) > 0 ? result->getInt(1) : 1; - next = result->next(); + if (this->currentPersistentID <= 0) { + LOG("Invalid persistent object ID in database. Aborting to prevent bad id generation."); + throw std::runtime_error("Invalid persistent object ID in database. Aborting to prevent bad id generation."); } - - delete result; - delete stmt; } catch (sql::SQLException& e) { - LOG("Unable to fetch max persistent object ID in use. Defaulting to 1."); + LOG("Unable to fetch max persistent object ID in use. This will cause issues. Aborting to prevent collisions."); LOG("SQL error: %s", e.what()); - this->currentPersistentID = 1; + throw; } } //! Generates a new persistent ID -uint32_t ObjectIDManager::GeneratePersistentID(void) { +uint32_t ObjectIDManager::GeneratePersistentID() { uint32_t toReturn = ++this->currentPersistentID; - // So we peroidically save our ObjID to the database: - // if (toReturn % 25 == 0) { // TEMP: DISABLED FOR DEBUG / DEVELOPMENT! - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt( - "UPDATE object_id_tracker SET last_object_id=?"); - stmt->setUInt(1, toReturn); - stmt->execute(); - delete stmt; - // } + SaveToDatabase(); return toReturn; } void ObjectIDManager::SaveToDatabase() { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt( - "UPDATE object_id_tracker SET last_object_id=?"); - stmt->setUInt(1, currentPersistentID); - stmt->execute(); - delete stmt; + Database::Get()->UpdatePersistentId(this->currentPersistentID); } diff --git a/dMasterServer/ObjectIDManager.h b/dMasterServer/ObjectIDManager.h index 1454d08f2..cdb6dcdf2 100644 --- a/dMasterServer/ObjectIDManager.h +++ b/dMasterServer/ObjectIDManager.h @@ -41,7 +41,7 @@ class ObjectIDManager { /*! \return The new persistent ID */ - uint32_t GeneratePersistentID(void); + uint32_t GeneratePersistentID(); void SaveToDatabase(); }; diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index 735eed257..6bd080572 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -27,6 +27,7 @@ #include "eConnectionType.h" #include "eServerMessageType.h" #include "eMasterMessageType.h" +#include "eGameMasterLevel.h" void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); @@ -64,120 +65,53 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { const char* szUsername = username.c_str(); // Fetch account details - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT password, banned, locked, play_key_id, gm_level FROM accounts WHERE name=? LIMIT 1;"); - stmt->setString(1, szUsername); + auto accountInfo = Database::Get()->GetAccountInfo(username); - sql::ResultSet* res = stmt->executeQuery(); - - if (res->rowsCount() == 0) { - LOG("No user found!"); + if (!accountInfo) { + LOG("No user by name %s found!", username.c_str()); AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::INVALID_USER, "", "", 2001, username); return; } - std::string sqlPass = ""; - bool sqlBanned = false; - bool sqlLocked = false; - uint32_t sqlPlayKey = 0; - uint32_t sqlGmLevel = 0; - - while (res->next()) { - sqlPass = res->getString(1).c_str(); - sqlBanned = res->getBoolean(2); - sqlLocked = res->getBoolean(3); - sqlPlayKey = res->getInt(4); - sqlGmLevel = res->getInt(5); - } - - delete stmt; - delete res; - //If we aren't running in live mode, then only GMs are allowed to enter: const auto& closedToNonDevs = Game::config->GetValue("closed_to_non_devs"); - if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && sqlGmLevel == 0) { + if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "The server is currently only open to developers.", "", 2001, username); return; } if (Game::config->GetValue("dont_use_keys") != "1") { //Check to see if we have a play key: - if (sqlPlayKey == 0 && sqlGmLevel == 0) { + if (accountInfo->playKeyId == 0 && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); LOG("User %s tried to log in, but they don't have a play key.", username.c_str()); return; } //Check if the play key is _valid_: - auto keyCheckStmt = Database::Get()->CreatePreppedStmt("SELECT active FROM `play_keys` WHERE id=?"); - keyCheckStmt->setInt(1, sqlPlayKey); - auto keyRes = keyCheckStmt->executeQuery(); - bool isKeyActive = false; + auto playKeyStatus = Database::Get()->IsPlaykeyActive(accountInfo->playKeyId); - if (keyRes->rowsCount() == 0 && sqlGmLevel == 0) { + if (!playKeyStatus || accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username); return; } - while (keyRes->next()) { - isKeyActive = (bool)keyRes->getInt(1); - } - - if (!isKeyActive && sqlGmLevel == 0) { + if (!playKeyStatus.value() && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your play key has been disabled.", "", 2001, username); LOG("User %s tried to log in, but their play key was disabled", username.c_str()); return; } } - if (sqlBanned) { + if (accountInfo->banned) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::BANNED, "", "", 2001, username); return; } - if (sqlLocked) { + if (accountInfo->locked) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::ACCOUNT_LOCKED, "", "", 2001, username); return; } - /* - * Updated hashing method: - * First attempt bcrypt. - * If that fails, fallback to old method and setup bcrypt for new login. - */ - - bool loginSuccess = true; - - int32_t bcryptState = ::bcrypt_checkpw(password.c_str(), sqlPass.c_str()); - - if (bcryptState != 0) { - // Fallback on old method - - std::string oldPassword = sha512(password + username); - - if (sqlPass != oldPassword) { - loginSuccess = false; - } else { - // Generate new hash for bcrypt - - char salt[BCRYPT_HASHSIZE]; - char hash[BCRYPT_HASHSIZE]; - - bcryptState = ::bcrypt_gensalt(12, salt); - - assert(bcryptState == 0); - - bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); - - assert(bcryptState == 0); - - sql::PreparedStatement* accountUpdate = Database::Get()->CreatePreppedStmt("UPDATE accounts SET password = ? WHERE name = ? LIMIT 1;"); - - accountUpdate->setString(1, std::string(hash, BCRYPT_HASHSIZE).c_str()); - accountUpdate->setString(2, szUsername); - - accountUpdate->executeUpdate(); - } - } else { - // Login success with bcrypt - } + bool loginSuccess = ::bcrypt_checkpw(password.c_str(), accountInfo->bcryptPassword.c_str()) == 0; if (!loginSuccess) { AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::WRONG_PASS, "", "", 2001, username); diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index b29fc756b..e08f5dbb5 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -352,24 +352,18 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa LWOOBJID idOfReceiver = LWOOBJID_EMPTY; { - auto characterIdFetch = Database::Get()->DoesCharacterExist(receiver); + auto characterIdFetch = Database::Get()->GetCharacterInfo(receiver); if (characterIdFetch) { - idOfReceiver = characterIdFetch.value(); + idOfReceiver = characterIdFetch->id; } } if (user->GetIsBestFriendMap().find(receiver) == user->GetIsBestFriendMap().end() && idOfReceiver != LWOOBJID_EMPTY) { - sql::PreparedStatement* stmt = Database::Get()->CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); - stmt->setInt(1, entity->GetObjectID()); - stmt->setInt(2, idOfReceiver); - stmt->setInt(3, idOfReceiver); - stmt->setInt(4, entity->GetObjectID()); + auto bffInfo = Database::Get()->GetBestFriendStatus(entity->GetObjectID(), idOfReceiver); - sql::ResultSet* res = stmt->executeQuery(); - - if (res->next()) { - isBestFriend = res->getInt("best_friend") == 3; + if (bffInfo) { + isBestFriend = bffInfo->bestFriendStatus == 3; } if (isBestFriend) { @@ -377,9 +371,6 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa tmpBestFriendMap[receiver] = true; user->SetIsBestFriendMap(tmpBestFriendMap); } - - delete res; - delete stmt; } else if (user->GetIsBestFriendMap().find(receiver) != user->GetIsBestFriendMap().end()) { isBestFriend = true; } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 3ee4bf7c4..81ea3d1c8 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -74,6 +74,7 @@ #include "ZCompression.h" #include "EntityManager.h" #include "CheatDetection.h" +#include "eGameMasterLevel.h" namespace Game { Logger* logger = nullptr; @@ -874,20 +875,15 @@ void HandlePacket(Packet* packet) { // If the check is turned on, validate the client's database checksum. if (Game::config->GetValue("check_fdb") == "1" && !databaseChecksum.empty()) { - uint32_t gmLevel = 0; - auto* stmt = Database::Get()->CreatePreppedStmt("SELECT gm_level FROM accounts WHERE name=? LIMIT 1;"); - stmt->setString(1, username.c_str()); - - auto* res = stmt->executeQuery(); - while (res->next()) { - gmLevel = res->getInt(1); + auto accountInfo = Database::Get()->GetAccountInfo(username); + if (!accountInfo) { + LOG("Client's account does not exist in the database, aborting connection."); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); + return; } - delete stmt; - delete res; - // Developers may skip this check - if (gmLevel < 8 && clientDatabaseChecksum != databaseChecksum) { + if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER && clientDatabaseChecksum != databaseChecksum) { LOG("Client's database checksum does not match the server's, aborting connection."); Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::WRONG_GAME_VERSION); return; @@ -951,7 +947,7 @@ void HandlePacket(Packet* packet) { CheckType::Entity, "Sending GM with a sending player that does not match their own. GM ID: %i", static_cast(messageID) - ); + ); if (isSender) GameMessageHandler::HandleMessage(&dataStream, packet->systemAddress, objectID, messageID); break; @@ -975,7 +971,7 @@ void HandlePacket(Packet* packet) { CheckType::User, "Sending login request with a sending player that does not match their own. Player ID: %llu", playerID - ); + ); if (!valid) return; @@ -1046,23 +1042,23 @@ void HandlePacket(Packet* packet) { if (!levelComponent) return; auto version = levelComponent->GetCharacterVersion(); - switch(version) { - case eCharacterVersion::RELEASE: - // TODO: Implement, super low priority - case eCharacterVersion::LIVE: - LOG("Updating Character Flags"); - c->SetRetroactiveFlags(); - levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); - case eCharacterVersion::PLAYER_FACTION_FLAGS: - LOG("Updating Vault Size"); - player->RetroactiveVaultSize(); - levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); - case eCharacterVersion::VAULT_SIZE: - LOG("Updaing Speedbase"); - levelComponent->SetRetroactiveBaseSpeed(); - levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); - case eCharacterVersion::UP_TO_DATE: - break; + switch (version) { + case eCharacterVersion::RELEASE: + // TODO: Implement, super low priority + case eCharacterVersion::LIVE: + LOG("Updating Character Flags"); + c->SetRetroactiveFlags(); + levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); + case eCharacterVersion::PLAYER_FACTION_FLAGS: + LOG("Updating Vault Size"); + player->RetroactiveVaultSize(); + levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); + case eCharacterVersion::VAULT_SIZE: + LOG("Updaing Speedbase"); + levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + case eCharacterVersion::UP_TO_DATE: + break; } player->GetCharacter()->SetTargetScene(""); @@ -1078,84 +1074,45 @@ void HandlePacket(Packet* packet) { if (g_CloneID != 0) { const auto& worldId = Game::zoneManager->GetZone()->GetZoneID(); - const auto zoneId = Game::server->GetZoneID(); + const auto zoneId = worldId.GetMapID(); const auto cloneId = g_CloneID; - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); - query.bind(1, (int)zoneId); - - auto result = query.execQuery(); - - if (result.eof() || result.fieldIsNull(0)) { - LOG("No property templates found for zone %d, not sending BBB", zoneId); - goto noBBB; - } - //Check for BBB models: - auto stmt = Database::Get()->CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - - int32_t templateId = result.getIntField(0); - - result.finalize(); + auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId); LWOOBJID propertyId = LWOOBJID_EMPTY; - auto propertyInfo = Database::Get()->GetPropertyInfo(templateId, cloneId); - if (propertyInfo) propertyId = propertyInfo->id; else { - LOG("Couldn't find property ID for template %i, clone %i", templateId, cloneId); + LOG("Couldn't find property ID for zone %i, clone %i", zoneId, cloneId); goto noBBB; } + for (auto& bbbModel : Database::Get()->GetUgcModels(propertyId)) { + LOG("Getting lxfml ugcID: %llu", bbbModel.id); - stmt->setUInt64(1, propertyId); - auto res = stmt->executeQuery(); - while (res->next()) { - LOG("Getting lxfml ugcID: %u", res->getUInt(1)); - - //Get lxfml: - auto stmtL = Database::Get()->CreatePreppedStmt("SELECT lxfml from ugc where id=?"); - stmtL->setUInt(1, res->getUInt(1)); - - auto lxres = stmtL->executeQuery(); + bbbModel.lxfmlData.seekg(0, std::ios::end); + size_t lxfmlSize = bbbModel.lxfmlData.tellg(); + bbbModel.lxfmlData.seekg(0); - while (lxres->next()) { - auto lxfml = lxres->getBlob(1); + //Send message: + LWOOBJID blueprintID = bbbModel.id; + GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); + GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); - lxfml->seekg(0, std::ios::end); - size_t lxfmlSize = lxfml->tellg(); - lxfml->seekg(0); + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + bitStream.Write(LWOOBJID_EMPTY); //always zero so that a check on the client passes + bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); + bitStream.Write(1); + bitStream.Write(blueprintID); - //Send message: - { - LWOOBJID blueprintID = res->getUInt(1); - GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); - GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); + bitStream.Write(lxfmlSize); - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); - bitStream.Write(LWOOBJID_EMPTY); //always zero so that a check on the client passes - bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); - bitStream.Write(1); - bitStream.Write(blueprintID); + bitStream.WriteAlignedBytes(reinterpret_cast(bbbModel.lxfmlData.str().c_str()), lxfmlSize); - bitStream.Write(lxfmlSize); - - for (size_t i = 0; i < lxfmlSize; ++i) - bitStream.Write(lxfml->get()); - - SystemAddress sysAddr = packet->systemAddress; - SEND_PACKET; - PacketUtils::SavePacket("lxfml packet " + std::to_string(res->getUInt(1)) + ".bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); - } - } - - delete stmtL; - delete lxres; + SystemAddress sysAddr = packet->systemAddress; + SEND_PACKET; + // PacketUtils::SavePacket("lxfml packet " + std::to_string(bbbModel.id) + ".bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); } - - delete stmt; - delete res; } noBBB: