Compare commits

..

1 Commits

Author SHA1 Message Date
David Markowitz
e76d70c9c4 fix: get entity from manager vs from character
fixes a possible crash due to null entity
2025-06-26 00:35:45 -07:00
356 changed files with 2650 additions and 6071 deletions

View File

@@ -1,29 +0,0 @@
# GitHub Copilot Instructions
* c++20 standard, please use the latest features except NO modules.
* use `.contains` for searching in associative containers
* use const as much as possible. If it can be const, it should be made const
* DO NOT USE const_cast EVER.
* use `cstdint` bitwidth types ALWAYS for integral types.
* NEVER use std::wstring. If wide strings are necessary, use std::u16string with conversion utilties in GeneralUtils.h.
* Functions are ALWAYS PascalCase.
* local variables are camelCase
* NEVER use snake case
* indentation is TABS, not SPACES.
* TABS are 4 spaces by default
* Use trailing braces ALWAYS
* global variables are prefixed with `g_`
* if global variables or functions are needed, they should be located in an anonymous namespace
* Use `GeneralUtils::TryParse` for ANY parsing of strings to integrals.
* Use brace initialization when possible.
* ALWAYS default initialize variables.
* Pointers should be avoided unless necessary. Use references when the pointer has been checked and should not be null
* headers should be as compact as possible. Do NOT include extra data that isnt needed.
* Remember to include logs (LOG macro uses printf style logging) while putting verbose logs under LOG_DEBUG.
* NEVER USE `RakNet::BitStream::ReadBit`
* NEVER assume pointers are good, always check if they are null. Once a pointer is checked and is known to be non-null, further accesses no longer need checking
* Be wary of TOCTOU. Prevent all possible issues relating to TOCTOU.
* new memory allocations should never be used unless absolutely necessary.
* new for reconstruction of objects is allowed
* Prefer following the format of the file over correct formatting. Consistency over correctness.
* When using auto, ALWAYS put a * for pointers.

View File

@@ -19,7 +19,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debuggi
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(FETCHCONTENT_QUIET FALSE) # GLM takes a long time to clone, this will at least show _something_ while its downloading
# Read variables from file
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
@@ -307,7 +306,7 @@ add_subdirectory(dServer)
add_subdirectory(dWeb)
# Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES glm::glm "dCommon" "dDatabase" "dNet" "raknet" "magic_enum")
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "magic_enum")
# Add platform specific common libraries
if(UNIX)

View File

@@ -187,8 +187,7 @@ Now that you are logged in, run the following commands.
```bash
# Creates a user for this computer which uses a password and grant said user all privileges.
# Change mydarkflameuser to a custom username and password to a custom password.
CREATE USER 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' WITH GRANT OPTION;
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# Then create a database for Darkflame Universe to use.

View File

@@ -6,8 +6,6 @@ FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
GIT_PROGRESS TRUE
GIT_SHALLOW 1
)
# For Windows: Prevent overriding the parent project's compiler/linker settings

View File

@@ -20,7 +20,7 @@
//Auth includes:
#include "AuthPackets.h"
#include "ServiceType.h"
#include "eConnectionType.h"
#include "MessageType/Server.h"
#include "MessageType/Auth.h"
@@ -52,7 +52,6 @@ int main(int argc, char** argv) {
//Create all the objects we need to run our service:
Server::SetupLogger("AuthServer");
if (!Game::logger) return EXIT_FAILURE;
Game::config->LogSettings();
LOG("Starting Auth server...");
LOG("Version: %s", PROJECT_VERSION);
@@ -93,7 +92,7 @@ int main(int argc, char** argv) {
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServiceType::AUTH, Game::config, &Game::lastSignal, masterPassword);
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal, masterPassword);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -168,11 +167,11 @@ void HandlePacket(Packet* packet) {
if (packet->length < 4) return;
if (packet->data[0] == ID_USER_PACKET_ENUM) {
if (static_cast<ServiceType>(packet->data[1]) == ServiceType::COMMON) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) {
AuthPackets::HandleHandshake(Game::server, packet);
}
} else if (static_cast<ServiceType>(packet->data[1]) == ServiceType::AUTH) {
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
if (static_cast<MessageType::Auth>(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) {
AuthPackets::HandleLoginRequest(Game::server, packet);
}

View File

@@ -1,4 +1,4 @@
set(DCHATFILTER_SOURCES "dChatFilter.cpp")
add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES})
target_link_libraries(dChatFilter dDatabase glm::glm)
target_link_libraries(dChatFilter dDatabase)

View File

@@ -14,6 +14,6 @@ add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}
add_library(dChatServer ${DCHATSERVER_SOURCES})
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer" "${PROJECT_SOURCE_DIR}/dChatFilter")
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter glm::glm)
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer mongoose dWeb)

View File

@@ -13,11 +13,11 @@
// The only thing not auto-handled is instance activities force joining the team on the server.
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const MessageType::Client type) {
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receivingPlayer);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, type);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, type);
}
void ChatIgnoreList::GetIgnoreList(Packet* packet) {
@@ -34,7 +34,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
if (!receiver.ignoredPlayers.empty()) {
LOG_DEBUG("Player %llu already has an ignore list, but is requesting it again.", playerId);
} else {
auto ignoreList = Database::Get()->GetIgnoreList(playerId);
auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId));
if (ignoreList.empty()) {
LOG_DEBUG("Player %llu has no ignores", playerId);
return;
@@ -43,6 +43,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
for (auto& ignoredPlayer : ignoreList) {
receiver.ignoredPlayers.emplace_back(ignoredPlayer.name, ignoredPlayer.id);
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(receiver.ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
}
}
@@ -113,8 +114,9 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
}
if (ignoredPlayerId != LWOOBJID_EMPTY) {
Database::Get()->AddIgnore(playerId, ignoredPlayerId);
Database::Get()->AddIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(ignoredPlayerId));
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT);
receiver.ignoredPlayers.emplace_back(toIgnoreStr, ignoredPlayerId);
LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str());
@@ -155,7 +157,7 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
return;
}
Database::Get()->RemoveIgnore(playerId, toRemove->playerId);
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
receiver.ignoredPlayers.erase(toRemove, receiver.ignoredPlayers.end());
CBITSTREAM;

View File

@@ -12,7 +12,7 @@
#include "RakString.h"
#include "dConfig.h"
#include "eObjectBits.h"
#include "ServiceType.h"
#include "eConnectionType.h"
#include "MessageType/Chat.h"
#include "MessageType/Client.h"
#include "MessageType/Game.h"
@@ -35,6 +35,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
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
@@ -60,11 +61,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Now, we need to send the friendlist to the server they came from:
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::GET_FRIENDS_LIST_RESPONSE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GET_FRIENDS_LIST_RESPONSE);
bitStream.Write<uint8_t>(0);
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
bitStream.Write<uint16_t>(player.friends.size());
@@ -160,7 +161,9 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
// Set the bits
GeneralUtils::SetBit(queryPlayerID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(queryPlayerID, eObjectBits::PERSISTENT);
GeneralUtils::SetBit(queryFriendID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(queryFriendID, eObjectBits::PERSISTENT);
// Since this player can either be the friend of someone else or be friends with someone else
// their column in the database determines what bit gets set. When the value hits 3, they
@@ -315,6 +318,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
}
// Convert friendID to LWOOBJID
GeneralUtils::SetBit(friendID, eObjectBits::PERSISTENT);
GeneralUtils::SetBit(friendID, eObjectBits::CHARACTER);
Database::Get()->RemoveFriend(playerID, friendID);
@@ -371,10 +375,10 @@ void ChatPacketHandler::HandleWho(Packet* packet) {
bool online = player;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(request.requestor);
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::WHO_RESPONSE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::WHO_RESPONSE);
bitStream.Write<uint8_t>(online);
bitStream.Write(player.zoneID.GetMapID());
bitStream.Write(player.zoneID.GetInstanceID());
@@ -394,10 +398,10 @@ void ChatPacketHandler::HandleShowAll(Packet* packet) {
if (!sender) return;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(request.requestor);
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::SHOW_ALL_RESPONSE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::SHOW_ALL_RESPONSE);
bitStream.Write<uint8_t>(!request.displayZoneData && !request.displayIndividualPlayers);
bitStream.Write(Game::playerContainer.GetPlayerCount());
bitStream.Write(Game::playerContainer.GetSimCount());
@@ -529,7 +533,7 @@ void ChatPacketHandler::OnAchievementNotify(RakNet::BitStream& bitstream, const
LOG_DEBUG("Sending achievement notify to %s", notify.targetPlayerName.GetAsString().c_str());
RakNet::BitStream worldStream;
BitStreamUtils::WriteHeader(worldStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(worldStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
worldStream.Write(friendData.playerID);
notify.WriteHeader(worldStream);
notify.Serialize(worldStream);
@@ -540,10 +544,10 @@ void ChatPacketHandler::OnAchievementNotify(RakNet::BitStream& bitstream, const
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(routeTo.playerID);
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::PRIVATE_CHAT_MESSAGE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::PRIVATE_CHAT_MESSAGE);
bitStream.Write(sender.playerID);
bitStream.Write(channel);
bitStream.Write<uint32_t>(0); // not used
@@ -575,11 +579,11 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
[bool] - is FTP*/
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(friendData.playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::UPDATE_FRIEND_NOTIFY);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::UPDATE_FRIEND_NOTIFY);
bitStream.Write<uint8_t>(notifyType);
std::string playerName = playerData.playerName.c_str();
@@ -612,11 +616,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
}
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::ADD_FRIEND_REQUEST);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_REQUEST);
bitStream.Write(LUWString(sender.playerName));
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
@@ -626,11 +630,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
// Portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::ADD_FRIEND_RESPONSE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_RESPONSE);
bitStream.Write(responseCode);
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.worldServerSysAddr != UNASSIGNED_SYSTEM_ADDRESS);
@@ -649,11 +653,11 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::REMOVE_FRIEND_RESPONSE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::REMOVE_FRIEND_RESPONSE);
bitStream.Write<uint8_t>(isSuccessful); //isOnline
bitStream.Write(LUWString(personToRemove));

View File

@@ -13,7 +13,7 @@
#include "Diagnostics.h"
#include "AssetManager.h"
#include "BinaryPathFinder.h"
#include "ServiceType.h"
#include "eConnectionType.h"
#include "PlayerContainer.h"
#include "ChatPacketHandler.h"
#include "MessageType/Chat.h"
@@ -59,7 +59,6 @@ int main(int argc, char** argv) {
//Create all the objects we need to run our service:
Server::SetupLogger("ChatServer");
if (!Game::logger) return EXIT_FAILURE;
Game::config->LogSettings();
//Read our config:
@@ -124,7 +123,7 @@ int main(int argc, char** argv) {
const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServiceType::CHAT, Game::config, &Game::lastSignal, masterPassword);
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal, masterPassword);
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
@@ -219,11 +218,11 @@ void HandlePacket(Packet* packet) {
CINSTREAM;
inStream.SetReadOffset(BYTES_TO_BITS(1));
ServiceType connection;
inStream.Read(connection);
if (connection != ServiceType::CHAT) return;
eConnectionType connection;
MessageType::Chat chatMessageID;
inStream.Read(connection);
if (connection != eConnectionType::CHAT) return;
inStream.Read(chatMessageID);
// Our packing byte wasnt there? Probably a false packet

View File

@@ -8,7 +8,7 @@
#include "GeneralUtils.h"
#include "BitStreamUtils.h"
#include "Database.h"
#include "ServiceType.h"
#include "eConnectionType.h"
#include "ChatPackets.h"
#include "dConfig.h"
#include "MessageType/Chat.h"
@@ -147,7 +147,7 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_MUTE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
bitStream.Write(player);
bitStream.Write(time);

View File

@@ -264,11 +264,11 @@ void TeamContainer::HandleTeamStatusRequest(Packet* packet) {
void TeamContainer::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::TEAM_INVITE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE);
bitStream.Write(LUWString(sender.playerName.c_str()));
bitStream.Write(sender.playerID);
@@ -279,7 +279,7 @@ void TeamContainer::SendTeamInvite(const PlayerData& receiver, const PlayerData&
void TeamContainer::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -306,7 +306,7 @@ void TeamContainer::SendTeamInviteConfirm(const PlayerData& receiver, bool bLead
void TeamContainer::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -331,7 +331,7 @@ void TeamContainer::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64Leade
void TeamContainer::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -348,7 +348,7 @@ void TeamContainer::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64Pl
void TeamContainer::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -377,7 +377,7 @@ void TeamContainer::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTr
void TeamContainer::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -403,7 +403,7 @@ void TeamContainer::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisba
void TeamContainer::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID);
//portion that will get routed:
@@ -652,7 +652,7 @@ void TeamContainer::TeamStatusUpdate(TeamData* team) {
void TeamContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
bitStream.Write(team->teamID);
bitStream.Write(deleteTeam);

View File

@@ -54,8 +54,6 @@ elseif (WIN32)
zlib
URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1
GIT_PROGRESS TRUE
GIT_SHALLOW 1
)
# Disable warning about no project version.
@@ -76,6 +74,5 @@ else ()
endif ()
target_link_libraries(dCommon
PUBLIC glm::glm
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
INTERFACE dDatabase)

View File

@@ -3,7 +3,6 @@
// C++
#include <charconv>
#include <cstdint>
#include <cmath>
#include <ctime>
#include <functional>
#include <optional>
@@ -19,9 +18,6 @@
#include "dPlatforms.h"
#include "Game.h"
#include "Logger.h"
#include "DluAssert.h"
#include <glm/ext/vector_float3.hpp>
enum eInventoryType : uint32_t;
enum class eObjectBits : size_t;
@@ -149,7 +145,7 @@ namespace GeneralUtils {
template <typename... Bases>
struct overload : Bases... {
using is_transparent = void;
using Bases::operator() ...;
using Bases::operator() ... ;
};
struct char_pointer_hash {
@@ -206,7 +202,7 @@ namespace GeneralUtils {
}
template<typename T>
requires(!Numeric<T>)
requires(!Numeric<T>)
[[nodiscard]] std::optional<T> TryParse(std::string_view str);
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
@@ -225,7 +221,7 @@ namespace GeneralUtils {
*/
template <std::floating_point T>
[[nodiscard]] std::optional<T> TryParse(std::string_view str) noexcept
try {
try {
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
size_t parseNum;
@@ -247,7 +243,7 @@ namespace GeneralUtils {
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<T> TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) {
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) {
const auto x = TryParse<float>(strX);
if (!x) return std::nullopt;
@@ -255,7 +251,7 @@ namespace GeneralUtils {
if (!y) return std::nullopt;
const auto z = TryParse<float>(strZ);
return z ? std::make_optional<T>(x.value(), y.value(), z.value()) : std::nullopt;
return z ? std::make_optional<NiPoint3>(x.value(), y.value(), z.value()) : std::nullopt;
}
/**
@@ -264,8 +260,8 @@ namespace GeneralUtils {
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<T> TryParse(const std::span<const std::string> str) {
return (str.size() == 3) ? TryParse<T>(str[0], str[1], str[2]) : std::nullopt;
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::span<const std::string> str) {
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
}
template <typename T>
@@ -303,12 +299,6 @@ namespace GeneralUtils {
return T();
}
template<typename Container>
inline Container::value_type GetRandomElement(const Container& container) {
DluAssert(!container.empty());
return container[GenerateRandomNumber<typename Container::size_type>(0, container.size() - 1)];
}
/**
* Casts the value of an enum entry to its underlying type
* @param entry Enum entry to cast
@@ -333,28 +323,4 @@ namespace GeneralUtils {
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
}
// https://www.quora.com/How-do-you-round-to-specific-increments-like-0-5-in-C
// Rounds to the nearest floating point value specified.
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
T RountToNearestEven(const T value, const T modulus) {
const auto modulo = std::fmod(value, modulus);
const auto abs_modulo_2 = std::abs(modulo * 2);
const auto abs_modulus = std::abs(modulus);
bool round_away_from_zero = false;
if (abs_modulo_2 > abs_modulus) {
round_away_from_zero = true;
} else if (abs_modulo_2 == abs_modulus) {
const auto trunc_quot = std::floor(std::abs(value / modulus));
const auto odd = std::fmod(trunc_quot, T{ 2 }) != 0;
round_away_from_zero = odd;
}
if (round_away_from_zero) {
return value + (std::copysign(modulus, value) - modulo);
} else {
return value - modulo;
}
}
}

View File

@@ -5,43 +5,13 @@
#include "TinyXmlUtils.h"
#include <ranges>
#include <unordered_map>
#include <unordered_set>
#include <functional>
#include <sstream>
namespace {
// The base LXFML xml file to use when creating new models.
std::string g_base = R"(<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<LXFML versionMajor="5" versionMinor="0">
<Meta>
<Application name="LEGO Universe" versionMajor="0" versionMinor="0"/>
<Brand name="LEGOUniverse"/>
<BrickSet version="457"/>
</Meta>
<Bricks>
</Bricks>
<RigidSystems>
</RigidSystems>
<GroupSystems>
<GroupSystem>
</GroupSystem>
</GroupSystems>
</LXFML>)";
}
Lxfml::Result Lxfml::NormalizePosition(const std::string_view data, const NiPoint3& curPosition) {
Lxfml::Result Lxfml::NormalizePosition(const std::string_view data) {
Result toReturn;
// Handle empty or invalid input
if (data.empty()) {
return toReturn;
}
tinyxml2::XMLDocument doc;
// Use length-based parsing to avoid expensive string copy
const auto err = doc.Parse(data.data(), data.size());
const auto err = doc.Parse(data.data());
if (err != tinyxml2::XML_SUCCESS) {
LOG("Failed to parse xml %s.", StringifiedEnum::ToString(err).data());
return toReturn;
}
@@ -50,6 +20,7 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data, const NiPoin
auto lxfml = reader["LXFML"];
if (!lxfml) {
LOG("Failed to find LXFML element.");
return toReturn;
}
@@ -73,45 +44,29 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data, const NiPoin
NiPoint3 lowest{ 10'000.0f, 10'000.0f, 10'000.0f };
NiPoint3 highest{ -10'000.0f, -10'000.0f, -10'000.0f };
NiPoint3 delta = NiPoint3Constant::ZERO;
if (curPosition == NiPoint3Constant::ZERO) {
// Calculate the lowest and highest points on the entire model
for (const auto& transformation : transformations | std::views::values) {
auto split = GeneralUtils::SplitString(transformation, ',');
if (split.size() < 12) continue;
auto xOpt = GeneralUtils::TryParse<float>(split[9]);
auto yOpt = GeneralUtils::TryParse<float>(split[10]);
auto zOpt = GeneralUtils::TryParse<float>(split[11]);
if (!xOpt.has_value() || !yOpt.has_value() || !zOpt.has_value()) continue;
auto x = xOpt.value();
auto y = yOpt.value();
auto z = zOpt.value();
if (x < lowest.x) lowest.x = x;
if (y < lowest.y) lowest.y = y;
if (z < lowest.z) lowest.z = z;
if (highest.x < x) highest.x = x;
if (highest.y < y) highest.y = y;
if (highest.z < z) highest.z = z;
// Calculate the lowest and highest points on the entire model
for (const auto& transformation : transformations | std::views::values) {
auto split = GeneralUtils::SplitString(transformation, ',');
if (split.size() < 12) {
LOG("Not enough in the split?");
continue;
}
delta = (highest - lowest) / 2.0f;
} else {
lowest = curPosition;
highest = curPosition;
delta = NiPoint3Constant::ZERO;
auto x = GeneralUtils::TryParse<float>(split[9]).value();
auto y = GeneralUtils::TryParse<float>(split[10]).value();
auto z = GeneralUtils::TryParse<float>(split[11]).value();
if (x < lowest.x) lowest.x = x;
if (y < lowest.y) lowest.y = y;
if (z < lowest.z) lowest.z = z;
if (highest.x < x) highest.x = x;
if (highest.y < y) highest.y = y;
if (highest.z < z) highest.z = z;
}
auto delta = (highest - lowest) / 2.0f;
auto newRootPos = lowest + delta;
// Need to snap this chosen position to the nearest valid spot
// on the LEGO grid
newRootPos.x = GeneralUtils::RountToNearestEven(newRootPos.x, 0.8f);
newRootPos.z = GeneralUtils::RountToNearestEven(newRootPos.z, 0.8f);
// Clamp the Y to the lowest point on the model
newRootPos.y = lowest.y;
@@ -119,19 +74,13 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data, const NiPoin
for (auto& transformation : transformations | std::views::values) {
auto split = GeneralUtils::SplitString(transformation, ',');
if (split.size() < 12) {
LOG("Not enough in the split?");
continue;
}
auto xOpt = GeneralUtils::TryParse<float>(split[9]);
auto yOpt = GeneralUtils::TryParse<float>(split[10]);
auto zOpt = GeneralUtils::TryParse<float>(split[11]);
if (!xOpt.has_value() || !yOpt.has_value() || !zOpt.has_value()) {
continue;
}
auto x = xOpt.value() - newRootPos.x + curPosition.x;
auto y = yOpt.value() - newRootPos.y + curPosition.y;
auto z = zOpt.value() - newRootPos.z + curPosition.z;
auto x = GeneralUtils::TryParse<float>(split[9]).value() - newRootPos.x;
auto y = GeneralUtils::TryParse<float>(split[10]).value() - newRootPos.y;
auto z = GeneralUtils::TryParse<float>(split[11]).value() - newRootPos.z;
std::stringstream stream;
for (int i = 0; i < 9; i++) {
stream << split[i];
@@ -166,345 +115,3 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data, const NiPoin
toReturn.center = newRootPos;
return toReturn;
}
// Deep-clone an XMLElement (attributes, text, and child elements) into a target document
// with maximum depth protection to prevent infinite loops
static tinyxml2::XMLElement* CloneElementDeep(const tinyxml2::XMLElement* src, tinyxml2::XMLDocument& dstDoc, int maxDepth = 100) {
if (!src || maxDepth <= 0) return nullptr;
auto* dst = dstDoc.NewElement(src->Name());
// copy attributes
for (const tinyxml2::XMLAttribute* attr = src->FirstAttribute(); attr; attr = attr->Next()) {
dst->SetAttribute(attr->Name(), attr->Value());
}
// copy children (elements and text)
for (const tinyxml2::XMLNode* child = src->FirstChild(); child; child = child->NextSibling()) {
if (const tinyxml2::XMLElement* childElem = child->ToElement()) {
// Recursively clone child elements with decremented depth
auto* clonedChild = CloneElementDeep(childElem, dstDoc, maxDepth - 1);
if (clonedChild) dst->InsertEndChild(clonedChild);
} else if (const tinyxml2::XMLText* txt = child->ToText()) {
auto* n = dstDoc.NewText(txt->Value());
dst->InsertEndChild(n);
} else if (const tinyxml2::XMLComment* c = child->ToComment()) {
auto* n = dstDoc.NewComment(c->Value());
dst->InsertEndChild(n);
}
}
return dst;
}
std::vector<Lxfml::Result> Lxfml::Split(const std::string_view data, const NiPoint3& curPosition) {
std::vector<Result> results;
// Handle empty or invalid input
if (data.empty()) {
return results;
}
// Prevent processing extremely large inputs that could cause hangs
if (data.size() > 10000000) { // 10MB limit
return results;
}
tinyxml2::XMLDocument doc;
// Use length-based parsing to avoid expensive string copy
const auto err = doc.Parse(data.data(), data.size());
if (err != tinyxml2::XML_SUCCESS) {
return results;
}
auto* lxfml = doc.FirstChildElement("LXFML");
if (!lxfml) {
return results;
}
// Build maps: partRef -> Part element, partRef -> Brick element, boneRef -> partRef, brickRef -> Brick element
std::unordered_map<std::string, tinyxml2::XMLElement*> partRefToPart;
std::unordered_map<std::string, tinyxml2::XMLElement*> partRefToBrick;
std::unordered_map<std::string, std::string> boneRefToPartRef;
std::unordered_map<std::string, tinyxml2::XMLElement*> brickByRef;
auto* bricksParent = lxfml->FirstChildElement("Bricks");
if (bricksParent) {
for (auto* brick = bricksParent->FirstChildElement("Brick"); brick; brick = brick->NextSiblingElement("Brick")) {
const char* brickRef = brick->Attribute("refID");
if (brickRef) brickByRef.emplace(std::string(brickRef), brick);
for (auto* part = brick->FirstChildElement("Part"); part; part = part->NextSiblingElement("Part")) {
const char* partRef = part->Attribute("refID");
if (partRef) {
partRefToPart.emplace(std::string(partRef), part);
partRefToBrick.emplace(std::string(partRef), brick);
}
auto* bone = part->FirstChildElement("Bone");
if (bone) {
const char* boneRef = bone->Attribute("refID");
if (boneRef) boneRefToPartRef.emplace(std::string(boneRef), partRef ? std::string(partRef) : std::string());
}
}
}
}
// Collect RigidSystem elements
std::vector<tinyxml2::XMLElement*> rigidSystems;
auto* rigidSystemsParent = lxfml->FirstChildElement("RigidSystems");
if (rigidSystemsParent) {
for (auto* rs = rigidSystemsParent->FirstChildElement("RigidSystem"); rs; rs = rs->NextSiblingElement("RigidSystem")) {
rigidSystems.push_back(rs);
}
}
// Collect top-level groups (immediate children of GroupSystem)
std::vector<tinyxml2::XMLElement*> groupRoots;
auto* groupSystemsParent = lxfml->FirstChildElement("GroupSystems");
if (groupSystemsParent) {
for (auto* gs = groupSystemsParent->FirstChildElement("GroupSystem"); gs; gs = gs->NextSiblingElement("GroupSystem")) {
for (auto* group = gs->FirstChildElement("Group"); group; group = group->NextSiblingElement("Group")) {
groupRoots.push_back(group);
}
}
}
// Track used bricks and rigidsystems
std::unordered_set<std::string> usedBrickRefs;
std::unordered_set<tinyxml2::XMLElement*> usedRigidSystems;
// Track used groups to avoid processing them twice
std::unordered_set<tinyxml2::XMLElement*> usedGroups;
// Helper to create output document from sets of brick refs and rigidsystem pointers
auto makeOutput = [&](const std::unordered_set<std::string>& bricksToInclude, const std::vector<tinyxml2::XMLElement*>& rigidSystemsToInclude, const std::vector<tinyxml2::XMLElement*>& groupsToInclude = {}) {
tinyxml2::XMLDocument outDoc;
outDoc.Parse(g_base.c_str());
auto* outRoot = outDoc.FirstChildElement("LXFML");
auto* outBricks = outRoot->FirstChildElement("Bricks");
auto* outRigidSystems = outRoot->FirstChildElement("RigidSystems");
auto* outGroupSystems = outRoot->FirstChildElement("GroupSystems");
// clone and insert bricks
for (const auto& bref : bricksToInclude) {
auto it = brickByRef.find(bref);
if (it == brickByRef.end()) continue;
tinyxml2::XMLElement* cloned = CloneElementDeep(it->second, outDoc);
if (cloned) outBricks->InsertEndChild(cloned);
}
// clone and insert rigidsystems
for (auto* rsPtr : rigidSystemsToInclude) {
tinyxml2::XMLElement* cloned = CloneElementDeep(rsPtr, outDoc);
if (cloned) outRigidSystems->InsertEndChild(cloned);
}
// clone and insert group(s) if requested
if (outGroupSystems && !groupsToInclude.empty()) {
// clear default children
while (outGroupSystems->FirstChild()) outGroupSystems->DeleteChild(outGroupSystems->FirstChild());
// create a GroupSystem element and append requested groups
auto* newGS = outDoc.NewElement("GroupSystem");
for (auto* gptr : groupsToInclude) {
tinyxml2::XMLElement* clonedG = CloneElementDeep(gptr, outDoc);
if (clonedG) newGS->InsertEndChild(clonedG);
}
outGroupSystems->InsertEndChild(newGS);
}
// Print to string
tinyxml2::XMLPrinter printer;
outDoc.Print(&printer);
// Normalize position and compute center using existing helper
std::string xmlString = printer.CStr();
if (xmlString.size() > 5000000) { // 5MB limit for normalization
Result emptyResult;
emptyResult.lxfml = xmlString;
return emptyResult;
}
auto normalized = NormalizePosition(xmlString, curPosition);
return normalized;
};
// 1) Process groups (each top-level Group becomes one output; nested groups are included)
for (auto* groupRoot : groupRoots) {
// Skip if this group was already processed as part of another group
if (usedGroups.find(groupRoot) != usedGroups.end()) continue;
// Helper to collect all partRefs in a group's subtree
std::function<void(const tinyxml2::XMLElement*, std::unordered_set<std::string>&)> collectParts = [&](const tinyxml2::XMLElement* g, std::unordered_set<std::string>& partRefs) {
if (!g) return;
const char* partAttr = g->Attribute("partRefs");
if (partAttr) {
for (auto& tok : GeneralUtils::SplitString(partAttr, ',')) partRefs.insert(tok);
}
for (auto* child = g->FirstChildElement("Group"); child; child = child->NextSiblingElement("Group")) collectParts(child, partRefs);
};
// Collect all groups that need to be merged into this output
std::vector<tinyxml2::XMLElement*> groupsToInclude{ groupRoot };
usedGroups.insert(groupRoot);
// Build initial sets of bricks and boneRefs from the starting group
std::unordered_set<std::string> partRefs;
collectParts(groupRoot, partRefs);
std::unordered_set<std::string> bricksIncluded;
std::unordered_set<std::string> boneRefsIncluded;
for (const auto& pref : partRefs) {
auto pit = partRefToBrick.find(pref);
if (pit != partRefToBrick.end()) {
const char* bref = pit->second->Attribute("refID");
if (bref) bricksIncluded.insert(std::string(bref));
}
auto partIt = partRefToPart.find(pref);
if (partIt != partRefToPart.end()) {
auto* bone = partIt->second->FirstChildElement("Bone");
if (bone) {
const char* bref = bone->Attribute("refID");
if (bref) boneRefsIncluded.insert(std::string(bref));
}
}
}
// Iteratively include any RigidSystems that reference any boneRefsIncluded
// and check if those rigid systems' bricks span other groups
bool changed = true;
std::vector<tinyxml2::XMLElement*> rigidSystemsToInclude;
int maxIterations = 1000; // Safety limit to prevent infinite loops
int iteration = 0;
while (changed && iteration < maxIterations) {
changed = false;
iteration++;
// First, expand rigid systems based on current boneRefsIncluded
for (auto* rs : rigidSystems) {
if (usedRigidSystems.find(rs) != usedRigidSystems.end()) continue;
// parse boneRefs of this rigid system (from its <Rigid> children)
bool intersects = false;
std::vector<std::string> rsBoneRefs;
for (auto* rigid = rs->FirstChildElement("Rigid"); rigid; rigid = rigid->NextSiblingElement("Rigid")) {
const char* battr = rigid->Attribute("boneRefs");
if (!battr) continue;
for (auto& tok : GeneralUtils::SplitString(battr, ',')) {
rsBoneRefs.push_back(tok);
if (boneRefsIncluded.find(tok) != boneRefsIncluded.end()) intersects = true;
}
}
if (!intersects) continue;
// include this rigid system and all boneRefs it references
usedRigidSystems.insert(rs);
rigidSystemsToInclude.push_back(rs);
for (const auto& br : rsBoneRefs) {
boneRefsIncluded.insert(br);
auto bpIt = boneRefToPartRef.find(br);
if (bpIt != boneRefToPartRef.end()) {
auto partRef = bpIt->second;
auto pbIt = partRefToBrick.find(partRef);
if (pbIt != partRefToBrick.end()) {
const char* bref = pbIt->second->Attribute("refID");
if (bref && bricksIncluded.insert(std::string(bref)).second) changed = true;
}
}
}
}
// Second, check if the newly included bricks span any other groups
// If so, merge those groups into the current output
for (auto* otherGroup : groupRoots) {
if (usedGroups.find(otherGroup) != usedGroups.end()) continue;
// Collect partRefs from this other group
std::unordered_set<std::string> otherPartRefs;
collectParts(otherGroup, otherPartRefs);
// Check if any of these partRefs correspond to bricks we've already included
bool spansOtherGroup = false;
for (const auto& pref : otherPartRefs) {
auto pit = partRefToBrick.find(pref);
if (pit != partRefToBrick.end()) {
const char* bref = pit->second->Attribute("refID");
if (bref && bricksIncluded.find(std::string(bref)) != bricksIncluded.end()) {
spansOtherGroup = true;
break;
}
}
}
if (spansOtherGroup) {
// Merge this group into the current output
usedGroups.insert(otherGroup);
groupsToInclude.push_back(otherGroup);
changed = true;
// Add all partRefs, boneRefs, and bricks from this group
for (const auto& pref : otherPartRefs) {
auto pit = partRefToBrick.find(pref);
if (pit != partRefToBrick.end()) {
const char* bref = pit->second->Attribute("refID");
if (bref) bricksIncluded.insert(std::string(bref));
}
auto partIt = partRefToPart.find(pref);
if (partIt != partRefToPart.end()) {
auto* bone = partIt->second->FirstChildElement("Bone");
if (bone) {
const char* bref = bone->Attribute("refID");
if (bref) boneRefsIncluded.insert(std::string(bref));
}
}
}
}
}
}
if (iteration >= maxIterations) {
// Iteration limit reached, stop processing to prevent infinite loops
// The file is likely malformed, so just skip further processing
return results;
}
// include bricks from bricksIncluded into used set
for (const auto& b : bricksIncluded) usedBrickRefs.insert(b);
// make output doc and push result (include all merged groups' XML)
auto normalized = makeOutput(bricksIncluded, rigidSystemsToInclude, groupsToInclude);
results.push_back(normalized);
}
// 2) Process remaining RigidSystems (each becomes its own file)
for (auto* rs : rigidSystems) {
if (usedRigidSystems.find(rs) != usedRigidSystems.end()) continue;
std::unordered_set<std::string> bricksIncluded;
// collect boneRefs referenced by this rigid system
for (auto* rigid = rs->FirstChildElement("Rigid"); rigid; rigid = rigid->NextSiblingElement("Rigid")) {
const char* battr = rigid->Attribute("boneRefs");
if (!battr) continue;
for (auto& tok : GeneralUtils::SplitString(battr, ',')) {
auto bpIt = boneRefToPartRef.find(tok);
if (bpIt != boneRefToPartRef.end()) {
auto partRef = bpIt->second;
auto pbIt = partRefToBrick.find(partRef);
if (pbIt != partRefToBrick.end()) {
const char* bref = pbIt->second->Attribute("refID");
if (bref) bricksIncluded.insert(std::string(bref));
}
}
}
}
// mark used
for (const auto& b : bricksIncluded) usedBrickRefs.insert(b);
usedRigidSystems.insert(rs);
std::vector<tinyxml2::XMLElement*> rsVec{ rs };
auto normalized = makeOutput(bricksIncluded, rsVec);
results.push_back(normalized);
}
// 3) Any remaining bricks not included become their own files
for (const auto& [bref, brickPtr] : brickByRef) {
if (usedBrickRefs.find(bref) != usedBrickRefs.end()) continue;
std::unordered_set<std::string> bricksIncluded{ bref };
auto normalized = makeOutput(bricksIncluded, {});
results.push_back(normalized);
usedBrickRefs.insert(bref);
}
return results;
}

View File

@@ -6,7 +6,6 @@
#include <string>
#include <string_view>
#include <vector>
#include "NiPoint3.h"
@@ -18,8 +17,7 @@ namespace Lxfml {
// Normalizes a LXFML model to be positioned relative to its local 0, 0, 0 rather than a game worlds 0, 0, 0.
// Returns a struct of its new center and the updated LXFML containing these edits.
[[nodiscard]] Result NormalizePosition(const std::string_view data, const NiPoint3& curPosition = NiPoint3Constant::ZERO);
[[nodiscard]] std::vector<Result> Split(const std::string_view data, const NiPoint3& curPosition = NiPoint3Constant::ZERO);
[[nodiscard]] Result NormalizePosition(const std::string_view data);
// these are only for the migrations due to a bug in one of the implementations.
[[nodiscard]] Result NormalizePositionOnlyFirstPart(const std::string_view data);

View File

@@ -6,14 +6,10 @@
\brief Defines a point in space in XYZ coordinates
*/
class NiPoint3;
class NiQuaternion;
typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoint3 class, but typedef'd for clarity in some cases
#include <glm/ext/vector_float3.hpp>
#include "NiQuaternion.h"
//! A custom class the defines a point in space
class NiPoint3 {
public:
@@ -25,12 +21,6 @@ public:
//! Initializer
constexpr NiPoint3() = default;
constexpr NiPoint3(const glm::vec3& vec) noexcept
: x{ vec.x }
, y{ vec.y }
, z{ vec.z } {
}
//! Initializer
/*!
\param x The x coordinate

View File

@@ -4,7 +4,6 @@
#endif
#include "NiQuaternion.h"
#include <glm/ext/quaternion_float.hpp>
// MARK: Getters / Setters

View File

@@ -3,18 +3,37 @@
// C++
#include <cmath>
#include <glm/gtx/quaternion.hpp>
// MARK: Member Functions
Vector3 QuatUtils::Euler(const NiQuaternion& quat) {
return glm::eulerAngles(quat);
Vector3 NiQuaternion::GetEulerAngles() const {
Vector3 angles;
// roll (x-axis rotation)
const float sinr_cosp = 2 * (w * x + y * z);
const float cosr_cosp = 1 - 2 * (x * x + y * y);
angles.x = std::atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
const float sinp = 2 * (w * y - z * x);
if (std::abs(sinp) >= 1) {
angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range
} else {
angles.y = std::asin(sinp);
}
// yaw (z-axis rotation)
const float siny_cosp = 2 * (w * z + x * y);
const float cosy_cosp = 1 - 2 * (y * y + z * z);
angles.z = std::atan2(siny_cosp, cosy_cosp);
return angles;
}
// MARK: Helper Functions
//! Look from a specific point in space to another point in space (Y-locked)
NiQuaternion QuatUtils::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
//To make sure we don't orient around the X/Z axis:
NiPoint3 source = sourcePoint;
NiPoint3 dest = destPoint;
@@ -32,11 +51,11 @@ NiQuaternion QuatUtils::LookAt(const NiPoint3& sourcePoint, const NiPoint3& dest
NiPoint3 vecB = vecA.CrossProduct(posZ);
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
return glm::angleAxis(rotAngle, glm::vec3{vecA.x, vecA.y, vecA.z});
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
}
//! Look from a specific point in space to another point in space
NiQuaternion QuatUtils::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
NiPoint3 posZ = NiPoint3Constant::UNIT_Z;
@@ -48,26 +67,37 @@ NiQuaternion QuatUtils::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoin
NiPoint3 vecB = vecA.CrossProduct(posZ);
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
return glm::angleAxis(rotAngle, glm::vec3{vecA.x, vecA.y, vecA.z});
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
}
//! Creates a Quaternion from a specific axis and angle relative to that axis
NiQuaternion QuatUtils::AxisAngle(const Vector3& axis, float angle) {
return glm::angleAxis(angle, glm::vec3(axis.x, axis.y, axis.z));
NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle) {
float halfAngle = angle * 0.5f;
float s = static_cast<float>(sin(halfAngle));
NiQuaternion q;
q.x = axis.GetX() * s;
q.y = axis.GetY() * s;
q.z = axis.GetZ() * s;
q.w = static_cast<float>(cos(halfAngle));
return q;
}
NiQuaternion QuatUtils::FromEuler(const NiPoint3& eulerAngles) {
return glm::quat(glm::vec3(eulerAngles.x, eulerAngles.y, eulerAngles.z));
}
NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles) {
// Abbreviations for the various angular functions
float cy = cos(eulerAngles.z * 0.5);
float sy = sin(eulerAngles.z * 0.5);
float cp = cos(eulerAngles.y * 0.5);
float sp = sin(eulerAngles.y * 0.5);
float cr = cos(eulerAngles.x * 0.5);
float sr = sin(eulerAngles.x * 0.5);
Vector3 QuatUtils::Forward(const NiQuaternion& quat) {
return quat * glm::vec3(0, 0, 1);
}
NiQuaternion q;
q.w = cr * cp * cy + sr * sp * sy;
q.x = sr * cp * cy - cr * sp * sy;
q.y = cr * sp * cy + sr * cp * sy;
q.z = cr * cp * sy - sr * sp * cy;
Vector3 QuatUtils::Up(const NiQuaternion& quat) {
return quat * glm::vec3(0, 1, 0);
}
Vector3 QuatUtils::Right(const NiQuaternion& quat) {
return quat * glm::vec3(1, 0, 0);
return q;
}

View File

@@ -1,27 +1,158 @@
#ifndef NIQUATERNION_H
#define NIQUATERNION_H
#ifndef __NIQUATERNION_H__
#define __NIQUATERNION_H__
// Custom Classes
#include "NiPoint3.h"
#define GLM_FORCE_QUAT_DATA_WXYZ
/*!
\file NiQuaternion.hpp
\brief Defines a quaternion in space in WXYZ coordinates
*/
#include <glm/ext/quaternion_float.hpp>
class NiQuaternion;
typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version of NiQuaternion
using Quaternion = glm::quat;
using NiQuaternion = Quaternion;
//! A class that defines a rotation in space
class NiQuaternion {
public:
float w{ 1 }; //!< The w coordinate
float x{ 0 }; //!< The x coordinate
float y{ 0 }; //!< The y coordinate
float z{ 0 }; //!< The z coordinate
namespace QuatUtils {
constexpr NiQuaternion IDENTITY = glm::identity<NiQuaternion>();
Vector3 Forward(const NiQuaternion& quat);
Vector3 Up(const NiQuaternion& quat);
Vector3 Right(const NiQuaternion& quat);
NiQuaternion LookAt(const NiPoint3& from, const NiPoint3& to);
NiQuaternion LookAtUnlocked(const NiPoint3& from, const NiPoint3& to);
Vector3 Euler(const NiQuaternion& quat);
NiQuaternion AxisAngle(const Vector3& axis, float angle);
NiQuaternion FromEuler(const NiPoint3& eulerAngles);
constexpr float PI_OVER_180 = glm::pi<float>() / 180.0f;
//! The initializer
constexpr NiQuaternion() = default;
//! The initializer
/*!
\param w The w coordinate
\param x The x coordinate
\param y The y coordinate
\param z The z coordinate
*/
constexpr NiQuaternion(const float w, const float x, const float y, const float z) noexcept
: w{ w }
, x{ x }
, y{ y }
, z{ z } {
}
// MARK: Setters / Getters
//! Gets the W coordinate
/*!
\return The w coordinate
*/
[[nodiscard]] constexpr float GetW() const noexcept;
//! Sets the W coordinate
/*!
\param w The w coordinate
*/
constexpr void SetW(const float w) noexcept;
//! Gets the X coordinate
/*!
\return The x coordinate
*/
[[nodiscard]] constexpr float GetX() const noexcept;
//! Sets the X coordinate
/*!
\param x The x coordinate
*/
constexpr void SetX(const float x) noexcept;
//! Gets the Y coordinate
/*!
\return The y coordinate
*/
[[nodiscard]] constexpr float GetY() const noexcept;
//! Sets the Y coordinate
/*!
\param y The y coordinate
*/
constexpr void SetY(const float y) noexcept;
//! Gets the Z coordinate
/*!
\return The z coordinate
*/
[[nodiscard]] constexpr float GetZ() const noexcept;
//! Sets the Z coordinate
/*!
\param z The z coordinate
*/
constexpr void SetZ(const float z) noexcept;
// MARK: Member Functions
//! Returns the forward vector from the quaternion
/*!
\return The forward vector of the quaternion
*/
[[nodiscard]] constexpr Vector3 GetForwardVector() const noexcept;
//! Returns the up vector from the quaternion
/*!
\return The up vector fo the quaternion
*/
[[nodiscard]] constexpr Vector3 GetUpVector() const noexcept;
//! Returns the right vector from the quaternion
/*!
\return The right vector of the quaternion
*/
[[nodiscard]] constexpr Vector3 GetRightVector() const noexcept;
[[nodiscard]] Vector3 GetEulerAngles() const;
// MARK: Operators
//! Operator to check for equality
constexpr bool operator==(const NiQuaternion& rot) const noexcept;
//! Operator to check for inequality
constexpr bool operator!=(const NiQuaternion& rot) const noexcept;
// MARK: Helper Functions
//! Look from a specific point in space to another point in space (Y-locked)
/*!
\param sourcePoint The source location
\param destPoint The destination location
\return The Quaternion with the rotation towards the destination
*/
[[nodiscard]] static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Look from a specific point in space to another point in space
/*!
\param sourcePoint The source location
\param destPoint The destination location
\return The Quaternion with the rotation towards the destination
*/
[[nodiscard]] static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Creates a Quaternion from a specific axis and angle relative to that axis
/*!
\param axis The axis that is used
\param angle The angle relative to this axis
\return A quaternion created from the axis and angle
*/
[[nodiscard]] static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
[[nodiscard]] static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
};
#endif // !NIQUATERNION_H
// Static Variables
namespace NiQuaternionConstant {
constexpr NiQuaternion IDENTITY(1, 0, 0, 0);
}
// Include constexpr and inline function definitions in a seperate file for readability
#include "NiQuaternion.inl"
#endif // !__NIQUATERNION_H__

75
dCommon/NiQuaternion.inl Normal file
View File

@@ -0,0 +1,75 @@
#pragma once
#ifndef __NIQUATERNION_H__
#error "This should only be included inline in NiQuaternion.h: Do not include directly!"
#endif
// MARK: Setters / Getters
//! Gets the W coordinate
constexpr float NiQuaternion::GetW() const noexcept {
return this->w;
}
//! Sets the W coordinate
constexpr void NiQuaternion::SetW(const float w) noexcept {
this->w = w;
}
//! Gets the X coordinate
constexpr float NiQuaternion::GetX() const noexcept {
return this->x;
}
//! Sets the X coordinate
constexpr void NiQuaternion::SetX(const float x) noexcept {
this->x = x;
}
//! Gets the Y coordinate
constexpr float NiQuaternion::GetY() const noexcept {
return this->y;
}
//! Sets the Y coordinate
constexpr void NiQuaternion::SetY(const float y) noexcept {
this->y = y;
}
//! Gets the Z coordinate
constexpr float NiQuaternion::GetZ() const noexcept {
return this->z;
}
//! Sets the Z coordinate
constexpr void NiQuaternion::SetZ(const float z) noexcept {
this->z = z;
}
// MARK: Member Functions
//! Returns the forward vector from the quaternion
constexpr Vector3 NiQuaternion::GetForwardVector() const noexcept {
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
//! Returns the up vector from the quaternion
constexpr Vector3 NiQuaternion::GetUpVector() const noexcept {
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
//! Returns the right vector from the quaternion
constexpr Vector3 NiQuaternion::GetRightVector() const noexcept {
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
// MARK: Operators
//! Operator to check for equality
constexpr bool NiQuaternion::operator==(const NiQuaternion& rot) const noexcept {
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
}
//! Operator to check for inequality
constexpr bool NiQuaternion::operator!=(const NiQuaternion& rot) const noexcept {
return !(*this == rot);
}

View File

@@ -24,7 +24,7 @@ struct LocalSpaceInfo {
struct PositionUpdate {
NiPoint3 position = NiPoint3Constant::ZERO;
NiQuaternion rotation = QuatUtils::IDENTITY;
NiQuaternion rotation = NiQuaternionConstant::IDENTITY;
bool onGround = false;
bool onRail = false;
NiPoint3 velocity = NiPoint3Constant::ZERO;

View File

@@ -81,9 +81,6 @@ public:
[[nodiscard]]
AssetStream GetFile(const char* name) const;
[[nodiscard]]
AssetStream GetFile(const std::string& name) const { return GetFile(name.c_str()); };
private:
void LoadPackIndex();

View File

@@ -47,8 +47,6 @@ void dConfig::LoadConfig() {
void dConfig::ReloadConfig() {
this->m_ConfigValues.clear();
LoadConfig();
for (const auto& handler : m_ConfigHandlers) handler();
LogSettings();
}
const std::string& dConfig::GetValue(std::string key) {
@@ -60,18 +58,6 @@ const std::string& dConfig::GetValue(std::string key) {
return this->m_ConfigValues[key];
}
void dConfig::AddConfigHandler(std::function<void()> handler) {
m_ConfigHandlers.push_back(handler);
}
void dConfig::LogSettings() const {
LOG("Configuration settings:");
for (const auto& [key, value] : m_ConfigValues) {
const auto& valueLog = key.find("password") != std::string::npos ? "<HIDDEN>" : value;
LOG(" %s = %s", key.c_str(), valueLog.c_str());
}
}
void dConfig::ProcessLine(const std::string& line) {
auto splitLoc = line.find('=');
auto key = line.substr(0, splitLoc);

View File

@@ -1,7 +1,5 @@
#pragma once
#include <fstream>
#include <functional>
#include <map>
#include <string>
@@ -31,15 +29,10 @@ public:
* Reloads the config file to reset values
*/
void ReloadConfig();
// Adds a function to be called when the config is (re)loaded
void AddConfigHandler(std::function<void()> handler);
void LogSettings() const;
private:
void ProcessLine(const std::string& line);
private:
std::map<std::string, std::string> m_ConfigValues;
std::vector<std::function<void()>> m_ConfigHandlers;
std::string m_ConfigFilePath;
};

View File

@@ -3,7 +3,9 @@
namespace MessageType {
enum class Master : uint32_t {
REQUEST_ZONE_TRANSFER = 1,
REQUEST_PERSISTENT_ID = 1,
REQUEST_PERSISTENT_ID_RESPONSE,
REQUEST_ZONE_TRANSFER,
REQUEST_ZONE_TRANSFER_RESPONSE,
SERVER_INFO,
REQUEST_SESSION_KEY,

View File

@@ -1,14 +0,0 @@
#ifndef __SERVICETYPE__H__
#define __SERVICETYPE__H__
enum class ServiceType : uint16_t {
COMMON = 0,
AUTH,
CHAT,
WORLD = 4,
CLIENT,
MASTER,
UNKNOWN
};
#endif //!__SERVICETYPE__H__

View File

@@ -10,7 +10,7 @@
#include "BitStream.h"
#include "BitStreamUtils.h"
#include "MessageType/Client.h"
#include "ServiceType.h"
#include "eConnectionType.h"
#pragma warning (disable:4251) //Disables SQL warnings
@@ -34,7 +34,7 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
#define CBITSTREAM RakNet::BitStream bitStream;
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::GAME_MSG);
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GAME_MSG);
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);

View File

@@ -18,9 +18,7 @@ enum class eCharacterVersion : uint32_t {
SPEED_BASE,
// Fixes nexus force explorer missions
NJ_JAYMISSIONS,
NEXUS_FORCE_EXPLORER, // Fixes pet ids in player inventories
PET_IDS, // Fixes pet ids in player inventories
UP_TO_DATE, // will become INVENTORY_PERSISTENT_IDS
UP_TO_DATE, // will become NEXUS_FORCE_EXPLORER
};
#endif //!__ECHARACTERVERSION__H__

View File

@@ -0,0 +1,14 @@
#ifndef __ECONNECTIONTYPE__H__
#define __ECONNECTIONTYPE__H__
enum class eConnectionType : uint16_t {
SERVER = 0,
AUTH,
CHAT,
WORLD = 4,
CLIENT,
MASTER,
UNKNOWN
};
#endif //!__ECONNECTIONTYPE__H__

View File

@@ -50,10 +50,7 @@ enum class eMissionState : int {
/**
* The mission has been completed before and has now been completed again. Used for daily missions.
*/
COMPLETE_READY_TO_COMPLETE = 12,
// The mission is failed (don't know where this is used)
FAILED = 16,
COMPLETE_READY_TO_COMPLETE = 12
};
#endif //!__MISSIONSTATE__H__

View File

@@ -1,12 +1,13 @@
#ifndef EOBJECTBITS_H
#define EOBJECTBITS_H
#ifndef __EOBJECTBITS__H__
#define __EOBJECTBITS__H__
#include <cstdint>
enum class eObjectBits : size_t {
PERSISTENT = 32,
CLIENT = 46,
SPAWNED = 58,
CHARACTER = 60
};
#endif //!EOBJECTBITS_H
#endif //!__EOBJECTBITS__H__

View File

@@ -15,7 +15,7 @@ target_include_directories(dDatabaseCDClient PUBLIC "."
"${PROJECT_SOURCE_DIR}/dCommon"
"${PROJECT_SOURCE_DIR}/dCommon/dEnums"
)
target_link_libraries(dDatabaseCDClient PRIVATE sqlite3 glm::glm)
target_link_libraries(dDatabaseCDClient PRIVATE sqlite3)
if (${CDCLIENT_CACHE_ALL})
add_compile_definitions(dDatabaseCDClient PRIVATE CDCLIENT_CACHE_ALL=${CDCLIENT_CACHE_ALL})

View File

@@ -10,5 +10,4 @@ add_dependencies(dDatabase conncpp_dylib)
target_include_directories(dDatabase PUBLIC ".")
target_link_libraries(dDatabase
PUBLIC dDatabaseCDClient dDatabaseGame
PRIVATE glm::glm)
PUBLIC dDatabaseCDClient dDatabaseGame)

View File

@@ -29,7 +29,7 @@ target_include_directories(dDatabaseGame PUBLIC "."
target_link_libraries(dDatabaseGame
INTERFACE dCommon
PRIVATE sqlite3 MariaDB::ConnCpp glm::glm)
PRIVATE sqlite3 MariaDB::ConnCpp)
# Glob together all headers that need to be precompiled
file(

View File

@@ -48,7 +48,7 @@ public:
virtual void Commit() = 0;
virtual bool GetAutoCommit() = 0;
virtual void SetAutoCommit(bool value) = 0;
virtual void DeleteCharacter(const LWOOBJID characterId) = 0;
virtual void DeleteCharacter(const uint32_t characterId) = 0;
};
#endif //!__GAMEDATABASE__H__

View File

@@ -14,7 +14,6 @@ public:
std::string bcryptPassword;
uint32_t id{};
uint32_t playKeyId{};
uint64_t muteExpire{};
bool banned{};
bool locked{};
eGameMasterLevel maxGmLevel{};

View File

@@ -14,7 +14,7 @@ enum class eActivityType : uint32_t {
class IActivityLog {
public:
// Update the activity log for the given account.
virtual void UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) = 0;
virtual void UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) = 0;
};
#endif //!__IACTIVITYLOG__H__

View File

@@ -9,7 +9,7 @@ class IBehaviors {
public:
struct Info {
LWOOBJID behaviorId{};
LWOOBJID characterId{};
uint32_t characterId{};
std::string behaviorInfo;
};

View File

@@ -11,7 +11,7 @@ public:
std::string clientVersion;
std::string otherPlayer;
std::string selection;
LWOOBJID characterId{};
uint32_t characterId{};
};
// Add a new bug report to the database.

View File

@@ -14,7 +14,7 @@ public:
struct Info {
std::string name;
std::string pendingName;
LWOOBJID id{};
uint32_t id{};
uint32_t accountId{};
bool needsRename{};
LWOCLONEID cloneId{};
@@ -25,25 +25,25 @@ public:
virtual std::vector<std::string> GetApprovedCharacterNames() = 0;
// Get the character info for the given character id.
virtual std::optional<ICharInfo::Info> GetCharacterInfo(const LWOOBJID charId) = 0;
virtual std::optional<ICharInfo::Info> GetCharacterInfo(const uint32_t charId) = 0;
// Get the character info for the given character name.
virtual std::optional<ICharInfo::Info> GetCharacterInfo(const std::string_view name) = 0;
// Get the character ids for the given account.
virtual std::vector<LWOOBJID> GetAccountCharacterIds(const LWOOBJID accountId) = 0;
virtual std::vector<uint32_t> 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 LWOOBJID characterId, const std::string_view name) = 0;
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 LWOOBJID characterId, const std::string_view name) = 0;
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 LWOOBJID characterId) = 0;
virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0;
virtual bool IsNameInUse(const std::string_view name) = 0;
};

View File

@@ -8,13 +8,13 @@
class ICharXml {
public:
// Get the character xml for the given character id.
virtual std::string GetCharacterXml(const LWOOBJID charId) = 0;
virtual std::string GetCharacterXml(const uint32_t charId) = 0;
// Update the character xml for the given character id.
virtual void UpdateCharacterXml(const LWOOBJID charId, const std::string_view lxfml) = 0;
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 LWOOBJID characterId, const std::string_view lxfml) = 0;
virtual void InsertCharacterXml(const uint32_t characterId, const std::string_view lxfml) = 0;
};
#endif //!__ICHARXML__H__

View File

@@ -8,7 +8,7 @@ class ICommandLog {
public:
// Insert a new slash command log entry.
virtual void InsertSlashCommandUsage(const LWOOBJID characterId, const std::string_view command) = 0;
virtual void InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) = 0;
};
#endif //!__ICOMMANDLOG__H__

View File

@@ -8,25 +8,25 @@
class IFriends {
public:
struct BestFriendStatus {
LWOOBJID playerCharacterId{};
LWOOBJID friendCharacterId{};
uint32_t playerCharacterId{};
uint32_t friendCharacterId{};
uint32_t bestFriendStatus{};
};
// Get the friends list for the given character id.
virtual std::vector<FriendData> GetFriendsList(const LWOOBJID charId) = 0;
virtual std::vector<FriendData> GetFriendsList(const uint32_t charId) = 0;
// Get the best friend status for the given player and friend character ids.
virtual std::optional<IFriends::BestFriendStatus> GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) = 0;
virtual std::optional<IFriends::BestFriendStatus> 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 LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId, const uint32_t bestFriendStatus) = 0;
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 LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) = 0;
virtual void AddFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) = 0;
// Remove a friend from the given character id.
virtual void RemoveFriend(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) = 0;
virtual void RemoveFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) = 0;
};
#endif //!__IFRIENDS__H__

View File

@@ -9,12 +9,12 @@ class IIgnoreList {
public:
struct Info {
std::string name;
LWOOBJID id;
uint32_t id;
};
virtual std::vector<Info> GetIgnoreList(const LWOOBJID playerId) = 0;
virtual void AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) = 0;
virtual void RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) = 0;
virtual std::vector<Info> GetIgnoreList(const uint32_t playerId) = 0;
virtual void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
virtual void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
};
#endif //!__IIGNORELIST__H__

View File

@@ -5,13 +5,12 @@
#include <optional>
#include <string>
#include <vector>
#include "dCommonVars.h"
class ILeaderboard {
public:
struct Entry {
LWOOBJID charId{};
uint32_t charId{};
uint32_t lastPlayedTimestamp{};
float primaryScore{};
float secondaryScore{};
@@ -37,12 +36,12 @@ public:
virtual std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) = 0;
virtual std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) = 0;
virtual std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) = 0;
virtual std::optional<Score> GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) = 0;
virtual std::optional<Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) = 0;
virtual void SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) = 0;
virtual void UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) = 0;
virtual void IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) = 0;
virtual void IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) = 0;
virtual void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) = 0;
virtual void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) = 0;
virtual void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) = 0;
virtual void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) = 0;
};
#endif //!__ILEADERBOARD__H__

View File

@@ -16,13 +16,13 @@ public:
virtual void InsertNewMail(const MailInfo& mail) = 0;
// Get the mail for the given character id.
virtual std::vector<MailInfo> GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) = 0;
virtual std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) = 0;
// Get the mail for the given mail id.
virtual std::optional<MailInfo> GetMail(const uint64_t mailId) = 0;
// Get the number of unread mail for the given character id.
virtual uint32_t GetUnreadMailCount(const LWOOBJID characterId) = 0;
virtual uint32_t GetUnreadMailCount(const uint32_t characterId) = 0;
// Mark the given mail as read.
virtual void MarkMailRead(const uint64_t mailId) = 0;

View File

@@ -6,19 +6,14 @@
class IObjectIdTracker {
public:
// Only the first 48 bits of the ids are the id, the last 16 bits are reserved for flags.
struct Range {
uint64_t minID{}; // Only the first 48 bits are the id, the last 16 bits are reserved for flags.
uint64_t maxID{}; // Only the first 48 bits are the id, the last 16 bits are reserved for flags.
};
// Get the current persistent id.
virtual std::optional<uint64_t> GetCurrentPersistentId() = 0;
virtual std::optional<uint32_t> GetCurrentPersistentId() = 0;
// Insert the default persistent id.
virtual void InsertDefaultPersistentId() = 0;
virtual Range GetPersistentIdRange() = 0;
// Update the persistent id.
virtual void UpdatePersistentId(const uint32_t newId) = 0;
};
#endif //!__IOBJECTIDTRACKER__H__

View File

@@ -13,7 +13,7 @@ public:
std::string description;
std::string rejectionReason;
LWOOBJID id{};
LWOOBJID ownerId{};
uint32_t ownerId{};
LWOCLONEID cloneId{};
int32_t privacyOption{};
uint32_t modApproved{};
@@ -27,7 +27,7 @@ public:
uint32_t mapId{};
std::string searchString;
ePropertySortType sortChoice{};
LWOOBJID playerId{};
uint32_t playerId{};
uint32_t numResults{};
uint32_t startIndex{};
uint32_t playerSort{};
@@ -39,9 +39,6 @@ public:
std::vector<IProperty::Info> entries;
};
// Get the property info for the given property id.
virtual std::optional<IProperty::Info> GetPropertyInfo(const LWOOBJID id) = 0;
// Get the property info for the given property id.
virtual std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) = 0;

View File

@@ -13,19 +13,19 @@ public:
}
NiPoint3 position;
NiQuaternion rotation = QuatUtils::IDENTITY;
NiQuaternion rotation;
LWOOBJID id{};
LOT lot{};
LWOOBJID ugcId{};
uint32_t ugcId{};
std::array<LWOOBJID, 5> behaviors{};
};
// Inserts a new UGC model into the database.
virtual void InsertNewUgcModel(
std::stringstream& sd0Data,
const uint64_t blueprintId,
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) = 0;
const uint32_t characterId) = 0;
// Get the property models for the given property id.
virtual std::vector<IPropertyContents::Model> GetPropertyModels(const LWOOBJID& propertyId) = 0;
@@ -45,6 +45,6 @@ public:
virtual void RemoveModel(const LWOOBJID& modelId) = 0;
// Gets a model by ID
virtual std::optional<Model> GetModel(const LWOOBJID modelID) = 0;
virtual Model GetModel(const LWOOBJID modelID) = 0;
};
#endif //!__IPROPERTIESCONTENTS__H__

View File

@@ -29,7 +29,5 @@ public:
// Inserts a new UGC model into the database.
virtual void UpdateUgcModelData(const LWOOBJID& modelId, std::stringstream& lxfml) = 0;
virtual std::optional<IUgc::Model> GetUgcModel(const LWOOBJID ugcId) = 0;
};
#endif //!__IUGC__H__

View File

@@ -7,7 +7,7 @@
class IUgcModularBuild {
public:
virtual void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) = 0;
virtual void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) = 0;
virtual void DeleteUgcBuild(const LWOOBJID bigId) = 0;
};

View File

@@ -100,7 +100,7 @@ void MySQLDatabase::SetAutoCommit(bool value) {
con->setAutoCommit(value);
}
void MySQLDatabase::DeleteCharacter(const LWOOBJID characterId) {
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);

View File

@@ -40,31 +40,31 @@ public:
std::vector<std::string> GetApprovedCharacterNames() override;
std::vector<FriendData> GetFriendsList(LWOOBJID charID) override;
std::vector<FriendData> GetFriendsList(uint32_t charID) override;
std::optional<IFriends::BestFriendStatus> GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) override;
void SetBestFriendStatus(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId, const uint32_t bestFriendStatus) override;
void AddFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void RemoveFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) override;
std::optional<IFriends::BestFriendStatus> 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 characterId, const eActivityType activityType, const LWOMAPID mapId) override;
void DeleteUgcModelData(const LWOOBJID& modelId) override;
void UpdateUgcModelData(const LWOOBJID& modelId, std::stringstream& lxfml) override;
std::vector<IUgc::Model> GetAllUgcModels() override;
void CreateMigrationHistoryTable() override;
bool IsMigrationRun(const std::string_view str) override;
void InsertMigration(const std::string_view str) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const LWOOBJID charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const uint32_t charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const std::string_view charId) override;
std::string GetCharacterXml(const LWOOBJID accountId) override;
void UpdateCharacterXml(const LWOOBJID characterId, const std::string_view lxfml) override;
std::string GetCharacterXml(const uint32_t accountId) override;
void UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) override;
std::optional<IAccounts::Info> GetAccountInfo(const std::string_view username) override;
void InsertNewCharacter(const ICharInfo::Info info) override;
void InsertCharacterXml(const LWOOBJID accountId, const std::string_view lxfml) override;
std::vector<LWOOBJID> GetAccountCharacterIds(LWOOBJID accountId) override;
void DeleteCharacter(const LWOOBJID characterId) override;
void SetCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void UpdateLastLoggedInCharacter(const LWOOBJID characterId) override;
void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override;
std::vector<uint32_t> 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<IPetNames::Info> GetPetNameInfo(const LWOOBJID& petId) override;
std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override;
@@ -83,30 +83,30 @@ public:
void InsertNewMail(const MailInfo& mail) override;
void InsertNewUgcModel(
std::stringstream& sd0Data,
const uint64_t blueprintId,
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) override;
std::vector<MailInfo> GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) override;
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const LWOOBJID characterId) 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 LWOOBJID characterId, const std::string_view command) 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 SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint64_t> GetCurrentPersistentId() override;
IObjectIdTracker::Range GetPersistentIdRange() override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
void AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
void RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const LWOOBJID playerId) override;
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
void AddBehavior(const IBehaviors::Info& info) override;
@@ -118,18 +118,16 @@ public:
std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) override;
std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) override;
std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) override;
void SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override;
void UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override;
std::optional<ILeaderboard::Score> GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) override;
void IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) override;
void IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) override;
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) override;
void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
std::optional<ILeaderboard::Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) override;
void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) override;
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override;
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override;
void DeleteUgcBuild(const LWOOBJID bigId) override;
uint32_t GetAccountCount() override;
bool IsNameInUse(const std::string_view name) override;
std::optional<IPropertyContents::Model> GetModel(const LWOOBJID modelID) override;
std::optional<IUgc::Model> GetUgcModel(const LWOOBJID ugcId) override;
std::optional<IProperty::Info> GetPropertyInfo(const LWOOBJID id) override;
IPropertyContents::Model GetModel(const LWOOBJID modelID) override;
sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
private:
@@ -170,91 +168,91 @@ private:
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::string_view param) {
LOG_DEBUG("%s", param.data());
// LOG("%s", param.data());
stmt->setString(index, param.data());
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const char* param) {
LOG_DEBUG("%s", param);
// LOG("%s", param);
stmt->setString(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::string param) {
LOG_DEBUG("%s", param.c_str());
// 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_DEBUG("%u", param);
// LOG("%u", param);
stmt->setByte(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint8_t param) {
LOG_DEBUG("%d", param);
// LOG("%d", param);
stmt->setByte(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int16_t param) {
LOG_DEBUG("%u", param);
// LOG("%u", param);
stmt->setShort(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint16_t param) {
LOG_DEBUG("%d", param);
// LOG("%d", param);
stmt->setShort(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint32_t param) {
LOG_DEBUG("%u", param);
// LOG("%u", param);
stmt->setUInt(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int32_t param) {
LOG_DEBUG("%d", param);
// LOG("%d", param);
stmt->setInt(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const int64_t param) {
LOG_DEBUG("%llu", param);
// LOG("%llu", param);
stmt->setInt64(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const uint64_t param) {
LOG_DEBUG("%llu", param);
// LOG("%llu", param);
stmt->setUInt64(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const float param) {
LOG_DEBUG("%f", param);
// LOG("%f", param);
stmt->setFloat(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const double param) {
LOG_DEBUG("%f", param);
// LOG("%f", param);
stmt->setDouble(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const bool param) {
LOG_DEBUG("%s", param ? "true" : "false");
// LOG("%d", param);
stmt->setBoolean(index, param);
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::istream* param) {
LOG_DEBUG("Blob");
// LOG("Blob");
// This is the one time you will ever see me use const_cast.
stmt->setBlob(index, const_cast<std::istream*>(param));
}
@@ -262,21 +260,10 @@ inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::istr
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::optional<uint32_t> param) {
if (param) {
LOG_DEBUG("%d", param.value());
// LOG("%d", param.value());
stmt->setInt(index, param.value());
} else {
LOG_DEBUG("Null");
stmt->setNull(index, sql::DataType::SQLNULL);
}
}
template<>
inline void SetParam(UniquePreppedStmtRef stmt, const int index, const std::optional<LWOOBJID> param) {
if (param) {
LOG_DEBUG("%d", param.value());
stmt->setInt64(index, param.value());
} else {
LOG_DEBUG("Null");
// LOG("Null");
stmt->setNull(index, sql::DataType::SQLNULL);
}
}

View File

@@ -3,7 +3,7 @@
#include "eGameMasterLevel.h"
std::optional<IAccounts::Info> MySQLDatabase::GetAccountInfo(const std::string_view username) {
auto result = ExecuteSelect("SELECT id, password, banned, locked, play_key_id, gm_level, mute_expire FROM accounts WHERE name = ? LIMIT 1;", 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;
@@ -16,7 +16,6 @@ std::optional<IAccounts::Info> MySQLDatabase::GetAccountInfo(const std::string_v
toReturn.banned = result->getBoolean("banned");
toReturn.locked = result->getBoolean("locked");
toReturn.playKeyId = result->getUInt("play_key_id");
toReturn.muteExpire = result->getUInt64("mute_expire");
return toReturn;
}

View File

@@ -1,6 +1,6 @@
#include "MySQLDatabase.h"
void MySQLDatabase::UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) {
void MySQLDatabase::UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) {
ExecuteInsert("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);",
characterId, static_cast<uint32_t>(activityType), static_cast<uint32_t>(time(NULL)), mapId);
}

View File

@@ -19,7 +19,7 @@ std::optional<ICharInfo::Info> CharInfoFromQueryResult(std::unique_ptr<sql::Resu
ICharInfo::Info toReturn;
toReturn.id = stmt->getInt64("id");
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");
@@ -30,7 +30,7 @@ std::optional<ICharInfo::Info> CharInfoFromQueryResult(std::unique_ptr<sql::Resu
return toReturn;
}
std::optional<ICharInfo::Info> MySQLDatabase::GetCharacterInfo(const LWOOBJID charId) {
std::optional<ICharInfo::Info> 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)
);
@@ -42,13 +42,13 @@ std::optional<ICharInfo::Info> MySQLDatabase::GetCharacterInfo(const std::string
);
}
std::vector<LWOOBJID> MySQLDatabase::GetAccountCharacterIds(const LWOOBJID accountId) {
std::vector<uint32_t> 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<LWOOBJID> toReturn;
std::vector<uint32_t> toReturn;
toReturn.reserve(result->rowsCount());
while (result->next()) {
toReturn.push_back(result->getInt64("id"));
toReturn.push_back(result->getUInt("id"));
}
return toReturn;
@@ -65,15 +65,15 @@ void MySQLDatabase::InsertNewCharacter(const ICharInfo::Info info) {
static_cast<uint32_t>(time(NULL)));
}
void MySQLDatabase::SetCharacterName(const LWOOBJID characterId, const std::string_view name) {
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<uint32_t>(time(NULL)), characterId);
}
void MySQLDatabase::SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) {
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<uint32_t>(time(NULL)), characterId);
}
void MySQLDatabase::UpdateLastLoggedInCharacter(const LWOOBJID characterId) {
void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1", static_cast<uint32_t>(time(NULL)), characterId);
}

View File

@@ -1,6 +1,6 @@
#include "MySQLDatabase.h"
std::string MySQLDatabase::GetCharacterXml(const LWOOBJID charId) {
std::string MySQLDatabase::GetCharacterXml(const uint32_t charId) {
auto result = ExecuteSelect("SELECT xml_data FROM charxml WHERE id = ? LIMIT 1;", charId);
if (!result->next()) {
@@ -10,10 +10,10 @@ std::string MySQLDatabase::GetCharacterXml(const LWOOBJID charId) {
return result->getString("xml_data").c_str();
}
void MySQLDatabase::UpdateCharacterXml(const LWOOBJID charId, const std::string_view lxfml) {
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 LWOOBJID characterId, const std::string_view lxfml) {
void MySQLDatabase::InsertCharacterXml(const uint32_t characterId, const std::string_view lxfml) {
ExecuteInsert("INSERT INTO `charxml` (`id`, `xml_data`) VALUES (?,?)", characterId, lxfml);
}

View File

@@ -1,5 +1,5 @@
#include "MySQLDatabase.h"
void MySQLDatabase::InsertSlashCommandUsage(const LWOOBJID characterId, const std::string_view command) {
void MySQLDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) {
ExecuteInsert("INSERT INTO command_log (character_id, command) VALUES (?, ?);", characterId, command);
}

View File

@@ -1,6 +1,6 @@
#include "MySQLDatabase.h"
std::vector<FriendData> MySQLDatabase::GetFriendsList(const LWOOBJID charId) {
std::vector<FriendData> 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
@@ -19,7 +19,7 @@ std::vector<FriendData> MySQLDatabase::GetFriendsList(const LWOOBJID charId) {
while (friendsList->next()) {
FriendData fd;
fd.friendID = friendsList->getUInt64("player");
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();
@@ -29,7 +29,7 @@ std::vector<FriendData> MySQLDatabase::GetFriendsList(const LWOOBJID charId) {
return toReturn;
}
std::optional<IFriends::BestFriendStatus> MySQLDatabase::GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
std::optional<IFriends::BestFriendStatus> 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,
@@ -42,14 +42,14 @@ std::optional<IFriends::BestFriendStatus> MySQLDatabase::GetBestFriendStatus(con
}
IFriends::BestFriendStatus toReturn;
toReturn.playerCharacterId = result->getUInt64("player_id");
toReturn.friendCharacterId = result->getUInt64("friend_id");
toReturn.playerCharacterId = result->getUInt("player_id");
toReturn.friendCharacterId = result->getUInt("friend_id");
toReturn.bestFriendStatus = result->getUInt("best_friend");
return toReturn;
}
void MySQLDatabase::SetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId, const uint32_t bestFriendStatus) {
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,
@@ -59,11 +59,11 @@ void MySQLDatabase::SetBestFriendStatus(const LWOOBJID playerCharacterId, const
);
}
void MySQLDatabase::AddFriend(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
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 LWOOBJID playerCharacterId, const LWOOBJID 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,

View File

@@ -1,22 +1,22 @@
#include "MySQLDatabase.h"
std::vector<IIgnoreList::Info> MySQLDatabase::GetIgnoreList(const LWOOBJID playerId) {
std::vector<IIgnoreList::Info> MySQLDatabase::GetIgnoreList(const uint32_t playerId) {
auto result = ExecuteSelect("SELECT ci.name AS name, il.ignored_player_id AS ignore_id FROM ignore_list AS il JOIN charinfo AS ci ON il.ignored_player_id = ci.id WHERE il.player_id = ?", playerId);
std::vector<IIgnoreList::Info> ignoreList;
ignoreList.reserve(result->rowsCount());
while (result->next()) {
ignoreList.push_back(IIgnoreList::Info{ result->getString("name").c_str(), result->getInt64("ignore_id") });
ignoreList.push_back(IIgnoreList::Info{ result->getString("name").c_str(), result->getUInt("ignore_id") });
}
return ignoreList;
}
void MySQLDatabase::AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void MySQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteInsert("INSERT IGNORE INTO ignore_list (player_id, ignored_player_id) VALUES (?, ?)", playerId, ignoredPlayerId);
}
void MySQLDatabase::RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void MySQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteDelete("DELETE FROM ignore_list WHERE player_id = ? AND ignored_player_id = ?", playerId, ignoredPlayerId);
}

View File

@@ -21,7 +21,7 @@ std::vector<ILeaderboard::Entry> ProcessQuery(UniqueResultSet& rows) {
while (rows->next()) {
auto& entry = entries.emplace_back();
entry.charId = rows->getUInt64("character_id");
entry.charId = rows->getUInt("character_id");
entry.lastPlayedTimestamp = rows->getUInt("lp_unix");
entry.primaryScore = rows->getFloat("primaryScore");
entry.secondaryScore = rows->getFloat("secondaryScore");
@@ -58,21 +58,21 @@ std::vector<ILeaderboard::Entry> MySQLDatabase::GetNsLeaderboard(const uint32_t
return ProcessQuery(leaderboard);
}
void MySQLDatabase::SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) {
void MySQLDatabase::SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
ExecuteInsert("INSERT leaderboard SET primaryScore = ?, secondaryScore = ?, tertiaryScore = ?, character_id = ?, game_id = ?;",
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
}
void MySQLDatabase::UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) {
void MySQLDatabase::UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
ExecuteInsert("UPDATE leaderboard SET primaryScore = ?, secondaryScore = ?, tertiaryScore = ?, timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;",
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
}
void MySQLDatabase::IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) {
void MySQLDatabase::IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) {
ExecuteUpdate("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;", playerId, gameId);
}
std::optional<ILeaderboard::Score> MySQLDatabase::GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) {
std::optional<ILeaderboard::Score> MySQLDatabase::GetPlayerScore(const uint32_t playerId, const uint32_t gameId) {
std::optional<ILeaderboard::Score> toReturn = std::nullopt;
auto res = ExecuteSelect("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;", playerId, gameId);
if (res->next()) {
@@ -86,6 +86,6 @@ std::optional<ILeaderboard::Score> MySQLDatabase::GetPlayerScore(const LWOOBJID
return toReturn;
}
void MySQLDatabase::IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) {
void MySQLDatabase::IncrementNumWins(const uint32_t playerId, const uint32_t gameId) {
ExecuteUpdate("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;", playerId, gameId);
}

View File

@@ -19,7 +19,7 @@ void MySQLDatabase::InsertNewMail(const MailInfo& mail) {
mail.itemCount);
}
std::vector<MailInfo> MySQLDatabase::GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) {
std::vector<MailInfo> 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 ?;",
@@ -61,7 +61,7 @@ std::optional<MailInfo> MySQLDatabase::GetMail(const uint64_t mailId) {
return toReturn;
}
uint32_t MySQLDatabase::GetUnreadMailCount(const LWOOBJID characterId) {
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()) {

View File

@@ -1,42 +1,17 @@
#include "MySQLDatabase.h"
std::optional<uint64_t> MySQLDatabase::GetCurrentPersistentId() {
std::optional<uint32_t> MySQLDatabase::GetCurrentPersistentId() {
auto result = ExecuteSelect("SELECT last_object_id FROM object_id_tracker");
if (!result->next()) {
return std::nullopt;
}
return result->getUInt64("last_object_id");
return result->getUInt("last_object_id");
}
void MySQLDatabase::InsertDefaultPersistentId() {
ExecuteInsert("INSERT INTO object_id_tracker VALUES (1);");
}
IObjectIdTracker::Range MySQLDatabase::GetPersistentIdRange() {
IObjectIdTracker::Range range;
auto prevCommit = GetAutoCommit();
SetAutoCommit(false);
// THIS MUST ABSOLUTELY NOT FAIL. These IDs are expected to be unique. As such a transactional select is used to safely get a range
// of IDs that will never be used again. A separate feature could track unused IDs and recycle them, but that is not implemented.
ExecuteCustomQuery("START TRANSACTION;");
// 200 seems like a good range to reserve at once. Only way this would be noticable is if a player
// added hundreds of items at once.
// Doing the update first ensures that all other connections are blocked from accessing this table until we commit.
auto result = ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = last_object_id + 200;");
// If no rows were updated, it means the table is empty, so we need to insert the default row first.
if (result == 0) {
InsertDefaultPersistentId();
result = ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = last_object_id + 200;");
}
// At this point all connections are waiting on us to finish the transaction, so we can safely select the ID we just set.
auto selectRes = ExecuteSelect("SELECT last_object_id FROM object_id_tracker;");
selectRes->next();
range.maxID = selectRes->getUInt64("last_object_id");
range.minID = range.maxID - 199;
ExecuteCustomQuery("COMMIT;");
SetAutoCommit(prevCommit);
return range;
void MySQLDatabase::UpdatePersistentId(const uint32_t newId) {
ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = ?;", newId);
}

View File

@@ -1,23 +1,6 @@
#include "MySQLDatabase.h"
#include "ePropertySortType.h"
IProperty::Info ReadPropertyInfo(UniqueResultSet& result) {
IProperty::Info info;
info.id = result->getUInt64("id");
info.ownerId = result->getInt64("owner_id");
info.cloneId = result->getUInt64("clone_id");
info.name = result->getString("name").c_str();
info.description = result->getString("description").c_str();
info.privacyOption = result->getInt("privacy_option");
info.rejectionReason = result->getString("rejection_reason").c_str();
info.lastUpdatedTime = result->getUInt("last_updated");
info.claimedTime = result->getUInt("time_claimed");
info.reputation = result->getUInt("reputation");
info.modApproved = result->getUInt("mod_approved");
info.performanceCost = result->getFloat("performance_cost");
return info;
}
std::optional<IProperty::PropertyEntranceResult> MySQLDatabase::GetProperties(const IProperty::PropertyLookup& params) {
std::optional<IProperty::PropertyEntranceResult> result;
std::string query;
@@ -134,7 +117,19 @@ std::optional<IProperty::PropertyEntranceResult> MySQLDatabase::GetProperties(co
while (properties->next()) {
if (!result) result = IProperty::PropertyEntranceResult();
result->entries.push_back(ReadPropertyInfo(properties));
auto& entry = result->entries.emplace_back();
entry.id = properties->getUInt64("id");
entry.ownerId = properties->getUInt64("owner_id");
entry.cloneId = properties->getUInt64("clone_id");
entry.name = properties->getString("name").c_str();
entry.description = properties->getString("description").c_str();
entry.privacyOption = properties->getInt("privacy_option");
entry.rejectionReason = properties->getString("rejection_reason").c_str();
entry.lastUpdatedTime = properties->getUInt("last_updated");
entry.claimedTime = properties->getUInt("time_claimed");
entry.reputation = properties->getUInt("reputation");
entry.modApproved = properties->getUInt("mod_approved");
entry.performanceCost = properties->getFloat("performance_cost");
}
return result;
@@ -149,7 +144,21 @@ std::optional<IProperty::Info> MySQLDatabase::GetPropertyInfo(const LWOMAPID map
return std::nullopt;
}
return ReadPropertyInfo(propertyEntry);
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");
toReturn.performanceCost = propertyEntry->getFloat("performance_cost");
return toReturn;
}
void MySQLDatabase::UpdatePropertyModerationInfo(const IProperty::Info& info) {
@@ -186,15 +195,3 @@ void MySQLDatabase::InsertNewProperty(const IProperty::Info& info, const uint32_
zoneId.GetMapID()
);
}
std::optional<IProperty::Info> MySQLDatabase::GetPropertyInfo(const LWOOBJID id) {
auto propertyEntry = ExecuteSelect(
"SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved, performance_cost "
"FROM properties WHERE id = ?;", id);
if (!propertyEntry->next()) {
return std::nullopt;
}
return ReadPropertyInfo(propertyEntry);
}

View File

@@ -64,27 +64,26 @@ void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) {
ExecuteDelete("DELETE FROM properties_contents WHERE id = ?;", modelId);
}
std::optional<IPropertyContents::Model> MySQLDatabase::GetModel(const LWOOBJID modelID) {
IPropertyContents::Model MySQLDatabase::GetModel(const LWOOBJID modelID) {
auto result = ExecuteSelect("SELECT * FROM properties_contents WHERE id = ?", modelID);
std::optional<IPropertyContents::Model> model = std::nullopt;
IPropertyContents::Model model{};
while (result->next()) {
model = IPropertyContents::Model{};
model->id = result->getUInt64("id");
model->lot = static_cast<LOT>(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");
model->behaviors[0] = result->getUInt64("behavior_1");
model->behaviors[1] = result->getUInt64("behavior_2");
model->behaviors[2] = result->getUInt64("behavior_3");
model->behaviors[3] = result->getUInt64("behavior_4");
model->behaviors[4] = result->getUInt64("behavior_5");
model.id = result->getUInt64("id");
model.lot = static_cast<LOT>(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");
model.behaviors[0] = result->getUInt64("behavior_1");
model.behaviors[1] = result->getUInt64("behavior_2");
model.behaviors[2] = result->getUInt64("behavior_3");
model.behaviors[3] = result->getUInt64("behavior_4");
model.behaviors[4] = result->getUInt64("behavior_5");
}
return model;

View File

@@ -1,17 +1,5 @@
#include "MySQLDatabase.h"
IUgc::Model ReadModel(UniqueResultSet& result) {
IUgc::Model model;
// blob is owned by the query, so we need to do a deep copy :/
std::unique_ptr<std::istream> blob(result->getBlob("lxfml"));
model.lxfmlData << blob->rdbuf();
model.id = result->getUInt64("ugcID");
model.modelID = result->getUInt64("modelID");
return model;
}
std::vector<IUgc::Model> MySQLDatabase::GetUgcModels(const LWOOBJID& propertyId) {
auto result = ExecuteSelect(
"SELECT lxfml, u.id as ugcID, pc.id as modelID 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;",
@@ -20,7 +8,14 @@ std::vector<IUgc::Model> MySQLDatabase::GetUgcModels(const LWOOBJID& propertyId)
std::vector<IUgc::Model> toReturn;
while (result->next()) {
toReturn.push_back(ReadModel(result));
IUgc::Model model;
// blob is owned by the query, so we need to do a deep copy :/
std::unique_ptr<std::istream> blob(result->getBlob("lxfml"));
model.lxfmlData << blob->rdbuf();
model.id = result->getUInt64("ugcID");
model.modelID = result->getUInt64("modelID");
toReturn.push_back(std::move(model));
}
return toReturn;
@@ -32,7 +27,14 @@ std::vector<IUgc::Model> MySQLDatabase::GetAllUgcModels() {
std::vector<IUgc::Model> models;
models.reserve(result->rowsCount());
while (result->next()) {
models.push_back(ReadModel(result));
IUgc::Model model;
model.id = result->getInt64("ugcID");
model.modelID = result->getUInt64("modelID");
// blob is owned by the query, so we need to do a deep copy :/
std::unique_ptr<std::istream> blob(result->getBlob("lxfml"));
model.lxfmlData << blob->rdbuf();
models.push_back(std::move(model));
}
return models;
@@ -43,10 +45,10 @@ void MySQLDatabase::RemoveUnreferencedUgcModels() {
}
void MySQLDatabase::InsertNewUgcModel(
std::stringstream& sd0Data, // cant be const sad
const uint64_t blueprintId,
std:: stringstream& sd0Data, // cant be const sad
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) {
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 (?,?,?,?,?,?,?)",
@@ -69,14 +71,3 @@ void MySQLDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::stringstrea
const std::istream stream(lxfml.rdbuf());
ExecuteUpdate("UPDATE ugc SET lxfml = ? WHERE id = ?;", &stream, modelId);
}
std::optional<IUgc::Model> MySQLDatabase::GetUgcModel(const LWOOBJID ugcId) {
auto result = ExecuteSelect("SELECT u.id AS ugcID, lxfml, pc.id AS modelID FROM ugc AS u JOIN properties_contents AS pc ON pc.ugc_id = u.id WHERE u.id = ?", ugcId);
std::optional<IUgc::Model> toReturn = std::nullopt;
if (result->next()) {
toReturn = ReadModel(result);
}
return toReturn;
}

View File

@@ -1,6 +1,6 @@
#include "MySQLDatabase.h"
void MySQLDatabase::InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) {
void MySQLDatabase::InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) {
ExecuteInsert("INSERT INTO ugc_modular_build (ugc_id, ldf_config, character_id) VALUES (?,?,?)", bigId, modules, characterId);
}

View File

@@ -61,13 +61,13 @@ bool SQLiteDatabase::GetAutoCommit() {
void SQLiteDatabase::SetAutoCommit(bool value) {
if (value) {
if (!GetAutoCommit()) con->compileStatement("COMMIT;").execDML();
} else {
if (GetAutoCommit()) con->compileStatement("BEGIN;").execDML();
} else {
if (!GetAutoCommit()) con->compileStatement("COMMIT;").execDML();
}
}
void SQLiteDatabase::DeleteCharacter(const LWOOBJID characterId) {
void SQLiteDatabase::DeleteCharacter(const uint32_t characterId) {
ExecuteDelete("DELETE FROM charxml WHERE id=?;", characterId);
ExecuteDelete("DELETE FROM command_log WHERE character_id=?;", characterId);
ExecuteDelete("DELETE FROM friends WHERE player_id=? OR friend_id=?;", characterId, characterId);

View File

@@ -38,31 +38,31 @@ public:
std::vector<std::string> GetApprovedCharacterNames() override;
std::vector<FriendData> GetFriendsList(LWOOBJID charID) override;
std::vector<FriendData> GetFriendsList(uint32_t charID) override;
std::optional<IFriends::BestFriendStatus> GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) override;
void SetBestFriendStatus(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId, const uint32_t bestFriendStatus) override;
void AddFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void RemoveFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) override;
std::optional<IFriends::BestFriendStatus> 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 characterId, const eActivityType activityType, const LWOMAPID mapId) override;
void DeleteUgcModelData(const LWOOBJID& modelId) override;
void UpdateUgcModelData(const LWOOBJID& modelId, std::stringstream& lxfml) override;
std::vector<IUgc::Model> GetAllUgcModels() override;
void CreateMigrationHistoryTable() override;
bool IsMigrationRun(const std::string_view str) override;
void InsertMigration(const std::string_view str) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const LWOOBJID charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const uint32_t charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const std::string_view charId) override;
std::string GetCharacterXml(const LWOOBJID accountId) override;
void UpdateCharacterXml(const LWOOBJID characterId, const std::string_view lxfml) override;
std::string GetCharacterXml(const uint32_t accountId) override;
void UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) override;
std::optional<IAccounts::Info> GetAccountInfo(const std::string_view username) override;
void InsertNewCharacter(const ICharInfo::Info info) override;
void InsertCharacterXml(const LWOOBJID accountId, const std::string_view lxfml) override;
std::vector<LWOOBJID> GetAccountCharacterIds(LWOOBJID accountId) override;
void DeleteCharacter(const LWOOBJID characterId) override;
void SetCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void UpdateLastLoggedInCharacter(const LWOOBJID characterId) override;
void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override;
std::vector<uint32_t> 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<IPetNames::Info> GetPetNameInfo(const LWOOBJID& petId) override;
std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override;
@@ -81,30 +81,30 @@ public:
void InsertNewMail(const MailInfo& mail) override;
void InsertNewUgcModel(
std::stringstream& sd0Data,
const uint64_t blueprintId,
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) override;
std::vector<MailInfo> GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) override;
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const LWOOBJID characterId) 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 LWOOBJID characterId, const std::string_view command) 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 SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint64_t> GetCurrentPersistentId() override;
IObjectIdTracker::Range GetPersistentIdRange() override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
void AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
void RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const LWOOBJID playerId) override;
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
void AddBehavior(const IBehaviors::Info& info) override;
@@ -116,18 +116,16 @@ public:
std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) override;
std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) override;
std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) override;
void SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override;
void UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override;
std::optional<ILeaderboard::Score> GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) override;
void IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) override;
void IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) override;
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) override;
void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
std::optional<ILeaderboard::Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) override;
void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) override;
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override;
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override;
void DeleteUgcBuild(const LWOOBJID bigId) override;
uint32_t GetAccountCount() override;
bool IsNameInUse(const std::string_view name) override;
std::optional<IPropertyContents::Model> GetModel(const LWOOBJID modelID) override;
std::optional<IUgc::Model> GetUgcModel(const LWOOBJID ugcId) override;
std::optional<IProperty::Info> GetPropertyInfo(const LWOOBJID id) override;
IPropertyContents::Model GetModel(const LWOOBJID modelID) override;
private:
CppSQLite3Statement CreatePreppedStmt(const std::string& query);
@@ -272,15 +270,4 @@ inline void SetParam(PreppedStmtRef stmt, const int index, const std::optional<u
}
}
template<>
inline void SetParam(PreppedStmtRef stmt, const int index, const std::optional<LWOOBJID> param) {
if (param) {
LOG("%d", param.value());
stmt.bind(index, static_cast<sqlite_int64>(param.value()));
} else {
LOG("Null");
stmt.bindNull(index);
}
}
#endif //!SQLITEDATABASE_H

View File

@@ -17,7 +17,6 @@ std::optional<IAccounts::Info> SQLiteDatabase::GetAccountInfo(const std::string_
toReturn.banned = result.getIntField("banned");
toReturn.locked = result.getIntField("locked");
toReturn.playKeyId = result.getIntField("play_key_id");
toReturn.muteExpire = static_cast<uint64_t>(result.getInt64Field("mute_expire"));
return toReturn;
}

View File

@@ -1,6 +1,6 @@
#include "SQLiteDatabase.h"
void SQLiteDatabase::UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) {
void SQLiteDatabase::UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) {
ExecuteInsert("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);",
characterId, static_cast<uint32_t>(activityType), static_cast<uint32_t>(time(NULL)), mapId);
}

View File

@@ -20,7 +20,7 @@ std::optional<ICharInfo::Info> CharInfoFromQueryResult(CppSQLite3Query stmt) {
ICharInfo::Info toReturn;
toReturn.id = stmt.getInt64Field("id");
toReturn.id = stmt.getIntField("id");
toReturn.name = stmt.getStringField("name");
toReturn.pendingName = stmt.getStringField("pending_name");
toReturn.needsRename = stmt.getIntField("needs_rename");
@@ -31,7 +31,7 @@ std::optional<ICharInfo::Info> CharInfoFromQueryResult(CppSQLite3Query stmt) {
return toReturn;
}
std::optional<ICharInfo::Info> SQLiteDatabase::GetCharacterInfo(const LWOOBJID charId) {
std::optional<ICharInfo::Info> SQLiteDatabase::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).second
);
@@ -43,12 +43,12 @@ std::optional<ICharInfo::Info> SQLiteDatabase::GetCharacterInfo(const std::strin
);
}
std::vector<LWOOBJID> SQLiteDatabase::GetAccountCharacterIds(const LWOOBJID accountId) {
std::vector<uint32_t> SQLiteDatabase::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<LWOOBJID> toReturn;
std::vector<uint32_t> toReturn;
while (!result.eof()) {
toReturn.push_back(result.getInt64Field("id"));
toReturn.push_back(result.getIntField("id"));
result.nextRow();
}
@@ -66,15 +66,15 @@ void SQLiteDatabase::InsertNewCharacter(const ICharInfo::Info info) {
static_cast<uint32_t>(time(NULL)));
}
void SQLiteDatabase::SetCharacterName(const LWOOBJID characterId, const std::string_view name) {
void SQLiteDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) {
ExecuteUpdate("UPDATE charinfo SET name = ?, pending_name = '', needs_rename = 0, last_login = ? WHERE id = ?;", name, static_cast<uint32_t>(time(NULL)), characterId);
}
void SQLiteDatabase::SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) {
void SQLiteDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) {
ExecuteUpdate("UPDATE charinfo SET pending_name = ?, needs_rename = 0, last_login = ? WHERE id = ?;", name, static_cast<uint32_t>(time(NULL)), characterId);
}
void SQLiteDatabase::UpdateLastLoggedInCharacter(const LWOOBJID characterId) {
void SQLiteDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ?;", static_cast<uint32_t>(time(NULL)), characterId);
}

View File

@@ -1,6 +1,6 @@
#include "SQLiteDatabase.h"
std::string SQLiteDatabase::GetCharacterXml(const LWOOBJID charId) {
std::string SQLiteDatabase::GetCharacterXml(const uint32_t charId) {
auto [_, result] = ExecuteSelect("SELECT xml_data FROM charxml WHERE id = ? LIMIT 1;", charId);
if (result.eof()) {
@@ -10,10 +10,10 @@ std::string SQLiteDatabase::GetCharacterXml(const LWOOBJID charId) {
return result.getStringField("xml_data");
}
void SQLiteDatabase::UpdateCharacterXml(const LWOOBJID charId, const std::string_view lxfml) {
void SQLiteDatabase::UpdateCharacterXml(const uint32_t charId, const std::string_view lxfml) {
ExecuteUpdate("UPDATE charxml SET xml_data = ? WHERE id = ?;", lxfml, charId);
}
void SQLiteDatabase::InsertCharacterXml(const LWOOBJID characterId, const std::string_view lxfml) {
void SQLiteDatabase::InsertCharacterXml(const uint32_t characterId, const std::string_view lxfml) {
ExecuteInsert("INSERT INTO `charxml` (`id`, `xml_data`) VALUES (?,?)", characterId, lxfml);
}

View File

@@ -1,5 +1,5 @@
#include "SQLiteDatabase.h"
void SQLiteDatabase::InsertSlashCommandUsage(const LWOOBJID characterId, const std::string_view command) {
void SQLiteDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) {
ExecuteInsert("INSERT INTO command_log (character_id, command) VALUES (?, ?);", characterId, command);
}

View File

@@ -1,6 +1,6 @@
#include "SQLiteDatabase.h"
std::vector<FriendData> SQLiteDatabase::GetFriendsList(const LWOOBJID charId) {
std::vector<FriendData> SQLiteDatabase::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
@@ -18,7 +18,7 @@ std::vector<FriendData> SQLiteDatabase::GetFriendsList(const LWOOBJID charId) {
while (!friendsList.eof()) {
FriendData fd;
fd.friendID = friendsList.getInt64Field("player");
fd.friendID = friendsList.getIntField("player");
fd.isBestFriend = friendsList.getIntField("bff") == 3; // 0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs
fd.friendName = friendsList.getStringField("name");
@@ -29,7 +29,7 @@ std::vector<FriendData> SQLiteDatabase::GetFriendsList(const LWOOBJID charId) {
return toReturn;
}
std::optional<IFriends::BestFriendStatus> SQLiteDatabase::GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
std::optional<IFriends::BestFriendStatus> SQLiteDatabase::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,
@@ -42,14 +42,14 @@ std::optional<IFriends::BestFriendStatus> SQLiteDatabase::GetBestFriendStatus(co
}
IFriends::BestFriendStatus toReturn;
toReturn.playerCharacterId = result.getInt64Field("player_id");
toReturn.friendCharacterId = result.getInt64Field("friend_id");
toReturn.playerCharacterId = result.getIntField("player_id");
toReturn.friendCharacterId = result.getIntField("friend_id");
toReturn.bestFriendStatus = result.getIntField("best_friend");
return toReturn;
}
void SQLiteDatabase::SetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId, const uint32_t bestFriendStatus) {
void SQLiteDatabase::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 = ?);",
bestFriendStatus,
playerCharacterId,
@@ -59,11 +59,11 @@ void SQLiteDatabase::SetBestFriendStatus(const LWOOBJID playerCharacterId, const
);
}
void SQLiteDatabase::AddFriend(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
void SQLiteDatabase::AddFriend(const uint32_t playerCharacterId, const uint32_t friendCharacterId) {
ExecuteInsert("INSERT OR IGNORE INTO friends (player_id, friend_id, best_friend) VALUES (?, ?, 0);", playerCharacterId, friendCharacterId);
}
void SQLiteDatabase::RemoveFriend(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
void SQLiteDatabase::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 = ?);",
playerCharacterId,
friendCharacterId,

View File

@@ -1,22 +1,22 @@
#include "SQLiteDatabase.h"
std::vector<IIgnoreList::Info> SQLiteDatabase::GetIgnoreList(const LWOOBJID playerId) {
std::vector<IIgnoreList::Info> SQLiteDatabase::GetIgnoreList(const uint32_t playerId) {
auto [_, result] = ExecuteSelect("SELECT ci.name AS name, il.ignored_player_id AS ignore_id FROM ignore_list AS il JOIN charinfo AS ci ON il.ignored_player_id = ci.id WHERE il.player_id = ?", playerId);
std::vector<IIgnoreList::Info> ignoreList;
while (!result.eof()) {
ignoreList.push_back(IIgnoreList::Info{ result.getStringField("name"), result.getInt64Field("ignore_id") });
ignoreList.push_back(IIgnoreList::Info{ result.getStringField("name"), static_cast<uint32_t>(result.getIntField("ignore_id")) });
result.nextRow();
}
return ignoreList;
}
void SQLiteDatabase::AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void SQLiteDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteInsert("INSERT OR IGNORE INTO ignore_list (player_id, ignored_player_id) VALUES (?, ?)", playerId, ignoredPlayerId);
}
void SQLiteDatabase::RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void SQLiteDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
ExecuteDelete("DELETE FROM ignore_list WHERE player_id = ? AND ignored_player_id = ?", playerId, ignoredPlayerId);
}

View File

@@ -20,7 +20,7 @@ std::vector<ILeaderboard::Entry> ProcessQuery(CppSQLite3Query& rows) {
while (!rows.eof()) {
auto& entry = entries.emplace_back();
entry.charId = rows.getInt64Field("character_id");
entry.charId = rows.getIntField("character_id");
entry.lastPlayedTimestamp = rows.getIntField("lp_unix");
entry.primaryScore = rows.getFloatField("primaryScore");
entry.secondaryScore = rows.getFloatField("secondaryScore");
@@ -58,17 +58,17 @@ std::vector<ILeaderboard::Entry> SQLiteDatabase::GetNsLeaderboard(const uint32_t
return ProcessQuery(result);
}
void SQLiteDatabase::SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) {
void SQLiteDatabase::SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
ExecuteInsert("INSERT INTO leaderboard (primaryScore, secondaryScore, tertiaryScore, character_id, game_id, last_played) VALUES (?,?,?,?,?,CURRENT_TIMESTAMP) ;",
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
}
void SQLiteDatabase::UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) {
void SQLiteDatabase::UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
ExecuteInsert("UPDATE leaderboard SET primaryScore = ?, secondaryScore = ?, tertiaryScore = ?, timesPlayed = timesPlayed + 1, last_played = CURRENT_TIMESTAMP WHERE character_id = ? AND game_id = ?;",
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
}
std::optional<ILeaderboard::Score> SQLiteDatabase::GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) {
std::optional<ILeaderboard::Score> SQLiteDatabase::GetPlayerScore(const uint32_t playerId, const uint32_t gameId) {
std::optional<ILeaderboard::Score> toReturn = std::nullopt;
auto [_, res] = ExecuteSelect("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;", playerId, gameId);
if (!res.eof()) {
@@ -82,10 +82,10 @@ std::optional<ILeaderboard::Score> SQLiteDatabase::GetPlayerScore(const LWOOBJID
return toReturn;
}
void SQLiteDatabase::IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) {
void SQLiteDatabase::IncrementNumWins(const uint32_t playerId, const uint32_t gameId) {
ExecuteUpdate("UPDATE leaderboard SET numWins = numWins + 1, last_played = CURRENT_TIMESTAMP WHERE character_id = ? AND game_id = ?;", playerId, gameId);
}
void SQLiteDatabase::IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) {
void SQLiteDatabase::IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) {
ExecuteUpdate("UPDATE leaderboard SET timesPlayed = timesPlayed + 1, last_played = CURRENT_TIMESTAMP WHERE character_id = ? AND game_id = ?;", playerId, gameId);
}

View File

@@ -18,7 +18,7 @@ void SQLiteDatabase::InsertNewMail(const MailInfo& mail) {
mail.itemCount);
}
std::vector<MailInfo> SQLiteDatabase::GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) {
std::vector<MailInfo> SQLiteDatabase::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 ?;",
@@ -60,7 +60,7 @@ std::optional<MailInfo> SQLiteDatabase::GetMail(const uint64_t mailId) {
return toReturn;
}
uint32_t SQLiteDatabase::GetUnreadMailCount(const LWOOBJID characterId) {
uint32_t SQLiteDatabase::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.eof()) {

View File

@@ -1,40 +1,17 @@
#include "SQLiteDatabase.h"
std::optional<uint64_t> SQLiteDatabase::GetCurrentPersistentId() {
std::optional<uint32_t> SQLiteDatabase::GetCurrentPersistentId() {
auto [_, result] = ExecuteSelect("SELECT last_object_id FROM object_id_tracker");
if (result.eof()) {
return std::nullopt;
}
return result.getInt64Field("last_object_id");
return result.getIntField("last_object_id");
}
void SQLiteDatabase::InsertDefaultPersistentId() {
ExecuteInsert("INSERT INTO object_id_tracker VALUES (1);");
}
IObjectIdTracker::Range SQLiteDatabase::GetPersistentIdRange() {
IObjectIdTracker::Range range;
auto prevCommit = GetAutoCommit();
SetAutoCommit(false); // This begins the transaction for us if one is not already in progress
// THIS MUST ABSOLUTELY NOT FAIL. These IDs are expected to be unique. As such a transactional select is used to safely get a range
// of IDs that will never be used again. A separate feature could track unused IDs and recycle them, but that is not implemented.
// 200 seems like a good range to reserve at once. Only way this would be noticable is if a player
// added hundreds of items at once.
// Doing the update first ensures that all other connections are blocked from accessing this table until we commit.
auto result = ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = last_object_id + 200;");
if (result == 0) {
InsertDefaultPersistentId();
result = ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = last_object_id + 200;");
}
// At this point all connections are waiting on us to finish the transaction, so we can safely select the ID we just set.
auto [_, selectResult] = ExecuteSelect("SELECT last_object_id FROM object_id_tracker;");
range.maxID = selectResult.getInt64Field("last_object_id");
range.minID = range.maxID - 199;
// We must commit here manually, this will unlock the database for all other servers
ExecuteCustomQuery("COMMIT;");
SetAutoCommit(prevCommit);
return range;
void SQLiteDatabase::UpdatePersistentId(const uint32_t newId) {
ExecuteUpdate("UPDATE object_id_tracker SET last_object_id = ?;", newId);
}

View File

@@ -1,23 +1,6 @@
#include "SQLiteDatabase.h"
#include "ePropertySortType.h"
IProperty::Info ReadPropertyInfo(CppSQLite3Query& propertyEntry) {
IProperty::Info toReturn;
toReturn.id = propertyEntry.getInt64Field("id");
toReturn.ownerId = propertyEntry.getInt64Field("owner_id");
toReturn.cloneId = propertyEntry.getInt64Field("clone_id");
toReturn.name = propertyEntry.getStringField("name");
toReturn.description = propertyEntry.getStringField("description");
toReturn.privacyOption = propertyEntry.getIntField("privacy_option");
toReturn.rejectionReason = propertyEntry.getStringField("rejection_reason");
toReturn.lastUpdatedTime = propertyEntry.getIntField("last_updated");
toReturn.claimedTime = propertyEntry.getIntField("time_claimed");
toReturn.reputation = propertyEntry.getIntField("reputation");
toReturn.modApproved = propertyEntry.getIntField("mod_approved");
toReturn.performanceCost = propertyEntry.getFloatField("performance_cost");
return toReturn;
}
std::optional<IProperty::PropertyEntranceResult> SQLiteDatabase::GetProperties(const IProperty::PropertyLookup& params) {
std::optional<IProperty::PropertyEntranceResult> result;
std::string query;
@@ -135,7 +118,19 @@ std::optional<IProperty::PropertyEntranceResult> SQLiteDatabase::GetProperties(c
auto& [_, properties] = propertiesRes;
if (!properties.eof() && !result.has_value()) result = IProperty::PropertyEntranceResult();
while (!properties.eof()) {
result->entries.push_back(ReadPropertyInfo(properties));
auto& entry = result->entries.emplace_back();
entry.id = properties.getInt64Field("id");
entry.ownerId = properties.getInt64Field("owner_id");
entry.cloneId = properties.getInt64Field("clone_id");
entry.name = properties.getStringField("name");
entry.description = properties.getStringField("description");
entry.privacyOption = properties.getIntField("privacy_option");
entry.rejectionReason = properties.getStringField("rejection_reason");
entry.lastUpdatedTime = properties.getIntField("last_updated");
entry.claimedTime = properties.getIntField("time_claimed");
entry.reputation = properties.getIntField("reputation");
entry.modApproved = properties.getIntField("mod_approved");
entry.performanceCost = properties.getFloatField("performance_cost");
properties.nextRow();
}
@@ -151,7 +146,21 @@ std::optional<IProperty::Info> SQLiteDatabase::GetPropertyInfo(const LWOMAPID ma
return std::nullopt;
}
return ReadPropertyInfo(propertyEntry);
IProperty::Info toReturn;
toReturn.id = propertyEntry.getInt64Field("id");
toReturn.ownerId = propertyEntry.getInt64Field("owner_id");
toReturn.cloneId = propertyEntry.getInt64Field("clone_id");
toReturn.name = propertyEntry.getStringField("name");
toReturn.description = propertyEntry.getStringField("description");
toReturn.privacyOption = propertyEntry.getIntField("privacy_option");
toReturn.rejectionReason = propertyEntry.getStringField("rejection_reason");
toReturn.lastUpdatedTime = propertyEntry.getIntField("last_updated");
toReturn.claimedTime = propertyEntry.getIntField("time_claimed");
toReturn.reputation = propertyEntry.getIntField("reputation");
toReturn.modApproved = propertyEntry.getIntField("mod_approved");
toReturn.performanceCost = propertyEntry.getFloatField("performance_cost");
return toReturn;
}
void SQLiteDatabase::UpdatePropertyModerationInfo(const IProperty::Info& info) {
@@ -188,15 +197,3 @@ void SQLiteDatabase::InsertNewProperty(const IProperty::Info& info, const uint32
zoneId.GetMapID()
);
}
std::optional<IProperty::Info> SQLiteDatabase::GetPropertyInfo(const LWOOBJID id) {
auto [_, propertyEntry] = ExecuteSelect(
"SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved, performance_cost "
"FROM properties WHERE id = ?;", id);
if (propertyEntry.eof()) {
return std::nullopt;
}
return ReadPropertyInfo(propertyEntry);
}

View File

@@ -64,28 +64,27 @@ void SQLiteDatabase::RemoveModel(const LWOOBJID& modelId) {
ExecuteDelete("DELETE FROM properties_contents WHERE id = ?;", modelId);
}
std::optional<IPropertyContents::Model> SQLiteDatabase::GetModel(const LWOOBJID modelID) {
IPropertyContents::Model SQLiteDatabase::GetModel(const LWOOBJID modelID) {
auto [_, result] = ExecuteSelect("SELECT * FROM properties_contents WHERE id = ?", modelID);
std::optional<IPropertyContents::Model> model = std::nullopt;
IPropertyContents::Model model{};
if (!result.eof()) {
do {
model = IPropertyContents::Model{};
model->id = result.getInt64Field("id");
model->lot = static_cast<LOT>(result.getIntField("lot"));
model->position.x = result.getFloatField("x");
model->position.y = result.getFloatField("y");
model->position.z = result.getFloatField("z");
model->rotation.w = result.getFloatField("rw");
model->rotation.x = result.getFloatField("rx");
model->rotation.y = result.getFloatField("ry");
model->rotation.z = result.getFloatField("rz");
model->ugcId = result.getInt64Field("ugc_id");
model->behaviors[0] = result.getInt64Field("behavior_1");
model->behaviors[1] = result.getInt64Field("behavior_2");
model->behaviors[2] = result.getInt64Field("behavior_3");
model->behaviors[3] = result.getInt64Field("behavior_4");
model->behaviors[4] = result.getInt64Field("behavior_5");
model.id = result.getInt64Field("id");
model.lot = static_cast<LOT>(result.getIntField("lot"));
model.position.x = result.getFloatField("x");
model.position.y = result.getFloatField("y");
model.position.z = result.getFloatField("z");
model.rotation.w = result.getFloatField("rw");
model.rotation.x = result.getFloatField("rx");
model.rotation.y = result.getFloatField("ry");
model.rotation.z = result.getFloatField("rz");
model.ugcId = result.getInt64Field("ugc_id");
model.behaviors[0] = result.getInt64Field("behavior_1");
model.behaviors[1] = result.getInt64Field("behavior_2");
model.behaviors[2] = result.getInt64Field("behavior_3");
model.behaviors[3] = result.getInt64Field("behavior_4");
model.behaviors[4] = result.getInt64Field("behavior_5");
} while (result.nextRow());
}

View File

@@ -1,17 +1,5 @@
#include "SQLiteDatabase.h"
IUgc::Model ReadModel(CppSQLite3Query& result) {
IUgc::Model model;
int blobSize{};
const auto* blob = result.getBlobField("lxfml", blobSize);
model.lxfmlData << std::string(reinterpret_cast<const char*>(blob), blobSize);
model.id = result.getInt64Field("ugcID");
model.modelID = result.getInt64Field("modelID");
return model;
}
std::vector<IUgc::Model> SQLiteDatabase::GetUgcModels(const LWOOBJID& propertyId) {
auto [_, result] = ExecuteSelect(
"SELECT lxfml, u.id AS ugcID, pc.id AS modelID 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;",
@@ -20,7 +8,14 @@ std::vector<IUgc::Model> SQLiteDatabase::GetUgcModels(const LWOOBJID& propertyId
std::vector<IUgc::Model> toReturn;
while (!result.eof()) {
toReturn.push_back(ReadModel(result));
IUgc::Model model;
int blobSize{};
const auto* blob = result.getBlobField("lxfml", blobSize);
model.lxfmlData << std::string(reinterpret_cast<const char*>(blob), blobSize);
model.id = result.getInt64Field("ugcID");
model.modelID = result.getInt64Field("modelID");
toReturn.push_back(std::move(model));
result.nextRow();
}
@@ -32,7 +27,14 @@ std::vector<IUgc::Model> SQLiteDatabase::GetAllUgcModels() {
std::vector<IUgc::Model> models;
while (!result.eof()) {
models.push_back(ReadModel(result));
IUgc::Model model;
model.id = result.getInt64Field("ugcID");
model.modelID = result.getInt64Field("modelID");
int blobSize{};
const auto* blob = result.getBlobField("lxfml", blobSize);
model.lxfmlData << std::string(reinterpret_cast<const char*>(blob), blobSize);
models.push_back(std::move(model));
result.nextRow();
}
@@ -45,9 +47,9 @@ void SQLiteDatabase::RemoveUnreferencedUgcModels() {
void SQLiteDatabase::InsertNewUgcModel(
std::stringstream& sd0Data, // cant be const sad
const uint64_t blueprintId,
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) {
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 (?,?,?,?,?,?,?)",
@@ -70,14 +72,3 @@ void SQLiteDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::stringstre
const std::istream stream(lxfml.rdbuf());
ExecuteUpdate("UPDATE ugc SET lxfml = ? WHERE id = ?;", &stream, modelId);
}
std::optional<IUgc::Model> SQLiteDatabase::GetUgcModel(const LWOOBJID ugcId) {
auto [_, result] = ExecuteSelect("SELECT u.id AS ugcID, pc.id AS modelID, lxfml FROM ugc AS u JOIN properties_contents AS pc ON pc.id = u.id WHERE u.id = ?;", ugcId);
std::optional<IUgc::Model> toReturn = std::nullopt;
if (!result.eof()) {
toReturn = ReadModel(result);
}
return toReturn;
}

View File

@@ -1,6 +1,6 @@
#include "SQLiteDatabase.h"
void SQLiteDatabase::InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) {
void SQLiteDatabase::InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) {
ExecuteInsert("INSERT INTO ugc_modular_build (ugc_id, ldf_config, character_id) VALUES (?,?,?)", bigId, modules, characterId);
}

View File

@@ -32,27 +32,27 @@ std::vector<std::string> TestSQLDatabase::GetApprovedCharacterNames() {
return {};
}
std::vector<FriendData> TestSQLDatabase::GetFriendsList(LWOOBJID charID) {
std::vector<FriendData> TestSQLDatabase::GetFriendsList(uint32_t charID) {
return {};
}
std::optional<IFriends::BestFriendStatus> TestSQLDatabase::GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) {
std::optional<IFriends::BestFriendStatus> TestSQLDatabase::GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) {
return {};
}
void TestSQLDatabase::SetBestFriendStatus(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId, const uint32_t bestFriendStatus) {
void TestSQLDatabase::SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) {
}
void TestSQLDatabase::AddFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) {
void TestSQLDatabase::AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) {
}
void TestSQLDatabase::RemoveFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) {
void TestSQLDatabase::RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) {
}
void TestSQLDatabase::UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) {
void TestSQLDatabase::UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) {
}
@@ -80,7 +80,7 @@ void TestSQLDatabase::InsertMigration(const std::string_view str) {
}
std::optional<ICharInfo::Info> TestSQLDatabase::GetCharacterInfo(const LWOOBJID charId) {
std::optional<ICharInfo::Info> TestSQLDatabase::GetCharacterInfo(const uint32_t charId) {
return {};
}
@@ -88,11 +88,11 @@ std::optional<ICharInfo::Info> TestSQLDatabase::GetCharacterInfo(const std::stri
return {};
}
std::string TestSQLDatabase::GetCharacterXml(const LWOOBJID accountId) {
std::string TestSQLDatabase::GetCharacterXml(const uint32_t accountId) {
return {};
}
void TestSQLDatabase::UpdateCharacterXml(const LWOOBJID characterId, const std::string_view lxfml) {
void TestSQLDatabase::UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) {
}
@@ -104,27 +104,27 @@ void TestSQLDatabase::InsertNewCharacter(const ICharInfo::Info info) {
}
void TestSQLDatabase::InsertCharacterXml(const LWOOBJID accountId, const std::string_view lxfml) {
void TestSQLDatabase::InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) {
}
std::vector<LWOOBJID> TestSQLDatabase::GetAccountCharacterIds(LWOOBJID accountId) {
std::vector<uint32_t> TestSQLDatabase::GetAccountCharacterIds(uint32_t accountId) {
return {};
}
void TestSQLDatabase::DeleteCharacter(const LWOOBJID characterId) {
void TestSQLDatabase::DeleteCharacter(const uint32_t characterId) {
}
void TestSQLDatabase::SetCharacterName(const LWOOBJID characterId, const std::string_view name) {
void TestSQLDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) {
}
void TestSQLDatabase::SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) {
void TestSQLDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) {
}
void TestSQLDatabase::UpdateLastLoggedInCharacter(const LWOOBJID characterId) {
void TestSQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
}
@@ -192,11 +192,11 @@ void TestSQLDatabase::InsertNewMail(const MailInfo& mail) {
}
void TestSQLDatabase::InsertNewUgcModel(std::stringstream& sd0Data, const uint64_t blueprintId, const uint32_t accountId, const LWOOBJID characterId) {
void TestSQLDatabase::InsertNewUgcModel(std::stringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) {
}
std::vector<MailInfo> TestSQLDatabase::GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) {
std::vector<MailInfo> TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
return {};
}
@@ -204,7 +204,7 @@ std::optional<MailInfo> TestSQLDatabase::GetMail(const uint64_t mailId) {
return {};
}
uint32_t TestSQLDatabase::GetUnreadMailCount(const LWOOBJID characterId) {
uint32_t TestSQLDatabase::GetUnreadMailCount(const uint32_t characterId) {
return {};
}
@@ -220,7 +220,7 @@ void TestSQLDatabase::ClaimMailItem(const uint64_t mailId) {
}
void TestSQLDatabase::InsertSlashCommandUsage(const LWOOBJID characterId, const std::string_view command) {
void TestSQLDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) {
}
@@ -244,7 +244,7 @@ void TestSQLDatabase::SetMasterInfo(const IServers::MasterInfo& info) {
}
std::optional<uint64_t> TestSQLDatabase::GetCurrentPersistentId() {
std::optional<uint32_t> TestSQLDatabase::GetCurrentPersistentId() {
return {};
}
@@ -252,6 +252,10 @@ void TestSQLDatabase::InsertDefaultPersistentId() {
}
void TestSQLDatabase::UpdatePersistentId(const uint32_t id) {
}
std::optional<uint32_t> TestSQLDatabase::GetDonationTotal(const uint32_t activityId) {
return {};
}
@@ -264,15 +268,15 @@ std::vector<IUgc::Model> TestSQLDatabase::GetUgcModels(const LWOOBJID& propertyI
return {};
}
void TestSQLDatabase::AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void TestSQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
}
void TestSQLDatabase::RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) {
void TestSQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
}
std::vector<IIgnoreList::Info> TestSQLDatabase::GetIgnoreList(const LWOOBJID playerId) {
std::vector<IIgnoreList::Info> TestSQLDatabase::GetIgnoreList(const uint32_t playerId) {
return {};
}
@@ -300,6 +304,3 @@ void TestSQLDatabase::UpdateAccountGmLevel(const uint32_t accountId, const eGame
}
IObjectIdTracker::Range TestSQLDatabase::GetPersistentIdRange() {
return {};
}

View File

@@ -17,31 +17,31 @@ class TestSQLDatabase : public GameDatabase {
std::vector<std::string> GetApprovedCharacterNames() override;
std::vector<FriendData> GetFriendsList(LWOOBJID charID) override;
std::vector<FriendData> GetFriendsList(uint32_t charID) override;
std::optional<IFriends::BestFriendStatus> GetBestFriendStatus(const LWOOBJID playerCharacterId, const LWOOBJID friendCharacterId) override;
void SetBestFriendStatus(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId, const uint32_t bestFriendStatus) override;
void AddFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void RemoveFriend(const LWOOBJID playerAccountId, const LWOOBJID friendAccountId) override;
void UpdateActivityLog(const LWOOBJID characterId, const eActivityType activityType, const LWOMAPID mapId) override;
std::optional<IFriends::BestFriendStatus> 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 characterId, const eActivityType activityType, const LWOMAPID mapId) override;
void DeleteUgcModelData(const LWOOBJID& modelId) override;
void UpdateUgcModelData(const LWOOBJID& modelId, std::stringstream& lxfml) override;
std::vector<IUgc::Model> GetAllUgcModels() override;
void CreateMigrationHistoryTable() override;
bool IsMigrationRun(const std::string_view str) override;
void InsertMigration(const std::string_view str) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const LWOOBJID charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const uint32_t charId) override;
std::optional<ICharInfo::Info> GetCharacterInfo(const std::string_view charId) override;
std::string GetCharacterXml(const LWOOBJID accountId) override;
void UpdateCharacterXml(const LWOOBJID characterId, const std::string_view lxfml) override;
std::string GetCharacterXml(const uint32_t accountId) override;
void UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) override;
std::optional<IAccounts::Info> GetAccountInfo(const std::string_view username) override;
void InsertNewCharacter(const ICharInfo::Info info) override;
void InsertCharacterXml(const LWOOBJID accountId, const std::string_view lxfml) override;
std::vector<LWOOBJID> GetAccountCharacterIds(LWOOBJID accountId) override;
void DeleteCharacter(const LWOOBJID characterId) override;
void SetCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void SetPendingCharacterName(const LWOOBJID characterId, const std::string_view name) override;
void UpdateLastLoggedInCharacter(const LWOOBJID characterId) override;
void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override;
std::vector<uint32_t> 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<IPetNames::Info> GetPetNameInfo(const LWOOBJID& petId) override;
std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override;
@@ -60,30 +60,30 @@ class TestSQLDatabase : public GameDatabase {
void InsertNewMail(const MailInfo& mail) override;
void InsertNewUgcModel(
std::stringstream& sd0Data,
const uint64_t blueprintId,
const uint32_t blueprintId,
const uint32_t accountId,
const LWOOBJID characterId) override;
std::vector<MailInfo> GetMailForPlayer(const LWOOBJID characterId, const uint32_t numberOfMail) override;
const uint32_t characterId) override;
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
uint32_t GetUnreadMailCount(const LWOOBJID characterId) 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 LWOOBJID characterId, const std::string_view command) 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 SetMasterInfo(const IServers::MasterInfo& info) override;
std::optional<uint64_t> GetCurrentPersistentId() override;
IObjectIdTracker::Range GetPersistentIdRange() override;
std::optional<uint32_t> GetCurrentPersistentId() override;
void InsertDefaultPersistentId() override;
void UpdatePersistentId(const uint32_t id) override;
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
void AddIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
void RemoveIgnore(const LWOOBJID playerId, const LWOOBJID ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const LWOOBJID playerId) override;
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
void AddBehavior(const IBehaviors::Info& info) override;
@@ -95,19 +95,17 @@ class TestSQLDatabase : public GameDatabase {
std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) override { return {}; };
std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) override { return {}; };
std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) override { return {}; };
void SaveScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override {};
void UpdateScore(const LWOOBJID playerId, const uint32_t gameId, const Score& score) override {};
std::optional<ILeaderboard::Score> GetPlayerScore(const LWOOBJID playerId, const uint32_t gameId) override { return {}; };
void IncrementNumWins(const LWOOBJID playerId, const uint32_t gameId) override {};
void IncrementTimesPlayed(const LWOOBJID playerId, const uint32_t gameId) override {};
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<LWOOBJID> characterId) override {};
void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override {};
void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override {};
std::optional<ILeaderboard::Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) override { return {}; };
void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) override {};
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override {};
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override {};
void DeleteUgcBuild(const LWOOBJID bigId) override {};
uint32_t GetAccountCount() override { return 0; };
bool IsNameInUse(const std::string_view name) override { return false; };
std::optional<IPropertyContents::Model> GetModel(const LWOOBJID modelID) override { return {}; }
std::optional<IProperty::Info> GetPropertyInfo(const LWOOBJID id) override { return {}; }
std::optional<IUgc::Model> GetUgcModel(const LWOOBJID ugcId) override { return {}; }
IPropertyContents::Model GetModel(const LWOOBJID modelID) override { return {}; }
};
#endif //!TESTSQLDATABASE_H

View File

@@ -48,7 +48,6 @@ void MigrationRunner::RunMigrations() {
bool runSd0Migrations = false;
bool runNormalizeMigrations = false;
bool runNormalizeAfterFirstPartMigrations = false;
bool runBrickBuildsNotOnGrid = false;
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/" / migrationFolder).string())) {
auto migration = LoadMigration("dlu/" + migrationFolder + "/", entry);
@@ -65,8 +64,6 @@ void MigrationRunner::RunMigrations() {
runNormalizeMigrations = true;
} else if (migration.name.ends_with("_normalize_model_positions_after_first_part.sql")) {
runNormalizeAfterFirstPartMigrations = true;
} else if (migration.name.ends_with("_brickbuilds_not_on_grid.sql")) {
runBrickBuildsNotOnGrid = true;
} else {
finalSQL.append(migration.data.c_str());
}
@@ -74,7 +71,7 @@ void MigrationRunner::RunMigrations() {
Database::Get()->InsertMigration(migration.name);
}
if (finalSQL.empty() && !runSd0Migrations && !runNormalizeMigrations && !runNormalizeAfterFirstPartMigrations && !runBrickBuildsNotOnGrid) {
if (finalSQL.empty() && !runSd0Migrations && !runNormalizeMigrations && !runNormalizeAfterFirstPartMigrations) {
LOG("Server database is up to date.");
return;
}
@@ -106,10 +103,6 @@ void MigrationRunner::RunMigrations() {
if (runNormalizeAfterFirstPartMigrations) {
ModelNormalizeMigration::RunAfterFirstPart();
}
if (runBrickBuildsNotOnGrid) {
ModelNormalizeMigration::RunBrickBuildGrid();
}
}
void MigrationRunner::RunSQLiteMigrations() {

View File

@@ -10,7 +10,7 @@ void ModelNormalizeMigration::Run() {
for (auto& [lxfmlData, id, modelID] : Database::Get()->GetAllUgcModels()) {
const auto model = Database::Get()->GetModel(modelID);
// only BBB models (lot 14) and models with a position of NiPoint3::ZERO need to have their position fixed.
if (!model || model->position != NiPoint3Constant::ZERO || model->lot != 14) continue;
if (model.position != NiPoint3Constant::ZERO || model.lot != 14) continue;
Sd0 sd0(lxfmlData);
const auto asStr = sd0.GetAsStringUncompressed();
@@ -23,7 +23,7 @@ void ModelNormalizeMigration::Run() {
LOG("Updated model %llu to have a center of %f %f %f", modelID, newCenter.x, newCenter.y, newCenter.z);
sd0.FromData(reinterpret_cast<const uint8_t*>(newLxfml.data()), newLxfml.size());
auto asStream = sd0.GetAsStream();
Database::Get()->UpdateModel(model->id, newCenter, model->rotation, model->behaviors);
Database::Get()->UpdateModel(model.id, newCenter, model.rotation, model.behaviors);
Database::Get()->UpdateUgcModelData(id, asStream);
}
Database::Get()->SetAutoCommit(oldCommit);
@@ -35,36 +35,15 @@ void ModelNormalizeMigration::RunAfterFirstPart() {
for (auto& [lxfmlData, id, modelID] : Database::Get()->GetAllUgcModels()) {
const auto model = Database::Get()->GetModel(modelID);
// only BBB models (lot 14) need to have their position fixed from the above blunder
if (!model || model->lot != 14) continue;
if (model.lot != 14) continue;
Sd0 sd0(lxfmlData);
const auto asStr = sd0.GetAsStringUncompressed();
const auto [newLxfml, newCenter] = Lxfml::NormalizePositionAfterFirstPart(asStr, model->position);
const auto [newLxfml, newCenter] = Lxfml::NormalizePositionAfterFirstPart(asStr, model.position);
sd0.FromData(reinterpret_cast<const uint8_t*>(newLxfml.data()), newLxfml.size());
auto asStream = sd0.GetAsStream();
Database::Get()->UpdateModel(model->id, newCenter, model->rotation, model->behaviors);
Database::Get()->UpdateUgcModelData(id, asStream);
}
Database::Get()->SetAutoCommit(oldCommit);
}
void ModelNormalizeMigration::RunBrickBuildGrid() {
const auto oldCommit = Database::Get()->GetAutoCommit();
Database::Get()->SetAutoCommit(false);
for (auto& [lxfmlData, id, modelID] : Database::Get()->GetAllUgcModels()) {
const auto model = Database::Get()->GetModel(modelID);
// only BBB models (lot 14) need to have their position fixed from the above blunder
if (!model || model->lot != 14) continue;
Sd0 sd0(lxfmlData);
const auto asStr = sd0.GetAsStringUncompressed();
const auto [newLxfml, newCenter] = Lxfml::NormalizePosition(asStr, model->position);
sd0.FromData(reinterpret_cast<const uint8_t*>(newLxfml.data()), newLxfml.size());
LOG("Updated model %llu to have a center of %f %f %f", modelID, newCenter.x, newCenter.y, newCenter.z);
auto asStream = sd0.GetAsStream();
Database::Get()->UpdateModel(model->id, newCenter, model->rotation, model->behaviors);
Database::Get()->UpdateModel(model.id, newCenter, model.rotation, model.behaviors);
Database::Get()->UpdateUgcModelData(id, asStream);
}
Database::Get()->SetAutoCommit(oldCommit);

View File

@@ -7,7 +7,6 @@
namespace ModelNormalizeMigration {
void Run();
void RunAfterFirstPart();
void RunBrickBuildGrid();
};
#endif //!MODELNORMALIZEMIGRATION_H

View File

@@ -23,7 +23,7 @@
#include "ePlayerFlag.h"
#include "CDPlayerFlagsTable.h"
Character::Character(LWOOBJID id, User* parentUser) {
Character::Character(uint32_t id, User* parentUser) {
//First load the name, etc:
m_ID = id;
m_ParentUser = parentUser;
@@ -50,10 +50,6 @@ void Character::UpdateInfoFromDatabase() {
//Load the xmlData now:
m_XMLData = Database::Get()->GetCharacterXml(m_ID);
if (m_XMLData.empty()) {
LOG("Character %s (%llu) has no xml data!", m_Name.c_str(), m_ID);
return;
}
m_ZoneID = 0; //TEMP! Set back to 0 when done. This is so we can see loading screen progress for testing.
m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused.
@@ -65,6 +61,7 @@ void Character::UpdateInfoFromDatabase() {
//Set our objectID:
m_ObjectID = m_ID;
GeneralUtils::SetBit(m_ObjectID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(m_ObjectID, eObjectBits::PERSISTENT);
m_OurEntity = nullptr;
m_BuildMode = false;
@@ -78,7 +75,7 @@ void Character::DoQuickXMLDataParse() {
if (m_XMLData.size() == 0) return;
if (m_Doc.Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) {
LOG("Loaded xmlData for character %s (%llu)!", m_Name.c_str(), m_ID);
LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
} else {
LOG("Failed to load xmlData (%i) (%s) (%s)!", m_Doc.ErrorID(), m_Doc.ErrorIDToName(m_Doc.ErrorID()), m_Doc.ErrorStr());
//Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true);
@@ -241,7 +238,7 @@ void Character::SetBuildMode(bool buildMode) {
void Character::SaveXMLToDatabase() {
// Check that we can actually _save_ before saving
if (!m_OurEntity) {
LOG("%llu:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
LOG("%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
return;
}
@@ -311,7 +308,7 @@ void Character::SaveXMLToDatabase() {
//For metrics, log the time it took to save:
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed = end - start;
LOG("%llu:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
LOG("%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
}
void Character::SetIsNewLogin() {
@@ -323,7 +320,7 @@ void Character::SetIsNewLogin() {
while (currentChild) {
auto* nextChild = currentChild->NextSiblingElement();
if (currentChild->Attribute("si")) {
LOG("Removed session flag (%s) from character %llu:%s, saving character to database", currentChild->Attribute("si"), GetID(), GetName().c_str());
LOG("Removed session flag (%s) from character %i:%s, saving character to database", currentChild->Attribute("si"), GetID(), GetName().c_str());
flags->DeleteChild(currentChild);
WriteToDatabase();
}
@@ -336,11 +333,8 @@ void Character::WriteToDatabase() {
tinyxml2::XMLPrinter printer(0, true, 0);
m_Doc.Print(&printer);
// Update the xml on the character for future use if needed
m_XMLData = printer.CStr();
//Finally, save to db:
Database::Get()->UpdateCharacterXml(m_ID, m_XMLData);
Database::Get()->UpdateCharacterXml(m_ID, printer.CStr());
}
void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
@@ -502,7 +496,7 @@ void Character::OnZoneLoad() {
// Remove all GM items
for (const auto lot : Inventory::GetAllGMItems()) {
inventoryComponent->RemoveItem(lot, inventoryComponent->GetLotCount(lot), eInventoryType::ALL);
inventoryComponent->RemoveItem(lot, inventoryComponent->GetLotCount(lot));
}
}

View File

@@ -23,7 +23,7 @@ enum class eLootSourceType : uint32_t;
*/
class Character {
public:
Character(LWOOBJID id, User* parentUser);
Character(uint32_t id, User* parentUser);
~Character();
/**
@@ -53,7 +53,7 @@ public:
* Gets the database ID of the character
* @return the database ID of the character
*/
LWOOBJID GetID() const { return m_ID; }
uint32_t GetID() const { return m_ID; }
/**
* Gets the (custom) name of the character
@@ -467,9 +467,9 @@ public:
private:
void UpdateInfoFromDatabase();
/**
* The ID of this character.
* The ID of this character. First 32 bits of the ObjectID.
*/
LWOOBJID m_ID{};
uint32_t m_ID{};
/**
* The 64-bit unique ID used in the game.
@@ -654,7 +654,7 @@ private:
/**
* The spawn rotation of this character when loading in
*/
NiQuaternion m_OriginalRotation = QuatUtils::IDENTITY;
NiQuaternion m_OriginalRotation;
/**
* The respawn points of this character, per world
@@ -682,9 +682,6 @@ private:
* NOTE: quick as there's no DB lookups
*/
void DoQuickXMLDataParse();
public:
const decltype(m_PlayerFlags)& GetPlayerFlags() const { return m_PlayerFlags; }
const decltype(m_SessionFlags)& GetSessionFlags() const { return m_SessionFlags; }
};
#endif // CHARACTER_H

View File

@@ -84,8 +84,6 @@
#include "GhostComponent.h"
#include "AchievementVendorComponent.h"
#include "VanityUtilities.h"
#include "ObjectIDManager.h"
#include "ePlayerFlag.h"
// Table includes
#include "CDComponentsRegistryTable.h"
@@ -99,8 +97,6 @@
#include "CDSkillBehaviorTable.h"
#include "CDZoneTableTable.h"
#include "StringifiedEnum.h"
#include <ranges>
Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate;
@@ -177,11 +173,8 @@ Entity::~Entity() {
CancelAllTimers();
CancelCallbackTimers();
for (auto& component : m_Components | std::views::values) {
if (component) {
delete component;
component = nullptr;
}
for (const auto& component : m_Components | std::views::values) {
if (component) delete component;
}
for (auto* const child : m_ChildEntities) {
@@ -194,17 +187,13 @@ Entity::~Entity() {
}
void Entity::Initialize() {
RegisterMsg<GameMessages::RequestServerObjectInfo>(this, &Entity::MsgRequestServerObjectInfo);
RegisterMsg<GameMessages::DropClientLoot>(this, &Entity::MsgDropClientLoot);
RegisterMsg<GameMessages::GetFactionTokenType>(this, &Entity::MsgGetFactionTokenType);
RegisterMsg<GameMessages::PickupItem>(this, &Entity::MsgPickupItem);
/**
* Setup trigger
*/
const auto triggerInfo = GetVarAsString(u"trigger_id");
if (!triggerInfo.empty()) AddComponent<TriggerComponent>(-1, triggerInfo);
if (!triggerInfo.empty()) AddComponent<TriggerComponent>(triggerInfo);
/**
* Setup groups
@@ -239,11 +228,11 @@ void Entity::Initialize() {
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
AddComponent<ModelComponent>(-1)->LoadBehaviors();
AddComponent<ModelComponent>()->LoadBehaviors();
AddComponent<RenderComponent>(-1);
AddComponent<RenderComponent>();
auto* destroyableComponent = AddComponent<DestroyableComponent>(-1);
auto* destroyableComponent = AddComponent<DestroyableComponent>();
destroyableComponent->SetHealth(1);
destroyableComponent->SetMaxHealth(1.0f);
destroyableComponent->SetFaction(-1, true);
@@ -259,42 +248,37 @@ void Entity::Initialize() {
*/
if (m_Character && m_Character->GetParentUser()) {
AddComponent<MissionComponent>(-1)->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<MissionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
}
const auto petComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET);
if (petComponentID > 0) {
AddComponent<PetComponent>(petComponentID);
const uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET);
if (petComponentId > 0) {
AddComponent<PetComponent>(petComponentId);
}
const auto minigameControlID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL);
if (minigameControlID > 0) {
AddComponent<MiniGameControlComponent>(minigameControlID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL) > 0) {
AddComponent<MiniGameControlComponent>();
}
const auto possessableComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
if (possessableComponentID > 0) {
AddComponent<PossessableComponent>(possessableComponentID);
const uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
if (possessableComponentId > 0) {
AddComponent<PossessableComponent>(possessableComponentId);
}
const auto moduleAssemblyID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY);
if (moduleAssemblyID > 0) {
AddComponent<ModuleAssemblyComponent>(moduleAssemblyID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY) > 0) {
AddComponent<ModuleAssemblyComponent>();
}
const auto racingStatsID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS);
if (racingStatsID > 0) {
AddComponent<RacingStatsComponent>(racingStatsID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS) > 0) {
AddComponent<RacingStatsComponent>();
}
const auto lupExhibitID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1);
if (lupExhibitID >= 0) {
AddComponent<LUPExhibitComponent>(lupExhibitID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1) >= 0) {
AddComponent<LUPExhibitComponent>();
}
const auto racingControlID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL);
if (racingControlID > 0) {
AddComponent<RacingControlComponent>(racingControlID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL) > 0) {
AddComponent<RacingControlComponent>();
}
const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_ENTRANCE);
@@ -302,7 +286,7 @@ void Entity::Initialize() {
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
}
const auto controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS);
const int32_t controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS);
if (controllablePhysicsComponentID > 0) {
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>(controllablePhysicsComponentID);
@@ -314,7 +298,7 @@ void Entity::Initialize() {
//If we came from another zone, put us in the starting loc
if (m_Character->GetZoneID() != Game::server->GetZoneID() || mapID == 1603) { // Exception for Moon Base as you tend to spawn on the roof.
NiPoint3 pos;
NiQuaternion rot = QuatUtils::IDENTITY;
NiQuaternion rot;
const auto& targetSceneName = m_Character->GetTargetScene();
auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName);
@@ -347,48 +331,46 @@ void Entity::Initialize() {
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
}
const auto rigidBodyPhantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS);
const int32_t rigidBodyPhantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS);
if (rigidBodyPhantomPhysicsComponentID > 0) {
AddComponent<RigidbodyPhantomPhysicsComponent>(rigidBodyPhantomPhysicsComponentID);
}
const auto phantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS);
const int32_t phantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS);
if (markedAsPhantom || phantomPhysicsComponentID > 0) {
AddComponent<PhantomPhysicsComponent>(phantomPhysicsComponentID)->SetPhysicsEffectActive(false);
}
const auto havokVehiclePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS);
const int32_t havokVehiclePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS);
if (havokVehiclePhysicsComponentID > 0) {
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>(havokVehiclePhysicsComponentID);
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
}
const auto soundTriggerID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1);
const auto racingSoundTriggerID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1);
if (soundTriggerID > -1) {
AddComponent<SoundTriggerComponent>(soundTriggerID);
} else if (racingSoundTriggerID > -1) {
AddComponent<RacingSoundTriggerComponent>(racingSoundTriggerID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
AddComponent<SoundTriggerComponent>();
} else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) {
AddComponent<RacingSoundTriggerComponent>();
}
const auto buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF);
if (buffComponentID > 0) {
AddComponent<BuffComponent>(buffComponentID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF) > 0) {
AddComponent<BuffComponent>();
}
const auto collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE);
const int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE);
if (collectibleComponentID > 0) {
AddComponent<CollectibleComponent>(collectibleComponentID, GetVarAs<int32_t>(u"collectible_id"));
AddComponent<CollectibleComponent>(GetVarAs<int32_t>(u"collectible_id"));
}
/**
* Multiple components require the destructible component.
*/
const auto quickBuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD);
const int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF);
const int quickBuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD);
int32_t componentID = -1;
int componentID = -1;
if (collectibleComponentID > 0) componentID = collectibleComponentID;
if (quickBuildComponentID > 0) componentID = quickBuildComponentID;
if (buffComponentID > 0) componentID = buffComponentID;
@@ -396,7 +378,7 @@ void Entity::Initialize() {
bool isSmashable = GetVarAs<int32_t>(u"is_smashable") != 0;
if (buffComponentID > 0 || collectibleComponentID > 0 || isSmashable) {
DestroyableComponent* comp = AddComponent<DestroyableComponent>(componentID);
DestroyableComponent* comp = AddComponent<DestroyableComponent>();
auto* const destCompTable = CDClientManager::GetTable<CDDestructibleComponentTable>();
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([componentID](const CDDestructibleComponent& entry) { return (entry.id == componentID); });
@@ -424,7 +406,6 @@ void Entity::Initialize() {
comp->SetIsSmashable(destCompData[0].isSmashable);
comp->SetLootMatrixID(destCompData[0].LootMatrixIndex);
comp->SetCurrencyIndex(destCompData[0].CurrencyIndex);
Loot::CacheMatrix(destCompData[0].LootMatrixIndex);
// Now get currency information
@@ -486,30 +467,27 @@ void Entity::Initialize() {
}
}
const auto characterID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER);
if (characterID > 0 || m_Character) {
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER) > 0 || m_Character) {
// Character Component always has a possessor, level, and forced movement components
AddComponent<PossessorComponent>(characterID);
AddComponent<PossessorComponent>();
// load in the xml for the level
AddComponent<LevelProgressionComponent>(characterID)->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<LevelProgressionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<PlayerForcedMovementComponent>(characterID);
AddComponent<PlayerForcedMovementComponent>();
auto& systemAddress = m_Character->GetParentUser() ? m_Character->GetParentUser()->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS;
AddComponent<CharacterComponent>(characterID, m_Character, systemAddress)->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<CharacterComponent>(m_Character, systemAddress)->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<GhostComponent>(characterID);
AddComponent<GhostComponent>();
}
const auto inventoryID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY);
if (inventoryID > 0 || m_Character) {
AddComponent<InventoryComponent>(inventoryID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) {
AddComponent<InventoryComponent>();
}
// if this component exists, then we initialize it. it's value is always 0
const auto multiZoneEntranceID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1);
if (multiZoneEntranceID > -1) {
AddComponent<MultiZoneEntranceComponent>(multiZoneEntranceID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) {
AddComponent<MultiZoneEntranceComponent>();
}
/**
@@ -561,7 +539,7 @@ void Entity::Initialize() {
}
if (!scriptName.empty() || client || m_Character || scriptComponentID >= 0) {
AddComponent<ScriptComponent>(scriptComponentID, scriptName, true, client && scriptName.empty());
AddComponent<ScriptComponent>(scriptName, true, client && scriptName.empty());
}
// ZoneControl script
@@ -570,27 +548,26 @@ void Entity::Initialize() {
const CDZoneTable* const zoneData = CDZoneTableTable::Query(zoneID.GetMapID());
if (zoneData != nullptr) {
const int32_t zoneScriptID = zoneData->scriptID;
int zoneScriptID = zoneData->scriptID;
CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID);
AddComponent<ScriptComponent>(zoneScriptID, zoneScriptData.script_name, true, false);
AddComponent<ScriptComponent>(zoneScriptData.script_name, true);
}
}
const auto skillID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1);
if (skillID > -1 || m_Character) {
AddComponent<SkillComponent>(skillID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1) != -1 || m_Character) {
AddComponent<SkillComponent>();
}
const auto combatAiID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI);
if (combatAiID > 0) {
AddComponent<BaseCombatAIComponent>(combatAiID);
const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI);
if (combatAiId > 0) {
AddComponent<BaseCombatAIComponent>(combatAiId);
}
if (quickBuildComponentID > 0) {
auto* const quickBuildComponent = AddComponent<QuickBuildComponent>(quickBuildComponentID);
if (const int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) {
auto* const quickBuildComponent = AddComponent<QuickBuildComponent>();
CDRebuildComponentTable* const rebCompTable = CDClientManager::GetTable<CDRebuildComponentTable>();
const std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([quickBuildComponentID](CDRebuildComponent entry) { return (entry.id == quickBuildComponentID); });
const std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == quickBuildComponentID); });
if (!rebCompData.empty()) {
quickBuildComponent->SetResetTime(rebCompData[0].reset_time);
@@ -635,63 +612,53 @@ void Entity::Initialize() {
}
}
const auto switchID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1);
if (switchID > -1) {
AddComponent<SwitchComponent>(switchID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1) != -1) {
AddComponent<SwitchComponent>();
}
const auto vendorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR);
const auto donationVendorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1);
const auto achievementVendorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ACHIEVEMENT_VENDOR, -1);
if (vendorID > 0) {
AddComponent<VendorComponent>(vendorID);
} else if (donationVendorID > -1) {
AddComponent<DonationVendorComponent>(donationVendorID);
} else if (achievementVendorID > -1) {
AddComponent<AchievementVendorComponent>(achievementVendorID);
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) {
AddComponent<VendorComponent>();
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
AddComponent<DonationVendorComponent>();
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ACHIEVEMENT_VENDOR, -1) != -1)) {
AddComponent<AchievementVendorComponent>();
}
const auto propertyVendorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1);
if (propertyVendorID > -1) {
AddComponent<PropertyVendorComponent>(propertyVendorID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
AddComponent<PropertyVendorComponent>();
}
const auto propertyManagementID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1);
if (propertyManagementID > -1) {
AddComponent<PropertyManagementComponent>(propertyManagementID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1) != -1) {
AddComponent<PropertyManagementComponent>();
}
const auto bouncerID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BOUNCER, -1);
if (bouncerID > -1) { // you have to determine it like this because all bouncers have a componentID of 0
AddComponent<BouncerComponent>(bouncerID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0
AddComponent<BouncerComponent>();
}
const auto renderComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
if ((renderComponentID > 0 && m_TemplateID != 2365) || m_Character) {
AddComponent<RenderComponent>(renderComponentID);
const int32_t renderComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
if ((renderComponentId > 0 && m_TemplateID != 2365) || m_Character) {
AddComponent<RenderComponent>(renderComponentId);
}
const auto missionOfferComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER, -1);
if (missionOfferComponentID > -1 || m_Character) {
AddComponent<MissionOfferComponent>(missionOfferComponentID);
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER) > 0) || m_Character) {
AddComponent<MissionOfferComponent>(m_TemplateID);
}
const auto buildBorderID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1);
if (buildBorderID > -1) {
AddComponent<BuildBorderComponent>(buildBorderID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1) != -1) {
AddComponent<BuildBorderComponent>();
}
// Scripted activity component
const auto scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY, -1);
if (scriptedActivityID > -1) {
const int32_t scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY, -1);
if (scriptedActivityID != -1) {
AddComponent<ScriptedActivityComponent>(scriptedActivityID);
}
const auto modelID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1);
if (modelID > -1 && !GetComponent<PetComponent>()) {
AddComponent<ModelComponent>(modelID)->LoadBehaviors();
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
AddComponent<ModelComponent>()->LoadBehaviors();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
auto* const destroyableComponent = AddComponent<DestroyableComponent>(-1);
auto* const destroyableComponent = AddComponent<DestroyableComponent>();
destroyableComponent->SetHealth(1);
destroyableComponent->SetMaxHealth(1.0f);
destroyableComponent->SetFaction(-1, true);
@@ -699,10 +666,9 @@ void Entity::Initialize() {
}
}
PetComponent* petComponent{};
const auto itemID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM);
if (itemID > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) {
AddComponent<ItemComponent>(itemID);
PetComponent* petComponent;
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) {
AddComponent<ItemComponent>();
}
// Shooting gallery component
@@ -711,17 +677,16 @@ void Entity::Initialize() {
AddComponent<ShootingGalleryComponent>(shootingGalleryComponentID);
}
const auto propertyID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1);
if (propertyID > -1) {
AddComponent<PropertyComponent>(propertyID);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) {
AddComponent<PropertyComponent>();
}
const auto rocketID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH);
if ((rocketID > 0)) {
AddComponent<RocketLaunchpadControlComponent>(rocketID);
const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH);
if ((rocketId > 0)) {
AddComponent<RocketLaunchpadControlComponent>(rocketId);
}
const auto railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR);
const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR);
if (railComponentID > 0) {
AddComponent<RailActivatorComponent>(railComponentID);
}
@@ -751,9 +716,9 @@ void Entity::Initialize() {
}
}
AddComponent<MovementAIComponent>(movementAIID, moveInfo);
AddComponent<MovementAIComponent>(moveInfo);
}
} else if (petComponentID > 0 || combatAiID > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) {
} else if (petComponentId > 0 || combatAiId > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) {
MovementAIInfo moveInfo{
.movementType = "",
.wanderRadius = 16,
@@ -763,7 +728,7 @@ void Entity::Initialize() {
.wanderDelayMax = 5,
};
AddComponent<MovementAIComponent>(-1, moveInfo);
AddComponent<MovementAIComponent>(moveInfo);
}
const std::string pathName = GetVarAsString(u"attached_path");
@@ -773,10 +738,10 @@ void Entity::Initialize() {
if (path) {
// if we have a moving platform path, then we need a moving platform component
if (path->pathType == PathType::MovingPlatform) {
AddComponent<MovingPlatformComponent>(-1, pathName);
AddComponent<MovingPlatformComponent>(pathName);
} else if (path->pathType == PathType::Movement) {
auto* const movementAIcomponent = GetComponent<MovementAIComponent>();
if (movementAIcomponent && combatAiID == 0) {
if (movementAIcomponent && combatAiId == 0) {
movementAIcomponent->SetPath(pathName);
} else {
MovementAIInfo moveInfo{
@@ -788,24 +753,24 @@ void Entity::Initialize() {
.wanderDelayMax = 5,
};
AddComponent<MovementAIComponent>(-1, moveInfo);
AddComponent<MovementAIComponent>(moveInfo);
}
}
} else {
// else we still need to setup moving platform if it has a moving platform comp but no path
const auto movingPlatformComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
if (movingPlatformComponentID >= 0) {
AddComponent<MovingPlatformComponent>(movingPlatformComponentID, pathName);
const int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
if (movingPlatformComponentId >= 0) {
AddComponent<MovingPlatformComponent>(pathName);
}
}
const auto proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR);
const int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR);
if (proximityMonitorID > 0) {
auto* const proxCompTable = CDClientManager::GetTable<CDProximityMonitorComponentTable>();
const auto proxCompData = proxCompTable->Query([proximityMonitorID](const CDProximityMonitorComponent& entry) { return (entry.id == proximityMonitorID); });
if (proxCompData.size() > 0) {
std::vector<std::string> proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ',');
AddComponent<ProximityMonitorComponent>(proximityMonitorID, std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
AddComponent<ProximityMonitorComponent>(std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
}
}
@@ -911,13 +876,12 @@ void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationNa
void Entity::SetProximityRadius(float proxRadius, std::string name) {
auto* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) proxMon = AddComponent<ProximityMonitorComponent>(-1);
if (!proxMon) proxMon = AddComponent<ProximityMonitorComponent>();
proxMon->SetProximityRadius(proxRadius, name);
}
void Entity::SetProximityRadius(dpEntity* entity, std::string name) {
auto* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) proxMon = AddComponent<ProximityMonitorComponent>(-1);
ProximityMonitorComponent* proxMon = AddComponent<ProximityMonitorComponent>();
proxMon->SetProximityRadius(entity, name);
}
@@ -935,7 +899,7 @@ void Entity::SetGMLevel(eGameMasterLevel value) {
// Update the chat server of our GM Level
{
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GMLEVEL_UPDATE);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GMLEVEL_UPDATE);
bitStream.Write(m_ObjectID);
bitStream.Write(m_GMLevel);
@@ -956,7 +920,7 @@ void Entity::WriteLDFData(const std::vector<LDFBaseData*>& ldf, RakNet::BitStrea
numberOfValidKeys--;
}
}
// Now write it to the main bitstream
outBitStream.Write<uint32_t>(settingStream.GetNumberOfBytesUsed() + 1 + sizeof(uint32_t));
outBitStream.Write<uint8_t>(0); //no compression used
@@ -1669,7 +1633,7 @@ void Entity::AddLootItem(const Loot::Info& info) const {
auto* const characterComponent = GetComponent<CharacterComponent>();
if (!characterComponent) return;
LOG("Player %llu has been allowed to pickup %i with id %llu", m_ObjectID, info.lot, info.id);
auto& droppedLoot = characterComponent->GetDroppedLoot();
droppedLoot[info.id] = info;
}
@@ -1698,9 +1662,11 @@ void Entity::PickupItem(const LWOOBJID& objectID) const {
auto* const skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
const auto skills = skillsTable->Query([&info](CDObjectSkills entry) {return (entry.objectTemplate == info.lot); });
for (const auto& skill : skills) {
const auto [skillComponent, missionComponent] = GetComponentsMut<SkillComponent, MissionComponent>();
auto* skillComponent = GetComponent<SkillComponent>();
if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID(), skill.castOnType, NiQuaternion(0, 0, 0, 0));
auto* missionComponent = GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID);
}
@@ -1912,7 +1878,7 @@ const NiQuaternion& Entity::GetRotation() const {
return rigidBodyPhantomPhysicsComponent->GetRotation();
}
return QuatUtils::IDENTITY;
return NiQuaternionConstant::IDENTITY;
}
void Entity::SetPosition(const NiPoint3& position) {
@@ -2208,7 +2174,7 @@ const NiPoint3& Entity::GetRespawnPosition() const {
const NiQuaternion& Entity::GetRespawnRotation() const {
auto* characterComponent = GetComponent<CharacterComponent>();
return characterComponent ? characterComponent->GetRespawnRotation() : QuatUtils::IDENTITY;
return characterComponent ? characterComponent->GetRespawnRotation() : NiQuaternionConstant::IDENTITY;
}
void Entity::SetRespawnPos(const NiPoint3& position) const {
@@ -2245,110 +2211,3 @@ bool Entity::HandleMsg(GameMessages::GameMsg& msg) const {
void Entity::RegisterMsg(const MessageType::Game msgId, std::function<bool(GameMessages::GameMsg&)> handler) {
m_MsgHandlers.emplace(msgId, handler);
}
bool Entity::MsgRequestServerObjectInfo(GameMessages::GameMsg& msg) {
auto& requestInfo = static_cast<GameMessages::RequestServerObjectInfo&>(msg);
AMFArrayValue response;
response.Insert("visible", true);
response.Insert("objectID", std::to_string(m_ObjectID));
response.Insert("serverInfo", true);
GameMessages::GetObjectReportInfo info{};
info.clientID = requestInfo.clientId;
info.bVerbose = requestInfo.bVerbose;
info.info = response.InsertArray("data");
auto& objectInfo = info.info->PushDebug("Object Details");
auto* table = CDClientManager::GetTable<CDObjectsTable>();
const auto& objTableInfo = table->GetByID(GetLOT());
objectInfo.PushDebug<AMFStringValue>("Name") = objTableInfo.name;
objectInfo.PushDebug<AMFIntValue>("Template ID(LOT)") = GetLOT();
objectInfo.PushDebug<AMFStringValue>("Object ID") = std::to_string(GetObjectID());
objectInfo.PushDebug<AMFStringValue>("Spawner's Object ID") = std::to_string(GetSpawnerID());
auto& componentDetails = objectInfo.PushDebug("Component Information");
for (const auto [id, component] : m_Components) {
componentDetails.PushDebug(StringifiedEnum::ToString(id));
}
auto& configData = objectInfo.PushDebug("Config Data");
for (const auto config : m_Settings) {
configData.PushDebug<AMFStringValue>(GeneralUtils::UTF16ToWTF8(config->GetKey())) = config->GetValueAsString();
}
HandleMsg(info);
auto* client = Game::entityManager->GetEntity(requestInfo.clientId);
if (client) GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, client->GetSystemAddress());
return true;
}
bool Entity::MsgDropClientLoot(GameMessages::GameMsg& msg) {
auto& dropLootMsg = static_cast<GameMessages::DropClientLoot&>(msg);
if (dropLootMsg.item != LOT_NULL && dropLootMsg.item != 0) {
Loot::Info info{
.id = dropLootMsg.lootID,
.lot = dropLootMsg.item,
.count = dropLootMsg.count,
};
AddLootItem(info);
}
if (dropLootMsg.item == LOT_NULL && dropLootMsg.currency != 0) {
RegisterCoinDrop(dropLootMsg.currency);
}
return true;
}
bool Entity::MsgGetFlag(GameMessages::GameMsg& msg) {
auto& flagMsg = static_cast<GameMessages::GetFlag&>(msg);
if (m_Character) flagMsg.flag = m_Character->GetPlayerFlag(flagMsg.flagID);
return true;
}
bool Entity::MsgGetFactionTokenType(GameMessages::GameMsg& msg) {
auto& tokenMsg = static_cast<GameMessages::GetFactionTokenType&>(msg);
GameMessages::GetFlag getFlagMsg{};
getFlagMsg.flagID = ePlayerFlag::ASSEMBLY_FACTION;
MsgGetFlag(getFlagMsg);
if (getFlagMsg.flag) tokenMsg.tokenType = 8318;
getFlagMsg.flagID = ePlayerFlag::SENTINEL_FACTION;
MsgGetFlag(getFlagMsg);
if (getFlagMsg.flag) tokenMsg.tokenType = 8319;
getFlagMsg.flagID = ePlayerFlag::PARADOX_FACTION;
MsgGetFlag(getFlagMsg);
if (getFlagMsg.flag) tokenMsg.tokenType = 8320;
getFlagMsg.flagID = ePlayerFlag::VENTURE_FACTION;
MsgGetFlag(getFlagMsg);
if (getFlagMsg.flag) tokenMsg.tokenType = 8321;
LOG("Returning token type %i", tokenMsg.tokenType);
return tokenMsg.tokenType != LOT_NULL;
}
bool Entity::MsgPickupItem(GameMessages::GameMsg& msg) {
auto& pickupItemMsg = static_cast<GameMessages::PickupItem&>(msg);
if (GetObjectID() == pickupItemMsg.lootOwnerID) {
PickupItem(pickupItemMsg.lootID);
} else {
auto* const characterComponent = GetComponent<CharacterComponent>();
if (!characterComponent) return false;
auto& droppedLoot = characterComponent->GetDroppedLoot();
const auto it = droppedLoot.find(pickupItemMsg.lootID);
if (it != droppedLoot.end()) {
CDObjectsTable* objectsTable = CDClientManager::GetTable<CDObjectsTable>();
const CDObjects& object = objectsTable->GetByID(it->second.lot);
if (object.id != 0 && object.type == "Powerup") {
return false; // Let powerups be duplicated
}
}
droppedLoot.erase(pickupItemMsg.lootID);
}
return true;
}

View File

@@ -2,7 +2,6 @@
#include <map>
#include <functional>
#include <tuple>
#include <typeinfo>
#include <type_traits>
#include <unordered_map>
@@ -162,12 +161,6 @@ public:
template<typename T>
T* GetComponent() const;
template<typename... T>
auto GetComponents() const;
template<typename... T>
auto GetComponentsMut() const;
template<typename T>
bool TryGetComponent(eReplicaComponentType componentId, T*& component) const;
@@ -175,12 +168,6 @@ public:
void AddComponent(eReplicaComponentType componentId, Component* component);
bool MsgRequestServerObjectInfo(GameMessages::GameMsg& msg);
bool MsgDropClientLoot(GameMessages::GameMsg& msg);
bool MsgGetFlag(GameMessages::GameMsg& msg);
bool MsgGetFactionTokenType(GameMessages::GameMsg& msg);
bool MsgPickupItem(GameMessages::GameMsg& msg);
// This is expceted to never return nullptr, an assert checks this.
CppScripts::Script* const GetScript() const;
@@ -342,16 +329,6 @@ public:
bool HandleMsg(GameMessages::GameMsg& msg) const;
void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) {
RegisterMsg(msgId, std::bind(handler, self, std::placeholders::_1));
}
template<typename T>
inline void RegisterMsg(auto* self, const auto handler) {
T msg;
RegisterMsg(msg.msgId, self, handler);
}
/**
* @brief The observable for player entity position updates.
*/
@@ -367,7 +344,7 @@ private:
std::vector<LDFBaseData*> m_NetworkSettings;
NiPoint3 m_DefaultPosition;
NiQuaternion m_DefaultRotation = QuatUtils::IDENTITY;
NiQuaternion m_DefaultRotation;
float m_Scale;
Spawner* m_Spawner;
@@ -602,13 +579,3 @@ inline ComponentType* Entity::AddComponent(VaArgs... args) {
// To allow a static cast here instead of a dynamic one.
return dynamic_cast<ComponentType*>(componentToReturn);
}
template<typename... T>
auto Entity::GetComponents() const {
return GetComponentsMut<const T...>();
}
template<typename... T>
auto Entity::GetComponentsMut() const {
return std::tuple{ GetComponent<T>()... };
}

View File

@@ -52,45 +52,6 @@ std::vector<LOT> EntityManager::m_GhostingExcludedLOTs = {
4967
};
template<typename T>
void ParseDelimSetting(std::set<T>& setting, const std::string_view settingName, const char delim = ',') {
const auto str = Game::config->GetValue(settingName.data());
setting.clear();
for (const auto& strVal : GeneralUtils::SplitString(str, delim)) {
const auto val = GeneralUtils::TryParse<T>(strVal);
if (val) {
setting.insert(val.value());
}
}
}
void EntityManager::ReloadConfig() {
auto hcmode = Game::config->GetValue("hardcore_mode");
m_HardcoreMode = hcmode.empty() ? false : (hcmode == "1");
auto hcUscorePercent = Game::config->GetValue("hardcore_lose_uscore_on_death_percent");
m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : GeneralUtils::TryParse<uint32_t>(hcUscorePercent).value_or(10);
auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier");
m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : GeneralUtils::TryParse<uint32_t>(hcUscoreMult).value_or(2);
auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death");
m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1");
ParseDelimSetting<LOT>(m_HardcoreExcludedItemDrops, "hardcore_excluded_item_drops");
// We don't need to save the worlds, just need to check if this one is in the list
std::set<LWOMAPID> worlds;
ParseDelimSetting<LWOMAPID>(worlds, "hardcore_uscore_reduced_worlds");
m_HardcoreUscoreReduced = worlds.contains(Game::zoneManager->GetZoneID().GetMapID());
ParseDelimSetting<LOT>(m_HardcoreUscoreReducedLots, "hardcore_uscore_reduced_lots");
ParseDelimSetting<LOT>(m_HardcoreUscoreExcludedEnemies, "hardcore_uscore_excluded_enemies");
ParseDelimSetting<LWOMAPID>(m_HardcoreDisabledWorlds, "hardcore_disabled_worlds");
auto hcXpReduction = Game::config->GetValue("hardcore_uscore_reduction");
m_HardcoreUscoreReduction = hcXpReduction.empty() ? 1.0f : GeneralUtils::TryParse<float>(hcXpReduction).value_or(1.0f);
m_HardcoreMode = GetHardcoreDisabledWorlds().contains(Game::zoneManager->GetZoneID().GetMapID()) ? false : m_HardcoreMode;
auto hcCoinKeep = Game::config->GetValue("hardcore_coin_keep");
m_HardcoreCoinKeep = hcCoinKeep.empty() ? false : GeneralUtils::TryParse<float>(hcCoinKeep).value_or(0.0f);
}
void EntityManager::Initialize() {
// Check if this zone has ghosting enabled
m_GhostingEnabled = std::find(
@@ -100,8 +61,15 @@ void EntityManager::Initialize() {
) == m_GhostingExcludedZones.end();
// grab hardcore mode settings and load them with sane defaults
Game::config->AddConfigHandler([]() {Game::entityManager->ReloadConfig();});
Game::entityManager->ReloadConfig();
auto hcmode = Game::config->GetValue("hardcore_mode");
m_HardcoreMode = hcmode.empty() ? false : (hcmode == "1");
auto hcUscorePercent = Game::config->GetValue("hardcore_lose_uscore_on_death_percent");
m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : std::stoi(hcUscorePercent);
auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier");
m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : std::stoi(hcUscoreMult);
auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death");
m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1");
// If cloneID is not zero, then hardcore mode is disabled
// aka minigames and props
if (Game::zoneManager->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false;
@@ -161,8 +129,6 @@ Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentE
// Set the zone control entity if the entity is a zone control object, this should only happen once
if (controller) {
m_ZoneControlEntity = entity;
// Proooooobably shouldn't ghost zoneControl
m_ZoneControlEntity->SetIsGhostingCandidate(false);
}
// Check if this entity is a respawn point, if so add it to the registry
@@ -313,8 +279,6 @@ std::vector<Entity*> EntityManager::GetEntitiesByComponent(const eReplicaCompone
withComp.push_back(entity);
}
} else {
for (auto* const entity : m_Entities | std::views::values) withComp.push_back(entity);
}
return withComp;
}
@@ -430,7 +394,7 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) {
}
}
UpdateGhosting(PlayerManager::GetPlayer(sysAddr));
UpdateGhosting(PlayerManager::GetPlayer(sysAddr), true);
}
void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) {
@@ -499,7 +463,7 @@ void EntityManager::UpdateGhosting() {
m_PlayersToUpdateGhosting.clear();
}
void EntityManager::UpdateGhosting(Entity* player) {
void EntityManager::UpdateGhosting(Entity* player, const bool constructAll) {
if (!player) return;
auto* missionComponent = player->GetComponent<MissionComponent>();
@@ -549,6 +513,9 @@ void EntityManager::UpdateGhosting(Entity* player) {
entity->SetObservers(entity->GetObservers() + 1);
// TODO: figure out if zone control should be ghosted at all
if (constructAll && entity->GetObjectID() == GetZoneControlEntity()->GetObjectID()) continue;
ConstructEntity(entity, player->GetSystemAddress());
}
}
@@ -638,14 +605,3 @@ void EntityManager::FireEventServerSide(Entity* origin, std::string args) {
bool EntityManager::IsExcludedFromGhosting(LOT lot) {
return std::find(m_GhostingExcludedLOTs.begin(), m_GhostingExcludedLOTs.end(), lot) != m_GhostingExcludedLOTs.end();
}
bool EntityManager::SendMessage(GameMessages::GameMsg& msg) const {
bool handled = false;
const auto entityItr = m_Entities.find(msg.target);
if (entityItr != m_Entities.end()) {
auto* const entity = entityItr->second;
if (entity) handled = entity->HandleMsg(msg);
}
return handled;
}

View File

@@ -14,10 +14,6 @@ class Player;
class User;
enum class eReplicaComponentType : uint32_t;
namespace GameMessages {
struct GameMsg;
}
struct SystemAddress;
class EntityManager {
@@ -58,7 +54,7 @@ public:
void SetGhostDistanceMin(float value);
void QueueGhostUpdate(LWOOBJID playerID);
void UpdateGhosting();
void UpdateGhosting(Entity* player);
void UpdateGhosting(Entity* player, const bool constructAll = false);
void CheckGhosting(Entity* entity);
Entity* GetGhostCandidate(LWOOBJID id) const;
bool GetGhostingEnabled() const;
@@ -75,19 +71,8 @@ public:
const uint32_t GetHardcoreLoseUscoreOnDeathPercent() { return m_HardcoreLoseUscoreOnDeathPercent; };
const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; };
const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; };
const std::set<LOT>& GetHardcoreExcludedItemDrops() { return m_HardcoreExcludedItemDrops; };
const float& GetHardcoreUscoreReduction() const { return m_HardcoreUscoreReduction; };
bool GetHardcoreUscoreReduced() const { return m_HardcoreUscoreReduced; };
const std::set<LOT>& GetHardcoreUscoreReducedLots() const { return m_HardcoreUscoreReducedLots; };
const std::set<LOT>& GetHardcoreUscoreExcludedEnemies() const { return m_HardcoreUscoreExcludedEnemies; };
const std::set<LWOMAPID>& GetHardcoreDisabledWorlds() const { return m_HardcoreDisabledWorlds; };
float GetHardcoreCoinKeep() const { return m_HardcoreCoinKeep; }
// Messaging
bool SendMessage(GameMessages::GameMsg& msg) const;
private:
void ReloadConfig();
void SerializeEntities();
void KillEntities();
void DeleteEntities();
@@ -120,13 +105,6 @@ private:
uint32_t m_HardcoreLoseUscoreOnDeathPercent;
bool m_HardcoreDropinventoryOnDeath;
uint32_t m_HardcoreUscoreEnemiesMultiplier;
std::set<LOT> m_HardcoreExcludedItemDrops;
float m_HardcoreUscoreReduction{};
bool m_HardcoreUscoreReduced{};
std::set<LOT> m_HardcoreUscoreReducedLots{};
std::set<LOT> m_HardcoreUscoreExcludedEnemies{};
std::set<LWOMAPID> m_HardcoreDisabledWorlds{};
float m_HardcoreCoinKeep{};
};
#endif // ENTITYMANAGER_H

View File

@@ -145,7 +145,7 @@ void QueryToLdf(Leaderboard& leaderboard, const std::vector<ILeaderboard::Entry>
}
}
std::vector<ILeaderboard::Entry> FilterToNumResults(const std::vector<ILeaderboard::Entry>& leaderboard, const LWOOBJID relatedPlayer, const Leaderboard::InfoType infoType, const uint32_t numResults) {
std::vector<ILeaderboard::Entry> FilterToNumResults(const std::vector<ILeaderboard::Entry>& leaderboard, const uint32_t relatedPlayer, const Leaderboard::InfoType infoType, const uint32_t numResults) {
std::vector<ILeaderboard::Entry> toReturn;
int32_t index = 0;
@@ -197,7 +197,7 @@ std::vector<ILeaderboard::Entry> FilterWeeklies(const std::vector<ILeaderboard::
return weeklyLeaderboard;
}
std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::Entry>& leaderboard, const LWOOBJID relatedPlayer) {
std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::Entry>& leaderboard, const uint32_t relatedPlayer) {
// Filter the leaderboard to only include friends of the player
auto friendOfPlayer = Database::Get()->GetFriendsList(relatedPlayer);
std::vector<ILeaderboard::Entry> friendsLeaderboard;
@@ -217,7 +217,7 @@ std::vector<ILeaderboard::Entry> ProcessLeaderboard(
const std::vector<ILeaderboard::Entry>& leaderboard,
const bool weekly,
const Leaderboard::InfoType infoType,
const LWOOBJID relatedPlayer,
const uint32_t relatedPlayer,
const uint32_t numResults) {
std::vector<ILeaderboard::Entry> toReturn;

View File

@@ -9,16 +9,6 @@ Team::Team() {
lootOption = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1;
}
LWOOBJID Team::GetNextLootOwner() {
lootRound++;
if (lootRound >= members.size()) {
lootRound = 0;
}
return members[lootRound];
}
TeamManager::TeamManager() {
}

View File

@@ -4,8 +4,6 @@
struct Team {
Team();
LWOOBJID GetNextLootOwner();
LWOOBJID teamID = LWOOBJID_EMPTY;
char lootOption = 0;
std::vector<LWOOBJID> members{};

View File

@@ -7,10 +7,6 @@
#include "dZoneManager.h"
#include "eServerDisconnectIdentifiers.h"
#include "eGameMasterLevel.h"
#include "BitStreamUtils.h"
#include "MessageType/Chat.h"
#include <chrono>
#include <ctime>
User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) {
m_AccountID = 0;
@@ -32,18 +28,18 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std:
if (userInfo) {
m_AccountID = userInfo->id;
m_MaxGMLevel = userInfo->maxGmLevel;
m_MuteExpire = userInfo->muteExpire;
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 characterList = Database::Get()->GetAccountCharacterIds(m_AccountID);
if (!characterList.empty()) {
const auto lastUsedCharacterId = characterList.front();
const uint32_t lastUsedCharacterId = characterList.front();
Character* character = new Character(lastUsedCharacterId, this);
character->UpdateFromDatabase();
m_Characters.push_back(character);
LOG("Loaded %llu as it is the last used char", lastUsedCharacterId);
LOG("Loaded %i as it is the last used char", lastUsedCharacterId);
}
}
}
@@ -95,28 +91,8 @@ Character* User::GetLastUsedChar() {
}
}
bool User::GetIsMuted() {
using namespace std::chrono;
constexpr auto refreshInterval = seconds{ 60 };
const auto now = steady_clock::now();
if (now - m_LastMuteCheck >= refreshInterval) {
m_LastMuteCheck = now;
if (const auto info = Database::Get()->GetAccountInfo(m_Username)) {
const auto expire = static_cast<time_t>(info->muteExpire);
if (expire != m_MuteExpire) {
m_MuteExpire = expire;
if (Game::chatServer && m_LoggedInCharID != 0) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_MUTE);
bitStream.Write(m_LoggedInCharID);
bitStream.Write(m_MuteExpire);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
}
}
}
}
return m_MuteExpire == 1 || m_MuteExpire > std::time(nullptr);
bool User::GetIsMuted() const {
return m_MuteExpire == 1 || m_MuteExpire > time(NULL);
}
time_t User::GetMuteExpire() const {

View File

@@ -3,7 +3,6 @@
#include <string>
#include <vector>
#include <chrono>
#include "RakNetTypes.h"
#include "dCommonVars.h"
@@ -47,7 +46,7 @@ public:
const std::unordered_map<std::string, bool>& GetIsBestFriendMap() { return m_IsBestFriendMap; }
void UpdateBestFriendValue(const std::string_view playerName, const bool newValue);
bool GetIsMuted();
bool GetIsMuted() const;
time_t GetMuteExpire() const;
void SetMuteExpire(time_t value);
@@ -73,8 +72,7 @@ private:
bool m_LastChatMessageApproved = false;
int m_AmountOfTimesOutOfSync = 0;
const int m_MaxDesyncAllowed = 12;
uint64_t m_MuteExpire;
std::chrono::steady_clock::time_point m_LastMuteCheck{};
time_t m_MuteExpire;
};
#endif // USER_H

Some files were not shown because too many files have changed in this diff Show More