Compare commits

..

5 Commits

Author SHA1 Message Date
Jett
0f4ebd7587 Start moving migration stuff! 2023-10-11 22:39:58 +01:00
Jett
44a5d83b1d Completely broken minor changes, just caching changes while moving machines 2023-10-10 13:55:58 +00:00
Jett
d61d3b0ce2 Implement more abstracted database functions. 2023-10-10 11:59:30 +00:00
Jett
6fb0677bd9 Resolve copy and past mistakes and further work. 2023-10-10 09:22:31 +00:00
Jett
8edfdd48a1 Start on replacing MySQL 2023-10-10 01:40:48 +01:00
254 changed files with 2824 additions and 3052 deletions

View File

@@ -148,19 +148,16 @@ foreach (resource_file ${RESOURCE_FILES})
endforeach()
message(STATUS "Resource file integrity check complete")
# if navmeshes directory does not exist, create it
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/navmeshes)
endif()
# Copy navmesh data on first build and extract it
configure_file(
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
COPYONLY
)
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
configure_file(
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
COPYONLY
)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PROJECT_BINARY_DIR}/navmeshes)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
endif()
# Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")

View File

@@ -224,44 +224,6 @@ sudo setcap 'cap_net_bind_service=+ep' AuthServer
```
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
### Linux Service
If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server.
_Note: You could use screen or tmux instead for virtual terminals_
To run the server non-interactively, we can use a systemctl service by copying the following file:
```shell
cp ./systemd.example /etc/systemd/system/darkflame.service
```
Make sure to edit the file in `/etc/systemd/system/darkflame.service` and change the:
- `User` and `Group` to the user that runs the darkflame server.
- `ExecPath` to the full file path of the server executable.
To register, enable and start the service use the following commands:
- Reload the systemd manager configuration to make it aware of the new service file:
```shell
systemctl daemon-reload
```
- Start the service:
```shell
systemctl start darkflame.service
```
- Enable OR disable the service to start on boot using:
```shell
systemctl enable darkflame.service
systemctl disable darkflame.service
```
- Verify that the service is running without errors:
```shell
systemctl status darkflame.service
```
- You can also restart, stop, or check the logs of the service using journalctl
```shell
systemctl restart darkflame.service
systemctl stop darkflame.service
journalctl -xeu darkflame.service
```
### First admin user
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
@@ -323,7 +285,6 @@ Below are known good SHA256 checksums of the client:
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
You must also make absolutely sure your LEGO Universe client is not in a Windows OneDrive. DLU is not and will not support a client being stored in a OneDrive, so ensure you have moved the client outside of that location.
### Darkflame Universe Client
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.

View File

@@ -7,7 +7,7 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "Diagnostics.h"
@@ -25,14 +25,14 @@
#include "Game.h"
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
Logger* SetupLogger();
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
int main(int argc, char** argv) {
@@ -51,38 +51,14 @@ int main(int argc, char** argv) {
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Auth server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
Game::logger->Log("AuthServer", "Starting Auth server...");
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
//Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password");
Database::Connect(Game::config);
try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
LOG("Got an error while connecting to the database: %s", ex.what());
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
return EXIT_FAILURE;
}
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1500;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
Game::randomEngine = std::mt19937(time(0));
@@ -92,7 +68,7 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterSock.hostAddress, masterSock.port, ServerType::Auth, Game::config, &Game::shouldShutdown);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -131,18 +107,7 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
Database::Connection->GetMasterServerIP();
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -151,9 +116,7 @@ int main(int argc, char** argv) {
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
std::this_thread::sleep_until(t);
}
//Delete our objects here:
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
delete Game::config;
@@ -161,7 +124,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
Logger* SetupLogger() {
dLogger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -170,7 +133,7 @@ Logger* SetupLogger() {
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
return new dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {

View File

@@ -8,7 +8,7 @@
#include <regex>
#include "dCommonVars.h"
#include "Logger.h"
#include "dLogger.h"
#include "dConfig.h"
#include "Database.h"
#include "Game.h"
@@ -31,16 +31,13 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
ReadWordlistDCF("blacklist.dcf", false);
}
//Read player names that are ok as well:
auto stmt = Database::CreatePreppedStmt("select name from charinfo;");
auto res = stmt->executeQuery();
while (res->next()) {
std::string line = res->getString(1).c_str();
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
m_ApprovedWords.push_back(CalculateHash(line));
// Read player names that are ok as well:
auto names = Database::Connection->GetAllCharacterNames();
for (auto& name : names) {
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
m_ApprovedWords.push_back(CalculateHash(name));
}
delete res;
delete stmt;
}
dChatFilter::~dChatFilter() {
@@ -144,7 +141,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
listOfBadSegments.emplace_back(position, originalSegment.length());
}
position += originalSegment.length() + 1;
position += segment.length() + 1;
}
return listOfBadSegments;

View File

@@ -7,7 +7,7 @@
#include "Game.h"
#include "dServer.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "dLogger.h"
#include "eAddFriendResponseCode.h"
#include "eAddFriendResponseType.h"
#include "RakString.h"
@@ -118,11 +118,6 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
inStream.Read(isBestFriendRequest);
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
if (!requestor) {
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
return;
}
if (requestor->playerName == playerName) {
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
return;
@@ -402,7 +397,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
LOG("Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
if (channel != 8) return;
@@ -532,13 +527,13 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
if (team->memberIDs.size() > 3) {
// no more teams greater than 4
LOG("Someone tried to invite a 5th player to a team");
Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team");
return;
}
SendTeamInvite(other, player);
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
}
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
@@ -552,7 +547,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
LWOOBJID leaderID = LWOOBJID_EMPTY;
inStream.Read(leaderID);
LOG("Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
if (declined) {
return;
@@ -561,13 +556,13 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
auto* team = playerContainer.GetTeam(leaderID);
if (team == nullptr) {
LOG("Failed to find team for leader (%llu)", leaderID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID);
team = playerContainer.GetTeam(playerID);
}
if (team == nullptr) {
LOG("Failed to find team for player (%llu)", playerID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID);
return;
}
@@ -583,7 +578,7 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
auto* team = playerContainer.GetTeam(playerID);
LOG("(%llu) leaving team", playerID);
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID);
if (team != nullptr) {
playerContainer.RemoveMember(team, playerID, false, false, true);
@@ -597,7 +592,7 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
@@ -627,7 +622,7 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
auto* promoted = playerContainer.GetPlayerData(promotedPlayer);

View File

@@ -6,7 +6,7 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "dChatFilter.h"
@@ -27,7 +27,7 @@
#include <MessageIdentifiers.h>
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
dChatFilter* chatFilter = nullptr;
@@ -37,7 +37,7 @@ namespace Game {
}
Logger* SetupLogger();
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
PlayerContainer playerContainer;
@@ -58,9 +58,9 @@ int main(int argc, char** argv) {
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Chat server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
Game::logger->Log("ChatServer", "Starting Chat server...");
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
try {
std::string clientPathStr = Game::config->GetValue("client_location");
@@ -72,39 +72,15 @@ int main(int argc, char** argv) {
Game::assetManager = new AssetManager(clientPath);
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
//Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password");
Database::Connect(Game::config);
try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
LOG("Got an error while connecting to the database: %s", ex.what());
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
return EXIT_FAILURE;
}
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1000;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50;
@@ -112,7 +88,7 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterSock.hostAddress, masterSock.port, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
@@ -155,18 +131,7 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
Database::Connection->GetMasterServerIP();
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -176,8 +141,8 @@ int main(int argc, char** argv) {
std::this_thread::sleep_until(t);
}
//Delete our objects here:
Database::Destroy("ChatServer");
// Delete our objects here:
Database::Destroy();
delete Game::server;
delete Game::logger;
delete Game::config;
@@ -185,7 +150,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
Logger* SetupLogger() {
dLogger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -194,16 +159,16 @@ Logger* SetupLogger() {
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
return new dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
LOG("A server has disconnected, erasing their connected players from the list.");
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
}
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
LOG("A server is connecting, awaiting user list.");
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
}
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
@@ -234,7 +199,7 @@ void HandlePacket(Packet* packet) {
}
default:
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
@@ -245,7 +210,7 @@ void HandlePacket(Packet* packet) {
break;
case eChatMessageType::GET_IGNORE_LIST:
LOG("Asked for ignore list, but is unimplemented right now.");
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
break;
case eChatMessageType::TEAM_GET_STATUS:
@@ -303,19 +268,19 @@ void HandlePacket(Packet* packet) {
break;
default:
LOG("Unknown CHAT id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
switch (static_cast<eWorldMessageType>(packet->data[3])) {
case eWorldMessageType::ROUTE_PACKET: {
LOG("Routing packet from world");
Game::logger->Log("ChatServer", "Routing packet from world");
break;
}
default:
LOG("Unknown World id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
}
}
}

View File

@@ -3,7 +3,7 @@
#include <iostream>
#include <algorithm>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "ChatPacketHandler.h"
#include "GeneralUtils.h"
#include "BitStreamUtils.h"
@@ -11,7 +11,6 @@
#include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "ChatPackets.h"
#include "dConfig.h"
PlayerContainer::PlayerContainer() {
}
@@ -20,10 +19,6 @@ PlayerContainer::~PlayerContainer() {
mPlayers.clear();
}
TeamData::TeamData() {
lootFlag = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1;
}
void PlayerContainer::InsertPlayer(Packet* packet) {
CINSTREAM_SKIP_HEADER;
PlayerData* data = new PlayerData();
@@ -44,16 +39,9 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
mPlayers.insert(std::make_pair(data->playerID, data));
LOG("Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
insertLog->setInt(1, data->playerID);
insertLog->setInt(2, 0);
insertLog->setUInt64(3, time(nullptr));
insertLog->setInt(4, data->zoneID.GetMapID());
insertLog->executeUpdate();
Database::Connection->InsertIntoActivityLog(data->playerID, 0, time(nullptr), data->zoneID.GetMapID());
}
void PlayerContainer::RemovePlayer(Packet* packet) {
@@ -87,17 +75,10 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
}
}
LOG("Removed user: %llu", playerID);
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
mPlayers.erase(playerID);
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
insertLog->setInt(1, playerID);
insertLog->setInt(2, 1);
insertLog->setUInt64(3, time(nullptr));
insertLog->setInt(4, player->zoneID.GetMapID());
insertLog->executeUpdate();
Database::Connection->InsertIntoActivityLog(playerID, 1, time(nullptr), player->zoneID.GetMapID());
}
void PlayerContainer::MuteUpdate(Packet* packet) {
@@ -110,7 +91,7 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
auto* player = this->GetPlayerData(playerID);
if (player == nullptr) {
LOG("Failed to find user: %llu", playerID);
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
return;
}
@@ -214,7 +195,7 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4){
LOG("Tried to add player to team that already had 4 players");
Game::logger->Log("PlayerContainer", "Tried to add player to team that already had 4 players");
auto* player = GetPlayerData(playerID);
if (!player) return;
ChatPackets::SendSystemMessage(player->sysAddr, u"The teams is full! You have not been added to a team!");

View File

@@ -18,7 +18,6 @@ struct PlayerData {
};
struct TeamData {
TeamData();
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
LWOOBJID leaderID = LWOOBJID_EMPTY;
std::vector<LWOOBJID> memberIDs{};

View File

@@ -2,7 +2,7 @@
#define __AMF3__H__
#include "dCommonVars.h"
#include "Logger.h"
#include "dLogger.h"
#include "Game.h"
#include <unordered_map>

View File

@@ -1,7 +1,7 @@
#include "AmfSerialize.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// Writes an AMFValue pointer to a RakNet::BitStream
template<>
@@ -29,7 +29,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
break;
}
default: {
LOG("Encountered unwritable AMFType %i!", type);
Game::logger->Log("AmfSerialize", "Encountered unwritable AMFType %i!", type);
}
case eAmf::Undefined:
case eAmf::Null:

View File

@@ -1,20 +0,0 @@
#pragma once
#include <cstdint>
namespace BrickByBrickFix {
/**
* @brief Deletes all broken BrickByBrick models that have invalid XML
*
* @return The number of BrickByBrick models that were truncated
*/
uint32_t TruncateBrokenBrickByBrickXml();
/**
* @brief Updates all BrickByBrick models in the database to be
* in the sd0 format as opposed to a zlib compressed format.
*
* @return The number of BrickByBrick models that were updated
*/
uint32_t UpdateBrickByBrickModelsToSd0();
};

View File

@@ -4,7 +4,7 @@ set(DCOMMON_SOURCES
"BinaryIO.cpp"
"dConfig.cpp"
"Diagnostics.cpp"
"Logger.cpp"
"dLogger.cpp"
"GeneralUtils.cpp"
"LDFFormat.cpp"
"MD5.cpp"
@@ -14,7 +14,6 @@ set(DCOMMON_SOURCES
"SHA512.cpp"
"Demangler.cpp"
"ZCompression.cpp"
"BrickByBrickFix.cpp"
"BinaryPathFinder.cpp"
"FdbToSqlite.cpp"
)

View File

@@ -1,6 +1,6 @@
#include "Diagnostics.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// If we're on Win32, we'll include our minidump writer
#ifdef _WIN32
@@ -9,7 +9,7 @@
#include <Dbghelp.h>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void make_minidump(EXCEPTION_POINTERS* e) {
auto hDbgHelp = LoadLibraryA("dbghelp");
@@ -28,7 +28,7 @@ void make_minidump(EXCEPTION_POINTERS* e) {
"_%4d%02d%02d_%02d%02d%02d.dmp",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
}
LOG("Creating crash dump %s", name);
Game::logger->Log("Diagnostics", "Creating crash dump %s", name);
auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
return;
@@ -83,7 +83,7 @@ struct bt_ctx {
static inline void Bt(struct backtrace_state* state) {
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
LOG("backtrace is enabled, crash dump located at %s", fileName.c_str());
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
FILE* file = fopen(fileName.c_str(), "w+");
if (file != nullptr) {
backtrace_print(state, 2, file);
@@ -118,7 +118,7 @@ void CatchUnhandled(int sig) {
#ifndef __include_backtrace__
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
LOG("Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
if (Diagnostics::GetProduceMemoryDump()) {
GenerateDump();
}
@@ -134,10 +134,6 @@ void CatchUnhandled(int sig) {
// Loop through the returned addresses, and get the symbols to be demangled
char** strings = backtrace_symbols(array, size);
FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) {
fprintf(file, "Error: signal %d:\n", sig);
}
// Print the stack trace
for (size_t i = 0; i < size; i++) {
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]'
@@ -158,15 +154,20 @@ void CatchUnhandled(int sig) {
}
}
LOG("[%02zu] %s", i, functionName.c_str());
if (file != NULL) {
fprintf(file, "[%02zu] %s\n", i, functionName.c_str());
}
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
}
# else // defined(__GNUG__)
backtrace_symbols_fd(array, size, STDOUT_FILENO);
# endif // defined(__GNUG__)
FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) {
// print out all the frames to stderr
fprintf(file, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, fileno(file));
fclose(file);
}
#else // __include_backtrace__
struct backtrace_state* state = backtrace_create_state(

View File

@@ -9,7 +9,7 @@
#include "CDClientDatabase.h"
#include "GeneralUtils.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "AssetManager.h"
#include "eSqliteDataType.h"
@@ -44,7 +44,7 @@ bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) {
LOG("Encountered error %s converting FDB to SQLite", e.errorMessage());
Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage());
return false;
}

View File

@@ -3,7 +3,7 @@
#include <random>
class dServer;
class Logger;
class dLogger;
class InstanceManager;
class dChatFilter;
class dConfig;
@@ -14,7 +14,7 @@ class EntityManager;
class dZoneManager;
namespace Game {
extern Logger* logger;
extern dLogger* logger;
extern dServer* server;
extern InstanceManager* im;
extern dChatFilter* chatFilter;

View File

@@ -13,7 +13,7 @@
#include "NiPoint3.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
enum eInventoryType : uint32_t;
enum class eObjectBits : size_t;

View File

@@ -4,7 +4,7 @@
#include "GeneralUtils.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// C++
#include <string_view>
@@ -48,7 +48,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
try {
type = static_cast<eLDFType>(strtol(ldfTypeAndValue.first.data(), &storage, 10));
} catch (std::exception) {
LOG("Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
Game::logger->Log("LDFFormat", "Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
return nullptr;
}
@@ -63,7 +63,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
case LDF_TYPE_S32: {
int32_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<int32_t>(key, data);
@@ -74,7 +74,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
case LDF_TYPE_FLOAT: {
float data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<float>(key, data);
@@ -84,7 +84,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
case LDF_TYPE_DOUBLE: {
double data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<double>(key, data);
@@ -101,7 +101,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
data = 0;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
}
@@ -119,7 +119,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
data = false;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
}
@@ -131,7 +131,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
case LDF_TYPE_U64: {
uint64_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<uint64_t>(key, data);
@@ -141,7 +141,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
case LDF_TYPE_OBJID: {
LWOOBJID data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<LWOOBJID>(key, data);
@@ -155,12 +155,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
}
case LDF_TYPE_UNKNOWN: {
LOG("Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
break;
}
default: {
LOG("Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
break;
}
}

View File

@@ -1,96 +0,0 @@
#include "Logger.h"
#include <algorithm>
#include <ctime>
#include <filesystem>
#include <stdarg.h>
Writer::~Writer() {
// Dont try to close stdcout...
if (!m_Outfile || m_IsConsoleWriter) return;
fclose(m_Outfile);
m_Outfile = NULL;
}
void Writer::Log(const char* time, const char* message) {
if (!m_Outfile) return;
fputs(time, m_Outfile);
fputs(message, m_Outfile);
}
void Writer::Flush() {
if (!m_Outfile) return;
fflush(m_Outfile);
}
FileWriter::FileWriter(const char* outpath) {
m_Outfile = fopen(outpath, "wt");
if (!m_Outfile) printf("Couldn't open %s for writing!\n", outpath);
m_Outpath = outpath;
m_IsConsoleWriter = false;
}
ConsoleWriter::ConsoleWriter(bool enabled) {
m_Enabled = enabled;
m_Outfile = stdout;
m_IsConsoleWriter = true;
}
Logger::Logger(const std::string& outpath, bool logToConsole, bool logDebugStatements) {
m_logDebugStatements = logDebugStatements;
std::filesystem::path outpathPath(outpath);
if (!std::filesystem::exists(outpathPath.parent_path())) std::filesystem::create_directories(outpathPath.parent_path());
m_Writers.push_back(std::make_unique<FileWriter>(outpath));
m_Writers.push_back(std::make_unique<ConsoleWriter>(logToConsole));
}
void Logger::vLog(const char* format, va_list args) {
time_t t = time(NULL);
struct tm* time = localtime(&t);
char timeStr[70];
strftime(timeStr, sizeof(timeStr), "[%d-%m-%y %H:%M:%S ", time);
char message[2048];
vsnprintf(message, 2048, format, args);
for (const auto& writer : m_Writers) {
writer->Log(timeStr, message);
}
}
void Logger::Log(const char* className, const char* format, ...) {
va_list args;
std::string log = std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void Logger::LogDebug(const char* className, const char* format, ...) {
if (!m_logDebugStatements) return;
va_list args;
std::string log = std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void Logger::Flush() {
for (const auto& writer : m_Writers) {
writer->Flush();
}
}
void Logger::SetLogToConsole(bool logToConsole) {
for (const auto& writer : m_Writers) {
if (writer->IsConsoleWriter()) writer->SetEnabled(logToConsole);
}
}
bool Logger::GetLogToConsole() const {
bool toReturn = false;
for (const auto& writer : m_Writers) {
if (writer->IsConsoleWriter()) toReturn |= writer->GetEnabled();
}
return toReturn;
}

View File

@@ -1,89 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#define STRINGIFY_IMPL(x) #x
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define GET_FILE_NAME(x, y) GetFileNameFromAbsolutePath(__FILE__ x y)
#define FILENAME_AND_LINE GET_FILE_NAME(":", STRINGIFY(__LINE__))
// Calculate the filename at compile time from the path.
// We just do this by scanning the path for the last '/' or '\' character and returning the string after it.
constexpr const char* GetFileNameFromAbsolutePath(const char* path) {
const char* file = path;
while (*path) {
char nextChar = *path++;
if (nextChar == '/' || nextChar == '\\') {
file = path;
}
}
return file;
}
// These have to have a constexpr variable to store the filename_and_line result in a local variable otherwise
// they will not be valid constexpr and will be evaluated at runtime instead of compile time!
// The full string is still stored in the binary, however the offset of the filename in the absolute paths
// is used in the instruction instead of the start of the absolute path.
#define LOG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->Log(str, message, ##__VA_ARGS__); } while(0)
#define LOG_DEBUG(message, ...) do { auto str = FILENAME_AND_LINE; Game::logger->LogDebug(str, message, ##__VA_ARGS__); } while(0)
// Writer class for writing data to files.
class Writer {
public:
Writer(bool enabled = true) : m_Enabled(enabled) {};
virtual ~Writer();
virtual void Log(const char* time, const char* message);
virtual void Flush();
void SetEnabled(bool disabled) { m_Enabled = disabled; }
bool GetEnabled() const { return m_Enabled; }
bool IsConsoleWriter() { return m_IsConsoleWriter; }
public:
bool m_Enabled = true;
bool m_IsConsoleWriter = false;
FILE* m_Outfile;
};
// FileWriter class for writing data to a file on a disk.
class FileWriter : public Writer {
public:
FileWriter(const char* outpath);
FileWriter(const std::string& outpath) : FileWriter(outpath.c_str()) {};
private:
std::string m_Outpath;
};
// ConsoleWriter class for writing data to the console.
class ConsoleWriter : public Writer {
public:
ConsoleWriter(bool enabled);
};
class Logger {
public:
Logger() = delete;
Logger(const std::string& outpath, bool logToConsole, bool logDebugStatements);
void Log(const char* filenameAndLine, const char* format, ...);
void LogDebug(const char* filenameAndLine, const char* format, ...);
void Flush();
bool GetLogToConsole() const;
void SetLogToConsole(bool logToConsole);
void SetLogDebugStatements(bool logDebugStatements) { m_logDebugStatements = logDebugStatements; }
private:
void vLog(const char* format, va_list args);
bool m_logDebugStatements;
std::vector<std::unique_ptr<Writer>> m_Writers;
};

View File

@@ -2,7 +2,7 @@
#include "AssetManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include <zlib.h>

View File

@@ -3,7 +3,6 @@
#include <vector>
#include <string>
#include <filesystem>
#include <fstream>
#pragma pack(push, 1)
struct PackRecord {

View File

@@ -1,7 +1,7 @@
#include "PackIndex.h"
#include "BinaryIO.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
PackIndex::PackIndex(const std::filesystem::path& filePath) {
m_FileStream = std::ifstream(filePath / "versions" / "primary.pki", std::ios::in | std::ios::binary);
@@ -34,7 +34,7 @@ PackIndex::PackIndex(const std::filesystem::path& filePath) {
m_PackFileIndices.push_back(packFileIndex);
}
LOG("Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
for (auto& item : m_PackPaths) {
std::replace(item.begin(), item.end(), '\\', '/');

View File

@@ -27,6 +27,20 @@ enum class ePermissionMap : uint64_t {
* The character has restricted chat access, bit 6.
*/
RestrictedChatAccess = 0x1 << 6,
//
// Combined permissions
//
/**
* The character is marked as 'old', restricted from trade and mail.
*/
Old = RestrictedTradeAccess | RestrictedMailAccess,
/**
* The character is soft banned, restricted from trade, mail, and chat.
*/
SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess,
};
#endif //!__EPERMISSIONMAP__H__

110
dCommon/dLogger.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "dLogger.h"
dLogger::dLogger(const std::string& outpath, bool logToConsole, bool logDebugStatements) {
m_logToConsole = logToConsole;
m_logDebugStatements = logDebugStatements;
m_outpath = outpath;
#ifdef _WIN32
mFile = std::ofstream(m_outpath);
if (!mFile) { printf("Couldn't open %s for writing!\n", outpath.c_str()); }
#else
fp = fopen(outpath.c_str(), "wt");
if (fp == NULL) { printf("Couldn't open %s for writing!\n", outpath.c_str()); }
#endif
}
dLogger::~dLogger() {
#ifdef _WIN32
mFile.close();
#else
if (fp != nullptr) {
fclose(fp);
fp = nullptr;
}
#endif
}
void dLogger::vLog(const char* format, va_list args) {
#ifdef _WIN32
time_t t = time(NULL);
struct tm time;
localtime_s(&time, &t);
char timeStr[70];
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time);
char message[2048];
vsnprintf(message, 2048, format, args);
if (m_logToConsole) std::cout << "[" << timeStr << "] " << message;
mFile << "[" << timeStr << "] " << message;
#else
time_t t = time(NULL);
struct tm* time = localtime(&t);
char timeStr[70];
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time);
char message[2048];
vsnprintf(message, 2048, format, args);
if (m_logToConsole) {
fputs("[", stdout);
fputs(timeStr, stdout);
fputs("] ", stdout);
fputs(message, stdout);
}
if (fp != nullptr) {
fputs("[", fp);
fputs(timeStr, fp);
fputs("] ", fp);
fputs(message, fp);
} else {
printf("Logger not initialized!\n");
}
#endif
}
void dLogger::LogBasic(const char* format, ...) {
va_list args;
va_start(args, format);
vLog(format, args);
va_end(args);
}
void dLogger::LogBasic(const std::string& message) {
LogBasic(message.c_str());
}
void dLogger::Log(const char* className, const char* format, ...) {
va_list args;
std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void dLogger::Log(const std::string& className, const std::string& message) {
Log(className.c_str(), message.c_str());
}
void dLogger::LogDebug(const char* className, const char* format, ...) {
if (!m_logDebugStatements) return;
va_list args;
std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format);
vLog(log.c_str(), args);
va_end(args);
}
void dLogger::LogDebug(const std::string& className, const std::string& message) {
LogDebug(className.c_str(), message.c_str());
}
void dLogger::Flush() {
#ifdef _WIN32
mFile.flush();
#else
if (fp != nullptr) {
std::fflush(fp);
}
#endif
}

38
dCommon/dLogger.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <ctime>
#include <cstdarg>
#include <string>
#include <fstream>
#include <iostream>
class dLogger {
public:
dLogger(const std::string& outpath, bool logToConsole, bool logDebugStatements);
~dLogger();
void SetLogToConsole(bool logToConsole) { m_logToConsole = logToConsole; }
void SetLogDebugStatements(bool logDebugStatements) { m_logDebugStatements = logDebugStatements; }
void vLog(const char* format, va_list args);
void LogBasic(const std::string& message);
void LogBasic(const char* format, ...);
void Log(const char* className, const char* format, ...);
void Log(const std::string& className, const std::string& message);
void LogDebug(const std::string& className, const std::string& message);
void LogDebug(const char* className, const char* format, ...);
void Flush();
const bool GetIsLoggingToConsole() const { return m_logToConsole; }
private:
bool m_logDebugStatements;
bool m_logToConsole;
std::string m_outpath;
std::ofstream mFile;
#ifndef _WIN32
//Glorious linux can run with SPEED:
FILE* fp = nullptr;
#endif
};

View File

@@ -1,7 +1,6 @@
set(DDATABASE_SOURCES "CDClientDatabase.cpp"
"CDClientManager.cpp"
"Database.cpp"
"MigrationRunner.cpp")
"Database.cpp")
add_subdirectory(Tables)
@@ -9,5 +8,17 @@ foreach(file ${DDATABASE_TABLES_SOURCES})
set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Tables/${file}")
endforeach()
add_subdirectory(Databases)
foreach (file ${DDATABASE_DATABASES_SOURCES})
set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Databases/${file}")
endforeach()
add_subdirectory(Databases/Migrations)
foreach (file ${DDATABASE_DATABASES_MIGRATIONS_SOURCES})
set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Databases/Migrations/${file}")
endforeach()
add_library(dDatabase STATIC ${DDATABASE_SOURCES})
target_link_libraries(dDatabase sqlite3 mariadbConnCpp)

View File

@@ -1,118 +1,26 @@
#include "Database.h"
#include "Game.h"
#include "dConfig.h"
#include "Logger.h"
using namespace std;
#pragma warning (disable:4251) //Disables SQL warnings
#include "Databases/MySQL.h"
sql::Driver* Database::driver;
sql::Connection* Database::con;
sql::Properties Database::props;
std::string Database::database;
void Database::Connect(dConfig* config) {
bool useSqlite = true;
if (config->GetValue("mysql_host") != "" && config->GetValue("mysql_database") != "" && config->GetValue("mysql_username") != "" && config->GetValue("mysql_password") != "") {
useSqlite = false;
}
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
if (useSqlite) {
//To bypass debug issues:
const char* szDatabase = database.c_str();
const char* szUsername = username.c_str();
const char* szPassword = password.c_str();
driver = sql::mariadb::get_driver_instance();
sql::Properties properties;
// The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where
// 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the
// presence of a /
// 2) even avoiding that, the connector still assumes you're connecting with a tcp socket
// So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost,
// which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate
// property manually (which the URL parsing fails to do)
const std::string UNIX_PROTO = "unix://";
const std::string PIPE_PROTO = "pipe://";
if (host.find(UNIX_PROTO) == 0) {
properties["hostName"] = "unix://localhost";
properties["localSocket"] = host.substr(UNIX_PROTO.length()).c_str();
} else if (host.find(PIPE_PROTO) == 0) {
properties["hostName"] = "pipe://localhost";
properties["pipe"] = host.substr(PIPE_PROTO.length()).c_str();
} else {
properties["hostName"] = host.c_str();
}
properties["user"] = szUsername;
properties["password"] = szPassword;
properties["autoReconnect"] = "true";
Database::props = properties;
Database::database = database;
Database::Connect();
}
void Database::Connect() {
// `connect(const Properties& props)` segfaults in windows debug, but
// `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly
if (Database::props.find("localSocket") != Database::props.end() || Database::props.find("pipe") != Database::props.end()) {
con = driver->connect(Database::props);
} else {
con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str());
}
con->setSchema(Database::database.c_str());
}
void Database::Destroy(std::string source, bool log) {
if (!con) return;
if (log) {
if (source != "") LOG("Destroying MySQL connection from %s!", source.c_str());
else LOG("Destroying MySQL connection!");
Database::Connection = new MySQLDatabase(config->GetValue("mysql_host"), config->GetValue("mysql_database"), config->GetValue("mysql_username"), config->GetValue("mysql_password"));
Database::ConnectionType = eConnectionTypes::MYSQL;
}
con->close();
delete con;
} //Destroy
sql::Statement* Database::CreateStmt() {
sql::Statement* toReturn = con->createStatement();
return toReturn;
} //CreateStmt
sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
const char* test = query.c_str();
size_t size = query.length();
sql::SQLString str(test, size);
if (!con) {
Connect();
LOG("Trying to reconnect to MySQL");
}
if (!con->isValid() || con->isClosed()) {
delete con;
con = nullptr;
Connect();
LOG("Trying to reconnect to MySQL from invalid or closed connection");
}
auto* stmt = con->prepareStatement(str);
return stmt;
} //CreatePreppedStmt
void Database::Commit() {
Database::con->commit();
Database::Connection->Connect();
}
bool Database::GetAutoCommit() {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
return con->getAutoCommit();
}
void Database::SetAutoCommit(bool value) {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
Database::con->setAutoCommit(value);
void Database::Destroy() {
Database::Connection->Destroy();
delete Database::Connection;
}

View File

@@ -1,31 +1,16 @@
#pragma once
#include <string>
#include <conncpp.hpp>
class MySqlException : public std::runtime_error {
public:
MySqlException() : std::runtime_error("MySQL error!") {}
MySqlException(const std::string& msg) : std::runtime_error(msg.c_str()) {}
};
#include "Databases/DatabaseBase.h"
class dConfig;
class Database {
private:
static sql::Driver* driver;
static sql::Connection* con;
static sql::Properties props;
static std::string database;
public:
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
static void Connect();
static void Destroy(std::string source = "", bool log = true);
static DatabaseBase* Connection;
static eConnectionTypes ConnectionType;
static sql::Statement* CreateStmt();
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
static void Commit();
static bool GetAutoCommit();
static void SetAutoCommit(bool value);
static std::string GetDatabase() { return database; }
static sql::Properties GetProperties() { return props; }
static void Connect(dConfig* config);
static void Destroy();
};

View File

@@ -0,0 +1 @@
set(DDATABASE_DATABASES_SOURCES "MySQL.cpp")

View File

@@ -0,0 +1,100 @@
#pragma once
#include <string>
#include <vector>
#include "RakNetTypes.h"
#include "Structures.h"
enum eConnectionTypes {
NONE,
MYSQL,
SQLITE
};
class DatabaseBase {
public:
virtual void Connect() = 0;
virtual void Destroy() = 0;
// Server Get
virtual SocketDescriptor GetMasterServerIP() = 0;
// Server Set
virtual void CreateServer(const std::string& name, const std::string& ip, uint16_t port, uint32_t state, uint32_t version) = 0;
virtual void SetServerIpAndPortByName(const std::string& name, const std::string& ip, uint16_t port) = 0;
// Misc
virtual void InsertIntoActivityLog(uint32_t playerId, uint32_t activityId, uint32_t timestamp, uint32_t zoneId) = 0;
virtual void InsertIntoCommandLog(uint32_t playerId, const std::string& command) = 0;
// Character Get
virtual CharacterInfo GetCharacterInfoByID(uint32_t id) = 0;
virtual CharacterInfo GetCharacterInfoByName(const std::string& name) = 0;
virtual std::string GetCharacterXMLByID(uint32_t id) = 0;
virtual std::vector<std::string> GetAllCharacterNames() = 0;
virtual std::vector<CharacterInfo> GetAllCharactersByAccountID(uint32_t accountId) = 0;
virtual bool IsCharacterNameAvailable(const std::string& name) = 0;
// Charater Write
virtual void CreateCharacterXML(uint32_t id, const std::string& xml) = 0;
virtual void UpdateCharacterXML(uint32_t id, const std::string& xml) = 0;
virtual void CreateCharacter(uint32_t id, uint32_t account_id, const std::string& name, const std::string& pending_name, bool needs_rename, uint64_t last_login) = 0;
virtual void ApproveCharacterName(uint32_t id, const std::string& newName) = 0;
virtual void SetPendingCharacterName(uint32_t id, const std::string& pendingName) = 0;
virtual void UpdateCharacterLastLogin(uint32_t id, uint64_t time) = 0;
// Character Delete
virtual void DeleteCharacter(uint32_t id) = 0;
// Friends Get
virtual bool AreBestFriends(uint32_t charId1, uint32_t charId2) = 0;
// Account Get
virtual AccountInfo GetAccountByName(const std::string& name) = 0;
virtual AccountInfo GetAccountByID(uint32_t id) = 0;
virtual uint32_t GetLatestCharacterOfAccount(uint32_t id) = 0;
// Account Set
virtual void BanAccount(uint32_t id) = 0;
virtual void MuteAccount(uint32_t id, uint64_t muteExpireDate) = 0;
// Pet Write
virtual void CreatePetName(uint64_t id, const std::string& name, bool approved) = 0;
// Pet Delete
virtual void DeletePetName(uint64_t id) = 0;
// Pet Get
virtual PetName GetPetName(uint64_t id) = 0;
// Keys Get
virtual bool IsKeyActive(uint32_t id) = 0;
// Object ID tracker Get
virtual uint32_t GetObjectIDTracker() = 0;
// Object ID tracker Set
virtual void SetObjectIDTracker(uint32_t id) = 0;
// Mail Get
virtual MailInfo GetMailByID(uint64_t id) = 0;
virtual std::vector<MailInfo> GetAllRecentMailOfUser(uint32_t id) = 0;
virtual uint32_t GetUnreadMailCountForUser(uint32_t id) = 0;
// Mail Write
virtual void WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId = 0, uint32_t attachmentLot = 0, uint64_t attachmentSubkey = 0, uint32_t attachmentCount = 0, bool wasRead = false) = 0;
virtual void SetMailAsRead(uint64_t id) = 0;
virtual void RemoveAttachmentFromMail(uint64_t id) = 0;
// Mail Delete
virtual void DeleteMail(uint64_t id) = 0;
// Property Get
virtual uint64_t GetPropertyFromTemplateAndClone(uint32_t templateId, uint32_t cloneId) = 0;
virtual std::vector<uint32_t> GetBBBModlesForProperty(uint32_t propertyId) = 0;
virtual std::istream GetLXFMLFromID(uint32_t id) = 0;
private:
};

View File

@@ -0,0 +1 @@
set(DDATABASE_DATABASES_MIGRATIONS_SOURCES "MigrationManager.cpp" "MySQLMigration.cpp")

View File

@@ -0,0 +1,90 @@
#include "MigrationManager.h"
#include <fstream>
#include <string>
#include "dLogger.h"
#include "GeneralUtils.h"
#include "CDClientDatabase.h"
#include "BinaryPathFinder.h"
Migration Migration::LoadMigration(const std::string& type, const std::string& dbType, const std::string& name) {
Migration migration{};
std::ifstream file(BinaryPathFinder::GetBinaryDir() / "migrations/" / type / dbType / name);
if (file.is_open()) {
std::string line;
std::string total = "";
while (std::getline(file, line)) {
total += line;
}
file.close();
migration.name = ;
migration.data = total;
}
return migration;
}
void MigrationManager::RunSQLiteMigrations() {
auto cdstmt = CDClientDatabase::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);");
cdstmt.execQuery().finalize();
cdstmt.finalize();
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) {
auto migration = Migration::LoadMigration("cdserver", "", entry);
if (migration.data.empty()) continue;
// Check if there is an entry in the migration history table on the cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
cdstmt.bind((int32_t)1, migration.name.c_str());
auto cdres = cdstmt.execQuery();
bool doExit = !cdres.eof();
cdres.finalize();
cdstmt.finalize();
if (doExit) continue;
// Check first if there is entry in the migration history table on the main database.
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
doExit = res->next();
delete res;
delete stmt;
if (doExit) {
// Insert into cdclient database if there is an entry in the main database but not the cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
cdstmt.bind((int32_t)1, migration.name.c_str());
cdstmt.execQuery().finalize();
cdstmt.finalize();
continue;
}
// Doing these 1 migration at a time since one takes a long time and some may think it is crashing.
// This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated".
Game::logger->Log("MigrationRunner", "Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str());
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) {
if (dml.empty()) continue;
try {
CDClientDatabase::ExecuteDML(dml.c_str());
} catch (CppSQLite3Exception& e) {
Game::logger->Log("MigrationRunner", "Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage());
}
}
// Insert into cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
cdstmt.bind((int32_t)1, migration.name.c_str());
cdstmt.execQuery().finalize();
cdstmt.finalize();
CDClientDatabase::ExecuteQuery("COMMIT;");
}
Game::logger->Log("MigrationRunner", "CDServer database is up to date.");
}

View File

@@ -0,0 +1,17 @@
#pragma once
class DatabaseBase;
struct Migration {
std::string data;
std::string name;
static Migration LoadMigration(const std::string& type, const std::string& dbType, const std::string& name);
};
class MigrationManager {
public:
void RunMigrations(DatabaseBase* db);
void RunSQLiteMigrations();
private:
};

View File

@@ -1,35 +1,93 @@
#include "BrickByBrickFix.h"
#include "MySQLMigration.h"
#include <memory>
#include <iostream>
#include <sstream>
#include <istream>
#include "CDClientDatabase.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "dLogger.h"
#include "BinaryPathFinder.h"
#include "ZCompression.h"
#include "tinyxml2.h"
#include "Database.h"
#include "Game.h"
#include "ZCompression.h"
#include "Logger.h"
#include "../MySQL.h"
//! Forward declarations
void MigrationRunner::RunMigrations(DatabaseBase* db) {
auto database = dynamic_cast<MySQLDatabase*>(db);
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
void WriteSd0Magic(char* input, uint32_t chunkSize);
bool CheckSd0Magic(sql::Blob* streamToCheck);
auto* stmt = database->CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
stmt->execute();
delete stmt;
/**
* @brief Truncates all models with broken data from the database.
*
* @return The number of models deleted
*/
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
sql::SQLString finalSQL = "";
bool runSd0Migrations = false;
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/mysql").string())) {
auto migration = Migration::LoadMigration("dlu", "mysql", entry);
if (migration.data.empty()) {
continue;
}
stmt = database->CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
bool doExit = res->next();
delete res;
delete stmt;
if (doExit) continue;
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
if (migration.name == "dlu/5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
finalSQL.append(migration.data.c_str());
}
stmt = database->CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
stmt->setString(1, migration.name.c_str());
stmt->execute();
delete stmt;
}
if (finalSQL.empty() && !runSd0Migrations) {
Game::logger->Log("MigrationRunner", "Server database is up to date.");
return;
}
if (!finalSQL.empty()) {
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
std::unique_ptr<sql::Statement> simpleStatement(Database::CreateStmt());
for (auto& query : migration) {
try {
if (query.empty()) continue;
simpleStatement->execute(query.c_str());
} catch (sql::SQLException& e) {
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
}
}
}
// Do this last on the off chance none of the other migrations have been run yet.
if (runSd0Migrations) {
uint32_t numberOfUpdatedModels = UpdateBrickByBrickModelsToSd0();
Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels);
uint32_t numberOfTruncatedModels = TruncateBrokenBrickByBrickXml();
Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels);
}
}
uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
uint32_t modelsTruncated{};
auto modelsToTruncate = GetModelsFromDatabase();
bool previousCommitValue = Database::GetAutoCommit();
Database::SetAutoCommit(false);
auto modelsToTruncate = GetModelsFromDatabase(database);
bool previousCommitValue = database->GetAutoCommit();
database->SetAutoCommit(false);
while (modelsToTruncate->next()) {
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(Database::CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(database->CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(database->CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
std::string completeUncompressedModel{};
uint32_t chunkCount{};
uint64_t modelId = modelsToTruncate->getInt(1);
@@ -59,14 +117,14 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
completeUncompressedModel.append((char*)uncompressedChunk.get());
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
} else {
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
break;
}
chunkCount++;
}
std::unique_ptr<tinyxml2::XMLDocument> document = std::make_unique<tinyxml2::XMLDocument>();
if (!document) {
LOG("Failed to initialize tinyxml document. Aborting.");
Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting.");
return 0;
}
@@ -75,7 +133,8 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
"</LXFML>",
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
) {
LOG("Brick-by-brick model %llu will be deleted!", modelId);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -84,7 +143,8 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
}
}
} else {
LOG("Brick-by-brick model %llu will be deleted!", modelId);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -93,8 +153,8 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
}
}
Database::Commit();
Database::SetAutoCommit(previousCommitValue);
database->Commit();
database->SetAutoCommit(previousCommitValue);
return modelsTruncated;
}
@@ -104,12 +164,14 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
*
* @return The number of models updated to SD0
*/
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
uint32_t UpdateBrickByBrickModelsToSd0(MySQLDatabase* database) {
uint32_t updatedModels = 0;
auto modelsToUpdate = GetModelsFromDatabase();
auto previousAutoCommitState = Database::GetAutoCommit();
Database::SetAutoCommit(false);
std::unique_ptr<sql::PreparedStatement> insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
auto previousAutoCommitState = database->GetAutoCommit();
database->SetAutoCommit(false);
std::unique_ptr<sql::PreparedStatement> insertionStatement(database->CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
while (modelsToUpdate->next()) {
int64_t modelId = modelsToUpdate->getInt64(1);
std::unique_ptr<sql::Blob> oldLxfml(modelsToUpdate->getBlob(2));
@@ -138,21 +200,24 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
insertionStatement->setInt64(2, modelId);
try {
insertionStatement->executeUpdate();
LOG("Updated model %i to sd0", modelId);
Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId);
updatedModels++;
} catch (sql::SQLException exception) {
LOG("Failed to update model %i. This model should be inspected manually to see why."
Game::logger->Log(
"BrickByBrickFix",
"Failed to update model %i. This model should be inspected manually to see why."
"The database error is %s", modelId, exception.what());
}
}
}
Database::Commit();
Database::SetAutoCommit(previousAutoCommitState);
database->Commit();
database->SetAutoCommit(previousAutoCommitState);
return updatedModels;
}
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase() {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase(MySQLDatabase* database) {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(database->CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
return std::unique_ptr<sql::ResultSet>(modelsRawDataQuery->executeQuery());
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "MigrationManager.h"
class MySQLMigrationManager : public MigrationManager {
public:
void RunMigrations(DatabaseBase* db) override;
void RunSQLiteMigrations() override;
private:
};

View File

@@ -0,0 +1,651 @@
#include "MySQL.h"
#pragma warning (disable:4251)
#include "Game.h"
#include "dConfig.h"
#include "dLogger.h"
MySQLDatabase::MySQLDatabase(const std::string& host, const std::string& database, const std::string& username, const std::string& password) {
this->m_Host = host;
this->m_Database = database;
this->m_Username = username;
this->m_Password = password;
m_Driver = sql::mariadb::get_driver_instance();
sql::Properties properties;
// The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where
// 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the
// presence of a /
// 2) even avoiding that, the connector still assumes you're connecting with a tcp socket
// So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost,
// which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate
// property manually (which the URL parsing fails to do)
const std::string UNIX_PROTO = "unix://";
const std::string PIPE_PROTO = "pipe://";
if (this->m_Host.find(UNIX_PROTO) == 0) {
properties["hostName"] = "unix://localhost";
properties["localSocket"] = this->m_Host.substr(UNIX_PROTO.length()).c_str();
} else if (this->m_Host.find(PIPE_PROTO) == 0) {
properties["hostName"] = "pipe://localhost";
properties["pipe"] = this->m_Host.substr(PIPE_PROTO.length()).c_str();
} else {
properties["hostName"] = this->m_Host.c_str();
}
properties["user"] = this->m_Username.c_str();
properties["password"] = this->m_Password.c_str();
properties["autoReconnect"] = "true";
this->m_Properties = properties;
this->m_Database = database;
}
MySQLDatabase::~MySQLDatabase() {
this->Destroy();
}
void MySQLDatabase::Connect() {
if (this->m_Properties.find("localSocket") != this->m_Properties.end() || this->m_Properties.find("pipe") != this->m_Properties.end()) {
this->m_Connection = m_Driver->connect(this->m_Properties);
} else {
this->m_Connection = m_Driver->connect(
this->m_Properties["hostName"].c_str(),
this->m_Properties["user"].c_str(),
this->m_Properties["password"].c_str()
);
}
this->m_Connection->setSchema(this->m_Database.c_str());
}
void MySQLDatabase::Destroy() {
if (this->m_Connection != nullptr) {
this->m_Connection->close();
delete this->m_Connection;
this->m_Connection = nullptr;
}
}
sql::Statement* MySQLDatabase::CreateStmt() {
sql::Statement* toReturn = this->m_Connection->createStatement();
return toReturn;
}
sql::PreparedStatement* MySQLDatabase::CreatePreppedStmt(const std::string& query) {
const char* test = query.c_str();
size_t size = query.length();
sql::SQLString str(test, size);
if (!this->m_Connection) {
Connect();
Game::logger->Log("Database", "Trying to reconnect to MySQL");
}
if (!this->m_Connection->isValid() || this->m_Connection->isClosed()) {
delete this->m_Connection;
this->m_Connection = nullptr;
Connect();
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection");
}
auto* stmt = this->m_Connection->prepareStatement(str);
return stmt;
}
std::unique_ptr<sql::PreparedStatement> MySQLDatabase::CreatePreppedStmtUnique(const std::string& query) {
std::unique_ptr<sql::PreparedStatement> stmt(CreatePreppedStmt(query));
return stmt;
}
std::unique_ptr<sql::ResultSet> MySQLDatabase::GetResultsOfStatement(sql::Statement* stmt) {
auto* res = stmt->executeQuery();
std::unique_ptr<sql::ResultSet> result(res);
return result;
}
void MySQLDatabase::Commit() {
this->m_Connection->commit();
}
bool MySQLDatabase::GetAutoCommit() {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
return m_Connection->getAutoCommit();
}
void MySQLDatabase::SetAutoCommit(bool value) {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
m_Connection->setAutoCommit(value);
}
SocketDescriptor MySQLDatabase::GetMasterServerIP() {
auto stmt = CreatePreppedStmtUnique("SELECT ip, port FROM servers WHERE name = 'master';");
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return SocketDescriptor(res->getInt("port"), res->getString("ip"));
}
return SocketDescriptor(0, "");
}
void MySQLDatabase::CreateServer(const std::string& name, const std::string& ip, uint16_t port, uint32_t state, uint32_t version) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO servers (name, ip, port, state, version) VALUES (?, ?, ?, ?, ?);");
stmt->setString(1, name);
stmt->setString(2, ip);
stmt->setInt(3, port);
stmt->setInt(4, state);
stmt->setInt(5, version);
stmt->execute();
}
void MySQLDatabase::SetServerIpAndPortByName(const std::string& name, const std::string& ip, uint16_t port) {
auto stmt = CreatePreppedStmtUnique("UPDATE servers SET ip = ?, port = ? WHERE name = ?;");
stmt->setString(1, ip);
stmt->setInt(2, port);
stmt->setString(3, name);
stmt->execute();
}
std::vector<std::string> MySQLDatabase::GetAllCharacterNames() {
auto stmt = CreatePreppedStmtUnique("SELECT name FROM charinfo;");
auto res = GetResultsOfStatement(stmt.get());
std::vector<std::string> names;
while (res->next()) {
names.push_back(res->getString("name").c_str());
}
return names;
}
bool MySQLDatabase::IsCharacterNameAvailable(const std::string& name) {
auto stmt = CreatePreppedStmtUnique("SELECT name FROM charinfo WHERE name = ? OR pending_name = ?;");
stmt->setString(1, name);
stmt->setString(2, name);
auto res = GetResultsOfStatement(stmt.get());
return !res->next();
}
void MySQLDatabase::InsertIntoActivityLog(uint32_t playerId, uint32_t activityId, uint32_t timestamp, uint32_t zoneId) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
stmt->setUInt(1, playerId);
stmt->setUInt(2, activityId);
stmt->setUInt(3, timestamp);
stmt->setUInt(4, zoneId);
stmt->executeUpdate();
}
void MySQLDatabase::InsertIntoCommandLog(uint32_t playerId, const std::string& command) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO command_log (character_id, command) VALUES (?, ?);");
stmt->setUInt(1, playerId);
stmt->setString(2, command);
stmt->executeUpdate();
}
CharacterInfo MySQLDatabase::GetCharacterInfoByID(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT account_id, name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id = ? LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
CharacterInfo info{};
info.AccountID = res->getUInt("account_id");
info.ID = id;
info.Name = res->getString("name");
info.PendingName = res->getString("pending_name");
info.NameRejected = res->getBoolean("needs_rename");
info.PropertyCloneID = res->getUInt("prop_clone_id");
info.PermissionMap = (ePermissionMap)res->getUInt("permission_map");
return info;
}
return CharacterInfo{};
}
CharacterInfo MySQLDatabase::GetCharacterInfoByName(const std::string& name) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE name = ?");
stmt->setString(1, name);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return GetCharacterInfoByID(res->getUInt("id"));
}
return CharacterInfo{};
}
uint32_t MySQLDatabase::GetLatestCharacterOfAccount(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE account_id = ? ORDER BY last_login DESC LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getUInt("id");
}
return 0;
}
std::string MySQLDatabase::GetCharacterXMLByID(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT xml_data FROM charxml WHERE id = ? LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getString("xml_data").c_str();
}
return "";
}
void MySQLDatabase::CreateCharacterXML(uint32_t id, const std::string& xml) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO charxml (id, xml_data) VALUES (?, ?);");
stmt->setUInt(1, id);
stmt->setString(2, xml);
stmt->executeUpdate();
}
void MySQLDatabase::UpdateCharacterXML(uint32_t id, const std::string& xml) {
auto stmt = CreatePreppedStmtUnique("UPDATE charxml SET xml_data = ? WHERE id = ?;");
stmt->setString(1, xml);
stmt->setUInt(2, id);
stmt->executeUpdate();
}
void MySQLDatabase::CreateCharacter(uint32_t id, uint32_t account_id, const std::string& name, const std::string& pending_name, bool needs_rename, uint64_t last_login) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO charinfo (id, account_id, name, pending_name, needs_rename, last_login) VALUES (?, ?, ?, ?, ?, ?);");
stmt->setUInt(1, id);
stmt->setUInt(2, account_id);
stmt->setString(3, name);
stmt->setString(4, pending_name);
stmt->setBoolean(5, needs_rename);
stmt->setUInt64(6, last_login);
stmt->execute();
}
void MySQLDatabase::ApproveCharacterName(uint32_t id, const std::string& newName) {
auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET name = ?, pending_name = '', needs_rename = 0, last_login = ? WHERE id = ? LIMIT 1");
stmt->setString(1, newName);
stmt->setUInt64(2, time(NULL));
stmt->setUInt(3, id);
stmt->execute();
}
void MySQLDatabase::SetPendingCharacterName(uint32_t id, const std::string& pendingName) {
auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET pending_name=?, needs_rename=0, last_login=? WHERE id=? LIMIT 1;");
stmt->setString(1, pendingName);
stmt->setUInt64(2, time(NULL));
stmt->setUInt(3, id);
stmt->execute();
}
void MySQLDatabase::UpdateCharacterLastLogin(uint32_t id, uint64_t time) {
auto stmt = CreatePreppedStmtUnique("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1;");
stmt->setUInt64(1, time);
stmt->setUInt(2, id);
stmt->execute();
}
void MySQLDatabase::DeleteCharacter(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("DELETE FROM charxml WHERE id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM command_log WHERE character_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM friends WHERE player_id = ? OR friend_id = ?;");
stmt->setUInt(1, id);
stmt->setUInt(2, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM leaderboard WHERE character_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM properties_contents WHERE property_id IN (SELECT id FROM properties WHERE owner_id = ?)");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM properties WHERE owner_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM ugc WHERE character_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM activity_log WHERE character_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM mail WHERE receiver_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
stmt = CreatePreppedStmtUnique("DELETE FROM charinfo WHERE id = ?;");
stmt->setUInt(1, id);
stmt->execute();
}
AccountInfo MySQLDatabase::GetAccountByName(const std::string& name) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM accounts WHERE name = ? LIMIT 1;");
stmt->setString(1, name);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return GetAccountByID(res->getUInt("id"));
}
return AccountInfo{};
}
bool MySQLDatabase::AreBestFriends(uint32_t goon1, uint32_t goon2) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;");
stmt->setUInt(1, goon1);
stmt->setUInt(2, goon2);
stmt->setUInt(3, goon2);
stmt->setUInt(4, goon1);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getInt("best_friend") == 3;
}
return false;
}
AccountInfo MySQLDatabase::GetAccountByID(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT name, password, gm_level, locked, banned, play_key_id, created_at, mute_expire FROM accounts WHERE id = ? LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
AccountInfo info{};
info.ID = id;
info.Name = res->getString("name");
info.Password = res->getString("password");
info.MaxGMLevel = res->getUInt("gm_level");
info.Locked = res->getBoolean("locked");
info.Banned = res->getBoolean("banned");
info.PlayKeyID = res->getUInt("play_key_id");
info.CreatedAt = res->getUInt64("created_at");
info.MuteExpire = res->getUInt64("mute_expire");
return info;
}
return AccountInfo{};
}
void MySQLDatabase::BanAccount(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE accounts SET banned = 1 WHERE id = ?;");
stmt->setUInt(1, id);
stmt->execute();
}
void MySQLDatabase::MuteAccount(uint32_t id, uint64_t muteExpireDate) {
auto stmt = CreatePreppedStmtUnique("UPDATE accounts SET mute_expire = ? WHERE id = ?;");
stmt->setUInt64(1, muteExpireDate);
stmt->setUInt(2, id);
stmt->execute();
}
std::vector<CharacterInfo> MySQLDatabase::GetAllCharactersByAccountID(uint32_t accountId) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE account_id = ? LIMIT 4;");
stmt->setUInt(1, accountId);
auto res = GetResultsOfStatement(stmt.get());
std::vector<CharacterInfo> characters;
while (res->next()) {
characters.push_back(GetCharacterInfoByID(res->getUInt("id")));
}
return characters;
}
void MySQLDatabase::CreatePetName(uint64_t id, const std::string& name, bool approved) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO pet_names (id, name, approved) VALUES (?, ?, ?);");
stmt->setUInt64(1, id);
stmt->setString(2, name);
stmt->setBoolean(3, approved);
stmt->execute();
}
void MySQLDatabase::DeletePetName(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("DELETE FROM pet_names WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
PetName MySQLDatabase::GetPetName(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT name, approved FROM pet_names WHERE id = ? LIMIT 1;");
stmt->setUInt64(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
PetName name{};
name.ID = id;
name.Name = res->getString("name");
name.Approved = res->getBoolean("approved");
return name;
}
return PetName{};
}
bool MySQLDatabase::IsKeyActive(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM play_keys WHERE id = ? AND active = 1 LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return true;
}
return false;
}
uint32_t MySQLDatabase::GetObjectIDTracker() {
auto stmt = CreatePreppedStmtUnique("SELECT last_object_id FROM object_id_tracker;");
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
uint32_t id = res->getUInt("last_object_id");
return id;
}
auto stmt = CreatePreppedStmtUnique("INSERT INTO object_id_tracker (last_object_id) VALUES (1);");
stmt->execute();
return 1;
}
void MySQLDatabase::SetObjectIDTracker(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE object_id_tracker SET last_object_id = ?;");
stmt->setUInt(1, id);
stmt->execute();
}
MailInfo MySQLDatabase::GetMailByID(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM mail WHERE id = ?;");
stmt->setUInt64(1, id);
auto res = GetResultsOfStatement(stmt.get());
if (res->next()) {
MailInfo mail{};
mail.ID = id;
mail.SenderID = res->getUInt("sender_id");
mail.SenderName = res->getString("sender_name");
mail.ReceiverID = res->getUInt("receiver_id");
mail.ReceiverName = res->getString("receiver_name");
mail.TimeSent = res->getUInt64("time_sent");
mail.Subject = res->getString("subject");
mail.Body = res->getString("body");
mail.AttachmentID = res->getUInt("attachment_id");
mail.AttachmentLOT = res->getUInt("attachment_lot");
mail.AttachmentSubkey = res->getUInt64("attachment_subkey");
mail.AttachmentCount = res->getUInt("attachment_count");
mail.WasRead = res->getBoolean("was_read");
return mail;
}
return MailInfo{};
}
std::vector<MailInfo> MySQLDatabase::GetAllRecentMailOfUser(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM mail WHERE receiver_id = ? LIMIT 20;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
std::vector<MailInfo> mail;
while (res->next()) {
MailInfo mailInfo{};
mailInfo.ID = res->getUInt64("id");
mailInfo.SenderID = res->getUInt("sender_id");
mailInfo.SenderName = res->getString("sender_name");
mailInfo.ReceiverID = res->getUInt("receiver_id");
mailInfo.ReceiverName = res->getString("receiver_name");
mailInfo.TimeSent = res->getUInt64("time_sent");
mailInfo.Subject = res->getString("subject");
mailInfo.Body = res->getString("body");
mailInfo.AttachmentID = res->getUInt("attachment_id");
mailInfo.AttachmentLOT = res->getUInt("attachment_lot");
mailInfo.AttachmentSubkey = res->getUInt64("attachment_subkey");
mailInfo.AttachmentCount = res->getUInt("attachment_count");
mailInfo.WasRead = res->getBoolean("was_read");
mail.push_back(mailInfo);
}
return mail;
}
uint32_t MySQLDatabase::GetUnreadMailCountForUser(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT COUNT(*) FROM mail WHERE receiver_id = ? AND was_read = 0;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getUInt(1);
}
return 0;
}
void MySQLDatabase::WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId, uint32_t attachmentLot, uint64_t attachmentSubkey, uint32_t attachmentCount, bool wasRead) {
auto stmt = CreatePreppedStmtUnique("INSERT INTO mail (sender_id, sender_name, receiver_id, receiver_name, time_sent, subject, body, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
stmt->setUInt(1, senderId);
stmt->setString(2, senderName);
stmt->setUInt(3, receiverId);
stmt->setString(4, receiverName);
stmt->setUInt64(5, sendTime);
stmt->setString(6, subject);
stmt->setString(7, body);
stmt->setUInt(8, attachmentId);
stmt->setUInt(9, attachmentLot);
stmt->setUInt64(10, attachmentSubkey);
stmt->setUInt(11, attachmentCount);
stmt->setBoolean(12, wasRead);
stmt->execute();
}
void MySQLDatabase::DeleteMail(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("DELETE FROM mail WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
void MySQLDatabase::SetMailAsRead(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE mail SET was_read = 1 WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
void MySQLDatabase::RemoveAttachmentFromMail(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE mail SET attachment_lot = 0 WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
uint64_t MySQLDatabase::GetPropertyFromTemplateAndClone(uint32_t templateId, uint32_t cloneId) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM properties WHERE template_id = ? AND clone_id = ? LIMIT 1;");
stmt->setUInt(1, templateId);
stmt->setUInt(2, cloneId);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getUInt64("id");
}
return 0;
}
std::vector<uint32_t> MySQLDatabase::GetBBBModlesForProperty(uint32_t propertyId) {
auto stmt = CreatePreppedStmtUnique("SELECT ugc_id FROM properties_contents WHERE lot = 14 AND property_id = ?;");
stmt->setUInt(1, propertyId);
auto res = GetResultsOfStatement(stmt.get());
std::vector<uint32_t> models;
while (res->next()) {
models.push_back(res->getUInt("ugc_id"));
}
return models;
}
std::istream* MySQLDatabase::GetLXFMLFromID(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT lxfml FROM ugc WHERE id = ? LIMIT 1;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
std::istream* blob = res->getBlob("lxfml");
return blob;
}
return new std::istream();
}

View File

@@ -0,0 +1,99 @@
#pragma once
#include "DatabaseBase.h"
#include <string>
#include <conncpp.hpp>
class MySqlException : public std::runtime_error {
public:
MySqlException() : std::runtime_error("MySQL error!") {}
MySqlException(const std::string& msg) : std::runtime_error(msg.c_str()) {}
};
class MySQLDatabase : public DatabaseBase {
public:
MySQLDatabase(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
~MySQLDatabase();
void Connect() override;
void Destroy() override;
sql::Statement* CreateStmt();
sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
std::unique_ptr<sql::PreparedStatement> CreatePreppedStmtUnique(const std::string& query);
std::unique_ptr<sql::ResultSet> GetResultsOfStatement(sql::Statement* stmt);
void Commit();
bool GetAutoCommit();
void SetAutoCommit(bool value);
SocketDescriptor GetMasterServerIP() override;
void CreateServer(const std::string& name, const std::string& ip, uint16_t port, uint32_t state, uint32_t version) override;
void SetServerIpAndPortByName(const std::string& name, const std::string& ip, uint16_t port) override;
void InsertIntoActivityLog(uint32_t playerId, uint32_t activityId, uint32_t timestamp, uint32_t zoneId) override;
void InsertIntoCommandLog(uint32_t playerId, const std::string& command) override;
CharacterInfo GetCharacterInfoByID(uint32_t id) override;
CharacterInfo GetCharacterInfoByName(const std::string& name) override;
std::string GetCharacterXMLByID(uint32_t id) override;
std::vector<std::string> GetAllCharacterNames() override;
std::vector<CharacterInfo> GetAllCharactersByAccountID(uint32_t accountId) override;
bool IsCharacterNameAvailable(const std::string& name) override;
void CreateCharacterXML(uint32_t id, const std::string& xml) override;
void UpdateCharacterXML(uint32_t id, const std::string& xml) override;
void CreateCharacter(uint32_t id, uint32_t account_id, const std::string& name, const std::string& pending_name, bool needs_rename, uint64_t last_login) override;
void ApproveCharacterName(uint32_t id, const std::string& newName) override;
void SetPendingCharacterName(uint32_t id, const std::string& pendingName) override;
void UpdateCharacterLastLogin(uint32_t id, uint64_t time) override;
void DeleteCharacter(uint32_t id) override;
bool AreBestFriends(uint32_t charId1, uint32_t charId2) override;
AccountInfo GetAccountByName(const std::string& name) override;
AccountInfo GetAccountByID(uint32_t id) override;
uint32_t GetLatestCharacterOfAccount(uint32_t id) override;
void BanAccount(uint32_t id) override;
void MuteAccount(uint32_t id, uint64_t muteExpireDate) override;
void CreatePetName(uint64_t id, const std::string& name, bool approved) override;
void DeletePetName(uint64_t id) override;
PetName GetPetName(uint64_t id) override;
bool IsKeyActive(uint32_t id) override;
uint32_t GetObjectIDTracker() override;
void SetObjectIDTracker(uint32_t id) override;
MailInfo GetMailByID(uint64_t id) override;
std::vector<MailInfo> GetAllRecentMailOfUser(uint32_t id) override;
uint32_t GetUnreadMailCountForUser(uint32_t id) override;
void WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId = 0, uint32_t attachmentLot = 0, uint64_t attachmentSubkey = 0, uint32_t attachmentCount = 0, bool wasRead = false) override;
void SetMailAsRead(uint64_t id) override;
void RemoveAttachmentFromMail(uint64_t id) override;
void DeleteMail(uint64_t id) override;
uint64_t GetPropertyFromTemplateAndClone(uint32_t templateId, uint32_t cloneId) override;
std::vector<uint32_t> GetBBBModlesForProperty(uint32_t propertyId) override;
std::istream GetLXFMLFromID(uint32_t id) override;
private:
std::string m_Host;
std::string m_Database;
std::string m_Username;
std::string m_Password;
sql::Connection* m_Connection;
sql::Driver* m_Driver;
sql::Properties m_Properties;
};

View File

@@ -0,0 +1,49 @@
#pragma once
#include <string>
#include "ePermissionMap.h"
struct CharacterInfo {
uint32_t AccountID;
uint32_t ID;
std::string Name;
std::string PendingName;
bool NameRejected;
uint32_t PropertyCloneID;
ePermissionMap PermissionMap;
};
struct AccountInfo {
uint32_t ID;
std::string Name;
std::string Password;
uint32_t MaxGMLevel;
bool Locked;
bool Banned;
uint32_t PlayKeyID;
uint64_t CreatedAt;
uint64_t MuteExpire;
};
struct PetName {
uint64_t ID;
std::string Name;
bool Approved;
};
struct MailInfo {
uint64_t ID;
uint32_t SenderID;
std::string SenderName;
uint32_t ReceiverID;
std::string ReceiverName;
uint64_t TimeSent;
std::string Subject;
std::string Body;
uint32_t AttachmentID;
uint32_t AttachmentLOT;
uint64_t AttachmentSubkey;
uint32_t AttachmentCount;
bool WasRead;
};

View File

@@ -1,158 +0,0 @@
#include "MigrationRunner.h"
#include "BrickByBrickFix.h"
#include "CDClientDatabase.h"
#include "Database.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "BinaryPathFinder.h"
#include <fstream>
Migration LoadMigration(std::string path) {
Migration migration{};
std::ifstream file(BinaryPathFinder::GetBinaryDir() / "migrations/" / path);
if (file.is_open()) {
std::string line;
std::string total = "";
while (std::getline(file, line)) {
total += line;
}
file.close();
migration.name = path;
migration.data = total;
}
return migration;
}
void MigrationRunner::RunMigrations() {
auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
stmt->execute();
delete stmt;
sql::SQLString finalSQL = "";
bool runSd0Migrations = false;
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) {
auto migration = LoadMigration("dlu/" + entry);
if (migration.data.empty()) {
continue;
}
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
bool doExit = res->next();
delete res;
delete stmt;
if (doExit) continue;
LOG("Running migration: %s", migration.name.c_str());
if (migration.name == "dlu/5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
finalSQL.append(migration.data.c_str());
}
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
stmt->setString(1, migration.name.c_str());
stmt->execute();
delete stmt;
}
if (finalSQL.empty() && !runSd0Migrations) {
LOG("Server database is up to date.");
return;
}
if (!finalSQL.empty()) {
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
std::unique_ptr<sql::Statement> simpleStatement(Database::CreateStmt());
for (auto& query : migration) {
try {
if (query.empty()) continue;
simpleStatement->execute(query.c_str());
} catch (sql::SQLException& e) {
LOG("Encountered error running migration: %s", e.what());
}
}
}
// Do this last on the off chance none of the other migrations have been run yet.
if (runSd0Migrations) {
uint32_t numberOfUpdatedModels = BrickByBrickFix::UpdateBrickByBrickModelsToSd0();
LOG("%i models were updated from zlib to sd0.", numberOfUpdatedModels);
uint32_t numberOfTruncatedModels = BrickByBrickFix::TruncateBrokenBrickByBrickXml();
LOG("%i models were truncated from the database.", numberOfTruncatedModels);
}
}
void MigrationRunner::RunSQLiteMigrations() {
auto cdstmt = CDClientDatabase::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);");
cdstmt.execQuery().finalize();
cdstmt.finalize();
auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
stmt->execute();
delete stmt;
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) {
auto migration = LoadMigration("cdserver/" + entry);
if (migration.data.empty()) continue;
// Check if there is an entry in the migration history table on the cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
cdstmt.bind((int32_t) 1, migration.name.c_str());
auto cdres = cdstmt.execQuery();
bool doExit = !cdres.eof();
cdres.finalize();
cdstmt.finalize();
if (doExit) continue;
// Check first if there is entry in the migration history table on the main database.
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
doExit = res->next();
delete res;
delete stmt;
if (doExit) {
// Insert into cdclient database if there is an entry in the main database but not the cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
cdstmt.bind((int32_t) 1, migration.name.c_str());
cdstmt.execQuery().finalize();
cdstmt.finalize();
continue;
}
// Doing these 1 migration at a time since one takes a long time and some may think it is crashing.
// This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated".
LOG("Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str());
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) {
if (dml.empty()) continue;
try {
CDClientDatabase::ExecuteDML(dml.c_str());
} catch (CppSQLite3Exception& e) {
LOG("Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage());
}
}
// Insert into cdclient database.
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
cdstmt.bind((int32_t) 1, migration.name.c_str());
cdstmt.execQuery().finalize();
cdstmt.finalize();
CDClientDatabase::ExecuteQuery("COMMIT;");
}
LOG("CDServer database is up to date.");
}

View File

@@ -1,13 +0,0 @@
#pragma once
#include <string>
struct Migration {
std::string data;
std::string name;
};
namespace MigrationRunner {
void RunMigrations();
void RunSQLiteMigrations();
};

View File

@@ -1,32 +1,4 @@
#include "CDLootTableTable.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
#include "CDItemComponentTable.h"
#include "eReplicaComponentType.h"
// Sort the tables by their rarity so the highest rarity items are first.
void SortTable(LootTableEntries& table) {
auto* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
// We modify the table in place so the outer loop keeps track of what is sorted
// and the inner loop finds the highest rarity item and swaps it with the current position
// of the outer loop.
for (auto oldItrOuter = table.begin(); oldItrOuter != table.end(); oldItrOuter++) {
auto lootToInsert = oldItrOuter;
// Its fine if this starts at 0, even if this doesnt match lootToInsert as the actual highest will
// either be found and overwrite these values, or the original is somehow zero and is still the highest rarity.
uint32_t highestLootRarity = 0;
for (auto oldItrInner = oldItrOuter; oldItrInner != table.end(); oldItrInner++) {
uint32_t itemComponentId = componentsRegistryTable->GetByIDAndType(oldItrInner->itemid, eReplicaComponentType::ITEM);
uint32_t rarity = itemComponentTable->GetItemComponentByID(itemComponentId).rarity;
if (rarity > highestLootRarity) {
highestLootRarity = rarity;
lootToInsert = oldItrInner;
}
}
std::swap(*oldItrOuter, *lootToInsert);
}
}
CDLootTable CDLootTableTable::ReadRow(CppSQLite3Query& tableData) const {
CDLootTable entry{};
@@ -60,9 +32,6 @@ void CDLootTableTable::LoadValuesFromDatabase() {
this->entries[lootTableIndex].push_back(ReadRow(tableData));
tableData.nextRow();
}
for (auto& [id, table] : this->entries) {
SortTable(table);
}
}
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
@@ -80,7 +49,6 @@ const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
this->entries[tableId].push_back(ReadRow(tableData));
tableData.nextRow();
}
SortTable(this->entries[tableId]);
return this->entries[tableId];
}

View File

@@ -2,7 +2,7 @@
#include "User.h"
#include "Database.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "dLogger.h"
#include "BitStream.h"
#include "Game.h"
#include <chrono>
@@ -26,39 +26,16 @@ Character::Character(uint32_t id, User* parentUser) {
//First load the name, etc:
m_ID = id;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the character
auto character = Database::Connection->GetCharacterInfoByID(m_ID);
m_Name = character.Name;
m_UnapprovedName = character.PendingName;
m_NameRejected = character.NameRejected;
m_PropertyCloneID = character.PropertyCloneID;
m_PermissionMap = character.PermissionMap;
stmt->setInt64(1, id);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_Name = res->getString(1).c_str();
m_UnapprovedName = res->getString(2).c_str();
m_NameRejected = res->getBoolean(3);
m_PropertyCloneID = res->getUInt(4);
m_PermissionMap = static_cast<ePermissionMap>(res->getUInt64(5));
}
delete res;
delete stmt;
//Load the xmlData now:
sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt(
"SELECT xml_data FROM charxml WHERE id=? LIMIT 1;"
);
xmlStmt->setInt64(1, id);
sql::ResultSet* xmlRes = xmlStmt->executeQuery();
while (xmlRes->next()) {
m_XMLData = xmlRes->getString(1).c_str();
}
delete xmlRes;
delete xmlStmt;
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
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.
@@ -85,38 +62,16 @@ Character::~Character() {
}
void Character::UpdateFromDatabase() {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the character
auto character = Database::Connection->GetCharacterInfoByID(m_ID);
m_Name = character.Name;
m_UnapprovedName = character.PendingName;
m_NameRejected = character.NameRejected;
m_PropertyCloneID = character.PropertyCloneID;
m_PermissionMap = character.PermissionMap;
stmt->setInt64(1, m_ID);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_Name = res->getString(1).c_str();
m_UnapprovedName = res->getString(2).c_str();
m_NameRejected = res->getBoolean(3);
m_PropertyCloneID = res->getUInt(4);
m_PermissionMap = static_cast<ePermissionMap>(res->getUInt64(5));
}
delete res;
delete stmt;
//Load the xmlData now:
sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt(
"SELECT xml_data FROM charxml WHERE id=? LIMIT 1;"
);
xmlStmt->setInt64(1, m_ID);
sql::ResultSet* xmlRes = xmlStmt->executeQuery();
while (xmlRes->next()) {
m_XMLData = xmlRes->getString(1).c_str();
}
delete xmlRes;
delete xmlStmt;
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
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.
@@ -145,16 +100,16 @@ void Character::DoQuickXMLDataParse() {
if (!m_Doc) return;
if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) {
LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
Game::logger->Log("Character", "Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
} else {
LOG("Failed to load xmlData!");
Game::logger->Log("Character", "Failed to load xmlData!");
//Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true);
return;
}
tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf");
if (!mf) {
LOG("Failed to find mf tag!");
Game::logger->Log("Character", "Failed to find mf tag!");
return;
}
@@ -173,14 +128,14 @@ void Character::DoQuickXMLDataParse() {
tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv");
if (!inv) {
LOG("Char has no inv!");
Game::logger->Log("Character", "Char has no inv!");
return;
}
tinyxml2::XMLElement* bag = inv->FirstChildElement("items")->FirstChildElement("in");
if (!bag) {
LOG("Couldn't find bag0!");
Game::logger->Log("Character", "Couldn't find bag0!");
return;
}
@@ -373,7 +328,7 @@ void Character::SaveXMLToDatabase() {
//Call upon the entity to update our xmlDoc:
if (!m_OurEntity) {
LOG("%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
Game::logger->Log("Character", "%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
return;
}
@@ -384,7 +339,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("%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
Game::logger->Log("Character", "%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
}
void Character::SetIsNewLogin() {
@@ -394,29 +349,23 @@ void Character::SetIsNewLogin() {
auto* currentChild = flags->FirstChildElement();
while (currentChild) {
auto* nextChild = currentChild->NextSiblingElement();
if (currentChild->Attribute("si")) {
flags->DeleteChild(currentChild);
LOG("Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str());
Game::logger->Log("Character", "Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str());
WriteToDatabase();
}
currentChild = nextChild;
currentChild = currentChild->NextSiblingElement();
}
}
void Character::WriteToDatabase() {
//Dump our xml into m_XMLData:
// Dump our xml into m_XMLData:
auto* printer = new tinyxml2::XMLPrinter(0, true, 0);
m_Doc->Print(printer);
m_XMLData = printer->CStr();
//Finally, save to db:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charxml SET xml_data=? WHERE id=?");
stmt->setString(1, m_XMLData.c_str());
stmt->setUInt(2, m_ID);
stmt->execute();
delete stmt;
delete printer;
// Save to DB
Database::Connection->UpdateCharacterXML(m_ID, m_XMLData);
}
void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
@@ -555,6 +504,15 @@ void Character::OnZoneLoad() {
return;
}
/**
* Restrict old character to 1 million coins
*/
if (HasPermission(ePermissionMap::Old)) {
if (GetCoins() > 1000000) {
SetCoins(1000000, eLootSourceType::NONE);
}
}
auto* inventoryComponent = m_OurEntity->GetComponent<InventoryComponent>();
if (inventoryComponent == nullptr) {

View File

@@ -2,7 +2,7 @@
#include "Entity.h"
#include "CDClientManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include <PacketUtils.h>
#include <functional>
#include "CDDestructibleComponentTable.h"
@@ -76,10 +76,6 @@
#include "eGameMasterLevel.h"
#include "eReplicaComponentType.h"
#include "eReplicaPacketType.h"
#include "ZoneControlComponent.h"
#include "RacingStatsComponent.h"
#include "CollectibleComponent.h"
#include "ItemComponent.h"
// Table includes
#include "CDComponentsRegistryTable.h"
@@ -99,6 +95,7 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity)
m_ParentEntity = parentEntity;
m_Character = nullptr;
m_GMLevel = eGameMasterLevel::CIVILIAN;
m_CollectibleID = 0;
m_NetworkID = 0;
m_Groups = {};
m_OwnerOverride = LWOOBJID_EMPTY;
@@ -156,7 +153,7 @@ void Entity::Initialize() {
const auto triggerInfo = GetVarAsString(u"trigger_id");
if (!triggerInfo.empty()) AddComponent<TriggerComponent>(triggerInfo);
if (!triggerInfo.empty()) m_Components.emplace(eReplicaComponentType::TRIGGER, new TriggerComponent(this, triggerInfo));
/**
* Setup groups
@@ -187,17 +184,21 @@ void Entity::Initialize() {
if (m_TemplateID == 14) {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this);
m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp));
AddComponent<ModelComponent>();
ModelComponent* modelcomp = new ModelComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, modelcomp));
AddComponent<RenderComponent>();
RenderComponent* render = new RenderComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
auto* destroyableComponent = AddComponent<DestroyableComponent>();
auto destroyableComponent = new DestroyableComponent(this);
destroyableComponent->SetHealth(1);
destroyableComponent->SetMaxHealth(1.0f);
destroyableComponent->SetFaction(-1, true);
destroyableComponent->SetIsSmashable(true);
m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent));
// We have all our components.
return;
}
@@ -209,46 +210,49 @@ void Entity::Initialize() {
*/
if (GetParentUser()) {
AddComponent<MissionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
auto missions = new MissionComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MISSION, missions));
missions->LoadFromXml(m_Character->GetXMLDoc());
}
uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET);
if (petComponentId > 0) {
AddComponent<PetComponent>(petComponentId);
m_Components.insert(std::make_pair(eReplicaComponentType::PET, new PetComponent(this, petComponentId)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) {
AddComponent<ZoneControlComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::ZONE_CONTROL, nullptr));
}
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
if (possessableComponentId > 0) {
AddComponent<PossessableComponent>(possessableComponentId);
m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSABLE, new PossessableComponent(this, possessableComponentId)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY) > 0) {
AddComponent<ModuleAssemblyComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::MODULE_ASSEMBLY, new ModuleAssemblyComponent(this)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS) > 0) {
AddComponent<RacingStatsComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_STATS, nullptr));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1) >= 0) {
AddComponent<LUPExhibitComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::LUP_EXHIBIT, new LUPExhibitComponent(this)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL) > 0) {
AddComponent<RacingControlComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_CONTROL, new RacingControlComponent(this)));
}
const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_ENTRANCE);
if (propertyEntranceComponentID > 0) {
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY_ENTRANCE,
new PropertyEntranceComponent(propertyEntranceComponentID, this)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) {
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>();
ControllablePhysicsComponent* controllablePhysics = new ControllablePhysicsComponent(this);
if (m_Character) {
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
@@ -281,6 +285,8 @@ void Entity::Initialize() {
controllablePhysics->SetPosition(m_DefaultPosition);
controllablePhysics->SetRotation(m_DefaultRotation);
}
m_Components.insert(std::make_pair(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysics));
}
// If an entity is marked a phantom, simple physics is made into phantom phyics.
@@ -288,56 +294,67 @@ void Entity::Initialize() {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
if (!markedAsPhantom && simplePhysicsComponentID > 0) {
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this);
m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) {
AddComponent<RigidbodyPhantomPhysicsComponent>();
RigidbodyPhantomPhysicsComponent* comp = new RigidbodyPhantomPhysicsComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, comp));
}
if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) {
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
PhantomPhysicsComponent* phantomPhysics = new PhantomPhysicsComponent(this);
phantomPhysics->SetPhysicsEffectActive(false);
m_Components.insert(std::make_pair(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysics));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) {
auto* vehiclePhysicsComponent = AddComponent<VehiclePhysicsComponent>();
VehiclePhysicsComponent* vehiclePhysicsComponent = new VehiclePhysicsComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent));
vehiclePhysicsComponent->SetPosition(m_DefaultPosition);
vehiclePhysicsComponent->SetRotation(m_DefaultRotation);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
AddComponent<SoundTriggerComponent>();
auto* comp = new SoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp));
} else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) {
AddComponent<RacingSoundTriggerComponent>();
auto* comp = new RacingSoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_SOUND_TRIGGER, comp));
}
//Also check for the collectible id:
m_CollectibleID = GetVarAs<int32_t>(u"collectible_id");
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF) > 0) {
AddComponent<BuffComponent>();
BuffComponent* comp = new BuffComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::BUFF, comp));
}
int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE);
if (collectibleComponentID > 0) {
AddComponent<CollectibleComponent>(GetVarAs<int32_t>(u"collectible_id"));
m_Components.insert(std::make_pair(eReplicaComponentType::COLLECTIBLE, nullptr));
}
/**
* Multiple components require the destructible component.
*/
int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF);
int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD);
int componentID = -1;
int componentID = 0;
if (collectibleComponentID > 0) componentID = collectibleComponentID;
if (rebuildComponentID > 0) componentID = rebuildComponentID;
if (buffComponentID > 0) componentID = buffComponentID;
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
bool isSmashable = GetVarAs<int32_t>(u"is_smashable") != 0;
if (buffComponentID > 0 || collectibleComponentID > 0 || isSmashable) {
DestroyableComponent* comp = AddComponent<DestroyableComponent>();
if (buffComponentID > 0 || collectibleComponentID > 0) {
DestroyableComponent* comp = new DestroyableComponent(this);
if (m_Character) {
comp->LoadFromXml(m_Character->GetXMLDoc());
} else {
@@ -356,7 +373,6 @@ void Entity::Initialize() {
comp->SetMaxHealth(destCompData[0].life);
comp->SetMaxImagination(destCompData[0].imagination);
comp->SetMaxArmor(destCompData[0].armor);
comp->SetDeathBehavior(destCompData[0].death_behavior);
comp->SetIsSmashable(destCompData[0].isSmashable);
@@ -377,7 +393,7 @@ void Entity::Initialize() {
}
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
comp->SetIsSmashable(comp->GetIsSmashable() | isSmashable);
comp->SetIsSmashable(comp->GetIsSmashable() | (GetVarAs<int32_t>(u"is_smashable") != 0));
}
} else {
comp->SetHealth(1);
@@ -410,39 +426,35 @@ void Entity::Initialize() {
}
}
// override the factions if needed.
auto setFaction = GetVarAsString(u"set_faction");
if (!setFaction.empty()) {
// TODO also split on space here however we do not have a general util for splitting on multiple characters yet.
std::vector<std::string> factionsToAdd = GeneralUtils::SplitString(setFaction, ';');
int32_t factionToAdd;
for (const auto faction : factionsToAdd) {
if (GeneralUtils::TryParse(faction, factionToAdd)) {
comp->AddFaction(factionToAdd, true);
}
}
}
m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER) > 0 || m_Character) {
// Character Component always has a possessor, level, and forced movement components
AddComponent<PossessorComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSOR, new PossessorComponent(this)));
// load in the xml for the level
AddComponent<LevelProgressionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
auto* levelComp = new LevelProgressionComponent(this);
levelComp->LoadFromXml(m_Character->GetXMLDoc());
m_Components.insert(std::make_pair(eReplicaComponentType::LEVEL_PROGRESSION, levelComp));
AddComponent<PlayerForcedMovementComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, new PlayerForcedMovementComponent(this)));
AddComponent<CharacterComponent>(m_Character)->LoadFromXml(m_Character->GetXMLDoc());
CharacterComponent* charComp = new CharacterComponent(this, m_Character);
charComp->LoadFromXml(m_Character->GetXMLDoc());
m_Components.insert(std::make_pair(eReplicaComponentType::CHARACTER, charComp));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) {
auto* xmlDoc = m_Character ? m_Character->GetXMLDoc() : nullptr;
AddComponent<InventoryComponent>(xmlDoc);
InventoryComponent* comp = nullptr;
if (m_Character) comp = new InventoryComponent(this, m_Character->GetXMLDoc());
else comp = new InventoryComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::INVENTORY, comp));
}
// if this component exists, then we initialize it. it's value is always 0
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) {
AddComponent<MultiZoneEntranceComponent>();
auto comp = new MultiZoneEntranceComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MULTI_ZONE_ENTRANCE, comp));
}
/**
@@ -493,7 +505,7 @@ void Entity::Initialize() {
}
if (!scriptName.empty() || client || m_Character || scriptComponentID >= 0) {
AddComponent<ScriptComponent>(scriptName, true, client && scriptName.empty());
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty())));
}
// ZoneControl script
@@ -505,137 +517,148 @@ void Entity::Initialize() {
if (zoneData != nullptr) {
int zoneScriptID = zoneData->scriptID;
CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID);
AddComponent<ScriptComponent>(zoneScriptData.script_name, true);
ScriptComponent* comp = new ScriptComponent(this, zoneScriptData.script_name, true);
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp));
}
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1) != -1 || m_Character) {
AddComponent<SkillComponent>();
SkillComponent* comp = new SkillComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SKILL, comp));
}
const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI);
if (combatAiId > 0) {
AddComponent<BaseCombatAIComponent>(combatAiId);
BaseCombatAIComponent* comp = new BaseCombatAIComponent(this, combatAiId);
m_Components.insert(std::make_pair(eReplicaComponentType::BASE_COMBAT_AI, comp));
}
if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) {
auto* rebuildComponent = AddComponent<RebuildComponent>();
RebuildComponent* comp = new RebuildComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::QUICK_BUILD, comp));
CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable<CDRebuildComponentTable>();
std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); });
if (rebCompData.size() > 0) {
rebuildComponent->SetResetTime(rebCompData[0].reset_time);
rebuildComponent->SetCompleteTime(rebCompData[0].complete_time);
rebuildComponent->SetTakeImagination(rebCompData[0].take_imagination);
rebuildComponent->SetInterruptible(rebCompData[0].interruptible);
rebuildComponent->SetSelfActivator(rebCompData[0].self_activator);
rebuildComponent->SetActivityId(rebCompData[0].activityID);
rebuildComponent->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
rebuildComponent->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
comp->SetResetTime(rebCompData[0].reset_time);
comp->SetCompleteTime(rebCompData[0].complete_time);
comp->SetTakeImagination(rebCompData[0].take_imagination);
comp->SetInterruptible(rebCompData[0].interruptible);
comp->SetSelfActivator(rebCompData[0].self_activator);
comp->SetActivityId(rebCompData[0].activityID);
comp->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
const auto rebuildResetTime = GetVar<float>(u"rebuild_reset_time");
if (rebuildResetTime != 0.0f) {
rebuildComponent->SetResetTime(rebuildResetTime);
comp->SetResetTime(rebuildResetTime);
// Known bug with moving platform in FV that casues it to build at the end instead of the start.
// This extends the smash time so players can ride up the lift.
if (m_TemplateID == 9483)
if (m_TemplateID == 9483) // Look away!
{
rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 25);
comp->SetResetTime(comp->GetResetTime() + 25);
}
}
const auto activityID = GetVar<int32_t>(u"activityID");
if (activityID > 0) {
rebuildComponent->SetActivityId(activityID);
comp->SetActivityId(activityID);
Loot::CacheMatrix(activityID);
}
const auto compTime = GetVar<float>(u"compTime");
if (compTime > 0) {
rebuildComponent->SetCompleteTime(compTime);
comp->SetCompleteTime(compTime);
}
}
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1) != -1) {
AddComponent<SwitchComponent>();
SwitchComponent* comp = new SwitchComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SWITCH, comp));
}
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) {
AddComponent<VendorComponent>();
VendorComponent* comp = new VendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp));
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
AddComponent<DonationVendorComponent>();
DonationVendorComponent* comp = new DonationVendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::DONATION_VENDOR, comp));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
AddComponent<PropertyVendorComponent>();
auto* component = new PropertyVendorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_VENDOR, component);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1) != -1) {
AddComponent<PropertyManagementComponent>();
auto* component = new PropertyManagementComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_MANAGEMENT, component);
}
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>();
BouncerComponent* comp = new BouncerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp));
}
int32_t renderComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
if ((renderComponentId > 0 && m_TemplateID != 2365) || m_Character) {
AddComponent<RenderComponent>(renderComponentId);
RenderComponent* render = new RenderComponent(this, renderComponentId);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
}
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER) > 0) || m_Character) {
AddComponent<MissionOfferComponent>(m_TemplateID);
m_Components.insert(std::make_pair(eReplicaComponentType::MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1) != -1) {
AddComponent<BuildBorderComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::BUILD_BORDER, new BuildBorderComponent(this)));
}
// Scripted activity component
int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY);
if ((scriptedActivityID > 0)) {
AddComponent<ScriptedActivityComponent>(scriptedActivityID);
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
AddComponent<ModelComponent>();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
auto* destroyableComponent = AddComponent<DestroyableComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, new ModelComponent(this)));
if (m_Components.find(eReplicaComponentType::DESTROYABLE) == m_Components.end()) {
auto destroyableComponent = new DestroyableComponent(this);
destroyableComponent->SetHealth(1);
destroyableComponent->SetMaxHealth(1.0f);
destroyableComponent->SetFaction(-1, true);
destroyableComponent->SetIsSmashable(true);
m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent));
}
}
PetComponent* petComponent;
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) {
AddComponent<ItemComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::ITEM, nullptr));
}
// Shooting gallery component
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) {
AddComponent<ShootingGalleryComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::SHOOTING_GALLERY, new ShootingGalleryComponent(this)));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) {
AddComponent<PropertyComponent>();
m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY, new PropertyComponent(this)));
}
const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH);
if ((rocketId > 0)) {
AddComponent<RocketLaunchpadControlComponent>(rocketId);
m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId)));
}
const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR);
if (railComponentID > 0) {
AddComponent<RailActivatorComponent>(railComponentID);
m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID)));
}
int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI);
@@ -663,7 +686,7 @@ void Entity::Initialize() {
}
}
AddComponent<MovementAIComponent>(moveInfo);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
}
} else if (petComponentId > 0 || combatAiId > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) {
MovementAIInfo moveInfo = MovementAIInfo();
@@ -674,18 +697,19 @@ void Entity::Initialize() {
moveInfo.wanderDelayMax = 5;
moveInfo.wanderDelayMin = 2;
AddComponent<MovementAIComponent>(moveInfo);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
}
std::string pathName = GetVarAsString(u"attached_path");
const Path* path = Game::zoneManager->GetZone()->GetPath(pathName);
//Check to see if we have an attached path and add the appropiate component to handle it:
if (path) {
if (path){
// if we have a moving platform path, then we need a moving platform component
if (path->pathType == PathType::MovingPlatform) {
AddComponent<MovingPlatformComponent>(pathName);
// else if we are a movement path
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
// else if we are a movement path
} /*else if (path->pathType == PathType::Movement) {
auto movementAIcomp = GetComponent<MovementAIComponent>();
if (movementAIcomp){
@@ -698,7 +722,8 @@ void Entity::Initialize() {
// else we still need to setup moving platform if it has a moving platform comp but no path
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
if (movingPlatformComponentId >= 0) {
AddComponent<MovingPlatformComponent>(pathName);
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
}
}
@@ -708,7 +733,8 @@ void Entity::Initialize() {
std::vector<CDProximityMonitorComponent> proxCompData = proxCompTable->Query([=](CDProximityMonitorComponent entry) { return (entry.id == proximityMonitorID); });
if (proxCompData.size() > 0) {
std::vector<std::string> proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ',');
AddComponent<ProximityMonitorComponent>(std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp));
}
}
@@ -799,6 +825,14 @@ bool Entity::HasComponent(const eReplicaComponentType componentId) const {
return m_Components.find(componentId) != m_Components.end();
}
void Entity::AddComponent(const eReplicaComponentType componentId, Component* component) {
if (HasComponent(componentId)) {
return;
}
m_Components.insert_or_assign(componentId, component);
}
std::vector<ScriptComponent*> Entity::GetScriptComponents() {
std::vector<ScriptComponent*> comps;
for (std::pair<eReplicaComponentType, void*> p : m_Components) {
@@ -827,13 +861,20 @@ 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>();
ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) {
proxMon = new ProximityMonitorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon);
}
proxMon->SetProximityRadius(proxRadius, name);
}
void Entity::SetProximityRadius(dpEntity* entity, std::string name) {
ProximityMonitorComponent* proxMon = AddComponent<ProximityMonitorComponent>();
ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) {
proxMon = new ProximityMonitorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon);
}
proxMon->SetProximityRadius(entity, name);
}
@@ -883,20 +924,10 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke
outBitStream->Write1(); //ldf data
RakNet::BitStream settingStream;
int32_t numberOfValidKeys = m_Settings.size();
// Writing keys value pairs the client does not expect to receive or interpret will result in undefined behavior,
// so we need to filter out any keys that are not valid and fix the number of valid keys to be correct.
// TODO should make this more efficient so that we dont waste loops evaluating the same condition twice
for (LDFBaseData* data : m_Settings) {
if (!data || data->GetValueType() == eLDFType::LDF_TYPE_UNKNOWN) {
numberOfValidKeys--;
}
}
settingStream.Write<uint32_t>(numberOfValidKeys);
settingStream.Write<uint32_t>(m_Settings.size());
for (LDFBaseData* data : m_Settings) {
if (data && data->GetValueType() != eLDFType::LDF_TYPE_UNKNOWN) {
if (data) {
data->WriteToPacket(&settingStream);
}
}
@@ -915,6 +946,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke
RakNet::BitStream settingStream;
settingStream.Write<uint32_t>(ldfData.size());
for (LDFBaseData* data : ldfData) {
if (data) {
data->WriteToPacket(&settingStream);
@@ -1048,14 +1080,13 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
destroyableSerialized = true;
}
CollectibleComponent* collectibleComponent;
if (TryGetComponent(eReplicaComponentType::COLLECTIBLE, collectibleComponent)) {
if (HasComponent(eReplicaComponentType::COLLECTIBLE)) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
destroyableSerialized = true;
collectibleComponent->Serialize(outBitStream, bIsInitialUpdate);
outBitStream->Write(m_CollectibleID); // Collectable component
}
PetComponent* petComponent;
@@ -1093,9 +1124,8 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
characterComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ItemComponent* itemComponent;
if (TryGetComponent(eReplicaComponentType::ITEM, itemComponent)) {
itemComponent->Serialize(outBitStream, bIsInitialUpdate);
if (HasComponent(eReplicaComponentType::ITEM)) {
outBitStream->Write0();
}
InventoryComponent* inventoryComponent;
@@ -1183,7 +1213,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
renderComponent->Serialize(outBitStream, bIsInitialUpdate);
}
if (modelComponent || !destroyableSerialized) {
if (modelComponent) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
@@ -1191,9 +1221,8 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
}
}
ZoneControlComponent* zoneControlComponent;
if (TryGetComponent(eReplicaComponentType::ZONE_CONTROL, zoneControlComponent)) {
zoneControlComponent->Serialize(outBitStream, bIsInitialUpdate);
if (HasComponent(eReplicaComponentType::ZONE_CONTROL)) {
outBitStream->Write<uint32_t>(0x40000000);
}
// BBB Component, unused currently
@@ -1523,17 +1552,7 @@ void Entity::Kill(Entity* murderer) {
}
if (!IsPlayer()) {
auto* destroyableComponent = GetComponent<DestroyableComponent>();
bool waitForDeathAnimation = false;
if (destroyableComponent) {
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0;
}
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
constexpr float DelayDeathTime = 12.0f;
if (waitForDeathAnimation) AddCallbackTimer(DelayDeathTime, [this]() { Game::entityManager->DestroyEntity(this); });
else Game::entityManager->DestroyEntity(this);
Game::entityManager->DestroyEntity(this);
}
const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");
@@ -2049,8 +2068,3 @@ void Entity::RetroactiveVaultSize() {
modelVault->SetSize(itemsVault->GetSize());
}
uint8_t Entity::GetCollectibleID() const {
auto* collectible = GetComponent<CollectibleComponent>();
return collectible ? collectible->GetCollectibleId() : 0;
}

View File

@@ -66,7 +66,7 @@ public:
eGameMasterLevel GetGMLevel() const { return m_GMLevel; }
uint8_t GetCollectibleID() const;
uint8_t GetCollectibleID() const { return uint8_t(m_CollectibleID); }
Entity* GetParentEntity() const { return m_ParentEntity; }
@@ -274,9 +274,6 @@ public:
template<typename T>
T GetVarAs(const std::u16string& name) const;
template<typename ComponentType, typename... VaArgs>
ComponentType* AddComponent(VaArgs... args);
/**
* Get the LDF data.
*/
@@ -504,36 +501,3 @@ T Entity::GetNetworkVar(const std::u16string& name) {
return LDFData<T>::Default;
}
/**
* @brief Adds a component of type ComponentType to this entity and forwards the arguments to the constructor.
*
* @tparam ComponentType The component class type to add. Must derive from Component.
* @tparam VaArgs The argument types to forward to the constructor.
* @param args The arguments to forward to the constructor. The first argument passed to the ComponentType constructor will be this entity.
* @return ComponentType* The added component. Will never return null.
*/
template<typename ComponentType, typename... VaArgs>
inline ComponentType* Entity::AddComponent(VaArgs... args) {
static_assert(std::is_base_of_v<Component, ComponentType>, "ComponentType must be a Component");
// Get the component if it already exists, or default construct a nullptr
auto*& componentToReturn = m_Components[ComponentType::ComponentType];
// If it doesn't exist, create it and forward the arguments to the constructor
if (!componentToReturn) {
componentToReturn = new ComponentType(this, std::forward<VaArgs>(args)...);
} else {
// In this case the block is already allocated and ready for use
// so we use a placement new to construct the component again as was requested by the caller.
// Placement new means we already have memory allocated for the object, so this just calls its constructor again.
// This is useful for when we want to create a new object in the same memory location as an old one.
componentToReturn->~Component();
new(componentToReturn) ComponentType(this, std::forward<VaArgs>(args)...);
}
// Finally return the created or already existing component.
// Because of the assert above, this should always be a ComponentType* but I need a way to guarantee the map cannot be modifed outside this function
// To allow a static cast here instead of a dynamic one.
return dynamic_cast<ComponentType*>(componentToReturn);
}

View File

@@ -16,7 +16,7 @@
#include "dZoneManager.h"
#include "MissionComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "MessageIdentifiers.h"
#include "dConfig.h"
#include "eTriggerEventType.h"
@@ -176,9 +176,8 @@ void EntityManager::DestroyEntity(Entity* entity) {
}
void EntityManager::SerializeEntities() {
for (int32_t i = 0; i < m_EntitiesToSerialize.size(); i++) {
const LWOOBJID toSerialize = m_EntitiesToSerialize.at(i);
auto* entity = GetEntity(toSerialize);
for (auto entry = m_EntitiesToSerialize.begin(); entry != m_EntitiesToSerialize.end(); entry++) {
auto* entity = GetEntity(*entry);
if (!entity) continue;
@@ -193,7 +192,7 @@ void EntityManager::SerializeEntities() {
if (entity->GetIsGhostingCandidate()) {
for (auto* player : Player::GetAllPlayers()) {
if (player->IsObserved(toSerialize)) {
if (player->IsObserved(*entry)) {
Game::server->Send(&stream, player->GetSystemAddress(), false);
}
}
@@ -205,12 +204,11 @@ void EntityManager::SerializeEntities() {
}
void EntityManager::KillEntities() {
for (int32_t i = 0; i < m_EntitiesToKill.size(); i++) {
const LWOOBJID toKill = m_EntitiesToKill.at(i);
auto* entity = GetEntity(toKill);
for (auto entry = m_EntitiesToKill.begin(); entry != m_EntitiesToKill.end(); entry++) {
auto* entity = GetEntity(*entry);
if (!entity) {
LOG("Attempting to kill null entity %llu", toKill);
Game::logger->Log("EntityManager", "Attempting to kill null entity %llu", *entry);
continue;
}
@@ -224,9 +222,8 @@ void EntityManager::KillEntities() {
}
void EntityManager::DeleteEntities() {
for (int32_t i = 0; i < m_EntitiesToDelete.size(); i++) {
const LWOOBJID toDelete = m_EntitiesToDelete.at(i);
auto entityToDelete = GetEntity(toDelete);
for (auto entry = m_EntitiesToDelete.begin(); entry != m_EntitiesToDelete.end(); entry++) {
auto entityToDelete = GetEntity(*entry);
if (entityToDelete) {
// Get all this info first before we delete the player.
auto networkIdToErase = entityToDelete->GetNetworkId();
@@ -240,9 +237,9 @@ void EntityManager::DeleteEntities() {
if (ghostingToDelete != m_EntitiesToGhost.end()) m_EntitiesToGhost.erase(ghostingToDelete);
} else {
LOG("Attempted to delete non-existent entity %llu", toDelete);
Game::logger->Log("EntityManager", "Attempted to delete non-existent entity %llu", *entry);
}
m_Entities.erase(toDelete);
m_Entities.erase(*entry);
}
m_EntitiesToDelete.clear();
}
@@ -333,7 +330,7 @@ const std::unordered_map<std::string, LWOOBJID>& EntityManager::GetSpawnPointEnt
void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr, const bool skipChecks) {
if (!entity) {
LOG("Attempted to construct null entity");
Game::logger->Log("EntityManager", "Attempted to construct null entity");
return;
}

View File

@@ -8,7 +8,7 @@
#include "Character.h"
#include "Game.h"
#include "GameMessages.h"
#include "Logger.h"
#include "dLogger.h"
#include "dConfig.h"
#include "CDClientManager.h"
#include "GeneralUtils.h"
@@ -236,7 +236,7 @@ void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t r
baseLookup += std::to_string(static_cast<uint32_t>(this->relatedPlayer));
}
baseLookup += " LIMIT 1";
LOG_DEBUG("query is %s", baseLookup.c_str());
Game::logger->LogDebug("LeaderboardManager", "query is %s", baseLookup.c_str());
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::CreatePreppedStmt(baseLookup));
baseQuery->setInt(1, this->gameID);
std::unique_ptr<sql::ResultSet> baseResult(baseQuery->executeQuery());
@@ -251,7 +251,7 @@ void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t r
int32_t res = snprintf(lookupBuffer.get(), STRING_LENGTH, queryBase.c_str(), orderBase.data(), filter.c_str(), resultStart, resultEnd);
DluAssert(res != -1);
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer.get()));
LOG_DEBUG("Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
Game::logger->LogDebug("LeaderboardManager", "Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
query->setInt(1, this->gameID);
if (this->infoType == InfoType::Friends) {
query->setInt(2, this->relatedPlayer);
@@ -358,7 +358,7 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activi
}
case Leaderboard::Type::None:
default:
LOG("Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
return;
}
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
@@ -377,7 +377,7 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activi
} else {
saveQuery = FormatInsert(leaderboardType, newScore, false);
}
LOG("save query %s %i %i", saveQuery.c_str(), playerID, activityId);
Game::logger->Log("LeaderboardManager", "save query %s %i %i", saveQuery.c_str(), playerID, activityId);
std::unique_ptr<sql::PreparedStatement> saveStatement(Database::CreatePreppedStmt(saveQuery));
saveStatement->setInt(1, playerID);
saveStatement->setInt(2, activityId);

View File

@@ -7,7 +7,7 @@
#include "MissionComponent.h"
#include "UserManager.h"
#include "EntityManager.h"
#include "Logger.h"
#include "dLogger.h"
#include "ZoneInstanceManager.h"
#include "WorldPackets.h"
#include "dZoneManager.h"
@@ -260,7 +260,7 @@ void Player::SetDroppedCoins(uint64_t value) {
}
Player::~Player() {
LOG("Deleted player");
Game::logger->Log("Player", "Deleted player");
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
const auto id = m_ObservedEntities[i];

View File

@@ -1,14 +1,8 @@
#include "TeamManager.h"
#include "EntityManager.h"
#include "Game.h"
#include "dConfig.h"
TeamManager* TeamManager::m_Address = nullptr; //For singleton method
Team::Team() {
lootOption = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1;
}
TeamManager::TeamManager() {
}

View File

@@ -2,15 +2,16 @@
#include "Entity.h"
struct Team {
Team();
struct Team
{
LWOOBJID teamID = LWOOBJID_EMPTY;
char lootOption = 0;
std::vector<LWOOBJID> members{};
char lootRound = 0;
};
class TeamManager {
class TeamManager
{
public:
static TeamManager* Instance() {
if (!m_Address) {

View File

@@ -4,7 +4,7 @@
#include "InventoryComponent.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "Item.h"
#include "Character.h"
#include "CharacterComponent.h"
@@ -67,7 +67,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) {
if (participant == m_ParticipantA) {
m_AcceptedA = !value;
LOG("Accepted from A (%d), B: (%d)", value, m_AcceptedB);
Game::logger->Log("Trade", "Accepted from A (%d), B: (%d)", value, m_AcceptedB);
auto* entityB = GetParticipantBEntity();
@@ -77,7 +77,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) {
} else if (participant == m_ParticipantB) {
m_AcceptedB = !value;
LOG("Accepted from B (%d), A: (%d)", value, m_AcceptedA);
Game::logger->Log("Trade", "Accepted from B (%d), A: (%d)", value, m_AcceptedA);
auto* entityA = GetParticipantAEntity();
@@ -125,7 +125,7 @@ void Trade::Complete() {
// First verify both players have the coins and items requested for the trade.
if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) {
LOG("Possible coin trade cheating attempt! Aborting trade.");
Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade.");
return;
}
@@ -133,11 +133,11 @@ void Trade::Complete() {
auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId);
if (itemToRemove) {
if (itemToRemove->GetCount() < tradeItem.itemCount) {
LOG("Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str());
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str());
return;
}
} else {
LOG("Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str());
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str());
return;
}
}
@@ -146,11 +146,11 @@ void Trade::Complete() {
auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId);
if (itemToRemove) {
if (itemToRemove->GetCount() < tradeItem.itemCount) {
LOG("Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str());
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str());
return;
}
} else {
LOG("Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str());
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str());
return;
}
}
@@ -194,7 +194,7 @@ void Trade::SendUpdateToOther(LWOOBJID participant) {
uint64_t coins;
std::vector<TradeItem> itemIds;
LOG("Attempting to send trade update");
Game::logger->Log("Trade", "Attempting to send trade update");
if (participant == m_ParticipantA) {
other = GetParticipantBEntity();
@@ -228,7 +228,7 @@ void Trade::SendUpdateToOther(LWOOBJID participant) {
items.push_back(tradeItem);
}
LOG("Sending trade update");
Game::logger->Log("Trade", "Sending trade update");
GameMessages::SendServerTradeUpdate(other->GetObjectID(), coins, items, other->GetSystemAddress());
}
@@ -279,7 +279,7 @@ Trade* TradingManager::NewTrade(LWOOBJID participantA, LWOOBJID participantB) {
trades[tradeId] = trade;
LOG("Created new trade between (%llu) <-> (%llu)", participantA, participantB);
Game::logger->Log("TradingManager", "Created new trade between (%llu) <-> (%llu)", participantA, participantB);
return trade;
}

View File

@@ -2,7 +2,7 @@
#include "Database.h"
#include "Character.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Game.h"
#include "dZoneManager.h"
#include "eServerDisconnectIdentifiers.h"
@@ -27,37 +27,21 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std:
//This needs to be re-enabled / updated whenever the mute stuff is moved to another table.
//This was only done because otherwise the website's account page dies and the website is waiting on a migration to wordpress.
//sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gmlevel, mute_expire FROM accounts WHERE name=? LIMIT 1;");
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gm_level FROM accounts WHERE name=? LIMIT 1;");
stmt->setString(1, username.c_str());
auto account = Database::Connection->GetAccountByName(username);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_AccountID = res->getUInt(1);
m_MaxGMLevel = static_cast<eGameMasterLevel>(res->getInt(2));
m_MuteExpire = 0; //res->getUInt64(3);
}
delete res;
delete stmt;
m_AccountID = account.ID;
m_MaxGMLevel = static_cast<eGameMasterLevel>(account.MaxGMLevel);
m_MuteExpire = 0;
//If we're loading a zone, we'll load the last used (aka current) character:
if (Game::server->GetZoneID() != 0) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 1;");
stmt->setUInt(1, m_AccountID);
uint32_t characterId = Database::Connection->GetLatestCharacterOfAccount(m_AccountID);
sql::ResultSet* res = stmt->executeQuery();
if (res->rowsCount() > 0) {
while (res->next()) {
LWOOBJID objID = res->getUInt64(1);
Character* character = new Character(uint32_t(objID), this);
m_Characters.push_back(character);
LOG("Loaded %llu as it is the last used char", objID);
}
if (characterId != 0) {
Character* character = new Character(characterId, this);
m_Characters.push_back(character);
Game::logger->Log("User", "Loaded %u as it is the last used char", characterId);
}
delete res;
delete stmt;
}
}
@@ -127,7 +111,7 @@ void User::UserOutOfSync() {
m_AmountOfTimesOutOfSync++;
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
//YEET
LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
Game::logger->Log("User", "User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
}
}

View File

@@ -6,14 +6,14 @@
#include "Database.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "User.h"
#include <WorldPackets.h>
#include "Character.h"
#include <BitStream.h>
#include "PacketUtils.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "Logger.h"
#include "dLogger.h"
#include "GeneralUtils.h"
#include "ZoneInstanceManager.h"
#include "dServer.h"
@@ -46,7 +46,7 @@ void UserManager::Initialize() {
AssetMemoryBuffer fnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_first.txt");
if (!fnBuff.m_Success) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str());
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream fnStream = std::istream(&fnBuff);
@@ -59,7 +59,7 @@ void UserManager::Initialize() {
AssetMemoryBuffer mnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_middle.txt");
if (!mnBuff.m_Success) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str());
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream mnStream = std::istream(&mnBuff);
@@ -72,7 +72,7 @@ void UserManager::Initialize() {
AssetMemoryBuffer lnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_last.txt");
if (!lnBuff.m_Success) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str());
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
}
std::istream lnStream = std::istream(&lnBuff);
@@ -86,7 +86,7 @@ void UserManager::Initialize() {
//Load our pre-approved names:
AssetMemoryBuffer chatListBuff = Game::assetManager->GetFileAsBuffer("chatplus_en_us.txt");
if (!chatListBuff.m_Success) {
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
throw std::runtime_error("Aborting initialization due to missing chat whitelist file.");
}
std::istream chatListStream = std::istream(&chatListBuff);
@@ -150,7 +150,7 @@ bool UserManager::DeleteUser(const SystemAddress& sysAddr) {
void UserManager::DeletePendingRemovals() {
for (auto* user : m_UsersToDelete) {
LOG("Deleted user %i", user->GetAccountID());
Game::logger->Log("UserManager", "Deleted user %i", user->GetAccountID());
delete user;
}
@@ -159,17 +159,7 @@ void UserManager::DeletePendingRemovals() {
}
bool UserManager::IsNameAvailable(const std::string& requestedName) {
bool toReturn = false; //To allow for a clean exit
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? OR pending_name=? LIMIT 1;");
stmt->setString(1, requestedName.c_str());
stmt->setString(2, requestedName.c_str());
sql::ResultSet* res = stmt->executeQuery();
if (res->rowsCount() == 0) toReturn = true;
delete stmt;
delete res;
return toReturn;
return Database::Connection->IsCharacterNameAvailable(requestedName);
}
std::string UserManager::GetPredefinedName(uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex) {
@@ -201,10 +191,8 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
User* u = GetUser(sysAddr);
if (!u) return;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 4;");
stmt->setUInt(1, u->GetAccountID());
auto charInfos = Database::Connection->GetAllCharactersByAccountID(u->GetAccountID());
sql::ResultSet* res = stmt->executeQuery();
std::vector<Character*>& chars = u->GetCharacters();
for (size_t i = 0; i < chars.size(); ++i) {
@@ -232,16 +220,12 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
chars.clear();
while (res->next()) {
LWOOBJID objID = res->getUInt64(1);
Character* character = new Character(uint32_t(objID), u);
for (const auto& info : charInfos) {
Character* character = new Character(info.ID, u);
character->SetIsNewLogin();
chars.push_back(character);
}
delete res;
delete stmt;
WorldPackets::SendCharacterList(sysAddr, u);
}
@@ -271,32 +255,28 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
LOT pantsLOT = FindCharPantsID(pantsColor);
if (name != "" && !UserManager::IsNameAvailable(name)) {
LOG("AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str());
Game::logger->Log("UserManager", "AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE);
return;
}
if (!IsNameAvailable(predefinedName)) {
LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str());
Game::logger->Log("UserManager", "AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE);
return;
}
if (name == "") {
LOG("AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str());
Game::logger->Log("UserManager", "AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str());
} else {
LOG("AccountID: %i is creating a character with name: %s (temporary: %s)", u->GetAccountID(), name.c_str(), predefinedName.c_str());
Game::logger->Log("UserManager", "AccountID: %i is creating a character with name: %s (temporary: %s)", u->GetAccountID(), name.c_str(), predefinedName.c_str());
}
//Now that the name is ok, we can get an objectID from Master:
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) {
sql::PreparedStatement* overlapStmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE id = ?");
overlapStmt->setUInt(1, objectID);
auto* overlapResult = overlapStmt->executeQuery();
if (overlapResult->next()) {
LOG("Character object id unavailable, check objectidtracker!");
auto character = Database::Connection->GetCharacterInfoByID(objectID);
if (character.AccountID != 0) {
Game::logger->Log("UserManager", "Character object id unavailable, check objectidtracker!");
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
return;
}
@@ -333,45 +313,32 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
xml3 << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
//Check to see if our name was pre-approved:
// Check to see if our name was pre-approved
bool nameOk = IsNamePreapproved(name);
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (name != "") {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)");
stmt->setUInt(1, objectID);
stmt->setUInt(2, u->GetAccountID());
stmt->setString(3, predefinedName.c_str());
stmt->setString(4, name.c_str());
stmt->setBoolean(5, false);
stmt->setUInt64(6, time(NULL));
if (nameOk) {
stmt->setString(3, name.c_str());
stmt->setString(4, "");
}
stmt->execute();
delete stmt;
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
nameOk ? name : predefinedName,
nameOk ? "" : name,
false,
time(NULL)
);
} else {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)");
stmt->setUInt(1, objectID);
stmt->setUInt(2, u->GetAccountID());
stmt->setString(3, predefinedName.c_str());
stmt->setString(4, "");
stmt->setBoolean(5, false);
stmt->setUInt64(6, time(NULL));
stmt->execute();
delete stmt;
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
predefinedName,
"",
false,
time(NULL)
);
}
//Now finally insert our character xml:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charxml`(`id`, `xml_data`) VALUES (?,?)");
stmt->setUInt(1, objectID);
stmt->setString(2, xml3.str().c_str());
stmt->execute();
delete stmt;
// Now finally insert our character xml
Database::Connection->CreateCharacterXML(objectID, xml3.str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
@@ -383,14 +350,14 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
User* u = GetUser(sysAddr);
if (!u) {
LOG("Couldn't get user to delete character");
Game::logger->Log("UserManager", "Couldn't get user to delete character");
return;
}
LWOOBJID objectID = PacketUtils::ReadS64(8, packet);
uint32_t charID = static_cast<uint32_t>(objectID);
LOG("Received char delete req for ID: %llu (%u)", objectID, charID);
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)", objectID, charID);
bool hasCharacter = CheatDetection::VerifyLwoobjidIsSender(
objectID,
@@ -402,74 +369,14 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
if (!hasCharacter) {
WorldPackets::SendCharacterDeleteResponse(sysAddr, false);
} else {
LOG("Deleting character %i", charID);
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM charxml WHERE id=? LIMIT 1;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM command_log WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;");
stmt->setUInt(1, charID);
stmt->setUInt(2, charID);
stmt->execute();
delete stmt;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
bitStream.Write(objectID);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"DELETE FROM properties_contents WHERE property_id IN (SELECT id FROM properties WHERE owner_id=?);"
);
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM properties WHERE owner_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM ugc WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM activity_log WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM mail WHERE receiver_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM charinfo WHERE id=? LIMIT 1;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
Game::logger->Log("UserManager", "Deleting character %i", charID);
Database::Connection->DeleteCharacter(charID);
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
bitStream.Write(objectID);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
WorldPackets::SendCharacterDeleteResponse(sysAddr, true);
}
@@ -478,7 +385,7 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet) {
User* u = GetUser(sysAddr);
if (!u) {
LOG("Couldn't get user to delete character");
Game::logger->Log("UserManager", "Couldn't get user to delete character");
return;
}
@@ -487,7 +394,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
GeneralUtils::ClearBit(objectID, eObjectBits::PERSISTENT);
uint32_t charID = static_cast<uint32_t>(objectID);
LOG("Received char rename request for ID: %llu (%u)", objectID, charID);
Game::logger->Log("UserManager", "Received char rename request for ID: %llu (%u)", objectID, charID);
std::string newName = PacketUtils::ReadString(16, packet, true);
@@ -519,25 +426,15 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
if (IsNameAvailable(newName)) {
if (IsNamePreapproved(newName)) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET name=?, pending_name='', needs_rename=0, last_login=? WHERE id=? LIMIT 1");
stmt->setString(1, newName);
stmt->setUInt64(2, time(NULL));
stmt->setUInt(3, character->GetID());
stmt->execute();
delete stmt;
Database::Connection->ApproveCharacterName(character->GetID(), newName);
LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str());
Game::logger->Log("UserManager", "Character %s now known as %s", character->GetName().c_str(), newName.c_str());
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
} else {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET pending_name=?, needs_rename=0, last_login=? WHERE id=? LIMIT 1");
stmt->setString(1, newName);
stmt->setUInt64(2, time(NULL));
stmt->setUInt(3, character->GetID());
stmt->execute();
delete stmt;
Database::Connection->SetPendingCharacterName(character->GetID(), newName);
LOG("Character %s has been renamed to %s and is pending approval by a moderator.", character->GetName().c_str(), newName.c_str());
Game::logger->Log("UserManager", "Character %s has been renamed to %s and is pending approval by a moderator.", character->GetName().c_str(), newName.c_str());
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
}
@@ -545,7 +442,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_IN_USE);
}
} else {
LOG("Unknown error occurred when renaming character, either hasCharacter or character variable != true.");
Game::logger->Log("UserManager", "Unknown error occurred when renaming character, either hasCharacter or character variable != true.");
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR);
}
}
@@ -553,7 +450,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID) {
User* u = GetUser(sysAddr);
if (!u) {
LOG("Couldn't get user to log in character");
Game::logger->Log("UserManager", "Couldn't get user to log in character");
return;
}
@@ -566,17 +463,13 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
}
if (hasCharacter && character) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charinfo SET last_login=? WHERE id=? LIMIT 1");
stmt->setUInt64(1, time(NULL));
stmt->setUInt(2, playerID);
stmt->execute();
delete stmt;
Database::Connection->UpdateCharacterLastLogin(playerID, time(NULL));
uint32_t zoneID = character->GetZoneID();
if (zoneID == LWOZONEID_INVALID) zoneID = 1000; //Send char to VE
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneID, character->GetZoneClone(), false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
if (character) {
character->SetZoneID(zoneID);
character->SetZoneInstance(zoneInstance);
@@ -586,7 +479,7 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
return;
});
} else {
LOG("Unknown error occurred when logging in a character, either hasCharacter or character variable != true.");
Game::logger->Log("UserManager", "Unknown error occurred when logging in a character, either hasCharacter or character variable != true.");
}
}
@@ -601,7 +494,7 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
tableData.finalize();
return shirtLOT;
} catch (const std::exception&) {
LOG("Failed to execute query! Using backup...");
Game::logger->Log("Character Create", "Failed to execute query! Using backup...");
// in case of no shirt found in CDServer, return problematic red vest.
return 4069;
}
@@ -616,7 +509,7 @@ uint32_t FindCharPantsID(uint32_t pantsColor) {
tableData.finalize();
return pantsLOT;
} catch (const std::exception&) {
LOG("Failed to execute query! Using backup...");
Game::logger->Log("Character Create", "Failed to execute query! Using backup...");
// in case of no pants color found in CDServer, return red pants.
return 2508;
}

View File

@@ -3,13 +3,13 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("AirMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
}
@@ -26,14 +26,14 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitS
uint32_t behaviorId{};
if (!bitStream->Read(behaviorId)) {
LOG("Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("AirMovementBehavior", "Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}
LWOOBJID target{};
if (!bitStream->Read(target)) {
LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("AirMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}

View File

@@ -1,7 +1,7 @@
#include "AndBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
for (auto* behavior : this->m_behaviors) {

View File

@@ -4,19 +4,19 @@
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "RebuildComponent.h"
#include "DestroyableComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
uint32_t targetCount{};
if (!bitStream->Read(targetCount)) {
LOG("Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("AreaOfEffectBehavior", "Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
}
@@ -28,7 +28,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
}
if (targetCount > this->m_maxTargets) {
LOG("Serialized size is greater than max targets! Size: %i, Max: %i", targetCount, this->m_maxTargets);
Game::logger->Log("AreaOfEffectBehavior", "Serialized size is greater than max targets! Size: %i, Max: %i", targetCount, this->m_maxTargets);
return;
}
@@ -41,7 +41,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
for (auto i = 0u; i < targetCount; ++i) {
LWOOBJID target{};
if (!bitStream->Read(target)) {
LOG("failed to read in target %i from bitStream, aborting target Handle!", i);
Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i);
};
targets.push_back(target);
}

View File

@@ -2,13 +2,13 @@
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("AttackDelayBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};

View File

@@ -1,10 +1,8 @@
#include "BasicAttackBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
#include "DestroyableComponent.h"
#include "BehaviorContext.h"
#include "eBasicAttackSuccessTypes.h"
@@ -15,15 +13,8 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
PlayFx(u"onhit", entity->GetObjectID()); //This damage animation doesn't seem to play consistently
PlayFx(u"onhit", entity->GetObjectID());
destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID);
//Handle player damage cooldown
if (entity->IsPlayer() && !this->m_DontApplyImmune) {
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
}
}
this->m_OnSuccess->Handle(context, bitStream, branch);
@@ -35,10 +26,10 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
uint16_t allocatedBits{};
if (!bitStream->Read(allocatedBits) || allocatedBits == 0) {
LOG_DEBUG("No allocated bits");
Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits");
return;
}
LOG_DEBUG("Number of allocated bits %i", allocatedBits);
Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits);
const auto baseAddress = bitStream->GetReadOffset();
DoHandleBehavior(context, bitStream, branch);
@@ -49,13 +40,13 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = Game::entityManager->GetEntity(branch.target);
if (!targetEntity) {
LOG("Target targetEntity %llu not found.", branch.target);
Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target);
return;
}
auto* destroyableComponent = targetEntity->GetComponent<DestroyableComponent>();
if (!destroyableComponent) {
LOG("No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT());
Game::logger->Log("BasicAttackBehavior", "No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT());
return;
}
@@ -64,7 +55,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
bool isSuccess{};
if (!bitStream->Read(isBlocked)) {
LOG("Unable to read isBlocked");
Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked");
return;
}
@@ -76,31 +67,30 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
}
if (!bitStream->Read(isImmune)) {
LOG("Unable to read isImmune");
Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune");
return;
}
if (isImmune) {
LOG_DEBUG("Target targetEntity %llu is immune!", branch.target);
this->m_OnFailImmune->Handle(context, bitStream, branch);
return;
}
if (!bitStream->Read(isSuccess)) {
LOG("failed to read success from bitstream");
Game::logger->Log("BasicAttackBehavior", "failed to read success from bitstream");
return;
}
if (isSuccess) {
uint32_t armorDamageDealt{};
if (!bitStream->Read(armorDamageDealt)) {
LOG("Unable to read armorDamageDealt");
Game::logger->Log("BasicAttackBehavior", "Unable to read armorDamageDealt");
return;
}
uint32_t healthDamageDealt{};
if (!bitStream->Read(healthDamageDealt)) {
LOG("Unable to read healthDamageDealt");
Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt");
return;
}
@@ -113,7 +103,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
bool died{};
if (!bitStream->Read(died)) {
LOG("Unable to read died");
Game::logger->Log("BasicAttackBehavior", "Unable to read died");
return;
}
auto previousArmor = destroyableComponent->GetArmor();
@@ -124,7 +114,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
uint8_t successState{};
if (!bitStream->Read(successState)) {
LOG("Unable to read success state");
Game::logger->Log("BasicAttackBehavior", "Unable to read success state");
return;
}
@@ -137,7 +127,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
break;
default:
if (static_cast<eBasicAttackSuccessTypes>(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) {
LOG("Unknown success state (%i)!", successState);
Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState);
return;
}
this->m_OnFailImmune->Handle(context, bitStream, branch);
@@ -167,13 +157,13 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream*
void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = Game::entityManager->GetEntity(branch.target);
if (!targetEntity) {
LOG("Target entity %llu is null!", branch.target);
Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target);
return;
}
auto* destroyableComponent = targetEntity->GetComponent<DestroyableComponent>();
if (!destroyableComponent || !destroyableComponent->GetParent()) {
LOG("No destroyable component on %llu", branch.target);
Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target);
return;
}
@@ -188,15 +178,11 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
return;
}
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
LOG_DEBUG("Damage cooldown timer currently %f s", destroyableComponent->GetDamageCooldownTimer());
const bool isImmune = (destroyableComponent->IsImmune()) || (destroyableComponent->IsCooldownImmune());
const bool isImmune = destroyableComponent->IsImmune();
bitStream->Write(isImmune);
if (isImmune) {
LOG_DEBUG("Target targetEntity %llu is immune!", branch.target);
this->m_OnFailImmune->Calculate(context, bitStream, branch);
return;
}
@@ -217,12 +203,6 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
bitStream->Write(isSuccess);
//Handle player damage cooldown
if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) {
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
}
eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE;
if (isSuccess) {
if (healthDamageDealt >= 1) {
@@ -247,7 +227,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
break;
default:
if (static_cast<eBasicAttackSuccessTypes>(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) {
LOG("Unknown success state (%i)!", successState);
Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState);
break;
}
this->m_OnFailImmune->Calculate(context, bitStream, branch);
@@ -256,8 +236,6 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
}
void BasicAttackBehavior::Load() {
this->m_DontApplyImmune = GetBoolean("dont_apply_immune");
this->m_MinDamage = GetInt("min damage");
if (this->m_MinDamage == 0) this->m_MinDamage = 1;

View File

@@ -10,14 +10,14 @@ public:
/**
* @brief Reads a 16bit short from the bitStream and when the actual behavior handling finishes with all of its branches, the bitStream
* is then offset to after the allocated bits for this stream.
*
*
*/
void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch);
/**
* @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server.
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
* @param bitStream The bitStream to deserialize. BitStreams will always check their bounds before reading in a behavior
* and will fail gracefully if an overread is detected.
* @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down.
@@ -27,13 +27,13 @@ public:
/**
* @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number
* of bits used is then written to where the 16bit short initially was.
*
*
*/
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
/**
* @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client
*
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
* @param bitStream The bitStream to serialize to.
* @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down.
@@ -44,12 +44,10 @@ public:
* @brief Loads this Behaviors parameters from the database. For this behavior specifically:
* max and min damage will always be the same. If min is less than max, they are both set to max.
* If an action is not in the database, then no action is taken for that result.
*
*
*/
void Load() override;
private:
bool m_DontApplyImmune;
uint32_t m_MinDamage;
uint32_t m_MaxDamage;

View File

@@ -4,7 +4,7 @@
#include "Behavior.h"
#include "CDActivitiesTable.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "BehaviorTemplates.h"
#include "BehaviorBranchContext.h"
#include <unordered_map>
@@ -278,12 +278,12 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
case BehaviorTemplates::BEHAVIOR_MOUNT: break;
case BehaviorTemplates::BEHAVIOR_SKILL_SET: break;
default:
//LOG("Failed to load behavior with invalid template id (%i)!", templateId);
//Game::logger->Log("Behavior", "Failed to load behavior with invalid template id (%i)!", templateId);
break;
}
if (behavior == nullptr) {
//LOG("Failed to load unimplemented template id (%i)!", templateId);
//Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!", templateId);
behavior = new EmptyBehavior(behaviorId);
}
@@ -306,7 +306,7 @@ BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) {
}
if (templateID == BehaviorTemplates::BEHAVIOR_EMPTY && behaviorId != 0) {
LOG("Failed to load behavior template with id (%i)!", behaviorId);
Game::logger->Log("Behavior", "Failed to load behavior template with id (%i)!", behaviorId);
}
return templateID;
@@ -426,7 +426,7 @@ Behavior::Behavior(const uint32_t behaviorId) {
// Make sure we do not proceed if we are trying to load an invalid behavior
if (templateInDatabase.behaviorID == 0) {
LOG("Failed to load behavior with id (%i)!", behaviorId);
Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!", behaviorId);
this->m_effectId = 0;
this->m_effectHandle = nullptr;

View File

@@ -4,7 +4,7 @@
#include "EntityManager.h"
#include "SkillComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "dServer.h"
#include "BitStreamUtils.h"
@@ -31,7 +31,7 @@ uint32_t BehaviorContext::GetUniqueSkillId() const {
auto* entity = Game::entityManager->GetEntity(this->originator);
if (entity == nullptr) {
LOG("Invalid entity for (%llu)!", this->originator);
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
return 0;
}
@@ -39,7 +39,7 @@ uint32_t BehaviorContext::GetUniqueSkillId() const {
auto* component = entity->GetComponent<SkillComponent>();
if (component == nullptr) {
LOG("No skill component attached to (%llu)!", this->originator);;
Game::logger->Log("BehaviorContext", "No skill component attached to (%llu)!", this->originator);;
return 0;
}
@@ -126,7 +126,7 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bit
}
if (!found) {
LOG("Failed to find behavior sync entry with sync id (%i)!", syncId);
Game::logger->Log("BehaviorContext", "Failed to find behavior sync entry with sync id (%i)!", syncId);
return;
}
@@ -135,7 +135,7 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bit
const auto branch = entry.branchContext;
if (behavior == nullptr) {
LOG("Invalid behavior for sync id (%i)!", syncId);
Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!", syncId);
return;
}
@@ -319,7 +319,7 @@ void BehaviorContext::FilterTargets(std::vector<Entity*>& targets, std::forward_
// if the caster is not there, return empty targets list
auto* caster = Game::entityManager->GetEntity(this->caster);
if (!caster) {
LOG_DEBUG("Invalid caster for (%llu)!", this->originator);
Game::logger->LogDebug("BehaviorContext", "Invalid caster for (%llu)!", this->originator);
targets.clear();
return;
}

View File

@@ -4,7 +4,7 @@
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
@@ -13,7 +13,7 @@ void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -43,7 +43,7 @@ void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branc
auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
@@ -13,7 +13,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) {
LOG("Invalid target (%llu)!", target);
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
return;
}
@@ -21,7 +21,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
auto* component = entity->GetComponent<DestroyableComponent>();
if (component == nullptr) {
LOG("Invalid target, no destroyable component (%llu)!", target);
Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target);
return;
}
@@ -47,7 +47,7 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch
auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) {
LOG("Invalid target (%llu)!", target);
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
return;
}
@@ -55,7 +55,7 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch
auto* component = entity->GetComponent<DestroyableComponent>();
if (component == nullptr) {
LOG("Invalid target, no destroyable component (%llu)!", target);
Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target);
return;
}

View File

@@ -5,7 +5,7 @@
#include "BehaviorContext.h"
#include "CharacterComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "PossessableComponent.h"
void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
@@ -17,7 +17,7 @@ void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt
return;
}
LOG("Activating car boost!");
Game::logger->Log("Car boost", "Activating car boost!");
auto* possessableComponent = entity->GetComponent<PossessableComponent>();
if (possessableComponent != nullptr) {
@@ -27,7 +27,7 @@ void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt
auto* characterComponent = possessor->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
LOG("Tracking car boost!");
Game::logger->Log("Car boost", "Tracking car boost!");
characterComponent->UpdatePlayerStatistic(RacingCarBoostsActivated);
}
}

View File

@@ -1,13 +1,13 @@
#include "ChainBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t chainIndex{};
if (!bitStream->Read(chainIndex)) {
LOG("Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ChainBehavior", "Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
}
@@ -16,7 +16,7 @@ void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
if (chainIndex < this->m_behaviors.size()) {
this->m_behaviors.at(chainIndex)->Handle(context, bitStream, branch);
} else {
LOG("chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ChainBehavior", "chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits());
}
}

View File

@@ -2,13 +2,13 @@
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
LOG("Unable to read handle from bitStream, aborting Handle! variable_type");
Game::logger->Log("ChargeUpBehavior", "Unable to read handle from bitStream, aborting Handle! variable_type");
return;
};

View File

@@ -4,14 +4,14 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -37,7 +37,7 @@ void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchCon
auto* target = Game::entityManager->GetEntity(second);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", second);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);
return;
}

View File

@@ -4,14 +4,14 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -35,7 +35,7 @@ void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchCont
auto* target = Game::entityManager->GetEntity(second);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", second);
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second);
return;
}

View File

@@ -10,7 +10,7 @@ void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG_DEBUG("Failed to find target (%llu)!", branch.target);
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -29,7 +29,7 @@ void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStr
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG_DEBUG("Failed to find target (%llu)!", branch.target);
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) {
@@ -13,7 +13,7 @@ void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
uint32_t handle{};
if (!bitStream->Read(handle)) {
LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ForceMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
}
context->RegisterSyncBehavior(handle, this, branch, this->m_Duration);
@@ -22,13 +22,13 @@ void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
uint32_t next{};
if (!bitStream->Read(next)) {
LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}
LWOOBJID target{};
if (!bitStream->Read(target)) {
LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}

View File

@@ -1,7 +1,7 @@
#include "HealBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "DestroyableComponent.h"
#include "eReplicaComponentType.h"
@@ -11,7 +11,7 @@ void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_strea
auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) {
LOG("Failed to find entity for (%llu)!", branch.target);
Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target);
return;
}
@@ -19,7 +19,7 @@ void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_strea
auto* destroyable = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE));
if (destroyable == nullptr) {
LOG("Failed to find destroyable component for %(llu)!", branch.target);
Game::logger->Log("HealBehavior", "Failed to find destroyable component for %(llu)!", branch.target);
return;
}

View File

@@ -3,7 +3,7 @@
#include "DestroyableComponent.h"
#include "dpWorld.h"
#include "EntityManager.h"
#include "Logger.h"
#include "dLogger.h"
void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {

View File

@@ -4,7 +4,7 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "ControllablePhysicsComponent.h"
#include "eStateChangeType.h"
@@ -13,7 +13,7 @@ void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt
auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -59,7 +59,7 @@ void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext bra
auto* target = Game::entityManager->GetEntity(second);
if (!target) {
LOG("Failed to find target (%llu)!", second);
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);
return;
}

View File

@@ -2,7 +2,7 @@
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "SkillComponent.h"
@@ -12,7 +12,7 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
bool unknown = false;
if (!bitStream->Read(unknown)) {
LOG("Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("InterruptBehavior", "Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -23,7 +23,7 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
bool unknown = false;
if (!bitStream->Read(unknown)) {
LOG("Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("InterruptBehavior", "Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -35,7 +35,7 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
bool unknown = false;
if (!bitStream->Read(unknown)) {
LOG("Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("InterruptBehavior", "Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
}

View File

@@ -7,13 +7,13 @@
#include "GameMessages.h"
#include "DestroyableComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bool unknown{};
if (!bitStream->Read(unknown)) {
LOG("Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("KnockbackBehavior", "Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
}

View File

@@ -1,7 +1,7 @@
#include "MovementSwitchBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t movementType{};
@@ -15,7 +15,7 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
this->m_movingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) {
return;
}
LOG("Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};

View File

@@ -2,7 +2,7 @@
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "SkillComponent.h"
#include "DestroyableComponent.h"

View File

@@ -3,7 +3,7 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "SkillComponent.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "eObjectBits.h"
@@ -12,14 +12,14 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
LWOOBJID target{};
if (!bitStream->Read(target)) {
LOG("Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) {
LOG("Failed to find originator (%llu)!", context->originator);
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
return;
}
@@ -27,7 +27,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
auto* skillComponent = entity->GetComponent<SkillComponent>();
if (skillComponent == nullptr) {
LOG("Failed to find skill component for (%llu)!", -context->originator);
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", -context->originator);
return;
}
@@ -35,7 +35,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
if (m_useMouseposit && !branch.isSync) {
NiPoint3 targetPosition = NiPoint3::ZERO;
if (!bitStream->Read(targetPosition)) {
LOG("Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
}
@@ -46,7 +46,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
LWOOBJID projectileId{};
if (!bitStream->Read(projectileId)) {
LOG("Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -64,7 +64,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) {
LOG("Failed to find originator (%llu)!", context->originator);
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
return;
}
@@ -72,7 +72,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
auto* skillComponent = entity->GetComponent<SkillComponent>();
if (skillComponent == nullptr) {
LOG("Failed to find skill component for (%llu)!", context->originator);
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", context->originator);
return;
@@ -81,7 +81,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
auto* other = Game::entityManager->GetEntity(branch.target);
if (other == nullptr) {
LOG("Invalid projectile target (%llu)!", branch.target);
Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target);
return;
}

View File

@@ -40,7 +40,7 @@ void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
if (zoneClone != 0) ChatPackets::SendSystemMessage(sysAddr, u"Transfering to your property!");
else ChatPackets::SendSystemMessage(sysAddr, u"Transfering back to previous world!");
LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
Game::logger->Log("PropertyTeleportBehavior", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
if (entity->GetCharacter()) {
entity->GetCharacter()->SetZoneID(zoneID);
entity->GetCharacter()->SetZoneInstance(zoneInstance);

View File

@@ -3,7 +3,7 @@
#include "DestroyableComponent.h"
#include "dpWorld.h"
#include "EntityManager.h"
#include "Logger.h"
#include "dLogger.h"
#include "Game.h"
#include "eReplicaComponentType.h"
@@ -11,7 +11,7 @@ void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_str
auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) {
LOG("Failed to find entity for (%llu)!", branch.target);
Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!", branch.target);
return;
}
@@ -19,7 +19,7 @@ void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_str
auto* destroyable = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE));
if (destroyable == nullptr) {
LOG("Failed to find destroyable component for %(llu)!", branch.target);
Game::logger->Log("RepairBehavior", "Failed to find destroyable component for %(llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "RebuildComponent.h"
#include "Entity.h"
@@ -15,7 +15,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
auto* origin = Game::entityManager->GetEntity(context->originator);
if (origin == nullptr) {
LOG("Failed to find self entity (%llu)!", context->originator);
Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!", context->originator);
return;
}
@@ -45,7 +45,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
);
if (entity == nullptr) {
LOG("Failed to spawn entity (%i)!", this->m_lot);
Game::logger->Log("SpawnBehavior", "Failed to spawn entity (%i)!", this->m_lot);
return;
}
@@ -82,7 +82,7 @@ void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext
auto* entity = Game::entityManager->GetEntity(second);
if (entity == nullptr) {
LOG("Failed to find spawned entity (%llu)!", second);
Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!", second);
return;
}

View File

@@ -3,7 +3,7 @@
#include "ControllablePhysicsComponent.h"
#include "BehaviorContext.h"
#include "BehaviorBranchContext.h"
#include "Logger.h"
#include "dLogger.h"
void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {

View File

@@ -5,7 +5,7 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "eReplicaComponentType.h"
@@ -17,14 +17,14 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
bool blocked{};
if (!bitStream->Read(blocked)) {
LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("StunBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -47,7 +47,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr
auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) {
LOG("Invalid self entity (%llu)!", context->originator);
Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!", context->originator);
return;
}
@@ -82,7 +82,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr
bitStream->Write(blocked);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -1,7 +1,7 @@
#include "SwitchBehavior.h"
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "Logger.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "BehaviorContext.h"
#include "BuffComponent.h"
@@ -11,7 +11,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
if (this->m_imagination > 0 || !this->m_isEnemyFaction) {
if (!bitStream->Read(state)) {
LOG("Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("SwitchBehavior", "Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
}
@@ -28,7 +28,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
return;
}
LOG_DEBUG("[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination());
Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination());
if (state) {
this->m_actionTrue->Handle(context, bitStream, branch);

View File

@@ -5,7 +5,7 @@
#include "BehaviorBranchContext.h"
#include "CDActivitiesTable.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "EntityManager.h"
@@ -13,7 +13,7 @@ void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
float value{};
if (!bitStream->Read(value)) {
LOG("Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};

View File

@@ -1,7 +1,7 @@
#include "TacArcBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "Entity.h"
#include "BehaviorContext.h"
#include "BaseCombatAIComponent.h"
@@ -16,7 +16,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
if (this->m_usePickedTarget && branch.target != LWOOBJID_EMPTY) {
auto target = Game::entityManager->GetEntity(branch.target);
if (!target) LOG("target %llu is null", branch.target);
if (!target) Game::logger->Log("TacArcBehavior", "target %llu is null", branch.target);
else {
targets.push_back(target);
context->FilterTargets(targets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
@@ -29,7 +29,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
bool hasTargets = false;
if (!bitStream->Read(hasTargets)) {
LOG("Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("TacArcBehavior", "Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -37,7 +37,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
bool blocked = false;
if (!bitStream->Read(blocked)) {
LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -50,12 +50,12 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
if (hasTargets) {
uint32_t count = 0;
if (!bitStream->Read(count)) {
LOG("Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
if (count > m_maxTargets) {
LOG("Bitstream has too many targets Max:%i Recv:%i", this->m_maxTargets, count);
Game::logger->Log("TacArcBehavior", "Bitstream has too many targets Max:%i Recv:%i", this->m_maxTargets, count);
return;
}
@@ -63,7 +63,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
LWOOBJID id{};
if (!bitStream->Read(id)) {
LOG("Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
@@ -71,7 +71,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
auto* canidate = Game::entityManager->GetEntity(id);
if (canidate) targets.push_back(canidate);
} else {
LOG("Bitstream has LWOOBJID_EMPTY as a target!");
Game::logger->Log("TacArcBehavior", "Bitstream has LWOOBJID_EMPTY as a target!");
}
}
@@ -85,7 +85,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) {
LOG("Invalid self for (%llu)!", context->originator);
Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator);
return;
}

View File

@@ -3,14 +3,14 @@
#include "BehaviorContext.h"
#include "BaseCombatAIComponent.h"
#include "EntityManager.h"
#include "Logger.h"
#include "dLogger.h"
void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
@@ -26,7 +26,7 @@ void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
LOG("Failed to find target (%llu)!", branch.target);
Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "NiPoint3.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
@@ -18,7 +18,7 @@ void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) {
LOG("Invalid self for (%llu)", context->originator);
Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)", context->originator);
return;
}

View File

@@ -540,7 +540,7 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) {
LOG("Invalid entity for checking validity (%llu)!", target);
Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!", target);
return false;
}
@@ -554,7 +554,7 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
auto* referenceDestroyable = m_Parent->GetComponent<DestroyableComponent>();
if (referenceDestroyable == nullptr) {
LOG("Invalid reference destroyable component on (%llu)!", m_Parent->GetObjectID());
Game::logger->Log("BaseCombatAIComponent", "Invalid reference destroyable component on (%llu)!", m_Parent->GetObjectID());
return false;
}

View File

@@ -47,7 +47,7 @@ struct AiSkillEntry
*/
class BaseCombatAIComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI;
BaseCombatAIComponent(Entity* parentEntity, uint32_t id);
~BaseCombatAIComponent() override;

View File

@@ -4,7 +4,7 @@
#include "dZoneManager.h"
#include "SwitchComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "GameMessages.h"
#include <BitStream.h>
#include "eTriggerEventType.h"
@@ -81,13 +81,13 @@ void BouncerComponent::LookupPetSwitch() {
Game::entityManager->SerializeEntity(m_Parent);
LOG("Loaded pet bouncer");
Game::logger->Log("BouncerComponent", "Loaded pet bouncer");
}
}
}
if (!m_PetSwitchLoaded) {
LOG("Failed to load pet bouncer");
Game::logger->Log("BouncerComponent", "Failed to load pet bouncer");
m_Parent->AddCallbackTimer(0.5f, [this]() {
LookupPetSwitch();

View File

@@ -12,7 +12,7 @@
*/
class BouncerComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER;
BouncerComponent(Entity* parentEntity);
~BouncerComponent() override;

View File

@@ -4,7 +4,7 @@
#include <stdexcept>
#include "DestroyableComponent.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "GameMessages.h"
#include "SkillComponent.h"
#include "ControllablePhysicsComponent.h"
@@ -334,7 +334,7 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
param.values.push_back(value);
} catch (std::invalid_argument& exception) {
LOG("Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
Game::logger->Log("BuffComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
}
}

View File

@@ -42,7 +42,7 @@ struct Buff
*/
class BuffComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF;
explicit BuffComponent(Entity* parent);

View File

@@ -4,7 +4,7 @@
#include "GameMessages.h"
#include "Entity.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "InventoryComponent.h"
#include "Item.h"
#include "PropertyManagementComponent.h"
@@ -24,7 +24,7 @@ void BuildBorderComponent::OnUse(Entity* originator) {
if (!entities.empty()) {
buildArea = entities[0]->GetObjectID();
LOG("Using PropertyPlaque");
Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque");
}
auto* inventoryComponent = originator->GetComponent<InventoryComponent>();
@@ -41,7 +41,7 @@ void BuildBorderComponent::OnUse(Entity* originator) {
inventoryComponent->PushEquippedItems();
LOG("Starting with %llu", buildArea);
Game::logger->Log("BuildBorderComponent", "Starting with %llu", buildArea);
if (PropertyManagementComponent::Instance() != nullptr) {
GameMessages::SendStartArrangingWithItem(

View File

@@ -16,7 +16,7 @@
*/
class BuildBorderComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BUILD_BORDER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BUILD_BORDER;
BuildBorderComponent(Entity* parent);
~BuildBorderComponent() override;

View File

@@ -3,13 +3,11 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"BuffComponent.cpp"
"BuildBorderComponent.cpp"
"CharacterComponent.cpp"
"CollectibleComponent.cpp"
"Component.cpp"
"ControllablePhysicsComponent.cpp"
"DestroyableComponent.cpp"
"DonationVendorComponent.cpp"
"InventoryComponent.cpp"
"ItemComponent.cpp"
"LevelProgressionComponent.cpp"
"LUPExhibitComponent.cpp"
"MissionComponent.cpp"
@@ -44,7 +42,4 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"SwitchComponent.cpp"
"TriggerComponent.cpp"
"VehiclePhysicsComponent.cpp"
"VendorComponent.cpp"
"ZoneControlComponent.cpp"
PARENT_SCOPE
)
"VendorComponent.cpp" PARENT_SCOPE)

View File

@@ -2,7 +2,7 @@
#include <BitStream.h>
#include "tinyxml2.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "GeneralUtils.h"
#include "dServer.h"
#include "dZoneManager.h"
@@ -16,7 +16,6 @@
#include "Amf3.h"
#include "eGameMasterLevel.h"
#include "eGameActivity.h"
#include <ctime>
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
m_Character = character;
@@ -179,7 +178,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
if (!character) {
LOG("Failed to find char tag while loading XML!");
Game::logger->Log("CharacterComponent", "Failed to find char tag while loading XML!");
return;
}
if (character->QueryAttribute("rpt", &m_Reputation) == tinyxml2::XML_NO_ATTRIBUTE) {
@@ -284,7 +283,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* minifig = doc->FirstChildElement("obj")->FirstChildElement("mf");
if (!minifig) {
LOG("Failed to find mf tag while updating XML!");
Game::logger->Log("CharacterComponent", "Failed to find mf tag while updating XML!");
return;
}
@@ -304,7 +303,7 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
if (!character) {
LOG("Failed to find char tag while updating XML!");
Game::logger->Log("CharacterComponent", "Failed to find char tag while updating XML!");
return;
}
@@ -352,7 +351,7 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
//
auto newUpdateTimestamp = std::time(nullptr);
LOG("Time since last save: %d", newUpdateTimestamp - m_LastUpdateTimestamp);
Game::logger->Log("TotalTimePlayed", "Time since last save: %d", newUpdateTimestamp - m_LastUpdateTimestamp);
m_TotalTimePlayed += newUpdateTimestamp - m_LastUpdateTimestamp;
character->SetAttribute("time", m_TotalTimePlayed);
@@ -382,7 +381,7 @@ Item* CharacterComponent::GetRocket(Entity* player) {
}
if (!rocket) {
LOG("Unable to find rocket to equip!");
Game::logger->Log("CharacterComponent", "Unable to find rocket to equip!");
return rocket;
}
return rocket;

View File

@@ -62,7 +62,7 @@ enum StatisticID {
*/
class CharacterComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::CHARACTER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::CHARACTER;
CharacterComponent(Entity* parent, Character* character);
~CharacterComponent() override;

View File

@@ -1,5 +0,0 @@
#include "CollectibleComponent.h"
void CollectibleComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
outBitStream->Write(GetCollectibleId());
}

View File

@@ -1,18 +0,0 @@
#ifndef __COLLECTIBLECOMPONENT__H__
#define __COLLECTIBLECOMPONENT__H__
#include "Component.h"
#include "eReplicaComponentType.h"
class CollectibleComponent : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::COLLECTIBLE;
CollectibleComponent(Entity* parentEntity, int32_t collectibleId) : Component(parentEntity), m_CollectibleId(collectibleId) {}
int16_t GetCollectibleId() const { return m_CollectibleId; }
void Serialize(RakNet::BitStream* outBitStream, bool isConstruction) override;
private:
int16_t m_CollectibleId = 0;
};
#endif //!__COLLECTIBLECOMPONENT__H__

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