Compare commits

..

32 Commits

Author SHA1 Message Date
EmosewaMC
383146a5c4 DIagnostics: Strengthened check 2023-11-07 14:04:02 -08:00
Gie "Max" Vanommeslaeghe
4c10faa852 Merge pull request #1265 from DarkflameUniverse/ugc_patch
fix: Ugc Remove async and second id usage
2023-11-07 19:09:37 +01:00
Gie "Max" Vanommeslaeghe
070d4a1fa8 Merge pull request #1267 from DarkflameUniverse/dummyfix
fix: Nexus Tower Combat Challenge exploding dummy
2023-11-07 19:03:12 +01:00
David Markowitz
6795dd189c CombatChallenge: Fix exploding dummy 2023-11-06 14:49:53 -08:00
David Markowitz
f40fce7711 Ugc: Remove async and second id usage 2023-11-06 01:41:28 -08:00
David Markowitz
797abb176a ChatFilter: Fix incorrect segment highlighting (#1255) 2023-11-05 17:19:26 -06:00
David Markowitz
0f9e951162 Database: Use null for accounts (#1253) 2023-11-05 01:00:31 -08:00
David Markowitz
cea0b98edf WorldServer: Fix crash from deleting last char (#1254)
Revert "WorldServer: Fix crash from deleting last char"

This reverts commit d9adafa1fef0ac88ed2b3b8ca6b97c2421a603e2.

Update WorldServer.cpp
2023-11-05 01:00:19 -08:00
David Markowitz
1e2d5605eb fix: Navmesh updates to Frostburgh and Forbidden Valley (#1251)
* Navmesh: Add Frostburgh mesh

* Navmesh: Add Frostburgh mesh

Also edit Forbidden Valley mesh
2023-11-04 10:42:39 -05:00
David Markowitz
32cf111810 Script: Fix incorrect kill method (#1248) 2023-11-04 10:42:28 -05:00
David Markowitz
65c743527e Add null check for loot drops (#1243)
fixes a crash
2023-10-28 05:32:19 -05:00
79752c9abc chore: remove rarity table debug log (#1245)
cause it's too noisy
2023-10-28 05:31:54 -05:00
David Markowitz
01efa72aad fix: Update navmeshes (#1229)
* re-add x and z checking for height

Now that we have better navmeshes, this will result in much better results and as such we can re-enable this check.

* Always run navmesh extraction

waste of time most of the time, but no other way to force update to the meshes easily.

* Navmeshes Version 2

- Add all missing zones
- Drastically improve several zones and their navmeshes, cleaning them up, making them more accurate and generally using more features of detour/recast.

* Update CMakeLists.txt

* update meshes

* Navmesh: Add pet cove navmesh

* Navmesh: Fix navmesh for fv
2023-10-27 23:19:43 -05:00
6f3950dae7 chore: remove uneeded old perm map check (#1240)
and remove unused softban perm
RIP DLU beta
2023-10-25 11:44:57 -05:00
David Markowitz
a5e46e2844 Chat: Fix possible nullptr access (#1238)
Fixes a possible nullptr access.  This is the only call to GetPlayerData where we do not check the result for some reason, so this PR adds in the check and a resulting log line.

Code compiles, unsure how to reproduce the issue, however here is the crash dump I used to deduce this being the possible issue

```

Error: signal 11:
[00] CatchUnhandled(int)(+0x316) [0x561469100336]
[01] /lib/x86_64-linux-gnu/libc.so.6(+0x42520) [0x7f65e8e45520]
[02] /DarkflameServer/build/ChatServer(+0x32719) [0x5614690fa719]
[03] HandlePacket(Packet*)(+0x2a0) [0x5614690fcfb0]
[04] /DarkflameServer/build/ChatServer(main+0x92e) [0x5614690fb75e]
[05] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7f65e8e2cd90]
[06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7f65e8e2ce40]
[07] /DarkflameServer/build/ChatServer(_start+0x25) [0x5614690fc375]
```
2023-10-24 02:26:55 -07:00
David Markowitz
3a37f9581c Character Select: Fix deleted memory access (#1237) 2023-10-24 02:26:39 -07:00
David Markowitz
025ff593ce Script: Fix unupdated new component (#1236) 2023-10-23 13:25:07 -07:00
aab60567ba fix: adding a proximity monitor when one exists already (#1235) 2023-10-23 12:24:17 -05:00
David Markowitz
9aa81f95cc Script: Fix crashes (#1233) 2023-10-23 09:56:12 -05:00
David Markowitz
5ea06f9bda EntityManager: Fix iterator invalidation (#1234)
Tested that servers still start up, and that zones like bons no longer hard crash when all players have left the world.
2023-10-23 08:55:38 -05:00
David Markowitz
ae349d6b15 feat: Add isolated and simplified path to add components (#1204)
* Components: Make ComponentType inline

Prevents the next commits ODR violation

* Components: Add new components

* Entity: Add headers

inline script component ComponentType

* Components: Flip constructor argument order

Entity comes first always

* Entity: Add generic AddComponent

Allows for much easier adding of components and is error proof by not allowing the user to add more than 1 of a specific component type to an Entity.

* Entity: Migrate all component constructors

Move all to the new variadic templates AddComponent function to reduce clutter and ways the component map is modified.
The new function makes no assumptions.  Component is assumed to not exist and is checked for with operator[].  This will construct a null component which will then be newed if the component didnt exist, or it will just get the current component if it does already exist.  No new component will be allocated or constructed if the component already exists and the already existing pointer is returned instead.

* Entity: Add placement new

For the case where the component may already exist, use a placement new to construct the component again, it would be constructed again, but would not need to go through the allocator.

* Entity: Add comments on likely new code

* Tests: Fix tests

* Update Entity.cpp

* Update SGCannon.cpp

* Entity: call destructor when re-constructing

* Update Entity.cpp

Update Entity.cpp

---------

Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com>
2023-10-22 20:08:49 -05:00
David Markowitz
22207ea9c9 Diagnostics: Fix error file (#1231) 2023-10-22 19:58:19 -05:00
David Markowitz
23d71340c9 Scripts: Fix possible nullptr access (#1232)
unsure how to reproduce the actual bug, however we can see that with the following crash dump
```
Entity::GetComponent(eReplicaComponentType) const(+0x4) [0x56095665e634]
BossSpiderQueenEnemyServer::OnDie(Entity*, Entity*)(+0x28d) [0x560956795d0d]
Entity::Kill(Entity*)(+0xf8) [0x5609566637a8]
ZoneAgProperty::BaseTimerDone(Entity*, std::string const&)(+0x89b) [0x56095683736b]
Entity::Update(float)(+0x2b6) [0x560956662676]
EntityManager::UpdateEntities(float)(+0x2e) [0x56095667305e]
```
that the actual crash issue starts at
```
Entity::Kill(Entity*)(+0xf8) [0x5609566637a8]
ZoneAgProperty::BaseTimerDone(Entity*, std::string const&)
```
BaseTimerDone calls Kill, and there is only 1 call to Kill in the function which calls Kill no arguments, meaning the killer is a nullptr.  This propogates its way to the BossSpiderQueenEnemyServer::OnDie wherein we blindly check the killer pointer without verifying that the pointer is actually valid.

This patch simply checks that killer is valid before access to address the hole.
2023-10-22 14:53:54 -07:00
David Markowitz
5942182486 feat: Abstract Logger and simplify code (#1207)
* Logger: Rename logger to Logger from dLogger

* Logger: Add compile time filename

Fix include issues
Add writers
Add macros
Add macro to force compilation

* Logger: Replace calls with macros

Allows for filename and line number to be logged

* Logger: Add comments

and remove extra define

Logger: Replace with unique_ptr

also flush console at exit. regular file writer should be flushed on file close.

Logger: Remove constexpr on variable

* Logger: Simplify code

* Update Logger.cpp
2023-10-21 16:31:55 -07:00
David Markowitz
131239538b Entity: Add missing destroyable case (#1228)
Adds a missing edge case on the client where you may have the is_smashable flag set, but dont actually have a destroyable component.  In this case you should create only a destroyable component and add it to the component and serialize it last after all other data.  We also needed to add the set_faction var reading and setting as this is how Oliver Sudden actually gets their faction since they have no actual information in the database, it is all stored in ldf keys.

Tested that Oliver Sudden no longer logs Unable to unserialize logs when serialized or constructed.
2023-10-19 12:42:43 -05:00
Gie "Max" Vanommeslaeghe
4c507e34a5 Merge pull request #1219 from DarkflameUniverse/lol
fix: Address race condition
2023-10-19 12:25:27 +02:00
David Markowitz
50921cce2d Loot: Fix rarity sorting (#1226)
Missed this step from the previous speedup.  rollloot numbers match within margin of error to numbers pre-cache improvement.
2023-10-18 09:18:47 -05:00
David Markowitz
3806891db0 Teams: Default team loot to ffa (#1224) 2023-10-18 09:18:22 -05:00
David Markowitz
ba91058736 Destroyable: Fix animated deaths (#1227)
Fixes #1222

addresses an issue where the death behavior of a destructible component was not being respected and enemies with destroyable components that had special death animations were not able to play the animation on death.  This pr adds in the hardcoded constant the client uses for the same metric of 12 seconds.

Tested that claiming Nimbus Rock and completing the property guards mission allows him to vacuum away and then network the destruction packet 12 seconds later.
2023-10-18 09:17:57 -05:00
David Markowitz
73e70badb7 Entity: fix bad ldf key serialization (#1225) 2023-10-17 08:45:46 -05:00
David Markowitz
e4cae35edb PhantomPhysics: Fix gravity (#1221)
Fix gravity not being adjusted when colliding with a phantom physics object

Tested that while on moonbase, the players gravity is no longer reset to 1 when they change their cheat info.
2023-10-16 07:55:57 -05:00
David Markowitz
2746683235 Master: Address race condition
Fix a race condition that would overwrite the port of zone 0 with the auth server port or a chat server port which would cause a domino effect of desynced server ports

Tested that a sleep(5) in auth still allows a player to connect and login without issues
2023-10-14 00:01:41 -07:00
250 changed files with 2855 additions and 2781 deletions

View File

@@ -148,17 +148,20 @@ foreach (resource_file ${RESOURCE_FILES})
endforeach()
message(STATUS "Resource file integrity check complete")
# Copy navmesh data on first build and extract it
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)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
# 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
)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PROJECT_BINARY_DIR}/navmeshes)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
# Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
foreach(file ${VANITY_FILES})

View File

@@ -7,7 +7,7 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "dLogger.h"
#include "Logger.h"
#include "Database.h"
#include "dConfig.h"
#include "Diagnostics.h"
@@ -25,14 +25,14 @@
#include "Game.h"
namespace Game {
dLogger* logger = nullptr;
Logger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
dLogger* SetupLogger();
Logger* SetupLogger();
void HandlePacket(Packet* packet);
int main(int argc, char** argv) {
@@ -51,14 +51,38 @@ 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");
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__);
LOG("Starting Auth server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
Database::Connect(Game::config);
//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");
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
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;
Game::randomEngine = std::mt19937(time(0));
@@ -68,7 +92,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, masterSock.hostAddress, masterSock.port, ServerType::Auth, Game::config, &Game::shouldShutdown);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -107,7 +131,18 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
Database::Connection->GetMasterServerIP();
//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;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -116,7 +151,9 @@ 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;
@@ -124,7 +161,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
dLogger* SetupLogger() {
Logger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -133,7 +170,7 @@ dLogger* SetupLogger() {
logDebugStatements = true;
#endif
return new dLogger(logPath, logToConsole, logDebugStatements);
return new Logger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {

View File

@@ -8,7 +8,7 @@
#include <regex>
#include "dCommonVars.h"
#include "dLogger.h"
#include "Logger.h"
#include "dConfig.h"
#include "Database.h"
#include "Game.h"
@@ -31,13 +31,16 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
ReadWordlistDCF("blacklist.dcf", false);
}
// 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));
//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));
}
delete res;
delete stmt;
}
dChatFilter::~dChatFilter() {
@@ -141,7 +144,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
listOfBadSegments.emplace_back(position, originalSegment.length());
}
position += segment.length() + 1;
position += originalSegment.length() + 1;
}
return listOfBadSegments;

View File

@@ -7,7 +7,7 @@
#include "Game.h"
#include "dServer.h"
#include "GeneralUtils.h"
#include "dLogger.h"
#include "Logger.h"
#include "eAddFriendResponseCode.h"
#include "eAddFriendResponseType.h"
#include "RakString.h"
@@ -118,6 +118,11 @@ 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;
@@ -397,7 +402,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
LOG("Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
if (channel != 8) return;
@@ -527,13 +532,13 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
if (team->memberIDs.size() > 3) {
// no more teams greater than 4
Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team");
LOG("Someone tried to invite a 5th player to a team");
return;
}
SendTeamInvite(other, player);
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
}
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
@@ -547,7 +552,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
LWOOBJID leaderID = LWOOBJID_EMPTY;
inStream.Read(leaderID);
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
LOG("Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
if (declined) {
return;
@@ -556,13 +561,13 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
auto* team = playerContainer.GetTeam(leaderID);
if (team == nullptr) {
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID);
LOG("Failed to find team for leader (%llu)", leaderID);
team = playerContainer.GetTeam(playerID);
}
if (team == nullptr) {
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID);
LOG("Failed to find team for player (%llu)", playerID);
return;
}
@@ -578,7 +583,7 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
auto* team = playerContainer.GetTeam(playerID);
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID);
LOG("(%llu) leaving team", playerID);
if (team != nullptr) {
playerContainer.RemoveMember(team, playerID, false, false, true);
@@ -592,7 +597,7 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
@@ -622,7 +627,7 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
LOG("(%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 "dLogger.h"
#include "Logger.h"
#include "Database.h"
#include "dConfig.h"
#include "dChatFilter.h"
@@ -27,7 +27,7 @@
#include <MessageIdentifiers.h>
namespace Game {
dLogger* logger = nullptr;
Logger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
dChatFilter* chatFilter = nullptr;
@@ -37,7 +37,7 @@ namespace Game {
}
dLogger* SetupLogger();
Logger* 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");
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__);
LOG("Starting Chat server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
try {
std::string clientPathStr = Game::config->GetValue("client_location");
@@ -72,15 +72,39 @@ int main(int argc, char** argv) {
Game::assetManager = new AssetManager(clientPath);
} catch (std::runtime_error& ex) {
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
LOG("Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
Database::Connect(Game::config);
//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");
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
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;
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50;
@@ -88,7 +112,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, masterSock.hostAddress, masterSock.port, ServerType::Chat, Game::config, &Game::shouldShutdown);
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::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
@@ -131,7 +155,18 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
Database::Connection->GetMasterServerIP();
//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;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -141,8 +176,8 @@ int main(int argc, char** argv) {
std::this_thread::sleep_until(t);
}
// Delete our objects here:
Database::Destroy();
//Delete our objects here:
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
delete Game::config;
@@ -150,7 +185,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
dLogger* SetupLogger() {
Logger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -159,16 +194,16 @@ dLogger* SetupLogger() {
logDebugStatements = true;
#endif
return new dLogger(logPath, logToConsole, logDebugStatements);
return new Logger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
LOG("A server has disconnected, erasing their connected players from the list.");
}
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
LOG("A server is connecting, awaiting user list.");
}
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
@@ -199,7 +234,7 @@ void HandlePacket(Packet* packet) {
}
default:
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
@@ -210,7 +245,7 @@ void HandlePacket(Packet* packet) {
break;
case eChatMessageType::GET_IGNORE_LIST:
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
LOG("Asked for ignore list, but is unimplemented right now.");
break;
case eChatMessageType::TEAM_GET_STATUS:
@@ -268,19 +303,19 @@ void HandlePacket(Packet* packet) {
break;
default:
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
LOG("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: {
Game::logger->Log("ChatServer", "Routing packet from world");
LOG("Routing packet from world");
break;
}
default:
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
LOG("Unknown World id: %i", int(packet->data[3]));
}
}
}

View File

@@ -3,7 +3,7 @@
#include <iostream>
#include <algorithm>
#include "Game.h"
#include "dLogger.h"
#include "Logger.h"
#include "ChatPacketHandler.h"
#include "GeneralUtils.h"
#include "BitStreamUtils.h"
@@ -11,6 +11,7 @@
#include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "ChatPackets.h"
#include "dConfig.h"
PlayerContainer::PlayerContainer() {
}
@@ -19,6 +20,10 @@ 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();
@@ -39,9 +44,16 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
mPlayers.insert(std::make_pair(data->playerID, data));
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
LOG("Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Database::Connection->InsertIntoActivityLog(data->playerID, 0, time(nullptr), 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();
}
void PlayerContainer::RemovePlayer(Packet* packet) {
@@ -75,10 +87,17 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
}
}
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
LOG("Removed user: %llu", playerID);
mPlayers.erase(playerID);
Database::Connection->InsertIntoActivityLog(playerID, 1, time(nullptr), player->zoneID.GetMapID());
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();
}
void PlayerContainer::MuteUpdate(Packet* packet) {
@@ -91,7 +110,7 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
auto* player = this->GetPlayerData(playerID);
if (player == nullptr) {
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
LOG("Failed to find user: %llu", playerID);
return;
}
@@ -195,7 +214,7 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4){
Game::logger->Log("PlayerContainer", "Tried to add player to team that already had 4 players");
LOG("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,6 +18,7 @@ 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 "dLogger.h"
#include "Logger.h"
#include "Game.h"
#include <unordered_map>

View File

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

View File

@@ -1,93 +1,35 @@
#include "MySQLMigration.h"
#include "BrickByBrickFix.h"
#include <istream>
#include <memory>
#include <iostream>
#include <sstream>
#include "CDClientDatabase.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "dLogger.h"
#include "BinaryPathFinder.h"
#include "ZCompression.h"
#include "tinyxml2.h"
#include "../MySQL.h"
#include "Database.h"
#include "Game.h"
#include "ZCompression.h"
#include "Logger.h"
void MigrationRunner::RunMigrations(DatabaseBase* db) {
auto database = dynamic_cast<MySQLDatabase*>(db);
//! Forward declarations
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;
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
void WriteSd0Magic(char* input, uint32_t chunkSize);
bool CheckSd0Magic(sql::Blob* streamToCheck);
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) {
/**
* @brief Truncates all models with broken data from the database.
*
* @return The number of models deleted
*/
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
uint32_t modelsTruncated{};
auto modelsToTruncate = GetModelsFromDatabase(database);
bool previousCommitValue = database->GetAutoCommit();
database->SetAutoCommit(false);
auto modelsToTruncate = GetModelsFromDatabase();
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);
@@ -117,14 +59,14 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
completeUncompressedModel.append((char*)uncompressedChunk.get());
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
} else {
Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
LOG("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) {
Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting.");
LOG("Failed to initialize tinyxml document. Aborting.");
return 0;
}
@@ -133,8 +75,7 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
"</LXFML>",
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
) {
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
LOG("Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -143,8 +84,7 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
}
}
} else {
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
LOG("Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -153,8 +93,8 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
}
}
database->Commit();
database->SetAutoCommit(previousCommitValue);
Database::Commit();
Database::SetAutoCommit(previousCommitValue);
return modelsTruncated;
}
@@ -164,14 +104,12 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
*
* @return The number of models updated to SD0
*/
uint32_t UpdateBrickByBrickModelsToSd0(MySQLDatabase* database) {
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
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));
@@ -200,24 +138,21 @@ uint32_t UpdateBrickByBrickModelsToSd0(MySQLDatabase* database) {
insertionStatement->setInt64(2, modelId);
try {
insertionStatement->executeUpdate();
Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId);
LOG("Updated model %i to sd0", modelId);
updatedModels++;
} catch (sql::SQLException exception) {
Game::logger->Log(
"BrickByBrickFix",
"Failed to update model %i. This model should be inspected manually to see why."
LOG("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(MySQLDatabase* database) {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(database->CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase() {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
return std::unique_ptr<sql::ResultSet>(modelsRawDataQuery->executeQuery());
}

20
dCommon/BrickByBrickFix.h Normal file
View File

@@ -0,0 +1,20 @@
#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"
"dLogger.cpp"
"Logger.cpp"
"GeneralUtils.cpp"
"LDFFormat.cpp"
"MD5.cpp"
@@ -14,6 +14,7 @@ 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 "dLogger.h"
#include "Logger.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 "dLogger.h"
#include "Logger.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);
}
Game::logger->Log("Diagnostics", "Creating crash dump %s", name);
LOG("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";
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
LOG("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";
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
LOG("Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
if (Diagnostics::GetProduceMemoryDump()) {
GenerateDump();
}
@@ -134,6 +134,10 @@ 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]'
@@ -141,7 +145,8 @@ void CatchUnhandled(int sig) {
std::string functionName = strings[i];
std::string::size_type start = functionName.find('(');
std::string::size_type end = functionName.find('+');
if (start != std::string::npos && end != std::string::npos) {
// strengthened check
if (start != std::string::npos && start + 1 < functionName.size() && end != std::string::npos && start < end) {
std::string demangled = functionName.substr(start + 1, end - start - 1);
demangled = Demangler::Demangle(demangled.c_str());
@@ -154,20 +159,15 @@ void CatchUnhandled(int sig) {
}
}
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
LOG("[%02zu] %s", i, functionName.c_str());
if (file != NULL) {
fprintf(file, "[%02zu] %s\n", 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 "dLogger.h"
#include "Logger.h"
#include "AssetManager.h"
#include "eSqliteDataType.h"
@@ -44,7 +44,7 @@ bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) {
Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage());
LOG("Encountered error %s converting FDB to SQLite", e.errorMessage());
return false;
}

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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) {
Game::logger->Log("LDFFormat", "Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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)) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("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: {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
LOG("Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
break;
}
default: {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
LOG("Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
break;
}
}

96
dCommon/Logger.cpp Normal file
View File

@@ -0,0 +1,96 @@
#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;
}

89
dCommon/Logger.h Normal file
View File

@@ -0,0 +1,89 @@
#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 "dLogger.h"
#include "Logger.h"
#include <zlib.h>

View File

@@ -3,6 +3,7 @@
#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 "dLogger.h"
#include "Logger.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);
}
Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
LOG("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,20 +27,6 @@ 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__

View File

@@ -1,110 +0,0 @@
#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
}

View File

@@ -1,38 +0,0 @@
#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,6 +1,7 @@
set(DDATABASE_SOURCES "CDClientDatabase.cpp"
"CDClientManager.cpp"
"Database.cpp")
"Database.cpp"
"MigrationRunner.cpp")
add_subdirectory(Tables)
@@ -8,17 +9,5 @@ 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,26 +1,118 @@
#include "Database.h"
#include "Game.h"
#include "dConfig.h"
#include "Logger.h"
using namespace std;
#include "Databases/MySQL.h"
#pragma warning (disable:4251) //Disables SQL warnings
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;
}
sql::Driver* Database::driver;
sql::Connection* Database::con;
sql::Properties Database::props;
std::string Database::database;
if (useSqlite) {
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
//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 {
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 = 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->Connect();
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();
}
void Database::Destroy() {
Database::Connection->Destroy();
delete Database::Connection;
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);
}

View File

@@ -1,16 +1,31 @@
#pragma once
#include <string>
#include <conncpp.hpp>
#include "Databases/DatabaseBase.h"
class dConfig;
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 Database {
private:
static sql::Driver* driver;
static sql::Connection* con;
static sql::Properties props;
static std::string database;
public:
static DatabaseBase* Connection;
static eConnectionTypes ConnectionType;
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 void Connect(dConfig* config);
static void Destroy();
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; }
};

View File

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

View File

@@ -1,100 +0,0 @@
#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

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

View File

@@ -1,90 +0,0 @@
#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

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

View File

@@ -1,651 +0,0 @@
#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

@@ -1,99 +0,0 @@
#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

@@ -1,49 +0,0 @@
#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

@@ -0,0 +1,158 @@
#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

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

View File

@@ -1,4 +1,32 @@
#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{};
@@ -32,6 +60,9 @@ 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) {
@@ -49,6 +80,7 @@ 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 "dLogger.h"
#include "Logger.h"
#include "BitStream.h"
#include "Game.h"
#include <chrono>
@@ -26,16 +26,39 @@ Character::Character(uint32_t id, User* parentUser) {
//First load the name, etc:
m_ID = id;
// 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;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
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;
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.
@@ -62,16 +85,38 @@ Character::~Character() {
}
void Character::UpdateFromDatabase() {
// 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;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
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;
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.
@@ -100,16 +145,16 @@ void Character::DoQuickXMLDataParse() {
if (!m_Doc) return;
if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) {
Game::logger->Log("Character", "Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
} else {
Game::logger->Log("Character", "Failed to load xmlData!");
LOG("Failed to load xmlData!");
//Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true);
return;
}
tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf");
if (!mf) {
Game::logger->Log("Character", "Failed to find mf tag!");
LOG("Failed to find mf tag!");
return;
}
@@ -128,14 +173,14 @@ void Character::DoQuickXMLDataParse() {
tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv");
if (!inv) {
Game::logger->Log("Character", "Char has no inv!");
LOG("Char has no inv!");
return;
}
tinyxml2::XMLElement* bag = inv->FirstChildElement("items")->FirstChildElement("in");
if (!bag) {
Game::logger->Log("Character", "Couldn't find bag0!");
LOG("Couldn't find bag0!");
return;
}
@@ -328,7 +373,7 @@ void Character::SaveXMLToDatabase() {
//Call upon the entity to update our xmlDoc:
if (!m_OurEntity) {
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());
LOG("%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
return;
}
@@ -339,7 +384,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;
Game::logger->Log("Character", "%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
LOG("%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
}
void Character::SetIsNewLogin() {
@@ -349,23 +394,29 @@ void Character::SetIsNewLogin() {
auto* currentChild = flags->FirstChildElement();
while (currentChild) {
auto* nextChild = currentChild->NextSiblingElement();
if (currentChild->Attribute("si")) {
flags->DeleteChild(currentChild);
Game::logger->Log("Character", "Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str());
LOG("Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str());
WriteToDatabase();
}
currentChild = currentChild->NextSiblingElement();
currentChild = nextChild;
}
}
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();
// Save to DB
Database::Connection->UpdateCharacterXML(m_ID, m_XMLData);
//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;
}
void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
@@ -504,15 +555,6 @@ 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 "dLogger.h"
#include "Logger.h"
#include <PacketUtils.h>
#include <functional>
#include "CDDestructibleComponentTable.h"
@@ -76,6 +76,10 @@
#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"
@@ -95,7 +99,6 @@ 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;
@@ -153,7 +156,7 @@ void Entity::Initialize() {
const auto triggerInfo = GetVarAsString(u"trigger_id");
if (!triggerInfo.empty()) m_Components.emplace(eReplicaComponentType::TRIGGER, new TriggerComponent(this, triggerInfo));
if (!triggerInfo.empty()) AddComponent<TriggerComponent>(triggerInfo);
/**
* Setup groups
@@ -184,21 +187,17 @@ void Entity::Initialize() {
if (m_TemplateID == 14) {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this);
m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp));
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
ModelComponent* modelcomp = new ModelComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, modelcomp));
AddComponent<ModelComponent>();
RenderComponent* render = new RenderComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
AddComponent<RenderComponent>();
auto destroyableComponent = new DestroyableComponent(this);
auto* destroyableComponent = AddComponent<DestroyableComponent>();
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;
}
@@ -210,49 +209,46 @@ void Entity::Initialize() {
*/
if (GetParentUser()) {
auto missions = new MissionComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MISSION, missions));
missions->LoadFromXml(m_Character->GetXMLDoc());
AddComponent<MissionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
}
uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET);
if (petComponentId > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::PET, new PetComponent(this, petComponentId)));
AddComponent<PetComponent>(petComponentId);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::ZONE_CONTROL, nullptr));
AddComponent<ZoneControlComponent>();
}
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
if (possessableComponentId > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSABLE, new PossessableComponent(this, possessableComponentId)));
AddComponent<PossessableComponent>(possessableComponentId);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY) > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::MODULE_ASSEMBLY, new ModuleAssemblyComponent(this)));
AddComponent<ModuleAssemblyComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS) > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_STATS, nullptr));
AddComponent<RacingStatsComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1) >= 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::LUP_EXHIBIT, new LUPExhibitComponent(this)));
AddComponent<LUPExhibitComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL) > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_CONTROL, new RacingControlComponent(this)));
AddComponent<RacingControlComponent>();
}
const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_ENTRANCE);
if (propertyEntranceComponentID > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY_ENTRANCE,
new PropertyEntranceComponent(propertyEntranceComponentID, this)));
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) {
ControllablePhysicsComponent* controllablePhysics = new ControllablePhysicsComponent(this);
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>();
if (m_Character) {
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
@@ -285,8 +281,6 @@ 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.
@@ -294,67 +288,56 @@ void Entity::Initialize() {
const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS);
if (!markedAsPhantom && simplePhysicsComponentID > 0) {
SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this);
m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp));
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) {
RigidbodyPhantomPhysicsComponent* comp = new RigidbodyPhantomPhysicsComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, comp));
AddComponent<RigidbodyPhantomPhysicsComponent>();
}
if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) {
PhantomPhysicsComponent* phantomPhysics = new PhantomPhysicsComponent(this);
phantomPhysics->SetPhysicsEffectActive(false);
m_Components.insert(std::make_pair(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysics));
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) {
VehiclePhysicsComponent* vehiclePhysicsComponent = new VehiclePhysicsComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent));
auto* vehiclePhysicsComponent = AddComponent<VehiclePhysicsComponent>();
vehiclePhysicsComponent->SetPosition(m_DefaultPosition);
vehiclePhysicsComponent->SetRotation(m_DefaultRotation);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
auto* comp = new SoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp));
AddComponent<SoundTriggerComponent>();
} else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) {
auto* comp = new RacingSoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_SOUND_TRIGGER, comp));
AddComponent<RacingSoundTriggerComponent>();
}
//Also check for the collectible id:
m_CollectibleID = GetVarAs<int32_t>(u"collectible_id");
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF) > 0) {
BuffComponent* comp = new BuffComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::BUFF, comp));
AddComponent<BuffComponent>();
}
int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE);
if (collectibleComponentID > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::COLLECTIBLE, nullptr));
AddComponent<CollectibleComponent>(GetVarAs<int32_t>(u"collectible_id"));
}
/**
* 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 = 0;
int componentID = -1;
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); });
if (buffComponentID > 0 || collectibleComponentID > 0) {
DestroyableComponent* comp = new DestroyableComponent(this);
bool isSmashable = GetVarAs<int32_t>(u"is_smashable") != 0;
if (buffComponentID > 0 || collectibleComponentID > 0 || isSmashable) {
DestroyableComponent* comp = AddComponent<DestroyableComponent>();
if (m_Character) {
comp->LoadFromXml(m_Character->GetXMLDoc());
} else {
@@ -373,6 +356,7 @@ 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);
@@ -393,7 +377,7 @@ void Entity::Initialize() {
}
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
comp->SetIsSmashable(comp->GetIsSmashable() | (GetVarAs<int32_t>(u"is_smashable") != 0));
comp->SetIsSmashable(comp->GetIsSmashable() | isSmashable);
}
} else {
comp->SetHealth(1);
@@ -426,35 +410,39 @@ void Entity::Initialize() {
}
}
m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp));
// 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);
}
}
}
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER) > 0 || m_Character) {
// Character Component always has a possessor, level, and forced movement components
m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSOR, new PossessorComponent(this)));
AddComponent<PossessorComponent>();
// load in the xml for the level
auto* levelComp = new LevelProgressionComponent(this);
levelComp->LoadFromXml(m_Character->GetXMLDoc());
m_Components.insert(std::make_pair(eReplicaComponentType::LEVEL_PROGRESSION, levelComp));
AddComponent<LevelProgressionComponent>()->LoadFromXml(m_Character->GetXMLDoc());
m_Components.insert(std::make_pair(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, new PlayerForcedMovementComponent(this)));
AddComponent<PlayerForcedMovementComponent>();
CharacterComponent* charComp = new CharacterComponent(this, m_Character);
charComp->LoadFromXml(m_Character->GetXMLDoc());
m_Components.insert(std::make_pair(eReplicaComponentType::CHARACTER, charComp));
AddComponent<CharacterComponent>(m_Character)->LoadFromXml(m_Character->GetXMLDoc());
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) {
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));
auto* xmlDoc = m_Character ? m_Character->GetXMLDoc() : nullptr;
AddComponent<InventoryComponent>(xmlDoc);
}
// 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) {
auto comp = new MultiZoneEntranceComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::MULTI_ZONE_ENTRANCE, comp));
AddComponent<MultiZoneEntranceComponent>();
}
/**
@@ -505,7 +493,7 @@ void Entity::Initialize() {
}
if (!scriptName.empty() || client || m_Character || scriptComponentID >= 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty())));
AddComponent<ScriptComponent>(scriptName, true, client && scriptName.empty());
}
// ZoneControl script
@@ -517,148 +505,137 @@ void Entity::Initialize() {
if (zoneData != nullptr) {
int zoneScriptID = zoneData->scriptID;
CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID);
ScriptComponent* comp = new ScriptComponent(this, zoneScriptData.script_name, true);
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp));
AddComponent<ScriptComponent>(zoneScriptData.script_name, true);
}
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1) != -1 || m_Character) {
SkillComponent* comp = new SkillComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SKILL, comp));
AddComponent<SkillComponent>();
}
const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI);
if (combatAiId > 0) {
BaseCombatAIComponent* comp = new BaseCombatAIComponent(this, combatAiId);
m_Components.insert(std::make_pair(eReplicaComponentType::BASE_COMBAT_AI, comp));
AddComponent<BaseCombatAIComponent>(combatAiId);
}
if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) {
RebuildComponent* comp = new RebuildComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::QUICK_BUILD, comp));
auto* rebuildComponent = AddComponent<RebuildComponent>();
CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable<CDRebuildComponentTable>();
std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); });
if (rebCompData.size() > 0) {
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);
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);
const auto rebuildResetTime = GetVar<float>(u"rebuild_reset_time");
if (rebuildResetTime != 0.0f) {
comp->SetResetTime(rebuildResetTime);
rebuildComponent->SetResetTime(rebuildResetTime);
if (m_TemplateID == 9483) // Look away!
// 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)
{
comp->SetResetTime(comp->GetResetTime() + 25);
rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 25);
}
}
const auto activityID = GetVar<int32_t>(u"activityID");
if (activityID > 0) {
comp->SetActivityId(activityID);
rebuildComponent->SetActivityId(activityID);
Loot::CacheMatrix(activityID);
}
const auto compTime = GetVar<float>(u"compTime");
if (compTime > 0) {
comp->SetCompleteTime(compTime);
rebuildComponent->SetCompleteTime(compTime);
}
}
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1) != -1) {
SwitchComponent* comp = new SwitchComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SWITCH, comp));
AddComponent<SwitchComponent>();
}
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) {
VendorComponent* comp = new VendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp));
AddComponent<VendorComponent>();
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
DonationVendorComponent* comp = new DonationVendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::DONATION_VENDOR, comp));
AddComponent<DonationVendorComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
auto* component = new PropertyVendorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_VENDOR, component);
AddComponent<PropertyVendorComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1) != -1) {
auto* component = new PropertyManagementComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_MANAGEMENT, component);
AddComponent<PropertyManagementComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0
BouncerComponent* comp = new BouncerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp));
AddComponent<BouncerComponent>();
}
int32_t renderComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
if ((renderComponentId > 0 && m_TemplateID != 2365) || m_Character) {
RenderComponent* render = new RenderComponent(this, renderComponentId);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
AddComponent<RenderComponent>(renderComponentId);
}
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER) > 0) || m_Character) {
m_Components.insert(std::make_pair(eReplicaComponentType::MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID)));
AddComponent<MissionOfferComponent>(m_TemplateID);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1) != -1) {
m_Components.insert(std::make_pair(eReplicaComponentType::BUILD_BORDER, new BuildBorderComponent(this)));
AddComponent<BuildBorderComponent>();
}
// Scripted activity component
int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY);
if ((scriptedActivityID > 0)) {
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID)));
AddComponent<ScriptedActivityComponent>(scriptedActivityID);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
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);
AddComponent<ModelComponent>();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
auto* destroyableComponent = AddComponent<DestroyableComponent>();
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)) {
m_Components.insert(std::make_pair(eReplicaComponentType::ITEM, nullptr));
AddComponent<ItemComponent>();
}
// Shooting gallery component
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::SHOOTING_GALLERY, new ShootingGalleryComponent(this)));
AddComponent<ShootingGalleryComponent>();
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) {
m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY, new PropertyComponent(this)));
AddComponent<PropertyComponent>();
}
const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH);
if ((rocketId > 0)) {
m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId)));
AddComponent<RocketLaunchpadControlComponent>(rocketId);
}
const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR);
if (railComponentID > 0) {
m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID)));
AddComponent<RailActivatorComponent>(railComponentID);
}
int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI);
@@ -686,7 +663,7 @@ void Entity::Initialize() {
}
}
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
AddComponent<MovementAIComponent>(moveInfo);
}
} else if (petComponentId > 0 || combatAiId > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) {
MovementAIInfo moveInfo = MovementAIInfo();
@@ -697,19 +674,18 @@ void Entity::Initialize() {
moveInfo.wanderDelayMax = 5;
moveInfo.wanderDelayMin = 2;
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
AddComponent<MovementAIComponent>(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) {
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
// else if we are a movement path
AddComponent<MovingPlatformComponent>(pathName);
// else if we are a movement path
} /*else if (path->pathType == PathType::Movement) {
auto movementAIcomp = GetComponent<MovementAIComponent>();
if (movementAIcomp){
@@ -722,8 +698,7 @@ 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) {
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
AddComponent<MovingPlatformComponent>(pathName);
}
}
@@ -733,8 +708,7 @@ 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, ',');
ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp));
AddComponent<ProximityMonitorComponent>(std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
}
}
@@ -825,14 +799,6 @@ 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) {
@@ -861,20 +827,13 @@ void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationNa
}
void Entity::SetProximityRadius(float proxRadius, std::string name) {
ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) {
proxMon = new ProximityMonitorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon);
}
auto* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) proxMon = AddComponent<ProximityMonitorComponent>();
proxMon->SetProximityRadius(proxRadius, name);
}
void Entity::SetProximityRadius(dpEntity* entity, std::string name) {
ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) {
proxMon = new ProximityMonitorComponent(this);
m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon);
}
ProximityMonitorComponent* proxMon = AddComponent<ProximityMonitorComponent>();
proxMon->SetProximityRadius(entity, name);
}
@@ -924,10 +883,20 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke
outBitStream->Write1(); //ldf data
RakNet::BitStream settingStream;
settingStream.Write<uint32_t>(m_Settings.size());
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);
for (LDFBaseData* data : m_Settings) {
if (data) {
if (data && data->GetValueType() != eLDFType::LDF_TYPE_UNKNOWN) {
data->WriteToPacket(&settingStream);
}
}
@@ -946,7 +915,6 @@ 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);
@@ -1080,13 +1048,14 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
destroyableSerialized = true;
}
if (HasComponent(eReplicaComponentType::COLLECTIBLE)) {
CollectibleComponent* collectibleComponent;
if (TryGetComponent(eReplicaComponentType::COLLECTIBLE, collectibleComponent)) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
destroyableSerialized = true;
outBitStream->Write(m_CollectibleID); // Collectable component
collectibleComponent->Serialize(outBitStream, bIsInitialUpdate);
}
PetComponent* petComponent;
@@ -1124,8 +1093,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
characterComponent->Serialize(outBitStream, bIsInitialUpdate);
}
if (HasComponent(eReplicaComponentType::ITEM)) {
outBitStream->Write0();
ItemComponent* itemComponent;
if (TryGetComponent(eReplicaComponentType::ITEM, itemComponent)) {
itemComponent->Serialize(outBitStream, bIsInitialUpdate);
}
InventoryComponent* inventoryComponent;
@@ -1213,7 +1183,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
renderComponent->Serialize(outBitStream, bIsInitialUpdate);
}
if (modelComponent) {
if (modelComponent || !destroyableSerialized) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
@@ -1221,8 +1191,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
}
}
if (HasComponent(eReplicaComponentType::ZONE_CONTROL)) {
outBitStream->Write<uint32_t>(0x40000000);
ZoneControlComponent* zoneControlComponent;
if (TryGetComponent(eReplicaComponentType::ZONE_CONTROL, zoneControlComponent)) {
zoneControlComponent->Serialize(outBitStream, bIsInitialUpdate);
}
// BBB Component, unused currently
@@ -1552,7 +1523,17 @@ void Entity::Kill(Entity* murderer) {
}
if (!IsPlayer()) {
Game::entityManager->DestroyEntity(this);
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);
}
const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");
@@ -2068,3 +2049,8 @@ 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 { return uint8_t(m_CollectibleID); }
uint8_t GetCollectibleID() const;
Entity* GetParentEntity() const { return m_ParentEntity; }
@@ -274,6 +274,9 @@ public:
template<typename T>
T GetVarAs(const std::u16string& name) const;
template<typename ComponentType, typename... VaArgs>
ComponentType* AddComponent(VaArgs... args);
/**
* Get the LDF data.
*/
@@ -501,3 +504,36 @@ 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 "dLogger.h"
#include "Logger.h"
#include "MessageIdentifiers.h"
#include "dConfig.h"
#include "eTriggerEventType.h"
@@ -176,8 +176,9 @@ void EntityManager::DestroyEntity(Entity* entity) {
}
void EntityManager::SerializeEntities() {
for (auto entry = m_EntitiesToSerialize.begin(); entry != m_EntitiesToSerialize.end(); entry++) {
auto* entity = GetEntity(*entry);
for (int32_t i = 0; i < m_EntitiesToSerialize.size(); i++) {
const LWOOBJID toSerialize = m_EntitiesToSerialize.at(i);
auto* entity = GetEntity(toSerialize);
if (!entity) continue;
@@ -192,7 +193,7 @@ void EntityManager::SerializeEntities() {
if (entity->GetIsGhostingCandidate()) {
for (auto* player : Player::GetAllPlayers()) {
if (player->IsObserved(*entry)) {
if (player->IsObserved(toSerialize)) {
Game::server->Send(&stream, player->GetSystemAddress(), false);
}
}
@@ -204,11 +205,12 @@ void EntityManager::SerializeEntities() {
}
void EntityManager::KillEntities() {
for (auto entry = m_EntitiesToKill.begin(); entry != m_EntitiesToKill.end(); entry++) {
auto* entity = GetEntity(*entry);
for (int32_t i = 0; i < m_EntitiesToKill.size(); i++) {
const LWOOBJID toKill = m_EntitiesToKill.at(i);
auto* entity = GetEntity(toKill);
if (!entity) {
Game::logger->Log("EntityManager", "Attempting to kill null entity %llu", *entry);
LOG("Attempting to kill null entity %llu", toKill);
continue;
}
@@ -222,8 +224,9 @@ void EntityManager::KillEntities() {
}
void EntityManager::DeleteEntities() {
for (auto entry = m_EntitiesToDelete.begin(); entry != m_EntitiesToDelete.end(); entry++) {
auto entityToDelete = GetEntity(*entry);
for (int32_t i = 0; i < m_EntitiesToDelete.size(); i++) {
const LWOOBJID toDelete = m_EntitiesToDelete.at(i);
auto entityToDelete = GetEntity(toDelete);
if (entityToDelete) {
// Get all this info first before we delete the player.
auto networkIdToErase = entityToDelete->GetNetworkId();
@@ -237,9 +240,9 @@ void EntityManager::DeleteEntities() {
if (ghostingToDelete != m_EntitiesToGhost.end()) m_EntitiesToGhost.erase(ghostingToDelete);
} else {
Game::logger->Log("EntityManager", "Attempted to delete non-existent entity %llu", *entry);
LOG("Attempted to delete non-existent entity %llu", toDelete);
}
m_Entities.erase(*entry);
m_Entities.erase(toDelete);
}
m_EntitiesToDelete.clear();
}
@@ -330,7 +333,7 @@ const std::unordered_map<std::string, LWOOBJID>& EntityManager::GetSpawnPointEnt
void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr, const bool skipChecks) {
if (!entity) {
Game::logger->Log("EntityManager", "Attempted to construct null entity");
LOG("Attempted to construct null entity");
return;
}

View File

@@ -8,7 +8,7 @@
#include "Character.h"
#include "Game.h"
#include "GameMessages.h"
#include "dLogger.h"
#include "Logger.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";
Game::logger->LogDebug("LeaderboardManager", "query is %s", baseLookup.c_str());
LOG_DEBUG("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()));
Game::logger->LogDebug("LeaderboardManager", "Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
LOG_DEBUG("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:
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
LOG("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);
}
Game::logger->Log("LeaderboardManager", "save query %s %i %i", saveQuery.c_str(), playerID, activityId);
LOG("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 "dLogger.h"
#include "Logger.h"
#include "ZoneInstanceManager.h"
#include "WorldPackets.h"
#include "dZoneManager.h"
@@ -260,7 +260,7 @@ void Player::SetDroppedCoins(uint64_t value) {
}
Player::~Player() {
Game::logger->Log("Player", "Deleted player");
LOG("Deleted player");
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
const auto id = m_ObservedEntities[i];

View File

@@ -1,8 +1,14 @@
#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,16 +2,15 @@
#include "Entity.h"
struct Team
{
struct Team {
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 "dLogger.h"
#include "Logger.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;
Game::logger->Log("Trade", "Accepted from A (%d), B: (%d)", value, m_AcceptedB);
LOG("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;
Game::logger->Log("Trade", "Accepted from B (%d), A: (%d)", value, m_AcceptedA);
LOG("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) {
Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade.");
LOG("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) {
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str());
LOG("Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str());
return;
}
} else {
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str());
LOG("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) {
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str());
LOG("Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str());
return;
}
} else {
Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str());
LOG("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;
Game::logger->Log("Trade", "Attempting to send trade update");
LOG("Attempting to send trade update");
if (participant == m_ParticipantA) {
other = GetParticipantBEntity();
@@ -228,7 +228,7 @@ void Trade::SendUpdateToOther(LWOOBJID participant) {
items.push_back(tradeItem);
}
Game::logger->Log("Trade", "Sending trade update");
LOG("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;
Game::logger->Log("TradingManager", "Created new trade between (%llu) <-> (%llu)", participantA, participantB);
LOG("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 "dLogger.h"
#include "Logger.h"
#include "Game.h"
#include "dZoneManager.h"
#include "eServerDisconnectIdentifiers.h"
@@ -27,21 +27,37 @@ 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.
auto account = Database::Connection->GetAccountByName(username);
//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());
m_AccountID = account.ID;
m_MaxGMLevel = static_cast<eGameMasterLevel>(account.MaxGMLevel);
m_MuteExpire = 0;
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;
//If we're loading a zone, we'll load the last used (aka current) character:
if (Game::server->GetZoneID() != 0) {
uint32_t characterId = Database::Connection->GetLatestCharacterOfAccount(m_AccountID);
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 1;");
stmt->setUInt(1, m_AccountID);
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);
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);
}
}
delete res;
delete stmt;
}
}
@@ -111,7 +127,7 @@ void User::UserOutOfSync() {
m_AmountOfTimesOutOfSync++;
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
//YEET
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);
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::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
}
}

View File

@@ -6,14 +6,14 @@
#include "Database.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.h"
#include "User.h"
#include <WorldPackets.h>
#include "Character.h"
#include <BitStream.h>
#include "PacketUtils.h"
#include "../dWorldServer/ObjectIDManager.h"
#include "dLogger.h"
#include "Logger.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) {
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str());
LOG("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) {
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str());
LOG("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) {
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str());
LOG("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) {
Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
LOG("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) {
Game::logger->Log("UserManager", "Deleted user %i", user->GetAccountID());
LOG("Deleted user %i", user->GetAccountID());
delete user;
}
@@ -159,7 +159,17 @@ void UserManager::DeletePendingRemovals() {
}
bool UserManager::IsNameAvailable(const std::string& requestedName) {
return Database::Connection->IsCharacterNameAvailable(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;
}
std::string UserManager::GetPredefinedName(uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex) {
@@ -191,8 +201,10 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
User* u = GetUser(sysAddr);
if (!u) return;
auto charInfos = Database::Connection->GetAllCharactersByAccountID(u->GetAccountID());
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 4;");
stmt->setUInt(1, u->GetAccountID());
sql::ResultSet* res = stmt->executeQuery();
std::vector<Character*>& chars = u->GetCharacters();
for (size_t i = 0; i < chars.size(); ++i) {
@@ -220,12 +232,16 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
chars.clear();
for (const auto& info : charInfos) {
Character* character = new Character(info.ID, u);
while (res->next()) {
LWOOBJID objID = res->getUInt64(1);
Character* character = new Character(uint32_t(objID), u);
character->SetIsNewLogin();
chars.push_back(character);
}
delete res;
delete stmt;
WorldPackets::SendCharacterList(sysAddr, u);
}
@@ -255,28 +271,32 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
LOT pantsLOT = FindCharPantsID(pantsColor);
if (name != "" && !UserManager::IsNameAvailable(name)) {
Game::logger->Log("UserManager", "AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str());
LOG("AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE);
return;
}
if (!IsNameAvailable(predefinedName)) {
Game::logger->Log("UserManager", "AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str());
LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE);
return;
}
if (name == "") {
Game::logger->Log("UserManager", "AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str());
LOG("AccountID: %i is creating a character with predefined name: %s", u->GetAccountID(), predefinedName.c_str());
} else {
Game::logger->Log("UserManager", "AccountID: %i is creating a character with name: %s (temporary: %s)", u->GetAccountID(), name.c_str(), predefinedName.c_str());
LOG("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) {
auto character = Database::Connection->GetCharacterInfoByID(objectID);
if (character.AccountID != 0) {
Game::logger->Log("UserManager", "Character object id unavailable, check objectidtracker!");
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!");
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
return;
}
@@ -313,32 +333,45 @@ 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 (u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (name != "") {
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
nameOk ? name : predefinedName,
nameOk ? "" : name,
false,
time(NULL)
);
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;
} else {
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
predefinedName,
"",
false,
time(NULL)
);
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;
}
// Now finally insert our character xml
Database::Connection->CreateCharacterXML(objectID, xml3.str());
//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;
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
@@ -350,14 +383,14 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
User* u = GetUser(sysAddr);
if (!u) {
Game::logger->Log("UserManager", "Couldn't get user to delete character");
LOG("Couldn't get user to delete character");
return;
}
LWOOBJID objectID = PacketUtils::ReadS64(8, packet);
uint32_t charID = static_cast<uint32_t>(objectID);
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)", objectID, charID);
LOG("Received char delete req for ID: %llu (%u)", objectID, charID);
bool hasCharacter = CheatDetection::VerifyLwoobjidIsSender(
objectID,
@@ -369,14 +402,74 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
if (!hasCharacter) {
WorldPackets::SendCharacterDeleteResponse(sysAddr, false);
} else {
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);
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;
}
WorldPackets::SendCharacterDeleteResponse(sysAddr, true);
}
@@ -385,7 +478,7 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet) {
User* u = GetUser(sysAddr);
if (!u) {
Game::logger->Log("UserManager", "Couldn't get user to delete character");
LOG("Couldn't get user to delete character");
return;
}
@@ -394,7 +487,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
GeneralUtils::ClearBit(objectID, eObjectBits::PERSISTENT);
uint32_t charID = static_cast<uint32_t>(objectID);
Game::logger->Log("UserManager", "Received char rename request for ID: %llu (%u)", objectID, charID);
LOG("Received char rename request for ID: %llu (%u)", objectID, charID);
std::string newName = PacketUtils::ReadString(16, packet, true);
@@ -426,15 +519,25 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
if (IsNameAvailable(newName)) {
if (IsNamePreapproved(newName)) {
Database::Connection->ApproveCharacterName(character->GetID(), 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;
Game::logger->Log("UserManager", "Character %s now known as %s", character->GetName().c_str(), newName.c_str());
LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str());
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
} else {
Database::Connection->SetPendingCharacterName(character->GetID(), newName);
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;
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());
LOG("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);
}
@@ -442,7 +545,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_IN_USE);
}
} else {
Game::logger->Log("UserManager", "Unknown error occurred when renaming character, either hasCharacter or character variable != true.");
LOG("Unknown error occurred when renaming character, either hasCharacter or character variable != true.");
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR);
}
}
@@ -450,7 +553,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID) {
User* u = GetUser(sysAddr);
if (!u) {
Game::logger->Log("UserManager", "Couldn't get user to log in character");
LOG("Couldn't get user to log in character");
return;
}
@@ -463,13 +566,17 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
}
if (hasCharacter && character) {
Database::Connection->UpdateCharacterLastLogin(playerID, time(NULL));
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;
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) {
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);
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);
if (character) {
character->SetZoneID(zoneID);
character->SetZoneInstance(zoneInstance);
@@ -479,7 +586,7 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
return;
});
} else {
Game::logger->Log("UserManager", "Unknown error occurred when logging in a character, either hasCharacter or character variable != true.");
LOG("Unknown error occurred when logging in a character, either hasCharacter or character variable != true.");
}
}
@@ -494,7 +601,7 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
tableData.finalize();
return shirtLOT;
} catch (const std::exception&) {
Game::logger->Log("Character Create", "Failed to execute query! Using backup...");
LOG("Failed to execute query! Using backup...");
// in case of no shirt found in CDServer, return problematic red vest.
return 4069;
}
@@ -509,7 +616,7 @@ uint32_t FindCharPantsID(uint32_t pantsColor) {
tableData.finalize();
return pantsLOT;
} catch (const std::exception&) {
Game::logger->Log("Character Create", "Failed to execute query! Using backup...");
LOG("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 "dLogger.h"
#include "Logger.h"
void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
Game::logger->Log("AirMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("AirMovementBehavior", "Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}
LWOOBJID target{};
if (!bitStream->Read(target)) {
Game::logger->Log("AirMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.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 "dLogger.h"
#include "Logger.h"
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "RebuildComponent.h"
#include "DestroyableComponent.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.h"
void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
uint32_t targetCount{};
if (!bitStream->Read(targetCount)) {
Game::logger->Log("AreaOfEffectBehavior", "Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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) {
Game::logger->Log("AreaOfEffectBehavior", "Serialized size is greater than max targets! Size: %i, Max: %i", targetCount, this->m_maxTargets);
LOG("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)) {
Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i);
LOG("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 "dLogger.h"
#include "Logger.h"
void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
Game::logger->Log("AttackDelayBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};

View File

@@ -1,7 +1,7 @@
#include "BasicAttackBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.h"
#include "EntityManager.h"
#include "DestroyableComponent.h"
#include "BehaviorContext.h"
@@ -26,10 +26,10 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
uint16_t allocatedBits{};
if (!bitStream->Read(allocatedBits) || allocatedBits == 0) {
Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits");
LOG_DEBUG("No allocated bits");
return;
}
Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits);
LOG_DEBUG("Number of allocated bits %i", allocatedBits);
const auto baseAddress = bitStream->GetReadOffset();
DoHandleBehavior(context, bitStream, branch);
@@ -40,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) {
Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target);
LOG("Target targetEntity %llu not found.", branch.target);
return;
}
auto* destroyableComponent = targetEntity->GetComponent<DestroyableComponent>();
if (!destroyableComponent) {
Game::logger->Log("BasicAttackBehavior", "No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT());
LOG("No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT());
return;
}
@@ -55,7 +55,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
bool isSuccess{};
if (!bitStream->Read(isBlocked)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked");
LOG("Unable to read isBlocked");
return;
}
@@ -67,7 +67,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
}
if (!bitStream->Read(isImmune)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune");
LOG("Unable to read isImmune");
return;
}
@@ -77,20 +77,20 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
}
if (!bitStream->Read(isSuccess)) {
Game::logger->Log("BasicAttackBehavior", "failed to read success from bitstream");
LOG("failed to read success from bitstream");
return;
}
if (isSuccess) {
uint32_t armorDamageDealt{};
if (!bitStream->Read(armorDamageDealt)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read armorDamageDealt");
LOG("Unable to read armorDamageDealt");
return;
}
uint32_t healthDamageDealt{};
if (!bitStream->Read(healthDamageDealt)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt");
LOG("Unable to read healthDamageDealt");
return;
}
@@ -103,7 +103,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
bool died{};
if (!bitStream->Read(died)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read died");
LOG("Unable to read died");
return;
}
auto previousArmor = destroyableComponent->GetArmor();
@@ -114,7 +114,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
uint8_t successState{};
if (!bitStream->Read(successState)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read success state");
LOG("Unable to read success state");
return;
}
@@ -127,7 +127,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
break;
default:
if (static_cast<eBasicAttackSuccessTypes>(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) {
Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState);
LOG("Unknown success state (%i)!", successState);
return;
}
this->m_OnFailImmune->Handle(context, bitStream, branch);
@@ -157,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) {
Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target);
LOG("Target entity %llu is null!", branch.target);
return;
}
auto* destroyableComponent = targetEntity->GetComponent<DestroyableComponent>();
if (!destroyableComponent || !destroyableComponent->GetParent()) {
Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target);
LOG("No destroyable component on %llu", branch.target);
return;
}
@@ -227,7 +227,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
break;
default:
if (static_cast<eBasicAttackSuccessTypes>(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) {
Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState);
LOG("Unknown success state (%i)!", successState);
break;
}
this->m_OnFailImmune->Calculate(context, bitStream, branch);

View File

@@ -4,7 +4,7 @@
#include "Behavior.h"
#include "CDActivitiesTable.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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:
//Game::logger->Log("Behavior", "Failed to load behavior with invalid template id (%i)!", templateId);
//LOG("Failed to load behavior with invalid template id (%i)!", templateId);
break;
}
if (behavior == nullptr) {
//Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!", templateId);
//LOG("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) {
Game::logger->Log("Behavior", "Failed to load behavior template with id (%i)!", behaviorId);
LOG("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) {
Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!", behaviorId);
LOG("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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
LOG("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) {
Game::logger->Log("BehaviorContext", "No skill component attached to (%llu)!", this->originator);;
LOG("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) {
Game::logger->Log("BehaviorContext", "Failed to find behavior sync entry with sync id (%i)!", syncId);
LOG("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) {
Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!", syncId);
LOG("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) {
Game::logger->LogDebug("BehaviorContext", "Invalid caster for (%llu)!", this->originator);
LOG_DEBUG("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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
LOG("Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
LOG("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) {
Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target);
LOG("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) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
LOG("Invalid target (%llu)!", target);
return;
}
@@ -55,7 +55,7 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch
auto* component = entity->GetComponent<DestroyableComponent>();
if (component == nullptr) {
Game::logger->Log("BuffBehavior", "Invalid target, no destroyable component (%llu)!", target);
LOG("Invalid target, no destroyable component (%llu)!", target);
return;
}

View File

@@ -5,7 +5,7 @@
#include "BehaviorContext.h"
#include "CharacterComponent.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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;
}
Game::logger->Log("Car boost", "Activating car boost!");
LOG("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) {
Game::logger->Log("Car boost", "Tracking car boost!");
LOG("Tracking car boost!");
characterComponent->UpdatePlayerStatistic(RacingCarBoostsActivated);
}
}

View File

@@ -1,13 +1,13 @@
#include "ChainBehavior.h"
#include "BehaviorBranchContext.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.h"
void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t chainIndex{};
if (!bitStream->Read(chainIndex)) {
Game::logger->Log("ChainBehavior", "Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 {
Game::logger->Log("ChainBehavior", "chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.h"
void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
uint32_t handle{};
if (!bitStream->Read(handle)) {
Game::logger->Log("ChargeUpBehavior", "Unable to read handle from bitStream, aborting Handle! variable_type");
LOG("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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);
LOG("Failed to find target (%llu)!", second);
return;
}

View File

@@ -4,14 +4,14 @@
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second);
LOG("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) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
LOG_DEBUG("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) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
LOG_DEBUG("Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -4,7 +4,7 @@
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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)) {
Game::logger->Log("ForceMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
return;
}
LWOOBJID target{};
if (!bitStream->Read(target)) {
Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("HealBehavior", "Failed to find destroyable component for %(llu)!", branch.target);
LOG("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 "dLogger.h"
#include "Logger.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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);
LOG("Failed to find target (%llu)!", second);
return;
}

View File

@@ -2,7 +2,7 @@
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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)) {
Game::logger->Log("InterruptBehavior", "Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("InterruptBehavior", "Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("InterruptBehavior", "Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.h"
void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bool unknown{};
if (!bitStream->Read(unknown)) {
Game::logger->Log("KnockbackBehavior", "Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.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;
}
Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.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 "dLogger.h"
#include "Logger.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)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
LOG("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) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", -context->originator);
LOG("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)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
LOG("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) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", context->originator);
LOG("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) {
Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target);
LOG("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!");
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);
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);
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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("RepairBehavior", "Failed to find destroyable component for %(llu)!", branch.target);
LOG("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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!", context->originator);
LOG("Failed to find self entity (%llu)!", context->originator);
return;
}
@@ -45,7 +45,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
);
if (entity == nullptr) {
Game::logger->Log("SpawnBehavior", "Failed to spawn entity (%i)!", this->m_lot);
LOG("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) {
Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!", second);
LOG("Failed to find spawned entity (%llu)!", second);
return;
}

View File

@@ -3,7 +3,7 @@
#include "ControllablePhysicsComponent.h"
#include "BehaviorContext.h"
#include "BehaviorBranchContext.h"
#include "dLogger.h"
#include "Logger.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 "dLogger.h"
#include "Logger.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)) {
Game::logger->Log("StunBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) {
Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target);
LOG("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) {
Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!", context->originator);
LOG("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) {
Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target);
LOG("Failed to find target (%llu)!", branch.target);
return;
}

View File

@@ -1,7 +1,7 @@
#include "SwitchBehavior.h"
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "dLogger.h"
#include "Logger.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)) {
Game::logger->Log("SwitchBehavior", "Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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;
}
Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination());
LOG_DEBUG("[%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 "dLogger.h"
#include "Logger.h"
#include "EntityManager.h"
@@ -13,7 +13,7 @@ void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
float value{};
if (!bitStream->Read(value)) {
Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 "dLogger.h"
#include "Logger.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) Game::logger->Log("TacArcBehavior", "target %llu is null", branch.target);
if (!target) LOG("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)) {
Game::logger->Log("TacArcBehavior", "Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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)) {
Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
if (count > m_maxTargets) {
Game::logger->Log("TacArcBehavior", "Bitstream has too many targets Max:%i Recv:%i", this->m_maxTargets, count);
LOG("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)) {
Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
LOG("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 {
Game::logger->Log("TacArcBehavior", "Bitstream has LWOOBJID_EMPTY as a target!");
LOG("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) {
Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator);
LOG("Invalid self for (%llu)!", context->originator);
return;
}

View File

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

View File

@@ -4,7 +4,7 @@
#include "NiPoint3.h"
#include "BehaviorContext.h"
#include "Game.h"
#include "dLogger.h"
#include "Logger.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) {
Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)", context->originator);
LOG("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) {
Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!", target);
LOG("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) {
Game::logger->Log("BaseCombatAIComponent", "Invalid reference destroyable component on (%llu)!", m_Parent->GetObjectID());
LOG("Invalid reference destroyable component on (%llu)!", m_Parent->GetObjectID());
return false;
}

View File

@@ -47,7 +47,7 @@ struct AiSkillEntry
*/
class BaseCombatAIComponent : public Component {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI;
inline 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 "dLogger.h"
#include "Logger.h"
#include "GameMessages.h"
#include <BitStream.h>
#include "eTriggerEventType.h"
@@ -81,13 +81,13 @@ void BouncerComponent::LookupPetSwitch() {
Game::entityManager->SerializeEntity(m_Parent);
Game::logger->Log("BouncerComponent", "Loaded pet bouncer");
LOG("Loaded pet bouncer");
}
}
}
if (!m_PetSwitchLoaded) {
Game::logger->Log("BouncerComponent", "Failed to load pet bouncer");
LOG("Failed to load pet bouncer");
m_Parent->AddCallbackTimer(0.5f, [this]() {
LookupPetSwitch();

View File

@@ -12,7 +12,7 @@
*/
class BouncerComponent : public Component {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER;
inline 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 "dLogger.h"
#include "Logger.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) {
Game::logger->Log("BuffComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
LOG("Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
}
}

View File

@@ -42,7 +42,7 @@ struct Buff
*/
class BuffComponent : public Component {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF;
inline 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 "dLogger.h"
#include "Logger.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();
Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque");
LOG("Using PropertyPlaque");
}
auto* inventoryComponent = originator->GetComponent<InventoryComponent>();
@@ -41,7 +41,7 @@ void BuildBorderComponent::OnUse(Entity* originator) {
inventoryComponent->PushEquippedItems();
Game::logger->Log("BuildBorderComponent", "Starting with %llu", buildArea);
LOG("Starting with %llu", buildArea);
if (PropertyManagementComponent::Instance() != nullptr) {
GameMessages::SendStartArrangingWithItem(

View File

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

View File

@@ -3,11 +3,13 @@ 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"
@@ -42,4 +44,7 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"SwitchComponent.cpp"
"TriggerComponent.cpp"
"VehiclePhysicsComponent.cpp"
"VendorComponent.cpp" PARENT_SCOPE)
"VendorComponent.cpp"
"ZoneControlComponent.cpp"
PARENT_SCOPE
)

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,18 @@
#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__

View File

@@ -1,7 +1,7 @@
#include "ControllablePhysicsComponent.h"
#include "Entity.h"
#include "BitStream.h"
#include "dLogger.h"
#include "Logger.h"
#include "Game.h"
#include "dpWorld.h"
@@ -52,7 +52,7 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Phy
return;
if (entity->GetLOT() == 1) {
Game::logger->Log("ControllablePhysicsComponent", "Using patch to load minifig physics");
LOG("Using patch to load minifig physics");
float radius = 1.5f;
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), radius, false);
@@ -161,7 +161,7 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
if (!character) {
Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag!");
LOG("Failed to find char tag!");
return;
}
@@ -181,7 +181,7 @@ void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
if (!character) {
Game::logger->Log("ControllablePhysicsComponent", "Failed to find char tag while updating XML!");
LOG("Failed to find char tag while updating XML!");
return;
}
@@ -268,7 +268,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) {
if (pos != m_ActivePickupRadiusScales.end()) {
m_ActivePickupRadiusScales.erase(pos);
} else {
Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size());
LOG_DEBUG("Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size());
return;
}
@@ -293,7 +293,7 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
if (pos != m_ActiveSpeedBoosts.end()) {
m_ActiveSpeedBoosts.erase(pos);
} else {
Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size());
LOG_DEBUG("Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size());
return;
}
@@ -311,7 +311,7 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){
if (m_IsInBubble) {
Game::logger->Log("ControllablePhysicsComponent", "Already in bubble");
LOG("Already in bubble");
return;
}
m_BubbleType = bubbleType;

View File

@@ -21,7 +21,7 @@ enum class eStateChangeType : uint32_t;
*/
class ControllablePhysicsComponent : public PhysicsComponent {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
ControllablePhysicsComponent(Entity* entity);
~ControllablePhysicsComponent() override;

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