Compare commits

..

9 Commits

Author SHA1 Message Date
David Markowitz
7d62ec543a add back header 2023-07-27 20:06:12 -07:00
David Markowitz
3bab2af1a4 Merge branch 'main' into cdclient-rework 2023-07-27 20:03:12 -07:00
Wincent Holm
633b87a5e7 Merge branch 'main' into cdclient-rework 2022-10-29 21:52:08 +02:00
wincent
3031f942dc Removed log statement 2022-10-29 21:46:09 +02:00
wincent
e3e9718db5 Reverted local hardcoded NET_VERSION value. 2022-08-11 16:40:17 +02:00
wincent
56f371216b Abstracted the CDClient tables
There is now an option to utilize shared memory for some CDClient tables by adding `CD_PROVIDER_MEMORY=1` to the CMakeVariables.txt file.

Allows masterconfig.ini to specify another run command for the world server, to allow for easier debugging through `valgrind`.
2022-08-11 16:36:03 +02:00
Wincent Holm
45ae46f6f1 Merge branch 'main' into cdclient-rework 2022-07-18 16:44:53 +02:00
wincent
db7f7c60b2 Optimizations to shared memory
Load the context at start in readonly mode instead of fetching for every entry.
2022-07-10 00:40:13 +02:00
wincent
34fa43ed93 Initial concept for CDClient rework.
Utilizes `boost::interprocess` to share a map between worlds.
The master server loads the table into memory, and the worlds hook into it when they want to get an entry.

This solves the issue of skill delay, but introduces the third-party library Boost.
There should be a conversation about the introduction of Boost — it is a large library and adds extra steps to the installation.
2022-07-09 22:59:36 +02:00
406 changed files with 5345 additions and 7249 deletions

View File

@@ -14,4 +14,4 @@ EXTERNAL_IP=localhost
MARIADB_USER=darkflame
MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
MARIADB_DATABASE=darkflame
MARIADB_DATABASE=darkflame

View File

@@ -148,19 +148,16 @@ foreach (resource_file ${RESOURCE_FILES})
endforeach()
message(STATUS "Resource file integrity check complete")
# if navmeshes directory does not exist, create it
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/navmeshes)
endif()
# Copy navmesh data on first build and extract it
configure_file(
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
COPYONLY
)
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
configure_file(
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
COPYONLY
)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PROJECT_BINARY_DIR}/navmeshes)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip)
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
endif()
# Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
@@ -325,6 +322,15 @@ link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)
# Include Boost
find_package(Boost COMPONENTS interprocess)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(dGame ${Boost_LIBRARIES})
endif()
# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE

View File

@@ -1,8 +1,12 @@
PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=1
PROJECT_VERSION_PATCH=1
PROJECT_VERSION_PATCH=0
# LICENSE
LICENSE=AGPL-3.0
# The network version.
# 171023 - Darkflame Universe client
# 171022 - Unmodded client
NET_VERSION=171022
# Debugging
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
__dynamic=1
@@ -18,5 +22,3 @@ __maria_db_connector_compile_jobs__=1
__enable_testing__=1
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
# Uncomment the below line to cache the entire CDClient into memory
# CDCLIENT_CACHE_ALL=1

View File

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

View File

@@ -7,7 +7,7 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "Diagnostics.h"
@@ -25,14 +25,14 @@
#include "Game.h"
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
Logger* SetupLogger();
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
int main(int argc, char** argv) {
@@ -51,9 +51,9 @@ int main(int argc, char** argv) {
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Auth server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
Game::logger->Log("AuthServer", "Starting Auth server...");
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
//Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host");
@@ -64,7 +64,7 @@ int main(int argc, char** argv) {
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());
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
@@ -161,7 +161,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
Logger* SetupLogger() {
dLogger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -170,7 +170,7 @@ Logger* SetupLogger() {
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
return new dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {

View File

@@ -8,7 +8,7 @@
#include <regex>
#include "dCommonVars.h"
#include "Logger.h"
#include "dLogger.h"
#include "dConfig.h"
#include "Database.h"
#include "Game.h"
@@ -144,7 +144,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
listOfBadSegments.emplace_back(position, originalSegment.length());
}
position += originalSegment.length() + 1;
position += segment.length() + 1;
}
return listOfBadSegments;

View File

@@ -3,11 +3,10 @@
#include "Database.h"
#include <vector>
#include "PacketUtils.h"
#include "BitStreamUtils.h"
#include "Game.h"
#include "dServer.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "dLogger.h"
#include "eAddFriendResponseCode.h"
#include "eAddFriendResponseType.h"
#include "RakString.h"
@@ -76,11 +75,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Now, we need to send the friendlist to the server they came from:
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
bitStream.Write<uint8_t>(0);
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
bitStream.Write((uint16_t)friends.size());
@@ -118,11 +117,6 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
inStream.Read(isBestFriendRequest);
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
if (!requestor) {
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
return;
}
if (requestor->playerName == playerName) {
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
return;
@@ -402,7 +396,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
LOG("Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
if (channel != 8) return;
@@ -418,21 +412,21 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
const auto otherName = std::string(otherMember->playerName.c_str());
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(otherMember->playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(otherMember->playerID);
bitStream.Write<uint8_t>(8);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(senderName));
PacketUtils::WritePacketWString(senderName, 33, &bitStream);
bitStream.Write(sender->playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(otherName));
PacketUtils::WritePacketWString(otherName, 33, &bitStream);
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(0); //teams?
bitStream.Write(LUWString(message, 512));
PacketUtils::WritePacketWString(message, 512, &bitStream);
SystemAddress sysAddr = otherMember->sysAddr;
SEND_PACKET;
@@ -440,7 +434,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
}
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
LWOOBJID senderID = PacketUtils::ReadS64(0x08, packet);
LWOOBJID senderID = PacketUtils::ReadPacketS64(0x08, packet);
std::string receiverName = PacketUtils::ReadString(0x66, packet, true);
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
@@ -457,21 +451,21 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
//To the sender:
{
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(goonA->playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(goonA->playerID);
bitStream.Write<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonAName));
PacketUtils::WritePacketWString(goonAName, 33, &bitStream);
bitStream.Write(goonA->playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonBName));
PacketUtils::WritePacketWString(goonBName, 33, &bitStream);
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(0); //success
bitStream.Write(LUWString(message, 512));
PacketUtils::WritePacketWString(message, 512, &bitStream);
SystemAddress sysAddr = goonA->sysAddr;
SEND_PACKET;
@@ -480,21 +474,21 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
//To the receiver:
{
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(goonB->playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(goonA->playerID);
bitStream.Write<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonAName));
PacketUtils::WritePacketWString(goonAName, 33, &bitStream);
bitStream.Write(goonA->playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonBName));
PacketUtils::WritePacketWString(goonBName, 33, &bitStream);
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(3); //new whisper
bitStream.Write(LUWString(message, 512));
PacketUtils::WritePacketWString(message, 512, &bitStream);
SystemAddress sysAddr = goonB->sysAddr;
SEND_PACKET;
@@ -532,13 +526,13 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
if (team->memberIDs.size() > 3) {
// no more teams greater than 4
LOG("Someone tried to invite a 5th player to a team");
Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team");
return;
}
SendTeamInvite(other, player);
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
}
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
@@ -552,7 +546,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
LWOOBJID leaderID = LWOOBJID_EMPTY;
inStream.Read(leaderID);
LOG("Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
if (declined) {
return;
@@ -561,13 +555,13 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
auto* team = playerContainer.GetTeam(leaderID);
if (team == nullptr) {
LOG("Failed to find team for leader (%llu)", leaderID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID);
team = playerContainer.GetTeam(playerID);
}
if (team == nullptr) {
LOG("Failed to find team for player (%llu)", playerID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID);
return;
}
@@ -583,7 +577,7 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
auto* team = playerContainer.GetTeam(playerID);
LOG("(%llu) leaving team", playerID);
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID);
if (team != nullptr) {
playerContainer.RemoveMember(team, playerID, false, false, true);
@@ -597,7 +591,7 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
@@ -627,7 +621,7 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
@@ -715,13 +709,13 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE);
bitStream.Write(LUWString(sender->playerName.c_str()));
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
bitStream.Write(sender->playerID);
SystemAddress sysAddr = receiver->sysAddr;
@@ -730,7 +724,7 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -757,7 +751,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -782,7 +776,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -799,7 +793,7 @@ void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64Play
void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -828,7 +822,7 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -854,7 +848,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
@@ -888,16 +882,16 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
[bool] - is FTP*/
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(friendData->playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY);
bitStream.Write<uint8_t>(notifyType);
std::string playerName = playerData->playerName.c_str();
bitStream.Write(LUWString(playerName));
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
bitStream.Write(playerData->zoneID.GetMapID());
bitStream.Write(playerData->zoneID.GetInstanceID());
@@ -927,12 +921,12 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
}
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST);
bitStream.Write(LUWString(sender->playerName.c_str()));
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST);
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
SystemAddress sysAddr = receiver->sysAddr;
@@ -943,16 +937,16 @@ void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sen
if (!receiver || !sender) return;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
// Portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE);
bitStream.Write(responseCode);
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
// Then write the player name
bitStream.Write(LUWString(sender->playerName.c_str()));
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
// Then if this is an acceptance code, write the following extra info.
if (responseCode == eAddFriendResponseType::ACCEPTED) {
bitStream.Write(sender->playerID);
@@ -968,13 +962,13 @@ void ChatPacketHandler::SendRemoveFriend(PlayerData* receiver, std::string& pers
if (!receiver) return;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID);
//portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE);
bitStream.Write<uint8_t>(isSuccessful); //isOnline
bitStream.Write(LUWString(personToRemove));
PacketUtils::WritePacketWString(personToRemove, 33, &bitStream);
SystemAddress sysAddr = receiver->sysAddr;
SEND_PACKET;

View File

@@ -6,7 +6,7 @@
//DLU Includes:
#include "dCommonVars.h"
#include "dServer.h"
#include "Logger.h"
#include "dLogger.h"
#include "Database.h"
#include "dConfig.h"
#include "dChatFilter.h"
@@ -27,17 +27,16 @@
#include <MessageIdentifiers.h>
namespace Game {
Logger* logger = nullptr;
dLogger* logger = nullptr;
dServer* server = nullptr;
dConfig* config = nullptr;
dChatFilter* chatFilter = nullptr;
AssetManager* assetManager = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
Logger* SetupLogger();
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
PlayerContainer playerContainer;
@@ -58,9 +57,9 @@ int main(int argc, char** argv) {
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
LOG("Starting Chat server...");
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
LOG("Compiled on: %s", __TIMESTAMP__);
Game::logger->Log("ChatServer", "Starting Chat server...");
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
try {
std::string clientPathStr = Game::config->GetValue("client_location");
@@ -72,7 +71,7 @@ int main(int argc, char** argv) {
Game::assetManager = new AssetManager(clientPath);
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
return EXIT_FAILURE;
}
@@ -86,7 +85,7 @@ int main(int argc, char** argv) {
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());
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
@@ -115,8 +114,6 @@ int main(int argc, char** argv) {
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"))));
Game::randomEngine = std::mt19937(time(0));
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -185,7 +182,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
Logger* SetupLogger() {
dLogger* SetupLogger() {
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string();
bool logToConsole = false;
bool logDebugStatements = false;
@@ -194,16 +191,16 @@ Logger* SetupLogger() {
logDebugStatements = true;
#endif
return new Logger(logPath, logToConsole, logDebugStatements);
return new dLogger(logPath, logToConsole, logDebugStatements);
}
void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
LOG("A server has disconnected, erasing their connected players from the list.");
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
}
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
LOG("A server is connecting, awaiting user list.");
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
}
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
@@ -234,7 +231,7 @@ void HandlePacket(Packet* packet) {
}
default:
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
@@ -245,7 +242,7 @@ void HandlePacket(Packet* packet) {
break;
case eChatMessageType::GET_IGNORE_LIST:
LOG("Asked for ignore list, but is unimplemented right now.");
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
break;
case eChatMessageType::TEAM_GET_STATUS:
@@ -303,19 +300,19 @@ void HandlePacket(Packet* packet) {
break;
default:
LOG("Unknown CHAT id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
switch (static_cast<eWorldMessageType>(packet->data[3])) {
case eWorldMessageType::ROUTE_PACKET: {
LOG("Routing packet from world");
Game::logger->Log("ChatServer", "Routing packet from world");
break;
}
default:
LOG("Unknown World id: %i", int(packet->data[3]));
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
}
}
}

View File

@@ -3,15 +3,13 @@
#include <iostream>
#include <algorithm>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
#include "ChatPacketHandler.h"
#include "GeneralUtils.h"
#include "BitStreamUtils.h"
#include "PacketUtils.h"
#include "Database.h"
#include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "ChatPackets.h"
#include "dConfig.h"
PlayerContainer::PlayerContainer() {
}
@@ -20,10 +18,6 @@ PlayerContainer::~PlayerContainer() {
mPlayers.clear();
}
TeamData::TeamData() {
lootFlag = Game::config->GetValue("default_team_loot") == "0" ? 0 : 1;
}
void PlayerContainer::InsertPlayer(Packet* packet) {
CINSTREAM_SKIP_HEADER;
PlayerData* data = new PlayerData();
@@ -44,7 +38,7 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
mPlayers.insert(std::make_pair(data->playerID, data));
LOG("Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
@@ -87,7 +81,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
}
}
LOG("Removed user: %llu", playerID);
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
mPlayers.erase(playerID);
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
@@ -110,7 +104,7 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
auto* player = this->GetPlayerData(playerID);
if (player == nullptr) {
LOG("Failed to find user: %llu", playerID);
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
return;
}
@@ -152,7 +146,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
bitStream.Write(player);
bitStream.Write(time);
@@ -213,14 +207,6 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
}
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4){
LOG("Tried to add player to team that already had 4 players");
auto* player = GetPlayerData(playerID);
if (!player) return;
ChatPackets::SendSystemMessage(player->sysAddr, u"The teams is full! You have not been added to a team!");
return;
}
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
if (index != team->memberIDs.end()) return;
@@ -359,7 +345,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
bitStream.Write(team->teamID);
bitStream.Write(deleteTeam);

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
#include "Database.h"
#include "Game.h"
#include "ZCompression.h"
#include "Logger.h"
#include "dLogger.h"
//! Forward declarations
@@ -59,14 +59,14 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
completeUncompressedModel.append((char*)uncompressedChunk.get());
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
} else {
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
break;
}
chunkCount++;
}
std::unique_ptr<tinyxml2::XMLDocument> document = std::make_unique<tinyxml2::XMLDocument>();
if (!document) {
LOG("Failed to initialize tinyxml document. Aborting.");
Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting.");
return 0;
}
@@ -75,7 +75,8 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
"</LXFML>",
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
) {
LOG("Brick-by-brick model %llu will be deleted!", modelId);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -84,7 +85,8 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
}
}
} else {
LOG("Brick-by-brick model %llu will be deleted!", modelId);
Game::logger->Log("BrickByBrickFix",
"Brick-by-brick model %llu will be deleted!", modelId);
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
ugcModelToDelete->execute();
@@ -138,10 +140,12 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
insertionStatement->setInt64(2, modelId);
try {
insertionStatement->executeUpdate();
LOG("Updated model %i to sd0", modelId);
Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId);
updatedModels++;
} catch (sql::SQLException exception) {
LOG("Failed to update model %i. This model should be inspected manually to see why."
Game::logger->Log(
"BrickByBrickFix",
"Failed to update model %i. This model should be inspected manually to see why."
"The database error is %s", modelId, exception.what());
}
}

View File

@@ -4,7 +4,7 @@ set(DCOMMON_SOURCES
"BinaryIO.cpp"
"dConfig.cpp"
"Diagnostics.cpp"
"Logger.cpp"
"dLogger.cpp"
"GeneralUtils.cpp"
"LDFFormat.cpp"
"MD5.cpp"
@@ -12,7 +12,7 @@ set(DCOMMON_SOURCES
"NiPoint3.cpp"
"NiQuaternion.cpp"
"SHA512.cpp"
"Demangler.cpp"
"Type.cpp"
"ZCompression.cpp"
"BrickByBrickFix.cpp"
"BinaryPathFinder.cpp"

View File

@@ -1,29 +0,0 @@
#include "Demangler.h"
#ifdef __GNUG__
#include <cstdlib>
#include <cxxabi.h>
#include <memory>
#include <typeinfo>
std::string Demangler::Demangle(const char* name) {
// some arbitrary value to eliminate the compiler warning
// -4 is not a valid return value for __cxa_demangle so we'll use that.
int status = -4;
// __cxa_demangle requires that we free the returned char*
std::unique_ptr<char, void (*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : "";
}
#else // __GNUG__
// does nothing if not g++
std::string Demangler::Demangle(const char* name) {
return name;
}
#endif // __GNUG__

View File

@@ -1,9 +0,0 @@
#pragma once
#include <string>
namespace Demangler {
// Given a char* containing a mangled name, return a std::string containing the demangled name.
// If the function fails for any reason, it returns an empty string.
std::string Demangle(const char* name);
}

View File

@@ -1,6 +1,6 @@
#include "Diagnostics.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// If we're on Win32, we'll include our minidump writer
#ifdef _WIN32
@@ -9,7 +9,7 @@
#include <Dbghelp.h>
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
void make_minidump(EXCEPTION_POINTERS* e) {
auto hDbgHelp = LoadLibraryA("dbghelp");
@@ -28,7 +28,7 @@ void make_minidump(EXCEPTION_POINTERS* e) {
"_%4d%02d%02d_%02d%02d%02d.dmp",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
}
LOG("Creating crash dump %s", name);
Game::logger->Log("Diagnostics", "Creating crash dump %s", name);
auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
return;
@@ -83,7 +83,7 @@ struct bt_ctx {
static inline void Bt(struct backtrace_state* state) {
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
LOG("backtrace is enabled, crash dump located at %s", fileName.c_str());
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
FILE* file = fopen(fileName.c_str(), "w+");
if (file != nullptr) {
backtrace_print(state, 2, file);
@@ -107,7 +107,7 @@ static void ErrorCallback(void* data, const char* msg, int errnum) {
}
#endif
#include "Demangler.h"
#include "Type.h"
void GenerateDump() {
std::string cmd = "sudo gcore " + std::to_string(getpid());
@@ -118,56 +118,55 @@ void CatchUnhandled(int sig) {
#ifndef __include_backtrace__
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
LOG("Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
if (Diagnostics::GetProduceMemoryDump()) {
GenerateDump();
}
constexpr uint8_t MaxStackTrace = 32;
void* array[MaxStackTrace];
void* array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, MaxStackTrace);
size = backtrace(array, 10);
# if defined(__GNUG__)
#if defined(__GNUG__) and defined(__dynamic)
// 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]'
// and extract '_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress' from it to be demangled into a proper name
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name
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) {
std::string demangled = functionName.substr(start + 1, end - start - 1);
demangled = Demangler::Demangle(demangled.c_str());
demangled = demangle(functionName.c_str());
// If the demangled string is not empty, then we can replace the mangled string with the demangled one
if (!demangled.empty()) {
demangled.push_back('(');
demangled += functionName.substr(end);
functionName = demangled;
if (demangled.empty()) {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str());
} else {
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 {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
}
}
# else // defined(__GNUG__)
#else
backtrace_symbols_fd(array, size, STDOUT_FILENO);
# endif // defined(__GNUG__)
#endif
#else // __include_backtrace__
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
struct backtrace_state* state = backtrace_create_state(
Diagnostics::GetProcessFileName().c_str(),
@@ -178,7 +177,7 @@ void CatchUnhandled(int sig) {
struct bt_ctx ctx = { state, 0 };
Bt(state);
#endif // __include_backtrace__
#endif
exit(EXIT_FAILURE);
}

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
#include "NiPoint3.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
enum eInventoryType : uint32_t;
enum class eObjectBits : size_t;
@@ -126,11 +126,6 @@ namespace GeneralUtils {
template <typename T>
T Parse(const char* value);
template <>
inline bool Parse(const char* value) {
return std::stoi(value);
}
template <>
inline int32_t Parse(const char* value) {
return std::stoi(value);

View File

@@ -4,7 +4,7 @@
#include "GeneralUtils.h"
#include "Game.h"
#include "Logger.h"
#include "dLogger.h"
// C++
#include <string_view>
@@ -48,7 +48,7 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
try {
type = static_cast<eLDFType>(strtol(ldfTypeAndValue.first.data(), &storage, 10));
} catch (std::exception) {
LOG("Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
Game::logger->Log("LDFFormat", "Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
return nullptr;
}
@@ -61,33 +61,35 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
}
case LDF_TYPE_S32: {
int32_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
int32_t data = static_cast<int32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
returnValue = new LDFData<int32_t>(key, data);
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<int32_t>(key, data);
break;
}
case LDF_TYPE_FLOAT: {
float data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
float data = strtof(ldfTypeAndValue.second.data(), &storage);
returnValue = new LDFData<float>(key, data);
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<float>(key, data);
break;
}
case LDF_TYPE_DOUBLE: {
double data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
double data = strtod(ldfTypeAndValue.second.data(), &storage);
returnValue = new LDFData<double>(key, data);
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<double>(key, data);
break;
}
@@ -100,8 +102,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") {
data = 0;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
data = static_cast<uint32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
}
@@ -118,8 +122,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") {
data = false;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
data = static_cast<bool>(strtol(ldfTypeAndValue.second.data(), &storage, 10));
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
}
@@ -129,22 +135,24 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
}
case LDF_TYPE_U64: {
uint64_t data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
uint64_t data = static_cast<uint64_t>(strtoull(ldfTypeAndValue.second.data(), &storage, 10));
returnValue = new LDFData<uint64_t>(key, data);
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<uint64_t>(key, data);
break;
}
case LDF_TYPE_OBJID: {
LWOOBJID data;
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
try {
LWOOBJID data = static_cast<LWOOBJID>(strtoll(ldfTypeAndValue.second.data(), &storage, 10));
returnValue = new LDFData<LWOOBJID>(key, data);
} catch (std::exception) {
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr;
}
returnValue = new LDFData<LWOOBJID>(key, data);
break;
}
@@ -155,12 +163,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
}
case LDF_TYPE_UNKNOWN: {
LOG("Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
break;
}
default: {
LOG("Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
break;
}
}

View File

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

View File

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

View File

@@ -129,19 +129,10 @@ NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
}
//! Operator for addition of vectors
NiPoint3& NiPoint3::operator+=(const NiPoint3& point) {
this->x += point.x;
this->y += point.y;
this->z += point.z;
return *this;
NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
NiPoint3& NiPoint3::operator*=(const float scalar) {
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
//! Operator for subtraction of vectors
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {

View File

@@ -136,9 +136,7 @@ public:
NiPoint3 operator+(const NiPoint3& point) const;
//! Operator for addition of vectors
NiPoint3& operator+=(const NiPoint3& point);
NiPoint3& operator*=(const float scalar);
NiPoint3 operator+=(const NiPoint3& point) const;
//! Operator for subtraction of vectors
NiPoint3 operator-(const NiPoint3& point) const;

27
dCommon/Type.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include "Type.h"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res{
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status == 0) ? res.get() : name;
}
#else
// does nothing if not g++
std::string demangle(const char* name) {
return name;
}
#endif

12
dCommon/Type.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <typeinfo>
std::string demangle(const char* name);
template <class T>
std::string type(const T& t) {
return demangle(typeid(t).name());
}

View File

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

View File

@@ -42,7 +42,7 @@ struct AssetMemoryBuffer : std::streambuf {
}
void close() {
free(m_Base);
delete m_Base;
}
};

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -101,7 +101,7 @@ enum class eReplicaComponentType : uint32_t {
TRADE,
USER_CONTROL,
IGNORE_LIST,
MULTI_ZONE_ENTRANCE,
ROCKET_LAUNCH_LUP,
BUFF_REAL, // the real buff component, should just be name BUFF
INTERACTION_MANAGER,
DONATION_VENDOR,

110
dCommon/dLogger.cpp Normal file
View File

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

38
dCommon/dLogger.h Normal file
View File

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

View File

@@ -0,0 +1,22 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
template <
typename KeyType,
typename MappedType
>
class CDAbstractProvider
{
public:
virtual void LoadClient() = 0;
virtual void LoadHost() = 0;
virtual const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) = 0;
};

View File

@@ -0,0 +1,124 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
#include "CDAbstractProvider.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>
template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryMap : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> Map;
public:
std::map<KeyType, MappedType> m_CacheMap;
std::string m_Name;
size_t m_Size;
bool m_Host;
Map* m_HostEntries;
boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;
CDAbstractSharedMemoryMap(std::string name, size_t size)
{
m_Name = name;
m_Size = size;
m_Host = false;
m_HostEntries = nullptr;
m_ClientAllocInst = nullptr;
m_ClientEntires = nullptr;
LoadClient();
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
const auto& cacheIt = m_CacheMap.find(key);
if (cacheIt != m_CacheMap.end()) {
return cacheIt->second;
}
const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end()) {
return defaultValue;
}
return it->second;
}
const void SetEntry(const KeyType& key, const MappedType& value) {
if (m_Host) {
// If we are already hosting, we cannot add to the map, throw an error
throw std::runtime_error("Can not add to a map that is already being hosted");
}
m_CacheMap.emplace(key, value);
}
void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_Name.c_str());
m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());
m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;
if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}
} catch (std::exception &e) {
// Not open
}
}
void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_Name.c_str());
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_Name.c_str(), m_Size);
ShmemAllocator alloc(segment.get_segment_manager());
m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc);
// Copy cache
for (const auto& pair : m_CacheMap) {
m_HostEntries->insert(std::make_pair(pair.first, pair.second));
}
m_Host = true;
LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_Name.c_str());
throw e;
}
}
};

View File

@@ -0,0 +1,150 @@
#pragma once
#include "CDAbstractProvider.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>
#include <mutex>
template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryProvider : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> Map;
public:
std::string m_Name;
std::string m_MapName;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;
std::function <int32_t(int32_t)> m_CalculateSize;
bool m_Cache;
std::unordered_map<KeyType, MappedType> m_CacheMap;
bool m_Host;
Map* m_HostEntries;
boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;
CDAbstractSharedMemoryProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, std::function <int32_t(int32_t)> calculateSize, bool cache)
{
m_Name = name;
m_MapName = name + "Map";
m_ParseEntry = parseEntry;
m_CalculateSize = calculateSize;
m_Cache = cache;
m_Host = false;
m_HostEntries = nullptr;
LoadClient();
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
if (m_Host) {
auto it = m_HostEntries->find(key);
if (it == m_HostEntries->end())
{
return defaultValue;
}
return it->second;
}
if (m_Cache) {
auto it = m_CacheMap.find(key);
if (it != m_CacheMap.end()) {
return it->second;
}
}
const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end())
{
if (m_Cache) {
m_CacheMap.emplace(key, defaultValue);
}
return defaultValue;
}
if (m_Cache) {
m_CacheMap.emplace(key, it->second);
}
return it->second;
}
void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_MapName.c_str());
m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());
m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;
if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}
} catch (boost::interprocess::interprocess_exception& e) {
// Not open
}
}
void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());
auto sizeQuery = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);
if (sizeQuery.eof()) {
throw std::runtime_error("Could not get size of table " + m_Name);
return;
}
int32_t size = sizeQuery.getIntField(0);
size = m_CalculateSize(size);
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_MapName.c_str(), size);
ShmemAllocator alloc_inst (segment.get_segment_manager());
m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc_inst);
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);
while (!tableData.eof()) {
ValueType entry = m_ParseEntry(tableData);
m_HostEntries->insert(entry);
tableData.nextRow();
}
tableData.finalize();
m_Host = true;
LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());
throw e;
}
}
};

View File

@@ -0,0 +1,74 @@
#pragma once
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "CDTable.h"
#include "CDAbstractProvider.h"
template <
typename KeyType,
typename MappedType
>
class CDAbstractSqliteProvider : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;
public:
std::string m_Name;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;
std::unordered_map<KeyType, MappedType> m_Entries;
CDAbstractSqliteProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, bool cache)
{
m_Name = name;
m_ParseEntry = parseEntry;
LoadClient();
}
void LoadClient() override {
// First, get the size of the table
uint32_t size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
m_Entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);
while (!tableData.eof()) {
auto entry = m_ParseEntry(tableData);
m_Entries.insert(entry);
tableData.nextRow();
}
tableData.finalize();
}
void LoadHost() override {
return;
}
const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
auto it = m_Entries.find(key);
if (it != m_Entries.end()) {
return it->second;
}
return defaultValue;
}
};

View File

@@ -13,7 +13,15 @@
#include <sstream>
#include <iostream>
//! The CDClient Database namespace
// Enable this to cache all entries in each table for fast access, comes with more memory cost
//#define CDCLIENT_CACHE_ALL
/*!
\file CDClientDatabase.hpp
\brief An interface between the CDClient.sqlite file and the server
*/
//! The CDClient Database namespace
namespace CDClientDatabase {
//! Opens a connection with the CDClient

View File

@@ -38,53 +38,51 @@
#include "CDFeatureGatingTable.h"
#include "CDRailActivatorComponent.h"
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
// A vanilla CDClient takes about 46MB of memory + the regular world data.
// #define CDCLIENT_CACHE_ALL
#ifdef CDCLIENT_CACHE_ALL
#define CDCLIENT_DONT_CACHE_TABLE(x) x
#else
#define CDCLIENT_DONT_CACHE_TABLE(x)
#endif
CDClientManager::CDClientManager() {
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
CDActivitiesTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase());
CDBehaviorParameterTable::Instance().LoadValuesFromDatabase();
CDBehaviorTemplateTable::Instance().LoadValuesFromDatabase();
CDBrickIDTableTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDComponentsRegistryTable::Instance().LoadValuesFromDatabase());
CDCurrencyTableTable::Instance().LoadValuesFromDatabase();
CDDestructibleComponentTable::Instance().LoadValuesFromDatabase();
CDEmoteTableTable::Instance().LoadValuesFromDatabase();
CDFeatureGatingTable::Instance().LoadValuesFromDatabase();
CDInventoryComponentTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDItemComponentTable::Instance().LoadValuesFromDatabase());
CDItemSetSkillsTable::Instance().LoadValuesFromDatabase();
CDItemSetsTable::Instance().LoadValuesFromDatabase();
CDLevelProgressionLookupTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDLootMatrixTable::Instance().LoadValuesFromDatabase());
CDCLIENT_DONT_CACHE_TABLE(CDLootTableTable::Instance().LoadValuesFromDatabase());
CDMissionEmailTable::Instance().LoadValuesFromDatabase();
CDMissionNPCComponentTable::Instance().LoadValuesFromDatabase();
CDMissionTasksTable::Instance().LoadValuesFromDatabase();
CDMissionsTable::Instance().LoadValuesFromDatabase();
CDMovementAIComponentTable::Instance().LoadValuesFromDatabase();
CDObjectSkillsTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase());
CDPhysicsComponentTable::Instance().LoadValuesFromDatabase();
CDPackageComponentTable::Instance().LoadValuesFromDatabase();
CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase();
CDPropertyTemplateTable::Instance().LoadValuesFromDatabase();
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
CDRarityTableTable::Instance().LoadValuesFromDatabase();
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
CDRewardsTable::Instance().LoadValuesFromDatabase();
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
CDZoneTableTable::Instance().LoadValuesFromDatabase();
CDActivityRewardsTable::Instance();
CDAnimationsTable::Instance();
CDBehaviorParameterTable::Instance();
CDBehaviorTemplateTable::Instance();
CDComponentsRegistryTable::Instance();
CDCurrencyTableTable::Instance();
CDDestructibleComponentTable::Instance();
CDEmoteTableTable::Instance();
CDInventoryComponentTable::Instance();
CDItemComponentTable::Instance();
CDItemSetsTable::Instance();
CDItemSetSkillsTable::Instance();
CDLevelProgressionLookupTable::Instance();
CDLootMatrixTable::Instance();
CDLootTableTable::Instance();
CDMissionNPCComponentTable::Instance();
CDMissionTasksTable::Instance();
CDMissionsTable::Instance();
CDObjectSkillsTable::Instance();
CDObjectsTable::Instance();
CDPhysicsComponentTable::Instance();
CDRebuildComponentTable::Instance();
CDScriptComponentTable::Instance();
CDSkillBehaviorTable::Instance();
CDZoneTableTable::Instance();
CDVendorComponentTable::Instance();
CDActivitiesTable::Instance();
CDPackageComponentTable::Instance();
CDProximityMonitorComponentTable::Instance();
CDMovementAIComponentTable::Instance();
CDBrickIDTableTable::Instance();
CDRarityTableTable::Instance();
CDMissionEmailTable::Instance();
CDRewardsTable::Instance();
CDPropertyEntranceComponentTable::Instance();
CDPropertyTemplateTable::Instance();
CDFeatureGatingTable::Instance();
CDRailActivatorComponentTable::Instance();
}
void CDClientManager::LoadHost() {
for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) {
itr->second->LoadHost();
}
CDTable::InitalizeHost();
}

41
dDatabase/CDProvider.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include "CDAbstractProvider.h"
/**
* Shared memory provider with CDAbstractSharedMemoryProvider<key, value>
*
* Depends on the boost::interprocess library — header only
*
* Requires that CD_PROVIDER_MEMORY is defined and CD_PROVIDER_SQLITE is not defined
*/
#if defined(CD_PROVIDER_MEMORY) && !defined(CD_PROVIDER_SQLITE)
#include "CDAbstractSharedMemoryProvider.h"
#define CD_PROVIDER(provider, key, value) CDAbstractSharedMemoryProvider<key, value>* provider; typedef key CD_KEY; typedef value CD_VALUE
#define NEW_CD_PROVIDER(provider, name, parser, size_calculator, cache) provider = new CDAbstractSharedMemoryProvider<CD_KEY, CD_VALUE>(name, parser, size_calculator, cache)
template<typename KeyType, typename MappedType>
using CDProvider = CDAbstractSharedMemoryProvider<KeyType, MappedType>;
#endif
/**
* SQLite provider with CDAbstractSqliteProvider<key, value>
*
* No extra dependencies
*
* Requires that CD_PROVIDER_SQLITE or CD_PROVIDER_MEMORY is not defined — the default option
*/
#if defined(CD_PROVIDER_SQLITE) || !defined(CD_PROVIDER_MEMORY)
#include "CDAbstractSqliteProvider.h"
#define CD_PROVIDER(provider, key, value) CDAbstractSqliteProvider<key, value>* provider; typedef key CD_KEY; typedef value CD_VALUE
#define NEW_CD_PROVIDER(provider, name, parser, size_calculator, cache) provider = new CDAbstractSqliteProvider<CD_KEY, CD_VALUE>(name, parser, cache)
template<typename KeyType, typename MappedType>
using CDProvider = CDAbstractSqliteProvider<KeyType, MappedType>;
#endif

View File

@@ -1,7 +1,7 @@
#include "Database.h"
#include "Game.h"
#include "dConfig.h"
#include "Logger.h"
#include "dLogger.h"
using namespace std;
#pragma warning (disable:4251) //Disables SQL warnings
@@ -64,8 +64,8 @@ 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!");
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!", source.c_str());
else Game::logger->Log("Database", "Destroying MySQL connection!");
}
con->close();
@@ -84,7 +84,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
if (!con) {
Connect();
LOG("Trying to reconnect to MySQL");
Game::logger->Log("Database", "Trying to reconnect to MySQL");
}
if (!con->isValid() || con->isClosed()) {
@@ -93,7 +93,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
con = nullptr;
Connect();
LOG("Trying to reconnect to MySQL from invalid or closed connection");
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection");
}
auto* stmt = con->prepareStatement(str);

View File

@@ -5,10 +5,10 @@
#include "Database.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "dLogger.h"
#include "BinaryPathFinder.h"
#include <fstream>
#include <istream>
Migration LoadMigration(std::string path) {
Migration migration{};
@@ -53,7 +53,7 @@ void MigrationRunner::RunMigrations() {
delete stmt;
if (doExit) continue;
LOG("Running migration: %s", migration.name.c_str());
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
if (migration.name == "dlu/5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
@@ -67,7 +67,7 @@ void MigrationRunner::RunMigrations() {
}
if (finalSQL.empty() && !runSd0Migrations) {
LOG("Server database is up to date.");
Game::logger->Log("MigrationRunner", "Server database is up to date.");
return;
}
@@ -79,7 +79,7 @@ void MigrationRunner::RunMigrations() {
if (query.empty()) continue;
simpleStatement->execute(query.c_str());
} catch (sql::SQLException& e) {
LOG("Encountered error running migration: %s", e.what());
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
}
}
}
@@ -87,9 +87,9 @@ void MigrationRunner::RunMigrations() {
// 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);
Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels);
uint32_t numberOfTruncatedModels = BrickByBrickFix::TruncateBrokenBrickByBrickXml();
LOG("%i models were truncated from the database.", numberOfTruncatedModels);
Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels);
}
}
@@ -135,14 +135,14 @@ void MigrationRunner::RunSQLiteMigrations() {
// 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());
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) {
LOG("Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage());
Game::logger->Log("MigrationRunner", "Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage());
}
}
@@ -154,5 +154,5 @@ void MigrationRunner::RunSQLiteMigrations() {
CDClientDatabase::ExecuteQuery("COMMIT;");
}
LOG("CDServer database is up to date.");
Game::logger->Log("MigrationRunner", "CDServer database is up to date.");
}

View File

@@ -1,6 +1,7 @@
#include "CDActivitiesTable.h"
void CDActivitiesTable::LoadValuesFromDatabase() {
CDActivitiesTable::CDActivitiesTable(void) {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Activities");
@@ -54,3 +55,8 @@ std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActiviti
return data;
}
std::vector<CDActivities> CDActivitiesTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -30,10 +30,9 @@ private:
std::vector<CDActivities> entries;
public:
void LoadValuesFromDatabase();
CDActivitiesTable();
// Queries the table with a custom "where" clause
std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate);
const std::vector<CDActivities>& GetEntries() const { return this->entries; }
std::vector<CDActivities> GetEntries(void) const;
};

View File

@@ -1,6 +1,6 @@
#include "CDActivityRewardsTable.h"
void CDActivityRewardsTable::LoadValuesFromDatabase() {
CDActivityRewardsTable::CDActivityRewardsTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -43,3 +43,8 @@ std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(
return data;
}
std::vector<CDActivityRewards> CDActivityRewardsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -18,10 +18,10 @@ private:
std::vector<CDActivityRewards> entries;
public:
void LoadValuesFromDatabase();
CDActivityRewardsTable();
// Queries the table with a custom "where" clause
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
std::vector<CDActivityRewards> GetEntries() const;
std::vector<CDActivityRewards> GetEntries(void) const;
};

View File

@@ -2,35 +2,6 @@
#include "GeneralUtils.h"
#include "Game.h"
void CDAnimationsTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
while (!tableData.eof()) {
std::string animation_type = tableData.getStringField("animation_type", "");
DluAssert(!animation_type.empty());
AnimationGroupID animationGroupID = tableData.getIntField("animationGroupID", -1);
DluAssert(animationGroupID != -1);
CDAnimation entry;
entry.animation_name = tableData.getStringField("animation_name", "");
entry.chance_to_play = tableData.getFloatField("chance_to_play", 1.0f);
UNUSED_COLUMN(entry.min_loops = tableData.getIntField("min_loops", 0);)
UNUSED_COLUMN(entry.max_loops = tableData.getIntField("max_loops", 0);)
entry.animation_length = tableData.getFloatField("animation_length", 0.0f);
UNUSED_COLUMN(entry.hideEquip = tableData.getIntField("hideEquip", 0) == 1;)
UNUSED_COLUMN(entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", 0) == 1;)
UNUSED_COLUMN(entry.restartable = tableData.getIntField("restartable", 0) == 1;)
UNUSED_COLUMN(entry.face_animation_name = tableData.getStringField("face_animation_name", "");)
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow();
}
tableData.finalize();
}
bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again.

View File

@@ -27,7 +27,6 @@ class CDAnimationsTable : public CDTable<CDAnimationsTable> {
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
public:
void LoadValuesFromDatabase();
/**
* Given an animationType and the previousAnimationName played, return the next animationType to play.
* If there are more than 1 animationTypes that can be played, one is selected at random but also does not allow

View File

@@ -1,55 +1,53 @@
#include "CDBehaviorParameterTable.h"
#include "GeneralUtils.h"
uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
uint64_t key = behaviorID;
key <<= 31U;
key |= parameterID;
return key;
}
void CDBehaviorParameterTable::LoadValuesFromDatabase() {
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
uint32_t uniqueParameterId = 0;
uint64_t hash = 0;
while (!tableData.eof()) {
uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
CDBehaviorParameter entry;
entry.behaviorID = tableData.getIntField("behaviorID", -1);
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
auto parameter = m_ParametersList.find(candidateStringToAdd);
uint32_t parameterId;
if (parameter != m_ParametersList.end()) {
parameterId = parameter->second;
entry.parameterID = parameter;
} else {
parameterId = m_ParametersList.insert(std::make_pair(candidateStringToAdd, m_ParametersList.size())).first->second;
entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first;
uniqueParameterId++;
}
uint64_t hash = GetKey(behaviorID, parameterId);
float value = tableData.getFloatField("value", -1.0f);
hash = entry.behaviorID;
hash = (hash << 31U) | entry.parameterID->second;
entry.value = tableData.getFloatField("value", -1.0f);
m_Entries.insert(std::make_pair(hash, value));
tableData.nextRow();
m_Entries.insert(std::make_pair(hash, entry));
}
tableData.finalize();
}
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
auto parameterID = this->m_ParametersList.find(name);
if (parameterID == this->m_ParametersList.end()) return defaultValue;
auto hash = GetKey(behaviorID, parameterID->second);
uint64_t hash = behaviorID;
hash = (hash << 31U) | parameterID->second;
// Search for specific parameter
auto it = m_Entries.find(hash);
return it != m_Entries.end() ? it->second : defaultValue;
const auto& it = m_Entries.find(hash);
return it != m_Entries.end() ? it->second.value : defaultValue;
}
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
uint64_t hashBase = behaviorID;
std::map<std::string, float> returnInfo;
for (auto& [parameterString, parameterId] : m_ParametersList) {
uint64_t hash = GetKey(hashBase, parameterId);
uint64_t hash;
for (auto& parameterCandidate : m_ParametersList) {
hash = (hashBase << 31U) | parameterCandidate.second;
auto infoCandidate = m_Entries.find(hash);
if (infoCandidate != m_Entries.end()) {
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value));
}
}
return returnInfo;
}

View File

@@ -5,15 +5,18 @@
#include <unordered_map>
#include <unordered_set>
struct CDBehaviorParameter {
unsigned int behaviorID; //!< The Behavior ID
std::unordered_map<std::string, uint32_t>::iterator parameterID; //!< The Parameter ID
float value; //!< The value of the behavior template
};
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
private:
typedef uint64_t BehaviorParameterHash;
typedef float BehaviorParameterValue;
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public:
void LoadValuesFromDatabase();
CDBehaviorParameterTable();
float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
std::map<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);

View File

@@ -1,6 +1,6 @@
#include "CDBehaviorTemplateTable.h"
void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -48,7 +48,7 @@ std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<boo
return data;
}
const std::vector<CDBehaviorTemplate>& CDBehaviorTemplateTable::GetEntries() const {
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
return this->entries;
}
@@ -64,3 +64,4 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav
return entry->second;
}
}

View File

@@ -6,10 +6,10 @@
#include <unordered_set>
struct CDBehaviorTemplate {
unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT)
unsigned int effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT)
unsigned int effectID; //!< The Effect ID attached
size_t effectHandle; //!< The effect handle
};
@@ -19,12 +19,11 @@ private:
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public:
void LoadValuesFromDatabase();
CDBehaviorTemplateTable();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
const std::vector<CDBehaviorTemplate>& GetEntries(void) const;
std::vector<CDBehaviorTemplate> GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
};

View File

@@ -1,6 +1,6 @@
#include "CDBrickIDTableTable.h"
void CDBrickIDTableTable::LoadValuesFromDatabase() {
CDBrickIDTableTable::CDBrickIDTableTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -39,7 +39,7 @@ std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBric
return data;
}
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
std::vector<CDBrickIDTable> CDBrickIDTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -21,9 +21,9 @@ private:
std::vector<CDBrickIDTable> entries;
public:
void LoadValuesFromDatabase();
CDBrickIDTableTable();
// Queries the table with a custom "where" clause
std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate);
const std::vector<CDBrickIDTable>& GetEntries() const;
std::vector<CDBrickIDTable> GetEntries(void) const;
};

View File

@@ -1,7 +1,26 @@
#include "CDComponentsRegistryTable.h"
#include "eReplicaComponentType.h"
void CDComponentsRegistryTable::LoadValuesFromDatabase() {
#define CDCLIENT_CACHE_ALL
CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
#ifdef CDCLIENT_CACHE_ALL
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ComponentsRegistry");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
//this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
while (!tableData.eof()) {
@@ -11,42 +30,65 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
entry.component_id = tableData.getIntField("component_id", -1);
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
this->mappedEntries.insert_or_assign(entry.id, 0);
tableData.nextRow();
}
tableData.finalize();
#endif
}
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
auto exists = mappedEntries.find(id);
if (exists != mappedEntries.end()) {
auto iter = mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
return iter == mappedEntries.end() ? defaultValue : iter->second;
const auto& iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
if (iter == this->mappedEntries.end()) {
return defaultValue;
}
// Now get the data. Get all components of this entity so we dont do a query for each component
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ComponentsRegistry WHERE id = ?;");
query.bind(1, static_cast<int32_t>(id));
return iter->second;
auto tableData = query.execQuery();
#ifndef CDCLIENT_CACHE_ALL
// Now get the data
std::stringstream query;
query << "SELECT * FROM ComponentsRegistry WHERE id = " << std::to_string(id);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1);
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_type = tableData.getIntField("component_type", -1);
entry.component_id = tableData.getIntField("component_id", -1);
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
//this->entries.push_back(entry);
//Darwin's stuff:
const auto& it = this->mappedEntries.find(entry.id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(entry.component_type);
if (iter == it->second.end()) {
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
}
} else {
std::map<unsigned int, unsigned int> map;
map.insert(std::make_pair(entry.component_type, entry.component_id));
this->mappedEntries.insert(std::make_pair(entry.id, map));
}
tableData.nextRow();
}
mappedEntries.insert_or_assign(id, 0);
tableData.finalize();
auto iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
const auto& it2 = this->mappedEntries.find(id);
if (it2 != mappedEntries.end()) {
const auto& iter = it2->second.find(componentType);
if (iter != it2->second.end()) {
return iter->second;
}
}
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
return defaultValue;
#endif
}

View File

@@ -13,9 +13,9 @@ struct CDComponentsRegistry {
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
private:
std::unordered_map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
std::map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
public:
void LoadValuesFromDatabase();
CDComponentsRegistryTable();
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);
};

View File

@@ -1,7 +1,7 @@
#include "CDCurrencyTableTable.h"
//! Constructor
void CDCurrencyTableTable::LoadValuesFromDatabase() {
CDCurrencyTableTable::CDCurrencyTableTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -43,7 +43,7 @@ std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCu
return data;
}
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
std::vector<CDCurrencyTable> CDCurrencyTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -23,9 +23,9 @@ private:
std::vector<CDCurrencyTable> entries;
public:
void LoadValuesFromDatabase();
CDCurrencyTableTable();
// Queries the table with a custom "where" clause
std::vector<CDCurrencyTable> Query(std::function<bool(CDCurrencyTable)> predicate);
const std::vector<CDCurrencyTable>& GetEntries() const;
std::vector<CDCurrencyTable> GetEntries(void) const;
};

View File

@@ -1,6 +1,8 @@
#include "CDDestructibleComponentTable.h"
void CDDestructibleComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDDestructibleComponentTable::CDDestructibleComponentTable(void) {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent");
@@ -50,7 +52,7 @@ std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::fu
return data;
}
const std::vector<CDDestructibleComponent>& CDDestructibleComponentTable::GetEntries() const {
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -25,9 +25,9 @@ private:
std::vector<CDDestructibleComponent> entries;
public:
void LoadValuesFromDatabase();
CDDestructibleComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);
const std::vector<CDDestructibleComponent>& GetEntries(void) const;
std::vector<CDDestructibleComponent> GetEntries(void) const;
};

View File

@@ -1,26 +1,40 @@
#include "CDEmoteTable.h"
void CDEmoteTableTable::LoadValuesFromDatabase() {
//! Constructor
CDEmoteTableTable::CDEmoteTableTable(void) {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
while (!tableData.eof()) {
CDEmoteTable entry;
entry.ID = tableData.getIntField("id", -1);
entry.animationName = tableData.getStringField("animationName", "");
entry.iconFilename = tableData.getStringField("iconFilename", "");
entry.channel = tableData.getIntField("channel", -1);
entry.locked = tableData.getIntField("locked", -1) != 0;
entry.localize = tableData.getIntField("localize", -1) != 0;
entry.locState = tableData.getIntField("locStatus", -1);
entry.gateVersion = tableData.getStringField("gate_version", "");
CDEmoteTable* entry = new CDEmoteTable();
entry->ID = tableData.getIntField("id", -1);
entry->animationName = tableData.getStringField("animationName", "");
entry->iconFilename = tableData.getStringField("iconFilename", "");
entry->channel = tableData.getIntField("channel", -1);
entry->locked = tableData.getIntField("locked", -1) != 0;
entry->localize = tableData.getIntField("localize", -1) != 0;
entry->locState = tableData.getIntField("locStatus", -1);
entry->gateVersion = tableData.getStringField("gate_version", "");
entries.insert(std::make_pair(entry.ID, entry));
entries.insert(std::make_pair(entry->ID, entry));
tableData.nextRow();
}
tableData.finalize();
}
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
auto itr = entries.find(id);
return itr != entries.end() ? &itr->second : nullptr;
//! Destructor
CDEmoteTableTable::~CDEmoteTableTable(void) {
for (auto e : entries) {
if (e.second) delete e.second;
}
entries.clear();
}
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
for (auto e : entries) {
if (e.first == id) return e.second;
}
return nullptr;
}

View File

@@ -28,10 +28,11 @@ struct CDEmoteTable {
class CDEmoteTableTable : public CDTable<CDEmoteTableTable> {
private:
std::map<int, CDEmoteTable> entries;
std::map<int, CDEmoteTable*> entries;
public:
void LoadValuesFromDatabase();
CDEmoteTableTable();
~CDEmoteTableTable();
// Returns an emote by ID
CDEmoteTable* GetEmote(int id);
};

View File

@@ -1,6 +1,7 @@
#include "CDFeatureGatingTable.h"
void CDFeatureGatingTable::LoadValuesFromDatabase() {
//! Constructor
CDFeatureGatingTable::CDFeatureGatingTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -52,7 +53,7 @@ bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
return false;
}
const std::vector<CDFeatureGating>& CDFeatureGatingTable::GetEntries() const {
std::vector<CDFeatureGating> CDFeatureGatingTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -16,12 +16,11 @@ private:
std::vector<CDFeatureGating> entries;
public:
void LoadValuesFromDatabase();
CDFeatureGatingTable();
// Queries the table with a custom "where" clause
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
bool FeatureUnlocked(const std::string& feature) const;
const std::vector<CDFeatureGating>& GetEntries(void) const;
std::vector<CDFeatureGating> GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDInventoryComponentTable.h"
void CDInventoryComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDInventoryComponentTable::CDInventoryComponentTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -41,7 +42,7 @@ std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function
return data;
}
const std::vector<CDInventoryComponent>& CDInventoryComponentTable::GetEntries() const {
std::vector<CDInventoryComponent> CDInventoryComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -15,9 +15,9 @@ private:
std::vector<CDInventoryComponent> entries;
public:
void LoadValuesFromDatabase();
CDInventoryComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate);
const std::vector<CDInventoryComponent>& GetEntries() const;
std::vector<CDInventoryComponent> GetEntries(void) const;
};

View File

@@ -3,7 +3,11 @@
CDItemComponent CDItemComponentTable::Default = {};
void CDItemComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDItemComponentTable::CDItemComponentTable(void) {
Default = CDItemComponent();
#ifdef CDCLIENT_CACHE_ALL
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent");
@@ -51,13 +55,13 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
entry.currencyLOT = tableData.getIntField("currencyLOT", -1);
entry.altCurrencyCost = tableData.getIntField("altCurrencyCost", -1);
entry.subItems = tableData.getStringField("subItems", "");
UNUSED_COLUMN(entry.audioEventUse = tableData.getStringField("audioEventUse", ""));
entry.audioEventUse = tableData.getStringField("audioEventUse", "");
entry.noEquipAnimation = tableData.getIntField("noEquipAnimation", -1) == 1 ? true : false;
entry.commendationLOT = tableData.getIntField("commendationLOT", -1);
entry.commendationCost = tableData.getIntField("commendationCost", -1);
UNUSED_COLUMN(entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", ""));
entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", "");
entry.currencyCosts = tableData.getStringField("currencyCosts", "");
UNUSED_COLUMN(entry.ingredientInfo = tableData.getStringField("ingredientInfo", ""));
entry.ingredientInfo = tableData.getStringField("ingredientInfo", "");
entry.locStatus = tableData.getIntField("locStatus", -1);
entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
@@ -67,6 +71,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
}
tableData.finalize();
#endif
}
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
@@ -75,10 +80,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
return it->second;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ItemComponent WHERE id = ?;");
query.bind(1, static_cast<int32_t>(skillID));
#ifndef CDCLIENT_CACHE_ALL
std::stringstream query;
auto tableData = query.execQuery();
query << "SELECT * FROM ItemComponent WHERE id = " << std::to_string(skillID);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
if (tableData.eof()) {
entries.insert(std::make_pair(skillID, Default));
return Default;
@@ -137,6 +144,7 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
if (it2 != this->entries.end()) {
return it2->second;
}
#endif
return Default;
}

View File

@@ -54,7 +54,7 @@ private:
std::map<unsigned int, CDItemComponent> entries;
public:
void LoadValuesFromDatabase();
CDItemComponentTable();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
// Gets an entry by ID

View File

@@ -1,6 +1,7 @@
#include "CDItemSetSkillsTable.h"
void CDItemSetSkillsTable::LoadValuesFromDatabase() {
//! Constructor
CDItemSetSkillsTable::CDItemSetSkillsTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -40,7 +41,7 @@ std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDIt
return data;
}
const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -14,11 +14,11 @@ private:
std::vector<CDItemSetSkills> entries;
public:
void LoadValuesFromDatabase();
CDItemSetSkillsTable();
// Queries the table with a custom "where" clause
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);
const std::vector<CDItemSetSkills>& GetEntries() const;
std::vector<CDItemSetSkills> GetEntries(void) const;
std::vector<CDItemSetSkills> GetBySkillID(unsigned int SkillSetID);
};

View File

@@ -1,6 +1,7 @@
#include "CDItemSetsTable.h"
void CDItemSetsTable::LoadValuesFromDatabase() {
//! Constructor
CDItemSetsTable::CDItemSetsTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -52,7 +53,7 @@ std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> p
return data;
}
const std::vector<CDItemSets>& CDItemSetsTable::GetEntries() const {
std::vector<CDItemSets> CDItemSetsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -26,10 +26,10 @@ private:
std::vector<CDItemSets> entries;
public:
void LoadValuesFromDatabase();
CDItemSetsTable();
// Queries the table with a custom "where" clause
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);
const std::vector<CDItemSets>& GetEntries(void) const;
std::vector<CDItemSets> GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDLevelProgressionLookupTable.h"
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
//! Constructor
CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -31,6 +32,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
tableData.finalize();
}
//! Queries the table with a custom "where" clause
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) {
std::vector<CDLevelProgressionLookup> data = cpplinq::from(this->entries)
@@ -40,7 +42,8 @@ std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::
return data;
}
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
//! Gets all the entries in the table
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -14,10 +14,10 @@ private:
std::vector<CDLevelProgressionLookup> entries;
public:
void LoadValuesFromDatabase();
CDLevelProgressionLookupTable();
// Queries the table with a custom "where" clause
std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate);
const std::vector<CDLevelProgressionLookup>& GetEntries() const;
// Gets all the entries in the table
std::vector<CDLevelProgressionLookup> GetEntries(void) const;
};

View File

@@ -1,19 +1,7 @@
#include "CDLootMatrixTable.h"
CDLootMatrix CDLootMatrixTable::ReadRow(CppSQLite3Query& tableData) const {
CDLootMatrix entry{};
if (tableData.eof()) return entry;
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
entry.percent = tableData.getFloatField("percent", -1.0f);
entry.minToDrop = tableData.getIntField("minToDrop", -1);
entry.maxToDrop = tableData.getIntField("maxToDrop", -1);
entry.flagID = tableData.getIntField("flagID", -1);
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
return entry;
}
void CDLootMatrixTable::LoadValuesFromDatabase() {
//! Constructor
CDLootMatrixTable::CDLootMatrixTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -24,6 +12,8 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
@@ -31,28 +21,33 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
while (!tableData.eof()) {
CDLootMatrix entry;
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
entry.percent = tableData.getFloatField("percent", -1.0f);
entry.minToDrop = tableData.getIntField("minToDrop", -1);
entry.maxToDrop = tableData.getIntField("maxToDrop", -1);
entry.id = tableData.getIntField("id", -1);
entry.flagID = tableData.getIntField("flagID", -1);
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
this->entries[lootMatrixIndex].push_back(ReadRow(tableData));
tableData.nextRow();
}
}
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto itr = this->entries.find(matrixId);
if (itr != this->entries.end()) {
return itr->second;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootMatrix where LootMatrixIndex = ?;");
query.bind(1, static_cast<int32_t>(matrixId));
auto tableData = query.execQuery();
while (!tableData.eof()) {
this->entries[matrixId].push_back(ReadRow(tableData));
this->entries.push_back(entry);
tableData.nextRow();
}
return this->entries[matrixId];
tableData.finalize();
}
std::vector<CDLootMatrix> CDLootMatrixTable::Query(std::function<bool(CDLootMatrix)> predicate) {
std::vector<CDLootMatrix> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
const std::vector<CDLootMatrix>& CDLootMatrixTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -4,26 +4,26 @@
#include "CDTable.h"
struct CDLootMatrix {
unsigned int LootMatrixIndex; //!< The Loot Matrix Index
unsigned int LootTableIndex; //!< The Loot Table Index
unsigned int RarityTableIndex; //!< The Rarity Table Index
float percent; //!< The percent that this matrix is used?
unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop
unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop
unsigned int id; //!< The ID of the Loot Matrix
unsigned int flagID; //!< ???
UNUSED(std::string gate_version); //!< The Gate Version
};
typedef uint32_t LootMatrixIndex;
typedef std::vector<CDLootMatrix> LootMatrixEntries;
class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
public:
void LoadValuesFromDatabase();
// Gets a matrix by ID or inserts a blank one if none existed.
const LootMatrixEntries& GetMatrix(uint32_t matrixId);
private:
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
std::vector<CDLootMatrix> entries;
public:
CDLootMatrixTable();
// Queries the table with a custom "where" clause
std::vector<CDLootMatrix> Query(std::function<bool(CDLootMatrix)> predicate);
const std::vector<CDLootMatrix>& GetEntries(void) const;
};

View File

@@ -1,43 +1,7 @@
#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{};
if (tableData.eof()) return entry;
entry.itemid = tableData.getIntField("itemid", -1);
entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false;
entry.sortPriority = tableData.getIntField("sortPriority", -1);
return entry;
}
void CDLootTableTable::LoadValuesFromDatabase() {
//! Constructor
CDLootTableTable::CDLootTableTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -48,6 +12,8 @@ void CDLootTableTable::LoadValuesFromDatabase() {
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
@@ -55,32 +21,32 @@ void CDLootTableTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable");
while (!tableData.eof()) {
CDLootTable entry;
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
entry.id = tableData.getIntField("id", -1);
entry.itemid = tableData.getIntField("itemid", -1);
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
entry.id = tableData.getIntField("id", -1);
entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false;
entry.sortPriority = tableData.getIntField("sortPriority", -1);
this->entries[lootTableIndex].push_back(ReadRow(tableData));
this->entries.push_back(entry);
tableData.nextRow();
}
for (auto& [id, table] : this->entries) {
SortTable(table);
}
tableData.finalize();
}
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
auto itr = this->entries.find(tableId);
if (itr != this->entries.end()) {
return itr->second;
}
//! Queries the table with a custom "where" clause
std::vector<CDLootTable> CDLootTableTable::Query(std::function<bool(CDLootTable)> predicate) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootTable WHERE LootTableIndex = ?;");
query.bind(1, static_cast<int32_t>(tableId));
auto tableData = query.execQuery();
std::vector<CDLootTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
while (!tableData.eof()) {
CDLootTable entry;
this->entries[tableId].push_back(ReadRow(tableData));
tableData.nextRow();
}
SortTable(this->entries[tableId]);
return this->entries[tableId];
return data;
}
//! Gets all the entries in the table
const std::vector<CDLootTable>& CDLootTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -6,21 +6,20 @@
struct CDLootTable {
unsigned int itemid; //!< The LOT of the item
unsigned int LootTableIndex; //!< The Loot Table Index
unsigned int id; //!< The ID
bool MissionDrop; //!< Whether or not this loot table is a mission drop
unsigned int sortPriority; //!< The sorting priority
};
typedef uint32_t LootTableIndex;
typedef std::vector<CDLootTable> LootTableEntries;
class CDLootTableTable : public CDTable<CDLootTableTable> {
private:
CDLootTable ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootTableIndex, LootTableEntries> entries;
std::vector<CDLootTable> entries;
public:
void LoadValuesFromDatabase();
CDLootTableTable();
// Queries the table with a custom "where" clause
const LootTableEntries& GetTable(uint32_t tableId);
std::vector<CDLootTable> Query(std::function<bool(CDLootTable)> predicate);
const std::vector<CDLootTable>& GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDMissionEmailTable.h"
void CDMissionEmailTable::LoadValuesFromDatabase() {
//! Constructor
CDMissionEmailTable::CDMissionEmailTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -47,7 +48,7 @@ std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMiss
}
//! Gets all the entries in the table
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
std::vector<CDMissionEmail> CDMissionEmailTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -20,9 +20,9 @@ private:
std::vector<CDMissionEmail> entries;
public:
void LoadValuesFromDatabase();
CDMissionEmailTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate);
const std::vector<CDMissionEmail>& GetEntries() const;
std::vector<CDMissionEmail> GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDMissionNPCComponentTable.h"
void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDMissionNPCComponentTable::CDMissionNPCComponentTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -44,7 +45,7 @@ std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::functi
}
//! Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& CDMissionNPCComponentTable::GetEntries() const {
std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -16,12 +16,12 @@ private:
std::vector<CDMissionNPCComponent> entries;
public:
void LoadValuesFromDatabase();
CDMissionNPCComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);
// Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& GetEntries() const;
std::vector<CDMissionNPCComponent> GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDMissionTasksTable.h"
void CDMissionTasksTable::LoadValuesFromDatabase() {
//! Constructor
CDMissionTasksTable::CDMissionTasksTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -55,14 +56,16 @@ std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missio
for (auto& entry : this->entries) {
if (entry.id == missionID) {
tasks.push_back(&entry);
CDMissionTasks* task = const_cast<CDMissionTasks*>(&entry);
tasks.push_back(task);
}
}
return tasks;
}
const std::vector<CDMissionTasks>& CDMissionTasksTable::GetEntries() const {
const std::vector<CDMissionTasks>& CDMissionTasksTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -24,12 +24,12 @@ private:
std::vector<CDMissionTasks> entries;
public:
void LoadValuesFromDatabase();
CDMissionTasksTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate);
std::vector<CDMissionTasks*> GetByMissionID(uint32_t missionID);
const std::vector<CDMissionTasks>& GetEntries() const;
const std::vector<CDMissionTasks>& GetEntries(void) const;
};

View File

@@ -2,7 +2,8 @@
CDMissions CDMissionsTable::Default = {};
void CDMissionsTable::LoadValuesFromDatabase() {
//! Constructor
CDMissionsTable::CDMissionsTable(void) {
// First, get the size of the table
unsigned int size = 0;

View File

@@ -65,12 +65,12 @@ private:
std::vector<CDMissions> entries;
public:
void LoadValuesFromDatabase();
CDMissionsTable();
// Queries the table with a custom "where" clause
std::vector<CDMissions> Query(std::function<bool(CDMissions)> predicate);
// Gets all the entries in the table
const std::vector<CDMissions>& GetEntries() const;
const std::vector<CDMissions>& GetEntries(void) const;
const CDMissions* GetPtrByMissionID(uint32_t missionID) const;

View File

@@ -1,6 +1,7 @@
#include "CDMovementAIComponentTable.h"
void CDMovementAIComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDMovementAIComponentTable::CDMovementAIComponentTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -36,6 +37,7 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() {
tableData.finalize();
}
//! Queries the table with a custom "where" clause
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::function<bool(CDMovementAIComponent)> predicate) {
std::vector<CDMovementAIComponent> data = cpplinq::from(this->entries)
@@ -45,7 +47,8 @@ std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::functi
return data;
}
const std::vector<CDMovementAIComponent>& CDMovementAIComponentTable::GetEntries(void) const {
//! Gets all the entries in the table
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -19,10 +19,10 @@ private:
std::vector<CDMovementAIComponent> entries;
public:
void LoadValuesFromDatabase();
CDMovementAIComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDMovementAIComponent> Query(std::function<bool(CDMovementAIComponent)> predicate);
// Gets all the entries in the table
const std::vector<CDMovementAIComponent>& GetEntries() const;
std::vector<CDMovementAIComponent> GetEntries(void) const;
};

View File

@@ -1,6 +1,7 @@
#include "CDObjectSkillsTable.h"
void CDObjectSkillsTable::LoadValuesFromDatabase() {
//! Constructor
CDObjectSkillsTable::CDObjectSkillsTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -32,6 +33,7 @@ void CDObjectSkillsTable::LoadValuesFromDatabase() {
tableData.finalize();
}
//! Queries the table with a custom "where" clause
std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObjectSkills)> predicate) {
std::vector<CDObjectSkills> data = cpplinq::from(this->entries)
@@ -41,6 +43,7 @@ std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObje
return data;
}
const std::vector<CDObjectSkills>& CDObjectSkillsTable::GetEntries() const {
//! Gets all the entries in the table
std::vector<CDObjectSkills> CDObjectSkillsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -15,12 +15,12 @@ private:
std::vector<CDObjectSkills> entries;
public:
void LoadValuesFromDatabase();
CDObjectSkillsTable();
// Queries the table with a custom "where" clause
std::vector<CDObjectSkills> Query(std::function<bool(CDObjectSkills)> predicate);
// Gets all the entries in the table
const std::vector<CDObjectSkills>& GetEntries() const;
std::vector<CDObjectSkills> GetEntries(void) const;
};

View File

@@ -1,6 +1,8 @@
#include "CDObjectsTable.h"
void CDObjectsTable::LoadValuesFromDatabase() {
//! Constructor
CDObjectsTable::CDObjectsTable(void) {
#ifdef CDCLIENT_CACHE_ALL
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Objects");
@@ -18,24 +20,25 @@ void CDObjectsTable::LoadValuesFromDatabase() {
CDObjects entry;
entry.id = tableData.getIntField("id", -1);
entry.name = tableData.getStringField("name", "");
UNUSED_COLUMN(entry.placeable = tableData.getIntField("placeable", -1);)
entry.placeable = tableData.getIntField("placeable", -1);
entry.type = tableData.getStringField("type", "");
UNUSED_COLUMN(entry.description = tableData.getStringField("description", "");)
UNUSED_COLUMN(entry.localize = tableData.getIntField("localize", -1);)
UNUSED_COLUMN(entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1);)
UNUSED_COLUMN(entry.displayName = tableData.getStringField("displayName", "");)
entry.description = tableData.getStringField("description", "");
entry.localize = tableData.getIntField("localize", -1);
entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1);
entry.displayName = tableData.getStringField("displayName", "");
entry.interactionDistance = tableData.getFloatField("interactionDistance", -1.0f);
UNUSED_COLUMN(entry.nametag = tableData.getIntField("nametag", -1);)
UNUSED_COLUMN(entry._internalNotes = tableData.getStringField("_internalNotes", "");)
UNUSED_COLUMN(entry.locStatus = tableData.getIntField("locStatus", -1);)
UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", "");)
UNUSED_COLUMN(entry.HQ_valid = tableData.getIntField("HQ_valid", -1);)
entry.nametag = tableData.getIntField("nametag", -1);
entry._internalNotes = tableData.getStringField("_internalNotes", "");
entry.locStatus = tableData.getIntField("locStatus", -1);
entry.gate_version = tableData.getStringField("gate_version", "");
entry.HQ_valid = tableData.getIntField("HQ_valid", -1);
this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow();
}
tableData.finalize();
#endif
m_default.id = 0;
}
@@ -46,10 +49,12 @@ const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) {
return it->second;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Objects WHERE id = ?;");
query.bind(1, static_cast<int32_t>(LOT));
#ifndef CDCLIENT_CACHE_ALL
std::stringstream query;
auto tableData = query.execQuery();
query << "SELECT * FROM Objects WHERE id = " << std::to_string(LOT);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
if (tableData.eof()) {
this->entries.insert(std::make_pair(LOT, m_default));
return m_default;
@@ -83,6 +88,7 @@ const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) {
if (it2 != entries.end()) {
return it2->second;
}
#endif
return m_default;
}

View File

@@ -26,7 +26,7 @@ private:
CDObjects m_default;
public:
void LoadValuesFromDatabase();
CDObjectsTable();
// Gets an entry by ID
const CDObjects& GetByID(unsigned int LOT);
};

View File

@@ -1,6 +1,7 @@
#include "CDPackageComponentTable.h"
void CDPackageComponentTable::LoadValuesFromDatabase() {
//! Constructor
CDPackageComponentTable::CDPackageComponentTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -42,7 +43,7 @@ std::vector<CDPackageComponent> CDPackageComponentTable::Query(std::function<boo
}
//! Gets all the entries in the table
const std::vector<CDPackageComponent>& CDPackageComponentTable::GetEntries() const {
std::vector<CDPackageComponent> CDPackageComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -14,9 +14,9 @@ private:
std::vector<CDPackageComponent> entries;
public:
void LoadValuesFromDatabase();
CDPackageComponentTable(void);
// Queries the table with a custom "where" clause
std::vector<CDPackageComponent> Query(std::function<bool(CDPackageComponent)> predicate);
const std::vector<CDPackageComponent>& GetEntries() const;
std::vector<CDPackageComponent> GetEntries(void) const;
};

View File

@@ -1,35 +1,46 @@
#include "CDPhysicsComponentTable.h"
void CDPhysicsComponentTable::LoadValuesFromDatabase() {
CDPhysicsComponentTable::CDPhysicsComponentTable(void) {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent");
while (!tableData.eof()) {
CDPhysicsComponent entry;
entry.id = tableData.getIntField("id", -1);
entry.bStatic = tableData.getIntField("static", -1) != 0;
entry.physicsAsset = tableData.getStringField("physics_asset", "");
CDPhysicsComponent* entry = new CDPhysicsComponent();
entry->id = tableData.getIntField("id", -1);
entry->bStatic = tableData.getIntField("static", -1) != 0;
entry->physicsAsset = tableData.getStringField("physics_asset", "");
UNUSED(entry->jump = tableData.getIntField("jump", -1) != 0);
UNUSED(entry->doublejump = tableData.getIntField("doublejump", -1) != 0);
entry.speed = tableData.getFloatField("speed", -1);
entry->speed = tableData.getFloatField("speed", -1);
UNUSED(entry->rotSpeed = tableData.getFloatField("rotSpeed", -1));
entry.playerHeight = tableData.getFloatField("playerHeight");
entry.playerRadius = tableData.getFloatField("playerRadius");
entry.pcShapeType = tableData.getIntField("pcShapeType");
entry.collisionGroup = tableData.getIntField("collisionGroup");
entry->playerHeight = tableData.getFloatField("playerHeight");
entry->playerRadius = tableData.getFloatField("playerRadius");
entry->pcShapeType = tableData.getIntField("pcShapeType");
entry->collisionGroup = tableData.getIntField("collisionGroup");
UNUSED(entry->airSpeed = tableData.getFloatField("airSpeed"));
UNUSED(entry->boundaryAsset = tableData.getStringField("boundaryAsset"));
UNUSED(entry->jumpAirSpeed = tableData.getFloatField("jumpAirSpeed"));
UNUSED(entry->friction = tableData.getFloatField("friction"));
UNUSED(entry->gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset"));
m_entries.insert(std::make_pair(entry.id, entry));
m_entries.insert(std::make_pair(entry->id, entry));
tableData.nextRow();
}
tableData.finalize();
}
CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) {
auto itr = m_entries.find(componentID);
return itr != m_entries.end() ? &itr->second : nullptr;
CDPhysicsComponentTable::~CDPhysicsComponentTable() {
for (auto e : m_entries) {
if (e.second) delete e.second;
}
m_entries.clear();
}
CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) {
for (auto e : m_entries) {
if (e.first == componentID) return e.second;
}
return nullptr;
}

View File

@@ -23,11 +23,12 @@ struct CDPhysicsComponent {
class CDPhysicsComponentTable : public CDTable<CDPhysicsComponentTable> {
public:
void LoadValuesFromDatabase();
CDPhysicsComponentTable();
~CDPhysicsComponentTable();
static const std::string GetTableName() { return "PhysicsComponent"; };
CDPhysicsComponent* GetByID(unsigned int componentID);
private:
std::map<unsigned int, CDPhysicsComponent> m_entries;
std::map<unsigned int, CDPhysicsComponent*> m_entries;
};

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