Compare commits

...

101 Commits

Author SHA1 Message Date
32772019eb Merge branch 'main' into movementAiPathing 2023-08-11 08:49:02 -05:00
David Markowitz
5eca25e42a refactor: Move CDClient Database away from constructor queries (#1164)
* Move away from constructor queries

Fix up other large tables to have proper backup lookups

Revert "idk im just dumb ig"

This reverts commit 5d5be5df53b8959b42b291613d7db749a65a3585.

idk im just dumb ig

* Fix slow components registry lookup

* add define for cdclient cache all

* Update CDBehaviorParameterTable.cpp
2023-08-10 23:27:40 -05:00
Gie "Max" Vanommeslaeghe
d233c7e2aa Merge pull request #1182 from DarkflameUniverse/fixRawReading
fix: RAW to OBJ parsing
2023-08-10 23:50:11 +02:00
beaceb947b fix: Properly read in scene metadata (#1170)
* fix: Properly read in scene metadata

* Fix reading in rental time and period from property path

* remove useless name in var
change hex to decimal so it's readable
fix scene transistion loop logic

* fix typoe and remove whitespace
2023-08-10 16:35:12 -05:00
David Markowitz
2cc13c6499 chore: Make serialize actually virtual (#1156)
* Make serialize actually virtual

* fix serialize and make update virutal

* Update VendorComponent.h

* Remove flag var

* Update SoundTriggerComponent.h

---------

Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com>
2023-08-10 14:33:15 -07:00
David Markowitz
ad81e341da add operator *= for vectors 2023-08-09 22:13:20 -07:00
David Markowitz
fe6be21008 fix raw reading 2023-08-09 22:08:32 -07:00
David Markowitz
7388d47b90 Fix if condition to actually return the value... 2023-08-09 00:05:37 -07:00
David Markowitz
8da23df5d6 Update height checker
- Only go up and down, do not deviate from the point you are on
- As a backup, use the nearestPoint on the nearestPoly, should detour be able to find one.
- Add a debug assert to fail the program should toReturn differ from nearestPoint[1].

Update dNavMesh.cpp

Update dNavMesh.cpp
2023-08-09 00:01:03 -07:00
David Markowitz
600f0974e7 Increase height because Nexus Tower is tall 2023-08-06 16:06:12 -07:00
David Markowitz
8117773c56 Add path height correction on world load 2023-08-06 15:41:38 -07:00
cefdfc696a fix: Implement proper Sound trigger component serialization (#1160)
* cleanup

* more cleanup and fully implement the sound trigger
and racing sound trigger

* more cleanup, and better defaults

* fixes and tested

* update initializor for guid and when to load sound guids

* make racing sound trigger it's own component

* fix type

* Remove global
move serializes

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
2023-08-06 15:38:12 -05:00
7e2747a2d2 fix: load fdbchecksum to verify, even on character selection (world 0) (#1176) 2023-08-04 17:48:45 -05:00
a29253d2f0 feature: Donation Vendor Component (#1168)
* refactor: Vendor inventory loading
Implement proper delta compression
dynamically determine multicostitems and standard cost items
Quatantine max's custom code

* WIP

* progress missions

* address feedback

* fix newline

* Cleanup

* oops

* fix default for nexus tower jawbox
cleanup some logs

* remove log

* remove include that got added back
2023-08-03 21:44:03 -05:00
David Markowitz
e5b69745aa feat: Remove NET_VERSION define (#1153)
* Remove NET_VERSION define

I get to test this on 4 different platforms.  yay...

* move stuff around

finally fixed you docker

i love this

Update Dockerfile

Update Dockerfile

change type

Update AuthPackets.cpp

Update AuthServer.cpp

* Update CMakeVariables.txt

* Update sharedconfig.ini
2023-08-03 21:38:33 -05:00
David Markowitz
040a78c386 fix: Remove usage of rand() and seed randomness for chatserver (#1152)
* Remove usage of rand(), time(0) to time(NULL)

Replace it with the random engine mt19937.
convert time(0) to time(NULL)

* update

* revert a bunch of changes
2023-08-03 21:38:19 -05:00
David Markowitz
d8a5fd49a4 chore: Small movementAiComponent cleanup (#1145)
* rename and cleanup file

* more

* fix broken function

* Further naming fixes

t

Revert "Further naming fixes"

This reverts commit 057189982ba56788d48f9265d815e6c562ba6328.

* next step

* undo all testing changes

* minor tweaks
2023-08-03 21:38:04 -05:00
David Markowitz
208ed02158 Fix incorrect kick out of rebuilds (#1120) 2023-08-03 21:37:27 -05:00
952786c166 chore: cleanup some vanity npc logic (#1174)
* Dont setup talk for vanity npc's if they are no phrases
no ghosting ldfkey for canity npc's

* void, oops

* formatting
2023-08-03 21:37:09 -05:00
David Markowitz
9a07020a51 perf: Behavior Parameter memory savings (#1166)
* Memory Savings Behavior Parameter table

* Update CDBehaviorParameterTable.h
2023-08-03 19:31:02 -07:00
a22ecf385f feature: add full known GM list (#1171)
* feature: add full GM list

* Fix compiling

* add tests
Fix more issues
2023-08-03 21:27:40 -05:00
c2b4aa4026 refactor: Vendor inventory loading (#1163)
* refactor: Vendor inventory loading
Implement proper delta compression
dynamically determine multicostitems and standard cost items
Quatantine max's custom code

* address feedback

* fix newline

* oops

* remove header

* fix default and const for

* he said make it a reference too, not just const
2023-08-03 05:51:52 -05:00
David Markowitz
0d48cfe8c0 fix: Nipoint3 Operator+= (#1172)
* fix operator +=

* fix operator +=
2023-07-31 00:22:56 -07:00
e299bf9b62 fix: read and store the zone transition width properly (#1169) 2023-07-30 23:49:43 -07:00
Daniel Seiler
304af7922a Update MariaDB for windows (#792)
* Update CMakeMariaDBLists.txt

* Update CMakeMariaDBLists.txt

---------

Co-authored-by: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com>
Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
2023-07-23 20:51:13 -05:00
TAHuntling
0610fe99f8 fix: Nexus Tower Combat Challenge can be started twice if two players start it at the same time (#1147)
* Nexus Tower Dummy Challenge Dual Instance Fix

Fix for dual instance starting when two players hit start on the challenge at the same time.

* Changed GetVar to GetNetworkVar

Changed the if statement to GetNetworkVar boolean of bInUse rather than GetVar boolean of bInUse
2023-07-23 16:04:45 -07:00
Gie "Max" Vanommeslaeghe
d1316cfc9f Merge pull request #1107 from EmosewaMC/first-draft-leaderboard-re-write
feat: Leaderboards
2023-07-24 00:29:17 +02:00
bd5ead40f6 feat: upgrade session keys to use mersenne twister (#1155)
* upgrade session keys to use mersenne twister

* arithmetic type static assert and windows min/max macro undef
2023-07-23 14:59:43 -07:00
David Markowitz
c791d1a237 feature: Auto update of ini files (#1154)
* Add auto update of ini files

Tested that config options that currently exist are not modified.

Tested that if the exact variable name is not located in the destination ini, the config option is added along with all of its corresponding comments.

Comments in the build files are ignored to prevent any possible name collision with comments.

* Fix typos and empty file issue
2023-07-23 12:09:07 -07:00
TAHuntling
54454973a1 Distance for pet digs increased slightly to help with navmesh issues (#1151) 2023-07-22 02:49:23 -07:00
David Markowitz
b87537c637 bump minor version 2023-07-22 02:16:53 -07:00
David Markowitz
a625d2eae5 Update SGCannon.cpp 2023-07-21 23:42:50 -07:00
David Markowitz
887e2a25f0 Fix race score bugs
num wins serialized properly
scores are saved and num wins and times played are incremented properly
2023-07-21 23:18:51 -07:00
David Markowitz
34392932b3 Merge branch 'main' into pr/1107 2023-07-21 19:40:30 -07:00
David Markowitz
cc251d0986 Update ActivityManager.cpp 2023-07-21 19:39:44 -07:00
David Markowitz
0c0f7216a1 Merge branch 'main' into pr/1107 2023-07-21 19:38:59 -07:00
TAHuntling
342da56678 Added Player Rewards for Solo Racing (#1150)
* Added Player Rewards for Solo Racing

* Fixed Dual PlayersRating multiplication

* Checking for solo player fixed

* Another change to fix issues
2023-07-21 19:37:31 -05:00
TAHuntling
11b0097488 freemoney type update (#1146)
Changed freemoney command to parse 64 bit integers as opposed to 32 bit
2023-07-19 09:07:41 -07:00
David Markowitz
3e3148e910 Move dZoneManager to game namespace (#1143)
* convert zone manager to game namespace

* Destroy logger last
2023-07-17 17:55:33 -05:00
David Markowitz
080a833144 Convert BrickDatabase to namespace (#1142)
* Convert BrickDatabase to namespace

This did not need to be a class.

* Fix linker errors

* convert to anonymous namespace

so the cache is unmodifiable outside the brickcache

* Move to lower scope level and remove log
2023-07-17 17:55:25 -05:00
David Markowitz
455f9470a5 Move EntityManager to Game namespace (#1140)
* Move EntityManager to Game namespace

* move initialization to later

Need to wait for dZoneManager to be initialized.

* Fix bugs

- Cannot delete from a RandomAccessIterator while in a range based for loop.

Touchup zone manager initialize

replace magic numbers with better named constants
replace magic zonecontrol id with a more readable hex alternative
condense stack variables
move initializers closer to their use
initialize entity manager with zone control

change initialize timings

If zone is not zero we expect to initialize the entity manager during zone manager initialization

Add constexpr for zone control LOT

* Add proper error handling

* revert vanity changes

* Update WorldServer.cpp

* Update dZoneManager.cpp
2023-07-15 13:56:33 -07:00
David Markowitz
e32cec6691 Merge branch 'first-draft-leaderboard-re-write' of https://github.com/EmosewaMC/DarkflameServer into first-draft-leaderboard-re-write 2023-06-21 21:53:23 -07:00
David Markowitz
85aa82b4b9 cleanup 2023-06-21 21:53:10 -07:00
David Markowitz
393733cc67 Update GameMessageHandler.cpp 2023-06-21 21:50:54 -07:00
David Markowitz
8156e5cc91 Update MigrationRunner.cpp 2023-06-21 21:50:16 -07:00
David Markowitz
d0e79d19fc Update Metrics.hpp 2023-06-21 21:48:58 -07:00
David Markowitz
45256a0338 Merge remote-tracking branch 'upstream/main' into first-draft-leaderboard-re-write 2023-06-21 21:48:22 -07:00
David Markowitz
238fc98ea5 Fix shooting gallery leaderboard bugs
- add weekly functionality for top scores
- Fix shooting gallery score saving
- remove extra leaderboard fetch
2023-06-21 21:46:11 -07:00
David Markowitz
d340874284 more bug fixing
- fix weekly leaderboards
- fix ag classic vs dlu scoring
- fix sorting for survival ns
- fix sorting for racing
2023-06-21 19:46:01 -07:00
EmosewaMC
c99e2a372b Add weekly filter 2023-06-05 16:04:56 -07:00
EmosewaMC
dab075fc39 forgor about this one 2023-06-05 15:19:52 -07:00
EmosewaMC
b4aa5db305 Comment out tests
rest in pepperoni tests
2023-06-05 15:10:08 -07:00
David Markowitz
259f0c8371 Working in game again
hooray
2023-06-05 04:10:59 -07:00
David Markowitz
a5e63529dc const and compile save 2023-06-05 02:50:40 -07:00
David Markowitz
c572f2a58d better tabs and organization 2023-06-05 02:43:02 -07:00
David Markowitz
5bff441c01 Fix query crashing
Just select all columns since we need most of them anyways
2023-06-05 02:31:49 -07:00
David Markowitz
96fc6e81d8 Update sql to work
The old way was supposed to work but doesn't.  Oh well!
2023-06-05 02:24:00 -07:00
David Markowitz
59d7121978 Merge remote-tracking branch 'upstream/main' into first-draft-leaderboard-re-write 2023-06-05 02:04:14 -07:00
EmosewaMC
8267823ca4 More simplification 2023-05-31 23:17:13 -07:00
EmosewaMC
b8878da61b Convert to using only floats
This will cover all of our bases for any type of score.  No need to do any conversions.
2023-05-31 23:05:19 -07:00
EmosewaMC
47deca6f4f Update migration
Better column names and maintainability
Better updating
Convert all data to floats
2023-05-31 23:04:33 -07:00
David Markowitz
8a1f275176 add a const 2023-05-31 03:10:28 -07:00
David Markowitz
e1a7b4993e look ma, more work 2023-05-30 18:21:10 -07:00
David Markowitz
0ecc5d83c3 Fix out of bounds access
Fixes an issue where we would try to access an array out of the physics bounds
2023-05-30 17:30:50 -07:00
EmosewaMC
a43e03255c It compiles at least now 2023-05-30 04:38:19 -07:00
EmosewaMC
83da45575e CONST 2023-05-30 04:28:50 -07:00
EmosewaMC
f5f599764d more const and views 2023-05-30 04:23:48 -07:00
EmosewaMC
7b1626901a Add some debug asserts 2023-05-30 04:18:32 -07:00
EmosewaMC
a595347211 Merge remote-tracking branch 'upstream/main' into first-draft-leaderboard-re-write 2023-05-30 04:11:53 -07:00
EmosewaMC
0107d05d55 draft 2023-05-30 04:11:37 -07:00
David Markowitz
f26e66da4d small updates to typs 2023-05-28 04:30:20 -07:00
David Markowitz
af1abe9e74 Use only ints 2023-05-10 01:32:55 -07:00
David Markowitz
4dba8d9225 Correct column order 2023-05-09 22:21:41 -07:00
David Markowitz
3448426caf commit 2023-05-09 22:00:13 -07:00
David Markowitz
7a067e7b48 Working in game!
- Add score saving for races
- Fix some bugs
- Still work to do.
2023-05-09 01:42:11 -07:00
David Markowitz
411c9eaf1f Remove dead code 2023-05-09 00:06:43 -07:00
David Markowitz
fcf5c5ea8a Resolve compiler errors 2023-05-09 00:06:26 -07:00
EmosewaMC
6c2312fe87 Implement page fetching 2023-05-08 19:59:10 -07:00
EmosewaMC
d98ad4b94f Implement leaderboard page offsets 2023-05-08 19:35:19 -07:00
EmosewaMC
5c086909ed Ready for implementation 2023-05-08 18:36:28 -07:00
David Markowitz
1c7ac93d4b Fix various bugs and make code cleaner.
Still have work to go.
2023-05-08 03:55:10 -07:00
David Markowitz
0f307ac4be Fix bugs
- Reinforce Query formatting
- Guarantee 11 rows are selected at a time by ranking by id, should there be more than an 11 way tie.
2023-05-08 02:46:55 -07:00
David Markowitz
bc518be654 Bug fixes and cleanup
Fix co-pilot induced column bugs
Fix insert/update statements
Added saving functionality
Added update clause for column
2023-05-07 04:09:10 -07:00
EmosewaMC
820b375c50 push 2023-05-07 00:31:38 -07:00
David Markowitz
3b8f18d2be Fix new lines 2023-05-05 21:33:30 -07:00
EmosewaMC
0faef7d791 Finished saving 2023-05-04 16:53:36 -07:00
EmosewaMC
28a0492201 Fix bugs 2023-05-04 14:48:26 -07:00
EmosewaMC
2ab995b9c3 Simplify snprintfs
so much better to read
2023-05-04 14:28:53 -07:00
EmosewaMC
8de528e77c Remove old code 2023-05-04 13:58:48 -07:00
David Markowitz
a3626a3b53 The query is supposed to get SMALLER
Still better than 9 different queries all with 1 minor change i guess.
2023-05-03 00:38:38 -07:00
David Markowitz
b5e3bd22e3 Merge remote-tracking branch 'upstream/main' into first-draft-leaderboard-re-write 2023-05-02 15:49:23 -07:00
EmosewaMC
48264e2cf4 push 2023-04-30 21:30:41 -07:00
David Markowitz
10a2c24d5e Add base MyStandings query 2023-04-26 02:10:57 -07:00
EmosewaMC
89f427ace0 Further work on leaderboards 2023-04-18 01:26:35 -07:00
EmosewaMC
08220d6852 Remove extra includes 2023-04-17 15:22:44 -07:00
EmosewaMC
42870028e4 Remove complex migration
Only shooting gallery had a value put in the wrong column.  All others were either already correct or unimplemented.
2023-04-17 15:19:13 -07:00
David Markowitz
fcb088d263 Further work on leaderboards
- Modularize tests
- Add migrations
- Fix switch case so it actually breaks
- Add in missing writes
- Beginning work on custom migration to move the leaderboard to the final state
2023-04-17 01:16:23 -07:00
EmosewaMC
ed2639ce4e Use inline functions 2023-04-14 01:32:52 -07:00
David Markowitz
41355cea58 Add remaining enum types 2023-04-13 21:55:09 -07:00
David Markowitz
c91f0d16b3 Get it compiling, add a test and optimize heavily 2023-04-13 00:45:03 -07:00
EmosewaMC
c02963013b first draft 2023-04-12 21:57:58 -07:00
379 changed files with 4950 additions and 3239 deletions

View File

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

View File

@@ -97,15 +97,56 @@ 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")
foreach(resource_file ${RESOURCE_FILES})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
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)
configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY
)
message("Moved ${resource_file} to project binary directory")
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()
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/)

View File

@@ -1,12 +1,8 @@
PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=0
PROJECT_VERSION_PATCH=4
PROJECT_VERSION_PATCH=1
# 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
@@ -22,3 +18,5 @@ __maria_db_connector_compile_jobs__=1
__enable_testing__=1
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
# Uncomment the below line to cache the entire CDClient into memory
# CDCLIENT_CACHE_ALL=1

View File

@@ -179,7 +179,7 @@ If you would like to build the server faster, append `-j<number>` where number i
### Notes
Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building:
* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory.
* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023.
* If you are using a Darkflame Universe client, ensure `client_net_version` in `build/sharedconfig.ini` 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,6 +29,7 @@ namespace Game {
dServer* server = nullptr;
dConfig* config = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
dLogger* SetupLogger();
@@ -83,6 +84,8 @@ int main(int argc, char** argv) {
delete res;
delete stmt;
Game::randomEngine = std::mt19937(time(0));
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50;
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.

View File

@@ -33,6 +33,7 @@ namespace Game {
dChatFilter* chatFilter = nullptr;
AssetManager* assetManager = nullptr;
bool shouldShutdown = false;
std::mt19937 randomEngine;
}
@@ -114,6 +115,8 @@ int main(int argc, char** argv) {
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
Game::randomEngine = std::mt19937(time(0));
//Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now();

View File

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

View File

@@ -111,29 +111,6 @@ 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);
@@ -223,4 +200,42 @@ 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

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

File diff suppressed because it is too large Load Diff

View File

@@ -13,15 +13,7 @@
#include <sstream>
#include <iostream>
// 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
//! The CDClient Database namespace
namespace CDClientDatabase {
//! Opens a connection with the CDClient

View File

@@ -38,43 +38,53 @@
#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();
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();
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
CDActivitiesTable::Instance().LoadValuesFromDatabase();
CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase());
CDBehaviorParameterTable::Instance().LoadValuesFromDatabase();
CDBehaviorTemplateTable::Instance().LoadValuesFromDatabase();
CDBrickIDTableTable::Instance().LoadValuesFromDatabase();
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();
CDLootMatrixTable::Instance().LoadValuesFromDatabase();
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();
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
#include "CDActivityRewardsTable.h"
CDActivityRewardsTable::CDActivityRewardsTable(void) {
void CDActivityRewardsTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;
@@ -43,8 +43,3 @@ 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:
CDActivityRewardsTable();
void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
std::vector<CDActivityRewards> GetEntries(void) const;
std::vector<CDActivityRewards> GetEntries() const;
};

View File

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

View File

@@ -5,18 +5,15 @@
#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:
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
typedef uint64_t BehaviorParameterHash;
typedef float BehaviorParameterValue;
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public:
CDBehaviorParameterTable();
void LoadValuesFromDatabase();
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"
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
// 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;
}
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
const std::vector<CDBehaviorTemplate>& CDBehaviorTemplateTable::GetEntries() const {
return this->entries;
}
@@ -64,4 +64,3 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav
return entry->second;
}
}

View File

@@ -19,11 +19,12 @@ private:
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public:
CDBehaviorTemplateTable();
void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
std::vector<CDBehaviorTemplate> GetEntries(void) const;
const std::vector<CDBehaviorTemplate>& GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
};

View File

@@ -1,6 +1,6 @@
#include "CDBrickIDTableTable.h"
CDBrickIDTableTable::CDBrickIDTableTable(void) {
void CDBrickIDTableTable::LoadValuesFromDatabase() {
// 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;
}
std::vector<CDBrickIDTable> CDBrickIDTableTable::GetEntries(void) const {
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -1,27 +1,37 @@
#include "CDComponentsRegistryTable.h"
#include "eReplicaComponentType.h"
#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);
void CDComponentsRegistryTable::LoadValuesFromDatabase() {
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1);
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
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();
}
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;
}
// 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));
auto tableData = query.execQuery();
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1);
@@ -33,61 +43,10 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
tableData.nextRow();
}
tableData.finalize();
#endif
}
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
const auto& iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
if (iter == this->mappedEntries.end()) {
return defaultValue;
}
return iter->second;
#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 = tableData.getIntField("component_type", -1);
entry.component_id = tableData.getIntField("component_id", -1);
//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();
}
tableData.finalize();
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 defaultValue;
#endif
mappedEntries.insert_or_assign(id, 0);
auto iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
}

View File

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

View File

@@ -1,7 +1,7 @@
#include "CDCurrencyTableTable.h"
//! Constructor
CDCurrencyTableTable::CDCurrencyTableTable(void) {
void CDCurrencyTableTable::LoadValuesFromDatabase() {
// 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;
}
std::vector<CDCurrencyTable> CDCurrencyTableTable::GetEntries(void) const {
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

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

View File

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

View File

@@ -1,40 +1,26 @@
#include "CDEmoteTable.h"
//! Constructor
CDEmoteTableTable::CDEmoteTableTable(void) {
void CDEmoteTableTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
while (!tableData.eof()) {
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", "");
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", "");
entries.insert(std::make_pair(entry->ID, entry));
entries.insert(std::make_pair(entry.ID, entry));
tableData.nextRow();
}
tableData.finalize();
}
//! 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;
auto itr = entries.find(id);
return itr != entries.end() ? &itr->second : nullptr;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,6 @@
#include "CDLevelProgressionLookupTable.h"
//! Constructor
CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) {
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;
@@ -32,7 +31,6 @@ CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) {
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)
@@ -42,8 +40,7 @@ std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::
return data;
}
//! Gets all the entries in the table
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::GetEntries(void) const {
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
return this->entries;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,12 +24,12 @@ private:
std::vector<CDMissionTasks> entries;
public:
CDMissionTasksTable();
void LoadValuesFromDatabase();
// 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(void) const;
const std::vector<CDMissionTasks>& GetEntries() const;
};

View File

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

View File

@@ -65,12 +65,12 @@ private:
std::vector<CDMissions> entries;
public:
CDMissionsTable();
void LoadValuesFromDatabase();
// 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(void) const;
const std::vector<CDMissions>& GetEntries() const;
const CDMissions* GetPtrByMissionID(uint32_t missionID) const;

View File

@@ -1,7 +1,6 @@
#include "CDMovementAIComponentTable.h"
//! Constructor
CDMovementAIComponentTable::CDMovementAIComponentTable(void) {
void CDMovementAIComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;
@@ -37,7 +36,6 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) {
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)
@@ -47,8 +45,7 @@ std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::functi
return data;
}
//! Gets all the entries in the table
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::GetEntries(void) const {
const std::vector<CDMovementAIComponent>& CDMovementAIComponentTable::GetEntries(void) const {
return this->entries;
}

View File

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

View File

@@ -1,7 +1,6 @@
#include "CDObjectSkillsTable.h"
//! Constructor
CDObjectSkillsTable::CDObjectSkillsTable(void) {
void CDObjectSkillsTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;
@@ -33,7 +32,6 @@ CDObjectSkillsTable::CDObjectSkillsTable(void) {
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)
@@ -43,7 +41,6 @@ std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObje
return data;
}
//! Gets all the entries in the table
std::vector<CDObjectSkills> CDObjectSkillsTable::GetEntries(void) const {
const std::vector<CDObjectSkills>& CDObjectSkillsTable::GetEntries() const {
return this->entries;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,46 +1,35 @@
#include "CDPhysicsComponentTable.h"
CDPhysicsComponentTable::CDPhysicsComponentTable(void) {
void CDPhysicsComponentTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent");
while (!tableData.eof()) {
CDPhysicsComponent* entry = new CDPhysicsComponent();
entry->id = tableData.getIntField("id", -1);
entry->bStatic = tableData.getIntField("static", -1) != 0;
entry->physicsAsset = tableData.getStringField("physics_asset", "");
CDPhysicsComponent entry;
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();
}
CDPhysicsComponentTable::~CDPhysicsComponentTable() {
for (auto e : m_entries) {
if (e.second) delete e.second;
}
m_entries.clear();
}
CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) {
for (auto e : m_entries) {
if (e.first == componentID) return e.second;
}
return nullptr;
auto itr = m_entries.find(componentID);
return itr != m_entries.end() ? &itr->second : nullptr;
}

View File

@@ -23,12 +23,11 @@ struct CDPhysicsComponent {
class CDPhysicsComponentTable : public CDTable<CDPhysicsComponentTable> {
public:
CDPhysicsComponentTable();
~CDPhysicsComponentTable();
void LoadValuesFromDatabase();
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;
};

View File

@@ -1,7 +1,6 @@
#include "CDPropertyEntranceComponentTable.h"
CDPropertyEntranceComponentTable::CDPropertyEntranceComponentTable() {
void CDPropertyEntranceComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table
size_t size = 0;

View File

@@ -11,12 +11,12 @@ struct CDPropertyEntranceComponent {
class CDPropertyEntranceComponentTable : public CDTable<CDPropertyEntranceComponentTable> {
public:
CDPropertyEntranceComponentTable();
void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
CDPropertyEntranceComponent GetByID(uint32_t id);
// Gets all the entries in the table
[[nodiscard]] std::vector<CDPropertyEntranceComponent> GetEntries() const { return entries; }
[[nodiscard]] const std::vector<CDPropertyEntranceComponent>& GetEntries() const { return entries; }
private:
std::vector<CDPropertyEntranceComponent> entries{};
CDPropertyEntranceComponent defaultEntry{};

View File

@@ -1,6 +1,6 @@
#include "CDPropertyTemplateTable.h"
CDPropertyTemplateTable::CDPropertyTemplateTable() {
void CDPropertyTemplateTable::LoadValuesFromDatabase() {
// First, get the size of the table
size_t size = 0;

View File

@@ -10,7 +10,7 @@ struct CDPropertyTemplate {
class CDPropertyTemplateTable : public CDTable<CDPropertyTemplateTable> {
public:
CDPropertyTemplateTable();
void LoadValuesFromDatabase();
static const std::string GetTableName() { return "PropertyTemplate"; };
CDPropertyTemplate GetByMapID(uint32_t mapID);

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#include "CDRailActivatorComponent.h"
#include "GeneralUtils.h"
CDRailActivatorComponentTable::CDRailActivatorComponentTable() {
void CDRailActivatorComponentTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RailActivatorComponent;");
while (!tableData.eof()) {
CDRailActivatorComponent entry;
@@ -52,7 +52,7 @@ CDRailActivatorComponent CDRailActivatorComponentTable::GetEntryByID(int32_t id)
return {};
}
std::vector<CDRailActivatorComponent> CDRailActivatorComponentTable::GetEntries() const {
const std::vector<CDRailActivatorComponent>& CDRailActivatorComponentTable::GetEntries() const {
return m_Entries;
}

View File

@@ -22,10 +22,10 @@ struct CDRailActivatorComponent {
class CDRailActivatorComponentTable : public CDTable<CDRailActivatorComponentTable> {
public:
CDRailActivatorComponentTable();
void LoadValuesFromDatabase();
static const std::string GetTableName() { return "RailActivatorComponent"; };
[[nodiscard]] CDRailActivatorComponent GetEntryByID(int32_t id) const;
[[nodiscard]] std::vector<CDRailActivatorComponent> GetEntries() const;
[[nodiscard]] const std::vector<CDRailActivatorComponent>& GetEntries() const;
private:
static std::pair<uint32_t, std::u16string> EffectPairFromString(std::string& str);
std::vector<CDRailActivatorComponent> m_Entries{};

View File

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

View File

@@ -31,7 +31,7 @@ private:
std::vector<CDRarityTable> entries;
public:
CDRarityTableTable();
void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDRarityTable> Query(std::function<bool(CDRarityTable)> predicate);

View File

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

View File

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

View File

@@ -1,35 +1,27 @@
#include "CDRewardsTable.h"
CDRewardsTable::CDRewardsTable(void) {
void CDRewardsTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Rewards");
while (!tableData.eof()) {
CDRewards* entry = new CDRewards();
entry->id = tableData.getIntField("id", -1);
entry->levelID = tableData.getIntField("LevelID", -1);
entry->missionID = tableData.getIntField("MissionID", -1);
entry->rewardType = tableData.getIntField("RewardType", -1);
entry->value = tableData.getIntField("value", -1);
entry->count = tableData.getIntField("count", -1);
CDRewards entry;
entry.id = tableData.getIntField("id", -1);
entry.levelID = tableData.getIntField("LevelID", -1);
entry.missionID = tableData.getIntField("MissionID", -1);
entry.rewardType = tableData.getIntField("RewardType", -1);
entry.value = tableData.getIntField("value", -1);
entry.count = tableData.getIntField("count", -1);
m_entries.insert(std::make_pair(entry->id, entry));
m_entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow();
}
tableData.finalize();
}
CDRewardsTable::~CDRewardsTable(void) {
for (auto e : m_entries) {
if (e.second) delete e.second;
}
m_entries.clear();
}
std::vector<CDRewards*> CDRewardsTable::GetByLevelID(uint32_t levelID) {
std::vector<CDRewards*> result{};
std::vector<CDRewards> CDRewardsTable::GetByLevelID(uint32_t levelID) {
std::vector<CDRewards> result{};
for (const auto& e : m_entries) {
if (e.second->levelID == levelID) result.push_back(e.second);
if (e.second.levelID == levelID) result.push_back(e.second);
}
return result;

View File

@@ -13,12 +13,11 @@ struct CDRewards {
class CDRewardsTable : public CDTable<CDRewardsTable> {
public:
CDRewardsTable();
~CDRewardsTable();
void LoadValuesFromDatabase();
static const std::string GetTableName() { return "Rewards"; };
std::vector<CDRewards*> GetByLevelID(uint32_t levelID);
std::vector<CDRewards> GetByLevelID(uint32_t levelID);
private:
std::map<uint32_t, CDRewards*> m_entries;
std::map<uint32_t, CDRewards> m_entries;
};

View File

@@ -1,7 +1,6 @@
#include "CDScriptComponentTable.h"
//! Constructor
CDScriptComponentTable::CDScriptComponentTable(void) {
void CDScriptComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;

View File

@@ -15,7 +15,7 @@ private:
CDScriptComponent m_ToReturnWhenNoneFound;
public:
CDScriptComponentTable();
void LoadValuesFromDatabase();
// Gets an entry by scriptID
const CDScriptComponent& GetByID(unsigned int id);
};

View File

@@ -1,8 +1,6 @@
#include "CDSkillBehaviorTable.h"
//#include "Logger.hpp"
//! Constructor
CDSkillBehaviorTable::CDSkillBehaviorTable(void) {
void CDSkillBehaviorTable::LoadValuesFromDatabase() {
m_empty = CDSkillBehavior();
// First, get the size of the table
@@ -51,13 +49,6 @@ CDSkillBehaviorTable::CDSkillBehaviorTable(void) {
tableData.finalize();
}
//! Queries the table with a custom "where" clause
std::vector<CDSkillBehavior> CDSkillBehaviorTable::Query(std::function<bool(CDSkillBehavior)> predicate) {
std::vector<CDSkillBehavior> data; //So MSVC shuts up
return data;
}
//! Gets an entry by ID
const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(unsigned int skillID) {
std::map<unsigned int, CDSkillBehavior>::iterator it = this->entries.find(skillID);
if (it != this->entries.end()) {

View File

@@ -31,9 +31,7 @@ private:
CDSkillBehavior m_empty;
public:
CDSkillBehaviorTable();
// Queries the table with a custom "where" clause
std::vector<CDSkillBehavior> Query(std::function<bool(CDSkillBehavior)> predicate);
void LoadValuesFromDatabase();
// Gets an entry by skillID
const CDSkillBehavior& GetSkillByID(unsigned int skillID);

View File

@@ -1,7 +1,6 @@
#include "CDVendorComponentTable.h"
//! Constructor
CDVendorComponentTable::CDVendorComponentTable(void) {
void CDVendorComponentTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;
@@ -22,7 +21,7 @@ CDVendorComponentTable::CDVendorComponentTable(void) {
while (!tableData.eof()) {
CDVendorComponent entry;
entry.id = tableData.getIntField("id", -1);
entry.buyScalar = tableData.getFloatField("buyScalar", -1.0f);
entry.buyScalar = tableData.getFloatField("buyScalar", 0.0f);
entry.sellScalar = tableData.getFloatField("sellScalar", -1.0f);
entry.refreshTimeSeconds = tableData.getFloatField("refreshTimeSeconds", -1.0f);
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
@@ -45,7 +44,7 @@ std::vector<CDVendorComponent> CDVendorComponentTable::Query(std::function<bool(
}
//! Gets all the entries in the table
std::vector<CDVendorComponent> CDVendorComponentTable::GetEntries(void) const {
const std::vector<CDVendorComponent>& CDVendorComponentTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -1,7 +1,6 @@
#include "CDZoneTableTable.h"
//! Constructor
CDZoneTableTable::CDZoneTableTable(void) {
void CDZoneTableTable::LoadValuesFromDatabase() {
// First, get the size of the table
unsigned int size = 0;

View File

@@ -38,7 +38,7 @@ private:
std::map<unsigned int, CDZoneTable> m_Entries;
public:
CDZoneTableTable();
void LoadValuesFromDatabase();
// Queries the table with a zoneID to find.
const CDZoneTable* Query(unsigned int zoneID);

View File

@@ -241,7 +241,7 @@ void Character::DoQuickXMLDataParse() {
//To try and fix the AG landing into:
if (m_ZoneID == 1000 && Game::server->GetZoneID() == 1100) {
//sneakily insert our position:
auto pos = dZoneManager::Instance()->GetZone()->GetSpawnPos();
auto pos = Game::zoneManager->GetZone()->GetSpawnPos();
character->SetAttribute("lzx", pos.x);
character->SetAttribute("lzy", pos.y);
character->SetAttribute("lzz", pos.z);
@@ -290,13 +290,13 @@ void Character::DoQuickXMLDataParse() {
void Character::UnlockEmote(int emoteID) {
m_UnlockedEmotes.push_back(emoteID);
GameMessages::SendSetEmoteLockState(EntityManager::Instance()->GetEntity(m_ObjectID), false, emoteID);
GameMessages::SendSetEmoteLockState(Game::entityManager->GetEntity(m_ObjectID), false, emoteID);
}
void Character::SetBuildMode(bool buildMode) {
m_BuildMode = buildMode;
auto* controller = dZoneManager::Instance()->GetZoneControlObject();
auto* controller = Game::zoneManager->GetZoneControlObject();
controller->OnFireEventServerSide(m_OurEntity, buildMode ? "OnBuildModeEnter" : "OnBuildModeLeave");
}
@@ -312,7 +312,7 @@ void Character::SaveXMLToDatabase() {
character->SetAttribute("gm", static_cast<uint32_t>(m_GMLevel));
character->SetAttribute("cc", m_Coins);
auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID();
auto zoneInfo = Game::zoneManager->GetZone()->GetZoneID();
// lzid garbage, binary concat of zoneID, zoneInstance and zoneClone
if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) {
uint64_t lzidConcat = zoneInfo.GetCloneID();
@@ -424,7 +424,7 @@ void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
if (value) {
// Update the mission component:
auto* player = EntityManager::Instance()->GetEntity(m_ObjectID);
auto* player = Game::entityManager->GetEntity(m_ObjectID);
if (player != nullptr) {
auto* missionComponent = player->GetComponent<MissionComponent>();
@@ -602,7 +602,7 @@ void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) {
m_Coins = newCoins;
GameMessages::SendSetCurrency(EntityManager::Instance()->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource);
GameMessages::SendSetCurrency(Game::entityManager->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource);
}
bool Character::HasBeenToWorld(LWOMAPID mapID) const {

View File

@@ -51,6 +51,7 @@
#include "BuildBorderComponent.h"
#include "MovementAIComponent.h"
#include "VendorComponent.h"
#include "DonationVendorComponent.h"
#include "RocketLaunchpadControlComponent.h"
#include "PropertyComponent.h"
#include "BaseCombatAIComponent.h"
@@ -70,6 +71,7 @@
#include "ShootingGalleryComponent.h"
#include "RailActivatorComponent.h"
#include "LUPExhibitComponent.h"
#include "RacingSoundTriggerComponent.h"
#include "TriggerComponent.h"
#include "eGameMasterLevel.h"
#include "eReplicaComponentType.h"
@@ -263,17 +265,17 @@ void Entity::Initialize() {
NiQuaternion rot;
const auto& targetSceneName = m_Character->GetTargetScene();
auto* targetScene = EntityManager::Instance()->GetSpawnPointEntity(targetSceneName);
auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName);
if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) {
pos = m_Character->GetRespawnPoint(mapID);
rot = dZoneManager::Instance()->GetZone()->GetSpawnRot();
rot = Game::zoneManager->GetZone()->GetSpawnRot();
} else if (targetScene != nullptr) {
pos = targetScene->GetPosition();
rot = targetScene->GetRotation();
} else {
pos = dZoneManager::Instance()->GetZone()->GetSpawnPos();
rot = dZoneManager::Instance()->GetZone()->GetSpawnRot();
pos = Game::zoneManager->GetZone()->GetSpawnPos();
rot = Game::zoneManager->GetZone()->GetSpawnRot();
}
controllablePhysics->SetPosition(pos);
@@ -317,6 +319,9 @@ void Entity::Initialize() {
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
auto* comp = new SoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp));
} else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) {
auto* comp = new RacingSoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_SOUND_TRIGGER, comp));
}
//Also check for the collectible id:
@@ -505,7 +510,7 @@ void Entity::Initialize() {
// ZoneControl script
if (m_TemplateID == 2365) {
CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>();
const auto zoneID = dZoneManager::Instance()->GetZoneID();
const auto zoneID = Game::zoneManager->GetZoneID();
const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID());
if (zoneData != nullptr) {
@@ -578,6 +583,9 @@ void Entity::Initialize() {
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) {
VendorComponent* comp = new VendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp));
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
DonationVendorComponent* comp = new DonationVendorComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::DONATION_VENDOR, comp));
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
@@ -691,7 +699,7 @@ void Entity::Initialize() {
}
std::string pathName = GetVarAsString(u"attached_path");
const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName);
const Path* path = Game::zoneManager->GetZone()->GetPath(pathName);
//Check to see if we have an attached path and add the appropiate component to handle it:
if (path){
@@ -735,7 +743,7 @@ void Entity::Initialize() {
}
});
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) {
if (!m_Character && Game::entityManager->GetGhostingEnabled()) {
// Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
goto no_ghosting;
@@ -1012,57 +1020,60 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
*/
bool destroyableSerialized = false;
bool bIsInitialUpdate = false;
if (packetType == eReplicaPacketType::CONSTRUCTION) bIsInitialUpdate = true;
unsigned int flags = 0;
bool bIsInitialUpdate = packetType == eReplicaPacketType::CONSTRUCTION;
PossessableComponent* possessableComponent;
if (TryGetComponent(eReplicaComponentType::POSSESSABLE, possessableComponent)) {
possessableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
possessableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ModuleAssemblyComponent* moduleAssemblyComponent;
if (TryGetComponent(eReplicaComponentType::MODULE_ASSEMBLY, moduleAssemblyComponent)) {
moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ControllablePhysicsComponent* controllablePhysicsComponent;
if (TryGetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) {
controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
}
SimplePhysicsComponent* simplePhysicsComponent;
if (TryGetComponent(eReplicaComponentType::SIMPLE_PHYSICS, simplePhysicsComponent)) {
simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
}
RigidbodyPhantomPhysicsComponent* rigidbodyPhantomPhysics;
if (TryGetComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) {
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate, flags);
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate);
}
VehiclePhysicsComponent* vehiclePhysicsComponent;
if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) {
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
}
PhantomPhysicsComponent* phantomPhysicsComponent;
if (TryGetComponent(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysicsComponent)) {
phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
}
SoundTriggerComponent* soundTriggerComponent;
if (TryGetComponent(eReplicaComponentType::SOUND_TRIGGER, soundTriggerComponent)) {
soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate);
}
RacingSoundTriggerComponent* racingSoundTriggerComponent;
if (TryGetComponent(eReplicaComponentType::RACING_SOUND_TRIGGER, racingSoundTriggerComponent)) {
racingSoundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate);
}
BuffComponent* buffComponent;
if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) {
buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
buffComponent->Serialize(outBitStream, bIsInitialUpdate);
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
destroyableSerialized = true;
}
@@ -1070,7 +1081,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
if (HasComponent(eReplicaComponentType::COLLECTIBLE)) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
destroyableSerialized = true;
outBitStream->Write(m_CollectibleID); // Collectable component
@@ -1078,7 +1089,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
PetComponent* petComponent;
if (TryGetComponent(eReplicaComponentType::PET, petComponent)) {
petComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
petComponent->Serialize(outBitStream, bIsInitialUpdate);
}
CharacterComponent* characterComponent;
@@ -1086,7 +1097,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
PossessorComponent* possessorComponent;
if (TryGetComponent(eReplicaComponentType::POSSESSOR, possessorComponent)) {
possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
possessorComponent->Serialize(outBitStream, bIsInitialUpdate);
} else {
// Should never happen, but just to be safe
outBitStream->Write0();
@@ -1094,7 +1105,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
LevelProgressionComponent* levelProgressionComponent;
if (TryGetComponent(eReplicaComponentType::LEVEL_PROGRESSION, levelProgressionComponent)) {
levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate);
} else {
// Should never happen, but just to be safe
outBitStream->Write0();
@@ -1102,13 +1113,13 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
PlayerForcedMovementComponent* playerForcedMovementComponent;
if (TryGetComponent(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, playerForcedMovementComponent)) {
playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate);
} else {
// Should never happen, but just to be safe
outBitStream->Write0();
}
characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
characterComponent->Serialize(outBitStream, bIsInitialUpdate);
}
if (HasComponent(eReplicaComponentType::ITEM)) {
@@ -1117,88 +1128,93 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
InventoryComponent* inventoryComponent;
if (TryGetComponent(eReplicaComponentType::INVENTORY, inventoryComponent)) {
inventoryComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
inventoryComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ScriptComponent* scriptComponent;
if (TryGetComponent(eReplicaComponentType::SCRIPT, scriptComponent)) {
scriptComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
scriptComponent->Serialize(outBitStream, bIsInitialUpdate);
}
SkillComponent* skillComponent;
if (TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) {
skillComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
skillComponent->Serialize(outBitStream, bIsInitialUpdate);
}
BaseCombatAIComponent* baseCombatAiComponent;
if (TryGetComponent(eReplicaComponentType::BASE_COMBAT_AI, baseCombatAiComponent)) {
baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate);
}
RebuildComponent* rebuildComponent;
if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, rebuildComponent)) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
}
destroyableSerialized = true;
rebuildComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
rebuildComponent->Serialize(outBitStream, bIsInitialUpdate);
}
MovingPlatformComponent* movingPlatformComponent;
if (TryGetComponent(eReplicaComponentType::MOVING_PLATFORM, movingPlatformComponent)) {
movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate);
}
SwitchComponent* switchComponent;
if (TryGetComponent(eReplicaComponentType::SWITCH, switchComponent)) {
switchComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
switchComponent->Serialize(outBitStream, bIsInitialUpdate);
}
VendorComponent* vendorComponent;
if (TryGetComponent(eReplicaComponentType::VENDOR, vendorComponent)) {
vendorComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
vendorComponent->Serialize(outBitStream, bIsInitialUpdate);
}
DonationVendorComponent* donationVendorComponent;
if (TryGetComponent(eReplicaComponentType::DONATION_VENDOR, donationVendorComponent)) {
donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate);
}
BouncerComponent* bouncerComponent;
if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) {
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ScriptedActivityComponent* scriptedActivityComponent;
if (TryGetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY, scriptedActivityComponent)) {
scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ShootingGalleryComponent* shootingGalleryComponent;
if (TryGetComponent(eReplicaComponentType::SHOOTING_GALLERY, shootingGalleryComponent)) {
shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate);
}
RacingControlComponent* racingControlComponent;
if (TryGetComponent(eReplicaComponentType::RACING_CONTROL, racingControlComponent)) {
racingControlComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
racingControlComponent->Serialize(outBitStream, bIsInitialUpdate);
}
LUPExhibitComponent* lupExhibitComponent;
if (TryGetComponent(eReplicaComponentType::LUP_EXHIBIT, lupExhibitComponent)) {
lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate);
}
ModelComponent* modelComponent;
if (TryGetComponent(eReplicaComponentType::MODEL, modelComponent)) {
modelComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
modelComponent->Serialize(outBitStream, bIsInitialUpdate);
}
RenderComponent* renderComponent;
if (TryGetComponent(eReplicaComponentType::RENDER, renderComponent)) {
renderComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
renderComponent->Serialize(outBitStream, bIsInitialUpdate);
}
if (modelComponent) {
DestroyableComponent* destroyableComponent;
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
destroyableSerialized = true;
}
}
@@ -1213,10 +1229,6 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
outBitStream->Write0();
}
void Entity::ResetFlags() {
// Unused
}
void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
//Naturally, we don't include any non-player components in this update function.
@@ -1284,12 +1296,12 @@ void Entity::Update(const float deltaTime) {
}
if (m_ShouldDestroyAfterUpdate) {
EntityManager::Instance()->DestroyEntity(this->GetObjectID());
Game::entityManager->DestroyEntity(this->GetObjectID());
}
}
void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status) {
Entity* other = EntityManager::Instance()->GetEntity(otherEntity);
Entity* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1303,7 +1315,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN
}
void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
auto* other = EntityManager::Instance()->GetEntity(otherEntity);
auto* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1350,7 +1362,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
}
void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) {
auto* other = EntityManager::Instance()->GetEntity(otherEntity);
auto* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1504,13 +1516,13 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (destroyableComponent == nullptr) {
Kill(EntityManager::Instance()->GetEntity(source));
Kill(Game::entityManager->GetEntity(source));
return;
}
auto* possessorComponent = GetComponent<PossessorComponent>();
if (possessorComponent) {
if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) {
auto* mount = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
auto* mount = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
if (mount) possessorComponent->Dismount(mount, true);
}
}
@@ -1538,20 +1550,20 @@ void Entity::Kill(Entity* murderer) {
}
if (!IsPlayer()) {
EntityManager::Instance()->DestroyEntity(this);
Game::entityManager->DestroyEntity(this);
}
const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");
if (!grpNameQBShowBricks.empty()) {
auto spawners = dZoneManager::Instance()->GetSpawnersByName(grpNameQBShowBricks);
auto spawners = Game::zoneManager->GetSpawnersByName(grpNameQBShowBricks);
Spawner* spawner = nullptr;
if (!spawners.empty()) {
spawner = spawners[0];
} else {
spawners = dZoneManager::Instance()->GetSpawnersInGroup(grpNameQBShowBricks);
spawners = Game::zoneManager->GetSpawnersInGroup(grpNameQBShowBricks);
if (!spawners.empty()) {
spawner = spawners[0];
@@ -1719,7 +1731,7 @@ void Entity::CancelCallbackTimers() {
void Entity::ScheduleKillAfterUpdate(Entity* murderer) {
//if (m_Info.spawner) m_Info.spawner->ScheduleKill(this);
EntityManager::Instance()->ScheduleForKill(this);
Game::entityManager->ScheduleForKill(this);
if (murderer) m_ScheduleKiller = murderer;
}
@@ -1763,7 +1775,7 @@ void Entity::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) {
Entity* Entity::GetOwner() const {
if (m_OwnerOverride != LWOOBJID_EMPTY) {
auto* other = EntityManager::Instance()->GetEntity(m_OwnerOverride);
auto* other = Game::entityManager->GetEntity(m_OwnerOverride);
if (other != nullptr) {
return other->GetOwner();
@@ -1907,7 +1919,7 @@ void Entity::SetPosition(NiPoint3 position) {
vehicel->SetPosition(position);
}
EntityManager::Instance()->SerializeEntity(this);
Game::entityManager->SerializeEntity(this);
}
void Entity::SetRotation(NiQuaternion rotation) {
@@ -1935,7 +1947,7 @@ void Entity::SetRotation(NiQuaternion rotation) {
vehicel->SetRotation(rotation);
}
EntityManager::Instance()->SerializeEntity(this);
Game::entityManager->SerializeEntity(this);
}
bool Entity::GetBoolean(const std::u16string& name) const {
@@ -1987,7 +1999,7 @@ std::vector<LWOOBJID>& Entity::GetTargetsInPhantom() {
for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) {
const auto id = m_TargetsInPhantom.at(i);
auto* entity = EntityManager::Instance()->GetEntity(id);
auto* entity = Game::entityManager->GetEntity(id);
if (entity == nullptr) {
continue;

View File

@@ -85,6 +85,7 @@ public:
bool GetPlayerReadyForUpdates() const { return m_PlayerIsReadyForUpdates; }
bool GetIsGhostingCandidate() const;
void SetIsGhostingCandidate(bool value) { m_IsGhostingCandidate = value; };
int8_t GetObservers() const;
@@ -173,7 +174,6 @@ public:
void WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType);
void WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType);
void ResetFlags();
void UpdateXMLDoc(tinyxml2::XMLDocument* doc);
void Update(float deltaTime);

View File

@@ -25,8 +25,6 @@
#include "eReplicaComponentType.h"
#include "eReplicaPacketType.h"
EntityManager* EntityManager::m_Address = nullptr;
// Configure which zones have ghosting disabled, mostly small worlds.
std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
// Small zones
@@ -62,7 +60,7 @@ void EntityManager::Initialize() {
m_GhostingEnabled = std::find(
m_GhostingExcludedZones.begin(),
m_GhostingExcludedZones.end(),
dZoneManager::Instance()->GetZoneID().GetMapID()
Game::zoneManager->GetZoneID().GetMapID()
) == m_GhostingExcludedZones.end();
// grab hardcore mode settings and load them with sane defaults
@@ -77,10 +75,7 @@ void EntityManager::Initialize() {
// If cloneID is not zero, then hardcore mode is disabled
// aka minigames and props
if (dZoneManager::Instance()->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false;
}
EntityManager::~EntityManager() {
if (Game::zoneManager->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false;
}
Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) {
@@ -588,12 +583,6 @@ bool EntityManager::GetGhostingEnabled() const {
return m_GhostingEnabled;
}
void EntityManager::ResetFlags() {
for (const auto& e : m_Entities) {
e.second->ResetFlags();
}
}
void EntityManager::ScheduleForKill(Entity* entity) {
// Deactivate switches if they die
if (!entity)

View File

@@ -1,12 +1,13 @@
#ifndef ENTITYMANAGER_H
#define ENTITYMANAGER_H
#include "dCommonVars.h"
#include <map>
#include <stack>
#include <vector>
#include <unordered_map>
#include "dCommonVars.h"
class Entity;
class EntityInfo;
class Player;
@@ -17,19 +18,8 @@ struct SystemAddress;
class EntityManager {
public:
static EntityManager* Instance() {
if (!m_Address) {
m_Address = new EntityManager();
m_Address->Initialize();
}
return m_Address;
}
void Initialize();
~EntityManager();
void UpdateEntities(float deltaTime);
Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY);
void DestroyEntity(const LWOOBJID& objectID);
@@ -69,8 +59,6 @@ public:
Entity* GetGhostCandidate(int32_t id);
bool GetGhostingEnabled() const;
void ResetFlags();
void ScheduleForKill(Entity* entity);
void ScheduleForDeletion(LWOOBJID entity);
@@ -89,7 +77,6 @@ private:
void KillEntities();
void DeleteEntities();
static EntityManager* m_Address; //For singleton method
static std::vector<LWOMAPID> m_GhostingExcludedZones;
static std::vector<LOT> m_GhostingExcludedLOTs;

View File

@@ -1,5 +1,8 @@
#include "LeaderboardManager.h"
#include <sstream>
#include <utility>
#include "Database.h"
#include "EntityManager.h"
#include "Character.h"
@@ -10,461 +13,400 @@
#include "CDClientManager.h"
#include "GeneralUtils.h"
#include "Entity.h"
#include "LDFFormat.h"
#include "DluAssert.h"
#include "CDActivitiesTable.h"
#include "Metrics.hpp"
Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries,
LWOOBJID relatedPlayer, LeaderboardType leaderboardType) {
this->relatedPlayer = relatedPlayer;
namespace LeaderboardManager {
std::map<GameID, Leaderboard::Type> leaderboardCache;
}
Leaderboard::Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type leaderboardType) {
this->gameID = gameID;
this->weekly = weekly;
this->infoType = infoType;
this->entries = std::move(entries);
this->leaderboardType = leaderboardType;
this->relatedPlayer = relatedPlayer;
}
std::u16string Leaderboard::ToString() const {
std::string leaderboard;
Leaderboard::~Leaderboard() {
Clear();
}
leaderboard += "ADO.Result=7:1\n";
leaderboard += "Result.Count=1:1\n";
leaderboard += "Result[0].Index=0:RowNumber\n";
leaderboard += "Result[0].RowCount=1:" + std::to_string(entries.size()) + "\n";
void Leaderboard::Clear() {
for (auto& entry : entries) for (auto ldfData : entry) delete ldfData;
}
auto index = 0;
for (const auto& entry : entries) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].LastPlayed=8:" + std::to_string(entry.lastPlayed) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].CharacterID=8:" + std::to_string(entry.playerID) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].NumPlayed=1:1\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].RowNumber=8:" + std::to_string(entry.placement) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Time=1:" + std::to_string(entry.time) + "\n";
inline void WriteLeaderboardRow(std::ostringstream& leaderboard, const uint32_t& index, LDFBaseData* data) {
leaderboard << "\nResult[0].Row[" << index << "]." << data->GetString();
}
// Only these minigames have a points system
if (leaderboardType == Survival || leaderboardType == ShootingGallery) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Points=1:" + std::to_string(entry.score) + "\n";
} else if (leaderboardType == SurvivalNS) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Wave=1:" + std::to_string(entry.score) + "\n";
void Leaderboard::Serialize(RakNet::BitStream* bitStream) const {
bitStream->Write(gameID);
bitStream->Write(infoType);
std::ostringstream leaderboard;
leaderboard << "ADO.Result=7:1"; // Unused in 1.10.64, but is in captures
leaderboard << "\nResult.Count=1:1"; // number of results, always 1
if (!this->entries.empty()) leaderboard << "\nResult[0].Index=0:RowNumber"; // "Primary key". Live doesn't include this if there are no entries.
leaderboard << "\nResult[0].RowCount=1:" << entries.size();
int32_t rowNumber = 0;
for (auto& entry : entries) {
for (auto* data : entry) {
WriteLeaderboardRow(leaderboard, rowNumber, data);
}
leaderboard += "Result[0].Row[" + std::to_string(index) + "].name=0:" + entry.playerName + "\n";
index++;
rowNumber++;
}
return GeneralUtils::UTF8ToUTF16(leaderboard);
// Serialize the thing to a BitStream
uint32_t leaderboardSize = leaderboard.tellp();
bitStream->Write<uint32_t>(leaderboardSize);
// Doing this all in 1 call so there is no possbility of a dangling pointer.
bitStream->WriteAlignedBytes(reinterpret_cast<const unsigned char*>(GeneralUtils::ASCIIToUTF16(leaderboard.str()).c_str()), leaderboardSize * sizeof(char16_t));
if (leaderboardSize > 0) bitStream->Write<uint16_t>(0);
bitStream->Write0();
bitStream->Write0();
}
std::vector<LeaderboardEntry> Leaderboard::GetEntries() {
return entries;
void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
Clear();
if (rows->rowsCount() == 0) return;
this->entries.reserve(rows->rowsCount());
while (rows->next()) {
constexpr int32_t MAX_NUM_DATA_PER_ROW = 9;
this->entries.push_back(std::vector<LDFBaseData*>());
auto& entry = this->entries.back();
entry.reserve(MAX_NUM_DATA_PER_ROW);
entry.push_back(new LDFData<uint64_t>(u"CharacterID", rows->getInt("character_id")));
entry.push_back(new LDFData<uint64_t>(u"LastPlayed", rows->getUInt64("lastPlayed")));
entry.push_back(new LDFData<int32_t>(u"NumPlayed", rows->getInt("timesPlayed")));
entry.push_back(new LDFData<std::u16string>(u"name", GeneralUtils::ASCIIToUTF16(rows->getString("name").c_str())));
entry.push_back(new LDFData<uint64_t>(u"RowNumber", rows->getInt("ranking")));
switch (leaderboardType) {
case Type::ShootingGallery:
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
// Score:1
entry.push_back(new LDFData<int32_t>(u"Streak", rows->getInt("secondaryScore")));
// Streak:1
entry.push_back(new LDFData<float>(u"HitPercentage", (rows->getInt("tertiaryScore") / 100.0f)));
// HitPercentage:3 between 0 and 1
break;
case Type::Racing:
entry.push_back(new LDFData<float>(u"BestTime", rows->getDouble("primaryScore")));
// BestLapTime:3
entry.push_back(new LDFData<float>(u"BestLapTime", rows->getDouble("secondaryScore")));
// BestTime:3
entry.push_back(new LDFData<int32_t>(u"License", 1));
// License:1 - 1 if player has completed mission 637 and 0 otherwise
entry.push_back(new LDFData<int32_t>(u"NumWins", rows->getInt("numWins")));
// NumWins:1
break;
case Type::UnusedLeaderboard4:
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
// Points:1
break;
case Type::MonumentRace:
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
// Time:1(?)
break;
case Type::FootRace:
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
// Time:1
break;
case Type::Survival:
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
// Points:1
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
// Time:1
break;
case Type::SurvivalNS:
entry.push_back(new LDFData<int32_t>(u"Wave", rows->getInt("primaryScore")));
// Wave:1
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
// Time:1
break;
case Type::Donations:
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
// Score:1
break;
case Type::None:
// This type is included here simply to resolve a compiler warning on mac about unused enum types
break;
default:
break;
}
}
}
uint32_t Leaderboard::GetGameID() const {
return gameID;
const std::string_view Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) {
// Use a switch case and return desc for all 3 columns if higher is better and asc if lower is better
switch (leaderboardType) {
case Type::Racing:
case Type::MonumentRace:
return "primaryScore ASC, secondaryScore ASC, tertiaryScore ASC";
case Type::Survival:
return Game::config->GetValue("classic_survival_scoring") == "1" ?
"secondaryScore DESC, primaryScore DESC, tertiaryScore DESC" :
"primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
case Type::SurvivalNS:
return "primaryScore DESC, secondaryScore ASC, tertiaryScore DESC";
case Type::ShootingGallery:
case Type::FootRace:
case Type::UnusedLeaderboard4:
case Type::Donations:
case Type::None:
default:
return "primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
}
}
uint32_t Leaderboard::GetInfoType() const {
return infoType;
void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t resultEnd) {
resultStart++;
resultEnd++;
// We need everything except 1 column so i'm selecting * from leaderboard
const std::string queryBase =
R"QUERY(
WITH leaderboardsRanked AS (
SELECT leaderboard.*, charinfo.name,
RANK() OVER
(
ORDER BY %s, UNIX_TIMESTAMP(last_played) ASC, id DESC
) AS ranking
FROM leaderboard JOIN charinfo on charinfo.id = leaderboard.character_id
WHERE game_id = ? %s
),
myStanding AS (
SELECT
ranking as myRank
FROM leaderboardsRanked
WHERE id = ?
),
lowestRanking AS (
SELECT MAX(ranking) AS lowestRank
FROM leaderboardsRanked
)
SELECT leaderboardsRanked.*, character_id, UNIX_TIMESTAMP(last_played) as lastPlayed, leaderboardsRanked.name, leaderboardsRanked.ranking FROM leaderboardsRanked, myStanding, lowestRanking
WHERE leaderboardsRanked.ranking
BETWEEN
LEAST(GREATEST(CAST(myRank AS SIGNED) - 5, %i), lowestRanking.lowestRank - 9)
AND
LEAST(GREATEST(myRank + 5, %i), lowestRanking.lowestRank)
ORDER BY ranking ASC;
)QUERY";
std::string friendsFilter =
R"QUERY(
AND (
character_id IN (
SELECT fr.requested_player FROM (
SELECT CASE
WHEN player_id = ? THEN friend_id
WHEN friend_id = ? THEN player_id
END AS requested_player
FROM friends
) AS fr
JOIN charinfo AS ci
ON ci.id = fr.requested_player
WHERE fr.requested_player IS NOT NULL
)
OR character_id = ?
)
)QUERY";
std::string weeklyFilter = " AND UNIX_TIMESTAMP(last_played) BETWEEN UNIX_TIMESTAMP(date_sub(now(),INTERVAL 1 WEEK)) AND UNIX_TIMESTAMP(now()) ";
std::string filter;
// Setup our filter based on the query type
if (this->infoType == InfoType::Friends) filter += friendsFilter;
if (this->weekly) filter += weeklyFilter;
const auto orderBase = GetOrdering(this->leaderboardType);
// For top query, we want to just rank all scores, but for all others we need the scores around a specific player
std::string baseLookup;
if (this->infoType == InfoType::Top) {
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " ORDER BY ";
baseLookup += orderBase.data();
} else {
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " AND character_id = ";
baseLookup += std::to_string(static_cast<uint32_t>(this->relatedPlayer));
}
baseLookup += " LIMIT 1";
Game::logger->LogDebug("LeaderboardManager", "query is %s", baseLookup.c_str());
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::CreatePreppedStmt(baseLookup));
baseQuery->setInt(1, this->gameID);
std::unique_ptr<sql::ResultSet> baseResult(baseQuery->executeQuery());
if (!baseResult->next()) return; // In this case, there are no entries in the leaderboard for this game.
uint32_t relatedPlayerLeaderboardId = baseResult->getInt("id");
// Create and execute the actual save here. Using a heap allocated buffer to avoid stack overflow
constexpr uint16_t STRING_LENGTH = 4096;
std::unique_ptr<char[]> lookupBuffer = std::make_unique<char[]>(STRING_LENGTH);
int32_t res = snprintf(lookupBuffer.get(), STRING_LENGTH, queryBase.c_str(), orderBase.data(), filter.c_str(), resultStart, resultEnd);
DluAssert(res != -1);
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer.get()));
Game::logger->LogDebug("LeaderboardManager", "Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
query->setInt(1, this->gameID);
if (this->infoType == InfoType::Friends) {
query->setInt(2, this->relatedPlayer);
query->setInt(3, this->relatedPlayer);
query->setInt(4, this->relatedPlayer);
query->setInt(5, relatedPlayerLeaderboardId);
} else {
query->setInt(2, relatedPlayerLeaderboardId);
}
std::unique_ptr<sql::ResultSet> result(query->executeQuery());
QueryToLdf(result);
}
void Leaderboard::Send(LWOOBJID targetID) const {
auto* player = EntityManager::Instance()->GetEntity(relatedPlayer);
void Leaderboard::Send(const LWOOBJID targetID) const {
auto* player = Game::entityManager->GetEntity(relatedPlayer);
if (player != nullptr) {
GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress());
}
}
void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time) {
const auto* player = EntityManager::Instance()->GetEntity(playerID);
if (player == nullptr)
return;
std::string FormatInsert(const Leaderboard::Type& type, const Score& score, const bool useUpdate) {
std::string insertStatement;
if (useUpdate) {
insertStatement =
R"QUERY(
UPDATE leaderboard
SET primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;
)QUERY";
} else {
insertStatement =
R"QUERY(
INSERT leaderboard SET
primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
character_id = ?, game_id = ?;
)QUERY";
}
auto* character = player->GetCharacter();
if (character == nullptr)
return;
constexpr uint16_t STRING_LENGTH = 400;
// Then fill in our score
char finishedQuery[STRING_LENGTH];
int32_t res = snprintf(finishedQuery, STRING_LENGTH, insertStatement.c_str(), score.GetPrimaryScore(), score.GetSecondaryScore(), score.GetTertiaryScore());
DluAssert(res != -1);
return finishedQuery;
}
auto* select = Database::CreatePreppedStmt("SELECT time, score FROM leaderboard WHERE character_id = ? AND game_id = ?;");
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore, const float tertiaryScore) {
const Leaderboard::Type leaderboardType = GetLeaderboardType(activityId);
select->setUInt64(1, character->GetID());
select->setInt(2, gameID);
auto any = false;
auto* result = select->executeQuery();
auto leaderboardType = GetLeaderboardType(gameID);
// Check if the new score is a high score
while (result->next()) {
any = true;
const auto storedTime = result->getInt(1);
const auto storedScore = result->getInt(2);
auto highscore = true;
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;"));
query->setInt(1, playerID);
query->setInt(2, activityId);
std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery());
std::string saveQuery("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;");
Score newScore(primaryScore, secondaryScore, tertiaryScore);
if (myScoreResult->next()) {
Score oldScore;
bool lowerScoreBetter = false;
switch (leaderboardType) {
case ShootingGallery:
if (score <= storedScore)
highscore = false;
// Higher score better
case Leaderboard::Type::ShootingGallery: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
oldScore.SetTertiaryScore(myScoreResult->getInt("tertiaryScore"));
break;
case Racing:
if (time >= storedTime)
highscore = false;
break;
case MonumentRace:
if (time >= storedTime)
highscore = false;
break;
case FootRace:
if (time <= storedTime)
highscore = false;
break;
case Survival:
if (classicSurvivalScoring) {
if (time <= storedTime) { // Based on time (LU live)
highscore = false;
}
} else {
if (score <= storedScore) // Based on score (DLU)
highscore = false;
}
break;
case SurvivalNS:
if (!(score > storedScore || (time < storedTime && score >= storedScore)))
highscore = false;
break;
default:
highscore = false;
}
case Leaderboard::Type::FootRace: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
break;
}
case Leaderboard::Type::Survival: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
break;
}
case Leaderboard::Type::SurvivalNS: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
break;
}
case Leaderboard::Type::UnusedLeaderboard4:
case Leaderboard::Type::Donations: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
newScore.SetPrimaryScore(oldScore.GetPrimaryScore() + newScore.GetPrimaryScore());
break;
}
case Leaderboard::Type::Racing: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
if (!highscore) {
delete select;
delete result;
// For wins we dont care about the score, just the time, so zero out the tertiary.
// Wins are updated later.
oldScore.SetTertiaryScore(0);
newScore.SetTertiaryScore(0);
lowerScoreBetter = true;
break;
}
case Leaderboard::Type::MonumentRace: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
lowerScoreBetter = true;
// Do score checking here
break;
}
case Leaderboard::Type::None:
default:
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
return;
}
}
delete select;
delete result;
if (any) {
auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ?, last_played=SYSDATE() WHERE character_id = ? AND game_id = ?;");
statement->setInt(1, time);
statement->setInt(2, score);
statement->setUInt64(3, character->GetID());
statement->setInt(4, gameID);
statement->execute();
delete statement;
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
// Nimbus station has a weird leaderboard where we need a custom scoring system
if (leaderboardType == Leaderboard::Type::SurvivalNS) {
newHighScore = newScore.GetPrimaryScore() > oldScore.GetPrimaryScore() ||
(newScore.GetPrimaryScore() == oldScore.GetPrimaryScore() && newScore.GetSecondaryScore() < oldScore.GetSecondaryScore());
} else if (leaderboardType == Leaderboard::Type::Survival && Game::config->GetValue("classic_survival_scoring") == "1") {
Score oldScoreFlipped(oldScore.GetSecondaryScore(), oldScore.GetPrimaryScore());
Score newScoreFlipped(newScore.GetSecondaryScore(), newScore.GetPrimaryScore());
newHighScore = newScoreFlipped > oldScoreFlipped;
}
if (newHighScore) {
saveQuery = FormatInsert(leaderboardType, newScore, true);
}
} else {
// Note: last_played will be set to SYSDATE() by default when inserting into leaderboard
auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);");
statement->setUInt64(1, character->GetID());
statement->setInt(2, gameID);
statement->setInt(3, time);
statement->setInt(4, score);
statement->execute();
saveQuery = FormatInsert(leaderboardType, newScore, false);
}
Game::logger->Log("LeaderboardManager", "save query %s %i %i", saveQuery.c_str(), playerID, activityId);
std::unique_ptr<sql::PreparedStatement> saveStatement(Database::CreatePreppedStmt(saveQuery));
saveStatement->setInt(1, playerID);
saveStatement->setInt(2, activityId);
saveStatement->execute();
delete statement;
// track wins separately
if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore != 0.0f) {
std::unique_ptr<sql::PreparedStatement> winUpdate(Database::CreatePreppedStmt("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;"));
winUpdate->setInt(1, playerID);
winUpdate->setInt(2, activityId);
winUpdate->execute();
}
}
Leaderboard* LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID) {
auto leaderboardType = GetLeaderboardType(gameID);
std::string query;
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
switch (infoType) {
case InfoType::Standings:
switch (leaderboardType) {
case ShootingGallery:
query = standingsScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = standingsTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? standingsTimeQuery : standingsScoreQuery;
break;
case SurvivalNS:
query = standingsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = standingsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
break;
case InfoType::Friends:
switch (leaderboardType) {
case ShootingGallery:
query = friendsScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = friendsTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? friendsTimeQuery : friendsScoreQuery;
break;
case SurvivalNS:
query = friendsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = friendsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
break;
default:
switch (leaderboardType) {
case ShootingGallery:
query = topPlayersScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = topPlayersTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? topPlayersTimeQuery : topPlayersScoreQuery;
break;
case SurvivalNS:
query = topPlayersScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = topPlayersTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
}
auto* statement = Database::CreatePreppedStmt(query);
statement->setUInt(1, gameID);
// Only the standings and friends leaderboards require the character ID to be set
if (infoType == Standings || infoType == Friends) {
auto characterID = 0;
const auto* player = EntityManager::Instance()->GetEntity(playerID);
if (player != nullptr) {
auto* character = player->GetCharacter();
if (character != nullptr)
characterID = character->GetID();
}
statement->setUInt64(2, characterID);
}
auto* res = statement->executeQuery();
std::vector<LeaderboardEntry> entries{};
uint32_t index = 0;
while (res->next()) {
LeaderboardEntry entry;
entry.playerID = res->getUInt64(4);
entry.playerName = res->getString(5);
entry.time = res->getUInt(1);
entry.score = res->getUInt(2);
entry.placement = res->getUInt(3);
entry.lastPlayed = res->getUInt(6);
entries.push_back(entry);
index++;
}
delete res;
delete statement;
return new Leaderboard(gameID, infoType, weekly, entries, playerID, leaderboardType);
void LeaderboardManager::SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart, const uint32_t resultEnd) {
Leaderboard leaderboard(gameID, infoType, weekly, playerID, GetLeaderboardType(gameID));
leaderboard.SetupLeaderboard(weekly, resultStart, resultEnd);
leaderboard.Send(targetID);
}
void LeaderboardManager::SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID,
LWOOBJID playerID) {
const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, infoType, weekly, playerID);
leaderboard->Send(targetID);
delete leaderboard;
}
Leaderboard::Type LeaderboardManager::GetLeaderboardType(const GameID gameID) {
auto lookup = leaderboardCache.find(gameID);
if (lookup != leaderboardCache.end()) return lookup->second;
LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) {
auto* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
std::vector<CDActivities> activities = activitiesTable->Query([=](const CDActivities& entry) {
return (entry.ActivityID == gameID);
std::vector<CDActivities> activities = activitiesTable->Query([gameID](const CDActivities& entry) {
return entry.ActivityID == gameID;
});
for (const auto& activity : activities) {
return static_cast<LeaderboardType>(activity.leaderboardType);
}
return LeaderboardType::None;
auto type = !activities.empty() ? static_cast<Leaderboard::Type>(activities.at(0).leaderboardType) : Leaderboard::Type::None;
leaderboardCache.insert_or_assign(gameID, type);
return type;
}
const std::string LeaderboardManager::topPlayersScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";

View File

@@ -1,80 +1,134 @@
#pragma once
#ifndef __LEADERBOARDMANAGER__H__
#define __LEADERBOARDMANAGER__H__
#include <map>
#include <memory>
#include <string_view>
#include <vector>
#include <climits>
#include "Singleton.h"
#include "dCommonVars.h"
#include "LDFFormat.h"
struct LeaderboardEntry {
uint64_t playerID;
std::string playerName;
uint32_t time;
uint32_t score;
uint32_t placement;
time_t lastPlayed;
namespace sql {
class ResultSet;
};
enum InfoType : uint32_t {
Top, // Top 11 all time players
Standings, // Ranking of the current player
Friends // Ranking between friends
namespace RakNet {
class BitStream;
};
enum LeaderboardType : uint32_t {
ShootingGallery,
Racing,
MonumentRace,
FootRace,
Survival = 5,
SurvivalNS = 6,
None = UINT_MAX
class Score {
public:
Score() {
primaryScore = 0;
secondaryScore = 0;
tertiaryScore = 0;
}
Score(const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0) {
this->primaryScore = primaryScore;
this->secondaryScore = secondaryScore;
this->tertiaryScore = tertiaryScore;
}
bool operator<(const Score& rhs) const {
return primaryScore < rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore < rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore < rhs.tertiaryScore);
}
bool operator>(const Score& rhs) const {
return primaryScore > rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore > rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore > rhs.tertiaryScore);
}
void SetPrimaryScore(const float score) { primaryScore = score; }
float GetPrimaryScore() const { return primaryScore; }
void SetSecondaryScore(const float score) { secondaryScore = score; }
float GetSecondaryScore() const { return secondaryScore; }
void SetTertiaryScore(const float score) { tertiaryScore = score; }
float GetTertiaryScore() const { return tertiaryScore; }
private:
float primaryScore;
float secondaryScore;
float tertiaryScore;
};
using GameID = uint32_t;
class Leaderboard {
public:
Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries,
LWOOBJID relatedPlayer = LWOOBJID_EMPTY, LeaderboardType = None);
std::vector<LeaderboardEntry> GetEntries();
[[nodiscard]] std::u16string ToString() const;
[[nodiscard]] uint32_t GetGameID() const;
[[nodiscard]] uint32_t GetInfoType() const;
void Send(LWOOBJID targetID) const;
// Enums for leaderboards
enum InfoType : uint32_t {
Top, // Top 11 all time players
MyStanding, // Ranking of the current player
Friends // Ranking between friends
};
enum Type : uint32_t {
ShootingGallery,
Racing,
MonumentRace,
FootRace,
UnusedLeaderboard4, // There is no 4 defined anywhere in the cdclient, but it takes a Score.
Survival,
SurvivalNS,
Donations,
None
};
Leaderboard() = delete;
Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type = None);
~Leaderboard();
/**
* @brief Resets the leaderboard state and frees its allocated memory
*
*/
void Clear();
/**
* Serialize the Leaderboard to a BitStream
*
* Expensive! Leaderboards are very string intensive so be wary of performatnce calling this method.
*/
void Serialize(RakNet::BitStream* bitStream) const;
/**
* Builds the leaderboard from the database based on the associated gameID
*
* @param resultStart The index to start the leaderboard at. Zero indexed.
* @param resultEnd The index to end the leaderboard at. Zero indexed.
*/
void SetupLeaderboard(bool weekly, uint32_t resultStart = 0, uint32_t resultEnd = 10);
/**
* Sends the leaderboard to the client specified by targetID.
*/
void Send(const LWOOBJID targetID) const;
// Helper function to get the columns, ordering and insert format for a leaderboard
static const std::string_view GetOrdering(Type leaderboardType);
private:
std::vector<LeaderboardEntry> entries{};
// Takes the resulting query from a leaderboard lookup and converts it to the LDF we need
// to send it to a client.
void QueryToLdf(std::unique_ptr<sql::ResultSet>& rows);
using LeaderboardEntry = std::vector<LDFBaseData*>;
using LeaderboardEntries = std::vector<LeaderboardEntry>;
LeaderboardEntries entries;
LWOOBJID relatedPlayer;
uint32_t gameID;
uint32_t infoType;
LeaderboardType leaderboardType;
GameID gameID;
InfoType infoType;
Leaderboard::Type leaderboardType;
bool weekly;
};
class LeaderboardManager {
public:
static LeaderboardManager* Instance() {
if (address == nullptr)
address = new LeaderboardManager;
return address;
}
static void SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID,
LWOOBJID playerID = LWOOBJID_EMPTY);
static Leaderboard* GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID = LWOOBJID_EMPTY);
static void SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time);
static LeaderboardType GetLeaderboardType(uint32_t gameID);
private:
static LeaderboardManager* address;
namespace LeaderboardManager {
void SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart = 0, const uint32_t resultEnd = 10);
// Modified 12/12/2021: Existing queries were renamed to be more descriptive.
static const std::string topPlayersScoreQuery;
static const std::string friendsScoreQuery;
static const std::string standingsScoreQuery;
static const std::string topPlayersScoreQueryAsc;
static const std::string friendsScoreQueryAsc;
static const std::string standingsScoreQueryAsc;
void SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0);
// Added 12/12/2021: Queries dictated by time are needed for certain minigames.
static const std::string topPlayersTimeQuery;
static const std::string friendsTimeQuery;
static const std::string standingsTimeQuery;
static const std::string topPlayersTimeQueryAsc;
static const std::string friendsTimeQueryAsc;
static const std::string standingsTimeQueryAsc;
Leaderboard::Type GetLeaderboardType(const GameID gameID);
extern std::map<GameID, Leaderboard::Type> leaderboardCache;
};
#endif //!__LEADERBOARDMANAGER__H__

View File

@@ -62,7 +62,7 @@ void Player::SetSystemAddress(const SystemAddress& value) {
void Player::SetRespawnPos(const NiPoint3 position) {
m_respawnPos = position;
m_Character->SetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID(), position);
m_Character->SetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID(), position);
}
void Player::SetRespawnRot(const NiQuaternion rotation) {
@@ -85,7 +85,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
const auto objid = GetObjectID();
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
auto* entity = EntityManager::Instance()->GetEntity(objid);
auto* entity = Game::entityManager->GetEntity(objid);
if (entity == nullptr) {
return;
@@ -108,7 +108,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift);
EntityManager::Instance()->DestructEntity(entity);
Game::entityManager->DestructEntity(entity);
return;
});
}
@@ -135,13 +135,13 @@ void Player::RemoveLimboConstruction(LWOOBJID objectId) {
void Player::ConstructLimboEntities() {
for (const auto objectId : m_LimboConstructions) {
auto* entity = EntityManager::Instance()->GetEntity(objectId);
auto* entity = Game::entityManager->GetEntity(objectId);
if (entity == nullptr) {
continue;
}
EntityManager::Instance()->ConstructEntity(entity, m_SystemAddress);
Game::entityManager->ConstructEntity(entity, m_SystemAddress);
}
m_LimboConstructions.clear();
@@ -224,7 +224,7 @@ Player* Player::GetPlayer(const SystemAddress& sysAddr) {
}
Player* Player::GetPlayer(const std::string& name) {
const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
for (auto* character : characters) {
if (!character->IsPlayer()) continue;
@@ -269,7 +269,7 @@ Player::~Player() {
continue;
}
auto* entity = EntityManager::Instance()->GetGhostCandidate(id);
auto* entity = Game::entityManager->GetGhostCandidate(id);
if (entity != nullptr) {
entity->SetObservers(entity->GetObservers() - 1);
@@ -285,12 +285,12 @@ Player::~Player() {
}
if (IsPlayer()) {
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity();
Entity* zoneControl = Game::entityManager->GetZoneControlEntity();
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
script->OnPlayerExit(zoneControl, this);
}
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {

View File

@@ -40,11 +40,11 @@ LWOOBJID Trade::GetParticipantB() const {
}
Entity* Trade::GetParticipantAEntity() const {
return EntityManager::Instance()->GetEntity(m_ParticipantA);
return Game::entityManager->GetEntity(m_ParticipantA);
}
Entity* Trade::GetParticipantBEntity() const {
return EntityManager::Instance()->GetEntity(m_ParticipantB);
return Game::entityManager->GetEntity(m_ParticipantB);
}
void Trade::SetCoins(LWOOBJID participant, uint64_t coins) {

View File

@@ -220,7 +220,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
skillComponent->Reset();
}
EntityManager::Instance()->DestroyEntity(chars[i]->GetEntity());
Game::entityManager->DestroyEntity(chars[i]->GetEntity());
chars[i]->SaveXMLToDatabase();

View File

@@ -39,7 +39,7 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitS
auto* behavior = CreateBehavior(behaviorId);
if (EntityManager::Instance()->GetEntity(target) != nullptr) {
if (Game::entityManager->GetEntity(target) != nullptr) {
branch.target = target;
}

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