Compare commits

..

122 Commits

Author SHA1 Message Date
David Markowitz
6240eefc7e local work 2023-07-11 00:26:27 -07:00
David Markowitz
949a6db4bc RailActivatorComponent pass 2023-07-11 00:23:27 -07:00
David Markowitz
49f3d757e5 ProximityMonitorComponent re-pass 2023-07-11 00:15:05 -07:00
David Markowitz
c204ea4009 PropertyVendorComponent pass 2023-07-11 00:07:08 -07:00
David Markowitz
a37ec326b9 idek if ill keep this but yeah 2023-07-11 00:02:59 -07:00
EmosewaMC
8678ed03c3 push no pass 2023-07-10 22:18:42 -07:00
David Markowitz
37bcc81694 PropertyComponent pass 2023-07-09 22:41:22 -07:00
David Markowitz
4d88f63338 PossessionComponent pass 2023-07-09 22:37:28 -07:00
David Markowitz
59831fc15d PhantomPhysicsComponent pass 2023-07-09 22:34:24 -07:00
David Markowitz
fe6b279ebb PossessableComponent pass 2023-07-09 22:34:18 -07:00
David Markowitz
598d88b307 PlayerForcedMovementComponent pass 2023-07-09 22:20:51 -07:00
David Markowitz
28637a206d PhantomPhysicsComponent pass 2023-07-09 22:17:57 -07:00
David Markowitz
87675aa62d PetComponent pass 2023-07-09 21:54:11 -07:00
David Markowitz
83780affbd MutableModelBehaviorComponent pass 2023-07-09 20:56:04 -07:00
David Markowitz
7ca9e59ef2 MultiZoneEntranceComponent pass 2023-07-09 20:52:48 -07:00
David Markowitz
d2a7e147cc I am throwing this one out later. 2023-07-09 20:44:08 -07:00
David Markowitz
8a512e5c76 MovementAiComponent pass 2023-07-09 20:38:47 -07:00
David Markowitz
2528e02b98 add final 2023-07-09 19:48:23 -07:00
David Markowitz
1b7be5d7db Merge branch 'components-wheeeee' of https://github.com/DarkflameUniverse/DarkflameServer into components-wheeeee 2023-07-09 19:45:35 -07:00
EmosewaMC
790bd6c03b Merge branch 'components-wheeeee' of https://github.com/DarkflameUniverse/DarkflameServer into components-wheeeee 2023-07-08 01:31:52 -07:00
EmosewaMC
28fbe20b97 ModuleAssemblyComponent pass 2023-07-08 01:31:26 -07:00
David Markowitz
cf53e35af5 SwitchComponent pass 2023-07-07 12:13:26 -07:00
EmosewaMC
5301346ed5 ModelBehaviorComponent pass 2023-07-05 20:37:16 -07:00
EmosewaMC
001f6a75eb MissionOfferComponent pass 2023-07-05 20:30:52 -07:00
EmosewaMC
950a1fe423 MissionComponent pass 2023-07-05 19:32:28 -07:00
197d1bcdee Merge branch 'main' into components-wheeeee 2023-07-05 07:59:52 -05:00
EmosewaMC
68a2a04e5d LUPExhibitComponent cleanup 2023-07-04 22:52:51 -07:00
EmosewaMC
cfec9801a8 LevelProgressionComponent cleanup 2023-07-04 22:38:46 -07:00
EmosewaMC
8ede5b87ca Fix compilation error; add final specifiers 2023-07-04 22:38:35 -07:00
EmosewaMC
c22040c6eb ItemComponent Pass
make use of Writing a length
add C include guard
2023-07-04 22:17:44 -07:00
6fb1786cf1 Add component order array
fix loop in inven comp
2023-06-29 12:44:06 -05:00
David Markowitz
81404d9671 InventoryComponent pass
- reduce scope usage
- bouncing returns
- std::for_each in some contexts
- extra nullptr checks
- constiness
- extra logs
- scoped enum type for eItemType
- lol serialization.
2023-06-28 01:20:41 -07:00
David Markowitz
0544eeba1f Add default constructor for EquipmentItem
Change struct constructors to proper constructors.
2023-06-27 02:01:43 -07:00
David Markowitz
c2fe7f6205 HavokVehicleComponent improvements
serialization, moving stuff to header, removal of update as we serialize dirty position so often this check is pointless.
2023-06-26 23:28:23 -07:00
David Markowitz
f55bec026d Donation Component serialization 2023-06-26 23:17:59 -07:00
David Markowitz
478b6ff6a9 Move empty definitions to header 2023-06-26 23:01:46 -07:00
David Markowitz
7c1265911c move ctor to header for collectible 2023-06-26 22:59:57 -07:00
David Markowitz
c6063aac66 Component serialization updates
- Fix serialization in multiple components so they don't get dirty flags reset when it was not intentional
2023-06-26 22:58:35 -07:00
David Markowitz
2abcb142ad Character fixes - get it compiling again
- Pass componentID to activity component constructor
- use int componentid so -1 can denote no component
2023-06-26 22:39:15 -07:00
David Markowitz
d9a3bea6d5 Merge branch 'components-wheeeee' of https://github.com/DarkflameUniverse/DarkflameServer into components-wheeeee 2023-06-26 21:59:02 -07:00
David Markowitz
fdcfbdee85 BuildBorderCleanup 2023-06-26 21:58:56 -07:00
fd182d222f Update activing and racing components
Hopefully not going to rename them for a third time, no way
2023-06-26 15:06:33 -05:00
68f90b7136 rename possessor to possession 2023-06-26 12:36:36 -05:00
David Markowitz
d29287f9d9 Buff Component fixes 2023-06-26 01:49:56 -07:00
David Markowitz
06acd23cb7 Use of final 2023-06-26 01:23:22 -07:00
David Markowitz
a5611e9c7f Bouncer cleanup
- Correct variable names
- Make serialization more efficient and make sense
- remove unneeded members
- more descriptive logs
- Move work to Startup
2023-06-26 01:19:49 -07:00
David Markowitz
34cfd45d40 CombatAI and Vendor 2023-06-26 00:15:25 -07:00
David Markowitz
ec9278286b Use better naming
- Remove use of Base.  It is implied if you inherit that the class inherited from is a Base.
- Fix compilation errors from said change.
2023-06-25 22:00:01 -07:00
David Markowitz
9121bf41c5 Entity work
- Add in bool cheks
- Fix component class files so they compile and link
- Fin inheritance
2023-06-25 21:47:35 -07:00
David Markowitz
fee1025982 Remove commented out logic, add ghosting exclusion
We dont create items that are in an inventory, so that path is pointless for us.
2023-06-25 21:05:25 -07:00
David Markowitz
3f328a18be Merge upstream ghosting candidate changes 2023-06-25 21:01:10 -07:00
485a88dfd4 move vars to be local 2023-06-24 01:56:13 -05:00
c237c16c33 group physicstogether in heirarchy 2023-06-23 16:56:56 -05:00
d44b18e38f rough logic around loading physics
as well as modelbehaviors
2023-06-23 12:01:41 -05:00
d153d66e26 Merge branch 'item-component' into components-wheeeee 2023-06-23 11:01:16 -05:00
34d22d2d0d AchievementVendor scaffold 2023-06-23 10:56:05 -05:00
bcbc5882dc Merge branch 'main' into components-wheeeee 2023-06-23 10:36:21 -05:00
f27e0400e7 scaffold activity based components 2023-06-23 10:30:03 -05:00
c78760db59 make inheritence clearer 2023-06-23 09:21:19 -05:00
907e045904 some tweaks 2023-06-23 01:10:06 -05:00
dc96fcba85 Vendor cleanup and start Donation Vendor impl 2023-06-23 00:56:25 -05:00
David Markowitz
e180430ede Finish header re-ordering 2023-06-17 18:41:51 -07:00
David Markowitz
1bdec00a61 More organization of header 2023-06-17 02:39:33 -07:00
David Markowitz
68a5cc1d89 Use better API terminology for radii
- SetProximityRadius just calls AddProximityRadius so its clear what is going on.
- created struct BoxDimensions for clear reading of what the floats are
2023-06-17 02:01:42 -07:00
David Markowitz
be17d1a467 Update DestroyableComponent.cpp 2023-06-16 02:02:33 -07:00
David Markowitz
a992a28088 Merge from upstream 2023-06-16 02:01:01 -07:00
David Markowitz
891648288a Organize Entity header
Probably the third or fourth pass of this darn header...  Just keep making it better every time
Rename some functions to make more sense to a reader
Use different method for Observing/subscribing to component events
Get rid of abomination of overloading GetParentUser
2023-06-16 01:56:02 -07:00
David Markowitz
92006123b8 Another consistency pass
- change NotifyObject to use u16 string
- move stuff to header that is inline
- use u16strings instead of converting to u16 string
- move entity to dEntity
2023-06-16 01:01:13 -07:00
David Markowitz
9a9b9aa813 Merge branch 'components-wheeeee' of https://github.com/DarkflameUniverse/DarkflameServer into components-wheeeee 2023-06-15 23:58:59 -07:00
David Markowitz
ea975965ca Fix typo 2023-06-15 23:58:39 -07:00
EmosewaMC
35e5d8497b Remove empty destructors 2023-06-15 02:32:30 -07:00
EmosewaMC
4d57eff946 Update includes 2023-06-15 02:28:27 -07:00
EmosewaMC
2a8f40f8e8 Finish file 2023-06-15 02:13:25 -07:00
EmosewaMC
355f4f4df8 Update Entity.cpp 2023-06-14 23:17:30 -07:00
EmosewaMC
451f7e76d7 switch to unique_ptrs for callback timers 2023-06-14 23:16:31 -07:00
EmosewaMC
83065dfb6f I havent checked if this compiled 2023-06-14 19:01:31 -07:00
fdd98ab825 fix other script calls 2023-06-13 22:01:51 -05:00
David Markowitz
31be1fbe4c remove script stuff 2023-06-13 19:55:27 -07:00
David Markowitz
d8e2e92428 use get 2023-06-13 19:47:14 -07:00
e389a619ad update heirarchy 2023-06-13 10:31:39 -05:00
David Markowitz
45bcc80a1b doesnt compile 2023-06-12 15:32:46 -07:00
David Markowitz
b2fee29ee0 Better log and comment 2023-06-12 04:37:38 -07:00
David Markowitz
326c495776 Use more clear control paths 2023-06-12 04:27:14 -07:00
David Markowitz
d224a86e93 Use only 1 script component per Entity
Serialization won't make sense if we allow two of the same component like that
2023-06-12 04:13:06 -07:00
David Markowitz
f9ac0a9dec few more pointer specifiers 2023-06-12 04:04:45 -07:00
David Markowitz
3f3810519d Extra * on one auto 2023-06-12 04:01:45 -07:00
David Markowitz
5be9146662 Specify auto ptr 2023-06-12 04:00:44 -07:00
David Markowitz
262b6ebb58 Remove old Entity Initialize 2023-06-12 03:55:07 -07:00
David Markowitz
6f38a150d3 Minor formatting change 2023-06-12 03:47:57 -07:00
David Markowitz
36c44ecc83 Fully re-implemented initialize 2023-06-12 01:29:43 -07:00
David Markowitz
fc719cbb0a Comment out done code 2023-06-11 04:46:22 -07:00
David Markowitz
f78ea1bbc9 whitespace and comments in quickbuild 2023-06-11 04:40:19 -07:00
David Markowitz
b43e5c2165 doesnt have a component 2023-06-11 04:39:28 -07:00
David Markowitz
5f139c75e0 Quickbuild and Destroyable reintegration 2023-06-11 04:37:53 -07:00
David Markowitz
77dc6ff312 Continued re-integration of Entity::Initialize 2023-06-11 03:06:18 -07:00
David Markowitz
0b5df9f0b1 Destroyable 2023-06-10 05:10:00 -07:00
David Markowitz
b91f84d884 Collectible, Item, further re-implement initialize 2023-06-10 04:46:48 -07:00
David Markowitz
cebe3c732a Update to actually work with component list 2023-06-10 00:14:20 -07:00
David Markowitz
5714ac558e Use std algorithms 2023-06-10 00:03:07 -07:00
David Markowitz
2a2799793d More robust tests 2023-06-09 23:05:44 -07:00
David Markowitz
1c23f3c030 Add test for component Whitelists 2023-06-09 23:02:28 -07:00
a68fa69e7a Rename RebuildComponent to QuickbuildComponent 2023-06-09 17:12:57 -05:00
David Markowitz
ddc5f0e117 Merge branch 'main' into components-wheeeee 2023-06-09 04:05:55 -07:00
David Markowitz
e3a716a9cf Further re-implement Entity::Initialize
wheee
2023-06-09 04:05:04 -07:00
David Markowitz
0b37dc1e4d Update includes for propertyEnteranceComponent
Class must be complete to be used in a MoveAssignment
2023-06-09 04:03:58 -07:00
David Markowitz
f2d28cc0bd Update CMakeLists.txt 2023-06-09 04:02:45 -07:00
David Markowitz
5da776a084 Add blank classes for some Components
Racing Stats

Minigame Control
2023-06-09 04:02:40 -07:00
David Markowitz
6f057204be Rename some variables
- Add order for loading Components
- Enforce all components have Entity* in the first argument
2023-06-09 02:46:01 -07:00
David Markowitz
f555ba8c25 Rename from GetOwningEntity to GetParentEntity 2023-06-09 01:28:01 -07:00
David Markowitz
e2dfa1809d Replace all auto with auto*
For components
2023-06-09 01:27:05 -07:00
David Markowitz
62aa863997 Remove shared pointer, ODR of componentType variable 2023-06-09 01:22:45 -07:00
EmosewaMC
ec00f5fd9d holy mother of const
Use const everywhere that makes sense
return const variables when it makes sense
const functions and variables again, where it makes sense
No raw access and modifications to protected members
Move template definitions to tcc file

idk how I feel about this one
2023-06-09 01:04:42 -07:00
d11e2db887 update component names, document heirarchy 2023-06-08 10:29:17 -05:00
David Markowitz
9e9e4dc087 Move to shared pointer 2023-06-07 00:23:50 -07:00
David Markowitz
ea9d0d8592 I hope this works 2023-06-06 20:48:30 -07:00
David Markowitz
716a5fcf37 Rename some variables in Component
And add more virtuals
2023-06-06 18:59:53 -07:00
15988afb4c hey it compiles 2023-03-20 21:14:52 -05:00
5e9a956bed Merge branch 'main' into item-component 2023-03-20 21:05:58 -05:00
c2d5be0e5d include 2023-03-20 20:59:11 -05:00
2ae9a92b55 fix cmake 2023-02-10 21:43:39 -06:00
50978620d8 Merge branch 'main' into item-component 2023-02-10 21:35:53 -06:00
c168f6c970 Break out the model component
into the model, item, and mutable model behaviors
2023-02-10 21:33:30 -06:00
575 changed files with 12545 additions and 15614 deletions

View File

@@ -10,7 +10,7 @@ trim_trailing_whitespace=true
end_of_line=lf
insert_final_newline=true
[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli}]
[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli,tcc,tpp}]
vc_generate_documentation_comments=doxygen_slash_star

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

@@ -97,56 +97,15 @@ make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
message(STATUS "Checking resource file integrity")
foreach (resource_file ${RESOURCE_FILES})
set(file_size 0)
if (EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
endif()
if (${file_size} EQUAL 0)
foreach(resource_file ${RESOURCE_FILES})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY
)
message(STATUS "Moved " ${resource_file} " to project binary directory")
elseif (resource_file MATCHES ".ini")
message(STATUS "Checking " ${resource_file} " for missing config options")
file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents)
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
set(parsed_current_file_contents "")
# Remove comment lines so they do not interfere with the variable parsing
foreach (line ${current_file_contents})
string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
string(APPEND parsed_current_file_contents ${line})
endif()
endforeach()
file(READ ${CMAKE_SOURCE_DIR}/resources/${resource_file} depot_file_contents)
string(REPLACE "\\\n" "" depot_file_contents ${depot_file_contents})
string(REPLACE "\n" ";" depot_file_contents ${depot_file_contents})
set(line_to_add "")
foreach (line ${depot_file_contents})
string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
string(REPLACE "=" ";" line_split ${line})
list(GET line_split 0 variable_name)
if (NOT ${parsed_current_file_contents} MATCHES ${variable_name})
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
set(line_to_add ${line_to_add} ${line})
foreach (line_to_append ${line_to_add})
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
endforeach()
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
endif()
set(line_to_add "")
else()
set(line_to_add ${line_to_add} ${line})
endif()
endforeach()
message("Moved ${resource_file} to project binary directory")
endif()
endforeach()
message(STATUS "Resource file integrity check complete")
# Copy navmesh data on first build and extract it
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
@@ -346,7 +305,7 @@ file(
file(
GLOB HEADERS_DGAME
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/dGame/Entity.h
${PROJECT_SOURCE_DIR}/dGame/dEntity/Entity.h
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h

View File

@@ -1,8 +1,12 @@
PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=1
PROJECT_VERSION_PATCH=1
PROJECT_VERSION_MINOR=0
PROJECT_VERSION_PATCH=4
# 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
@@ -13,10 +17,8 @@ __dynamic=1
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
# __compile_backtrace__=1
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
__maria_db_connector_compile_jobs__=1
__maria_db_connector_compile_jobs__=
# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done.
__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.

View File

@@ -29,7 +29,6 @@ namespace Game {
dServer* server = nullptr;
dConfig* config = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
dLogger* SetupLogger();
@@ -55,12 +54,34 @@ int main(int argc, char** argv) {
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
Database::Connect(Game::config);
//Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password");
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
return EXIT_FAILURE;
}
Game::randomEngine = std::mt19937(time(0));
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1500;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50;
@@ -68,7 +89,7 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterSock.hostAddress, masterSock.port, ServerType::Auth, Game::config, &Game::shouldShutdown);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -107,7 +128,18 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
Database::Connection->GetMasterServerIP();
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -116,7 +148,9 @@ int main(int argc, char** argv) {
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
std::this_thread::sleep_until(t);
}
//Delete our objects here:
Database::Destroy("AuthServer");
delete Game::server;
delete Game::logger;
delete Game::config;

View File

@@ -31,13 +31,16 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
ReadWordlistDCF("blacklist.dcf", false);
}
// Read player names that are ok as well:
auto names = Database::Connection->GetAllCharacterNames();
for (auto& name : names) {
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
m_ApprovedWords.push_back(CalculateHash(name));
//Read player names that are ok as well:
auto stmt = Database::CreatePreppedStmt("select name from charinfo;");
auto res = stmt->executeQuery();
while (res->next()) {
std::string line = res->getString(1).c_str();
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
m_ApprovedWords.push_back(CalculateHash(line));
}
delete res;
delete stmt;
}
dChatFilter::~dChatFilter() {

View File

@@ -3,7 +3,6 @@
#include "Database.h"
#include <vector>
#include "PacketUtils.h"
#include "BitStreamUtils.h"
#include "Game.h"
#include "dServer.h"
#include "GeneralUtils.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());
@@ -413,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;
@@ -435,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);
@@ -452,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;
@@ -475,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;
@@ -710,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;
@@ -725,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:
@@ -752,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:
@@ -777,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:
@@ -794,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:
@@ -823,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:
@@ -849,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:
@@ -883,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());
@@ -922,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;
@@ -938,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);
@@ -963,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

@@ -33,7 +33,6 @@ namespace Game {
dChatFilter* chatFilter = nullptr;
AssetManager* assetManager = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
@@ -77,10 +76,34 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
Database::Connect(Game::config);
//Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password");
// Get Master server IP and port
SocketDescriptor masterSock = Database::Connection->GetMasterServerIP();
try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) {
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what());
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
return EXIT_FAILURE;
}
//Find out the master's IP:
std::string masterIP;
uint32_t masterPort = 1000;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50;
@@ -88,11 +111,9 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterSock.hostAddress, masterSock.port, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
Game::randomEngine = std::mt19937(time(0));
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();
@@ -131,7 +152,18 @@ int main(int argc, char** argv) {
//Every 10 min we ping our sql server to keep it alive hopefully:
if (framesSinceLastSQLPing >= sqlPingTime) {
Database::Connection->GetMasterServerIP();
//Find out the master's IP for absolutely no reason:
std::string masterIP;
uint32_t masterPort;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
auto res = stmt->executeQuery();
while (res->next()) {
masterIP = res->getString(1).c_str();
masterPort = res->getInt(2);
}
delete res;
delete stmt;
framesSinceLastSQLPing = 0;
} else framesSinceLastSQLPing++;
@@ -141,8 +173,8 @@ int main(int argc, char** argv) {
std::this_thread::sleep_until(t);
}
// Delete our objects here:
Database::Destroy();
//Delete our objects here:
Database::Destroy("ChatServer");
delete Game::server;
delete Game::logger;
delete Game::config;

View File

@@ -6,11 +6,10 @@
#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"
PlayerContainer::PlayerContainer() {
}
@@ -41,7 +40,14 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
mPlayers.insert(std::make_pair(data->playerID, data));
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
Database::Connection->InsertIntoActivityLog(data->playerID, 0, time(nullptr), data->zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
insertLog->setInt(1, data->playerID);
insertLog->setInt(2, 0);
insertLog->setUInt64(3, time(nullptr));
insertLog->setInt(4, data->zoneID.GetMapID());
insertLog->executeUpdate();
}
void PlayerContainer::RemovePlayer(Packet* packet) {
@@ -78,7 +84,14 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
mPlayers.erase(playerID);
Database::Connection->InsertIntoActivityLog(playerID, 1, time(nullptr), player->zoneID.GetMapID());
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
insertLog->setInt(1, playerID);
insertLog->setInt(2, 1);
insertLog->setUInt64(3, time(nullptr));
insertLog->setInt(4, player->zoneID.GetMapID());
insertLog->executeUpdate();
}
void PlayerContainer::MuteUpdate(Packet* packet) {
@@ -133,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);
@@ -194,14 +207,6 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
}
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
if (team->memberIDs.size() >= 4){
Game::logger->Log("PlayerContainer", "Tried to add player to team that already had 4 players");
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;
@@ -340,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

@@ -1,93 +1,35 @@
#include "MySQLMigration.h"
#include "BrickByBrickFix.h"
#include <istream>
#include <memory>
#include <iostream>
#include <sstream>
#include "CDClientDatabase.h"
#include "Game.h"
#include "GeneralUtils.h"
#include "dLogger.h"
#include "BinaryPathFinder.h"
#include "ZCompression.h"
#include "tinyxml2.h"
#include "../MySQL.h"
#include "Database.h"
#include "Game.h"
#include "ZCompression.h"
#include "dLogger.h"
void MigrationRunner::RunMigrations(DatabaseBase* db) {
auto database = dynamic_cast<MySQLDatabase*>(db);
//! Forward declarations
auto* stmt = database->CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
stmt->execute();
delete stmt;
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
void WriteSd0Magic(char* input, uint32_t chunkSize);
bool CheckSd0Magic(sql::Blob* streamToCheck);
sql::SQLString finalSQL = "";
bool runSd0Migrations = false;
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/mysql").string())) {
auto migration = Migration::LoadMigration("dlu", "mysql", entry);
if (migration.data.empty()) {
continue;
}
stmt = database->CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name.c_str());
auto* res = stmt->executeQuery();
bool doExit = res->next();
delete res;
delete stmt;
if (doExit) continue;
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
if (migration.name == "dlu/5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
finalSQL.append(migration.data.c_str());
}
stmt = database->CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
stmt->setString(1, migration.name.c_str());
stmt->execute();
delete stmt;
}
if (finalSQL.empty() && !runSd0Migrations) {
Game::logger->Log("MigrationRunner", "Server database is up to date.");
return;
}
if (!finalSQL.empty()) {
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
std::unique_ptr<sql::Statement> simpleStatement(Database::CreateStmt());
for (auto& query : migration) {
try {
if (query.empty()) continue;
simpleStatement->execute(query.c_str());
} catch (sql::SQLException& e) {
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
}
}
}
// Do this last on the off chance none of the other migrations have been run yet.
if (runSd0Migrations) {
uint32_t numberOfUpdatedModels = UpdateBrickByBrickModelsToSd0();
Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels);
uint32_t numberOfTruncatedModels = TruncateBrokenBrickByBrickXml();
Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels);
}
}
uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
/**
* @brief Truncates all models with broken data from the database.
*
* @return The number of models deleted
*/
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
uint32_t modelsTruncated{};
auto modelsToTruncate = GetModelsFromDatabase(database);
bool previousCommitValue = database->GetAutoCommit();
database->SetAutoCommit(false);
auto modelsToTruncate = GetModelsFromDatabase();
bool previousCommitValue = Database::GetAutoCommit();
Database::SetAutoCommit(false);
while (modelsToTruncate->next()) {
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(database->CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(database->CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(Database::CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
std::string completeUncompressedModel{};
uint32_t chunkCount{};
uint64_t modelId = modelsToTruncate->getInt(1);
@@ -153,8 +95,8 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
}
}
database->Commit();
database->SetAutoCommit(previousCommitValue);
Database::Commit();
Database::SetAutoCommit(previousCommitValue);
return modelsTruncated;
}
@@ -164,14 +106,12 @@ uint32_t TruncateBrokenBrickByBrickXml(MySQLDatabase* database) {
*
* @return The number of models updated to SD0
*/
uint32_t UpdateBrickByBrickModelsToSd0(MySQLDatabase* database) {
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
uint32_t updatedModels = 0;
auto modelsToUpdate = GetModelsFromDatabase();
auto previousAutoCommitState = database->GetAutoCommit();
database->SetAutoCommit(false);
std::unique_ptr<sql::PreparedStatement> insertionStatement(database->CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
auto previousAutoCommitState = Database::GetAutoCommit();
Database::SetAutoCommit(false);
std::unique_ptr<sql::PreparedStatement> insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
while (modelsToUpdate->next()) {
int64_t modelId = modelsToUpdate->getInt64(1);
std::unique_ptr<sql::Blob> oldLxfml(modelsToUpdate->getBlob(2));
@@ -210,14 +150,13 @@ uint32_t UpdateBrickByBrickModelsToSd0(MySQLDatabase* database) {
}
}
}
database->Commit();
database->SetAutoCommit(previousAutoCommitState);
Database::Commit();
Database::SetAutoCommit(previousAutoCommitState);
return updatedModels;
}
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase(MySQLDatabase* database) {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(database->CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase() {
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
return std::unique_ptr<sql::ResultSet>(modelsRawDataQuery->executeQuery());
}

20
dCommon/BrickByBrickFix.h Normal file
View File

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

View File

@@ -12,8 +12,9 @@ set(DCOMMON_SOURCES
"NiPoint3.cpp"
"NiQuaternion.cpp"
"SHA512.cpp"
"Demangler.cpp"
"Type.cpp"
"ZCompression.cpp"
"BrickByBrickFix.cpp"
"BinaryPathFinder.cpp"
"FdbToSqlite.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

@@ -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());
@@ -122,43 +122,41 @@ void CatchUnhandled(int sig) {
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);
// 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());
}
} else {
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
}
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
FILE* file = fopen(fileName.c_str(), "w+");
if (file != NULL) {
@@ -168,7 +166,7 @@ void CatchUnhandled(int sig) {
fclose(file);
}
#else // __include_backtrace__
#else
struct backtrace_state* state = backtrace_create_state(
Diagnostics::GetProcessFileName().c_str(),
@@ -179,7 +177,7 @@ void CatchUnhandled(int sig) {
struct bt_ctx ctx = { state, 0 };
Bt(state);
#endif // __include_backtrace__
#endif
exit(EXIT_FAILURE);
}

View File

@@ -10,8 +10,6 @@ class dConfig;
class RakPeerInterface;
class AssetManager;
struct SystemAddress;
class EntityManager;
class dZoneManager;
namespace Game {
extern dLogger* logger;
@@ -24,6 +22,4 @@ namespace Game {
extern AssetManager* assetManager;
extern SystemAddress chatSysAddr;
extern bool shouldShutdown;
extern EntityManager* entityManager;
extern dZoneManager* zoneManager;
}

View File

@@ -111,6 +111,29 @@ namespace GeneralUtils {
*/
bool CheckBit(int64_t value, uint32_t index);
// MARK: Random Number Generation
//! Generates a random number
/*!
\param min The minimum the generate from
\param max The maximum to generate to
*/
template <typename T>
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
std::uniform_int_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
} else if (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
}
return T();
}
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
std::u16string ReadWString(RakNet::BitStream* inStream);
@@ -126,11 +149,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);
@@ -205,42 +223,4 @@ namespace GeneralUtils {
std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
}
// MARK: Random Number Generation
//! Generates a random number
/*!
\param min The minimum the generate from
\param max The maximum to generate to
*/
template <typename T>
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
std::uniform_int_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
} else if (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
}
return T();
}
// on Windows we need to undef these or else they conflict with our numeric limits calls
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
#ifdef _WIN32
#undef min
#undef max
#endif
template <typename T>
inline T GenerateRandomNumber() {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
}
}

View File

@@ -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)) {
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)) {
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)) {
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,7 +102,9 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") {
data = 0;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), 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,7 +122,9 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") {
data = false;
} else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), 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)) {
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)) {
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;
}

View File

@@ -33,7 +33,7 @@ public:
virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
virtual const std::u16string& GetKey() = 0;
virtual const std::u16string& GetKey() const = 0;
virtual eLDFType GetValueType() = 0;
@@ -117,7 +117,7 @@ public:
/*!
\return The key
*/
const std::u16string& GetKey(void) override { return this->key; }
const std::u16string& GetKey(void) const override { return this->key; }
//! Gets the LDF Type
/*!

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

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

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);
@@ -57,6 +56,13 @@ const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
const LOT LOT_ZONE_CONTROL = 2365;
const LOT LOT_3D_AMBIENT_SOUND = 6368;
const LOT LOT_MODEL_IN_WORLD = 14;
const LOT LOT_THINKING_CAP = 6086;
const LOT LOT_ROCKET = 6416;
const LOT LOT_LEGACY_RESPAWN_POINT = 4945;
const float PI = 3.14159f;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
#ifndef __EPHYSICSBEHAVIORTYPE__H__
#define __EPHYSICSBEHAVIORTYPE__H__
#include <cstdint>
enum class ePhysicsBehaviorType : int32_t {
INVALID = -1,
GROUND,
FLYING,
STANDARD,
DYNAMIC
};
#endif //!__EPHYSICSBEHAVIORTYPE__H__

View File

@@ -11,14 +11,14 @@ enum class eReplicaComponentType : uint32_t {
CHARACTER,
SCRIPT,
BOUNCER,
BUFF, // buff is really 98, this is DESTROYABLE
DESTROYABLE,
GHOST,
SKILL,
SPAWNER,
SPAWN,
ITEM,
REBUILD,
REBUILD_START,
REBUILD_ACTIVATOR,
MODULAR_BUILD,
BUILD_CONTROLLER,
BUILD_ACTIVATOR,
ICON_ONLY,
VENDOR,
INVENTORY,
@@ -33,8 +33,8 @@ enum class eReplicaComponentType : uint32_t {
PET,
PLATFORM_BOUNDARY,
MODULE,
ARCADE,
VEHICLE_PHYSICS, // Havok demo based
JETPACKPAD,
HAVOK_VEHICLE_PHYSICS,
MOVEMENT_AI,
EXHIBIT,
OVERHEAD_ICON,
@@ -46,23 +46,23 @@ enum class eReplicaComponentType : uint32_t {
SCRIPTED_ACTIVITY,
PHANTOM_PHYSICS,
SPRINGPAD,
MODEL,
MODEL_BEHAVIOR,
PROPERTY_ENTRANCE,
FX,
PROPERTY_MANAGEMENT,
VEHICLE_PHYSICS_NEW, // internal physics based on havok
VEHICLE_PHYSICS,
PHYSICS_SYSTEM,
QUICK_BUILD,
SWITCH,
ZONE_CONTROL, // Minigame
CHANGLING,
MINIGAME_CONTROL,
CHANGLING_BUILD,
CHOICE_BUILD,
PACKAGE,
SOUND_REPEATER,
SOUND_AMBIENT_2D,
SOUND_AMBIENT_3D,
PRECONDITION,
PLAYER_FLAG,
FLAG,
CUSTOM_BUILD_ASSEMBLY,
BASE_COMBAT_AI,
MODULE_ASSEMBLY,
@@ -71,8 +71,8 @@ enum class eReplicaComponentType : uint32_t {
GENERIC_ACTIVATOR,
PROPERTY_VENDOR,
HF_LIGHT_DIRECTION_GADGET,
ROCKET_LAUNCH,
ROCKET_LANDING,
ROCKET_LAUNCHPAD_CONTROL,
ROCKET_ANIMATION_CONTROL,
TRIGGER,
DROPPED_LOOT,
RACING_CONTROL,
@@ -84,7 +84,7 @@ enum class eReplicaComponentType : uint32_t {
SOUND_TRIGGER,
PROXIMITY_MONITOR,
RACING_SOUND_TRIGGER,
CHAT,
CHAT_BUBBLE,
FRIENDS_LIST,
GUILD,
LOCAL_SYSTEM,
@@ -102,11 +102,11 @@ enum class eReplicaComponentType : uint32_t {
USER_CONTROL,
IGNORE_LIST,
MULTI_ZONE_ENTRANCE,
BUFF_REAL, // the real buff component, should just be name BUFF
BUFF,
INTERACTION_MANAGER,
DONATION_VENDOR,
COMBAT_MEDIATOR,
COMMENDATION_VENDOR,
ACHIEVEMENT_VENDOR,
GATE_RUSH_CONTROL,
RAIL_ACTIVATOR,
ROLLER,
@@ -114,14 +114,14 @@ enum class eReplicaComponentType : uint32_t {
CRAFTING,
POSSESSABLE,
LEVEL_PROGRESSION,
POSSESSOR,
POSSESSION,
MOUNT_CONTROL,
UNKNOWN_112,
PROPERTY_PLAQUE,
BUILD_BORDER,
UNKNOWN_115,
CULLING_PLANE,
DESTROYABLE = 1000 // Actually 7
NUMBER_OF_COMPONENTS
};
#endif //!__EREPLICACOMPONENTTYPE__H__

View File

@@ -0,0 +1,13 @@
#ifndef __EUGCMODERATIONSTATUS__H__
#define __EUGCMODERATIONSTATUS__H__
#include <cstdint>
enum class eUgcModerationStatus : uint32_t {
NoStatus,
Approved,
Rejected,
};
#endif //!__EUGCMODERATIONSTATUS__H__

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,43 @@
#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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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,30 +1,26 @@
#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));
m_Entries.insert(std::make_pair(hash, entry));
tableData.nextRow();
}
@@ -34,22 +30,27 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
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

@@ -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,25 @@
#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 +29,72 @@ 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
}
std::vector<std::pair<eReplicaComponentType, uint32_t>> CDComponentsRegistryTable::GetTemplateComponents(LOT templateId) {
std::vector<std::pair<eReplicaComponentType, uint32_t>> components;
for (int8_t i = 0; static_cast<eReplicaComponentType>(i) < eReplicaComponentType::NUMBER_OF_COMPONENTS; i++) {
auto compId = GetByIDAndType(templateId, static_cast<eReplicaComponentType>(i), -1);
if (compId != -1) components.push_back(std::make_pair(static_cast<eReplicaComponentType>(i), compId));
}
return components;
}

View File

@@ -2,6 +2,7 @@
// Custom Classes
#include "CDTable.h"
#include "dCommonVars.h"
enum class eReplicaComponentType : uint32_t;
struct CDComponentsRegistry {
@@ -13,9 +14,10 @@ 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);
std::vector<std::pair<eReplicaComponentType, uint32_t>> GetTemplateComponents(LOT templateId);
};

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

@@ -1,9 +1,15 @@
#include "CDItemComponentTable.h"
#include "GeneralUtils.h"
#include "eItemType.h"
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 +57,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,20 +73,23 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
}
tableData.finalize();
#endif
}
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
const auto& it = this->entries.find(skillID);
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int id) {
const auto& it = this->entries.find(id);
if (it != this->entries.end()) {
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(id);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
if (tableData.eof()) {
entries.insert(std::make_pair(skillID, Default));
entries.insert(std::make_pair(id, Default));
return Default;
}
@@ -91,7 +100,7 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
entry.baseValue = tableData.getIntField("baseValue", -1);
entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false;
entry.rarity = tableData.getIntField("rarity", 0);
entry.itemType = tableData.getIntField("itemType", -1);
entry.itemType = static_cast<eItemType>(tableData.getIntField("itemType", -1));
entry.itemInfo = tableData.getInt64Field("itemInfo", -1);
entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false;
entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false;
@@ -133,10 +142,11 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
tableData.nextRow();
}
const auto& it2 = this->entries.find(skillID);
const auto& it2 = this->entries.find(id);
if (it2 != this->entries.end()) {
return it2->second;
}
#endif
return Default;
}

View File

@@ -4,13 +4,15 @@
#include "CDTable.h"
#include "dCommonVars.h"
enum class eItemType : int32_t;
struct CDItemComponent {
unsigned int id; //!< The Component ID
std::string equipLocation; //!< The equip location
unsigned int baseValue; //!< The monetary base value of the item
bool isKitPiece; //!< Whether or not the item belongs to a kit
unsigned int rarity; //!< The rarity of the item
unsigned int itemType; //!< The item type
eItemType itemType; //!< The item type
int64_t itemInfo; //!< The item info
bool inLootTable; //!< Whether or not the item is in a loot table
bool inVendor; //!< Whether or not the item is in a vendor inventory
@@ -54,11 +56,11 @@ 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
const CDItemComponent& GetItemComponentByID(unsigned int skillID);
const CDItemComponent& GetItemComponentByID(unsigned int id);
static CDItemComponent Default;
};

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,15 +1,7 @@
#include "CDLootTableTable.h"
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;
@@ -20,6 +12,8 @@ void CDLootTableTable::LoadValuesFromDatabase() {
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
@@ -27,28 +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));
tableData.nextRow();
}
}
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
auto itr = this->entries.find(tableId);
if (itr != this->entries.end()) {
return itr->second;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootTable WHERE LootTableIndex = ?;");
query.bind(1, static_cast<int32_t>(tableId));
auto tableData = query.execQuery();
while (!tableData.eof()) {
CDLootTable entry;
this->entries[tableId].push_back(ReadRow(tableData));
this->entries.push_back(entry);
tableData.nextRow();
}
return this->entries[tableId];
tableData.finalize();
}
//! Queries the table with a custom "where" clause
std::vector<CDLootTable> CDLootTableTable::Query(std::function<bool(CDLootTable)> predicate) {
std::vector<CDLootTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
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,43 @@
#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) {
auto itr = m_entries.find(componentID);
return itr != m_entries.end() ? itr->second : 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