Compare commits

..

195 Commits

Author SHA1 Message Date
David Markowitz
c7d01dbb82 Merge branch 'main' into add-sqlite 2024-12-04 00:43:43 -08:00
David Markowitz
ec4ec2133b fix: logging uninitialized memory (#1658)
fixes an issue where the console would halt because we printed a control code which did such
2024-12-03 15:01:43 -06:00
David Markowitz
218a3f2d0d Update BaseFootRaceManager.cpp (#1657) 2024-11-27 16:26:10 -06:00
David Markowitz
c37a0c86c1 fix: Old level files not loading (#1656)
* emmo help

* fix parsing live data

---------

Co-authored-by: Aaron Kimbre <aronwk.aaron@gmail.com>
2024-11-26 22:14:07 -06:00
David Markowitz
9e7ef8c4ee fix: Player activated switches (#1655) 2024-11-25 22:55:50 -06:00
David Markowitz
ec501831e6 fix: Remove database requirements for Property Entrance Component and greatly simplify logic (#1650)
* remove complex queries and move logic to dDatabase

remove unused code

Use correct id

fix arrows

use correct parameter

fix queries

Update Property.cpp

remove unused header

remove extra include

* fix tests

* Update dGame/dComponents/PropertyEntranceComponent.h

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>

* Update dGame/User.h

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>

---------

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>
2024-11-23 15:56:31 -06:00
David Markowitz
5b8d2b19a3 fix: stack traces work again (#1653) 2024-11-23 01:33:21 -08:00
17f81d13a3 fix: normalize mixed slashes when looking for files (#1654) 2024-11-23 01:32:31 -08:00
jadebenn
53877a0bc3 refactor: Rewrite AMF and property behavior logic to use smart pointers, references, and string_views over raw pointers and std::string& (#1452)
* Rewrite AMF and behavior logic to use smart pointers, references, and string_views over raw pointers and std::string&

* fix m_BehaviorID initialization

* Fix BlockDefinition member naming

* remove redundant reset()s

* Replace UB forward template declarations with header include

* remove unneeded comment

* remove non-const ref getters

* simplify default behavior id initialization

* Fix invalidated use of Getter to set a value

* Update AddStripMessage.cpp - change push_back to emplace_back

* fix pointer to ref conversion mistake (should not have directly grabbed from the other branch commit)

* deref

* VERY experimental testing of forward declaration of templates - probably will revert

* Revert changes (as expected)

* Update BlockDefinition.h - remove extraneous semicolons

* Update BlockDefinition.h - remove linebreak

* Update Amf3.h member naming scheme

* fix duplicated code

* const iterators

* const pointers

* reviving this branch

* update read switch cases
2024-11-18 20:45:24 -06:00
jadebenn
83f8646936 fix: Cache compiler variables so external tools can recognize the compiler in use (#1649) 2024-11-17 20:55:01 -06:00
Tiernan
d8b86072d4 Fixed Misspelling of Tresure variable for petcomponent (#1617) 2024-11-17 18:48:48 -08:00
David Markowitz
112c2367cc fix: laggy property models (and probably more) (#1646)
* fix laggy property models (and probably more)

global fix correcting the initial physics motion state from 0 to 5 (confirm in client).  packet captures from a few worlds (didnt scan more than 5 files) show that the value for simple physics was either 5, or 4 for property models, or 1 for property models with behaviors.

properties with pre-built models no longer lag and values of physics types should be correct across the board

* will test this briefly
2024-11-17 20:44:35 -06:00
jadebenn
c7dd8205a4 feat: Make use of CMake presets to enable easy switching between debug and release configurations on all platforms (#1439)
* Add MSVC optimization flags

* test moving flags to json

* Update CMakePresets.json

* testing

* trying more variations on the flags

* third test

* testing if these even have any effect

* ditto

* final(?) try for now

* ONE MORE TIME

* trying 'init' flags instead

* export the compile commands so I can see if they're having any effect

* move out g++ O2 flag

* add Linux debug preset

* update CMake presets

* edit macos presets

* try adding build types back to mac

* macos refuses to work :(

* try using compiler flags for mac instead

* fix typo in windows preset

* build reorganization and experimental clang support

* temporarily remove macos build for testing purposes

* updated cmake workflows

* unexclude toolchain dir

* update .gitignore

* fix build directory issue

* edit build script

* update cmake configs

* attempted docker fix

* try zero-initializinng this struct to solve docker issue

* try fixing macos build

* one last MacOS try for the night

* try disabling an apple-specific build rule

* more fiddling with mac test builds

* try and narrow down the macos build failure cause

* try stripping out all the custom macos test logic again

* I'm really just throwing everything to the wall and seeing what sticks

* more macos tinkering

* implib

* try manual link directory specification

* save me

* aaaaaaaaa

* paths paths paths

* Revert "paths paths paths"

This reverts commit 9a7d86aa6c.

* Revert "aaaaaaaaa"

This reverts commit 338279c396.

* Revert "save me"

This reverts commit bd73aa21a9.

* Revert "try manual link directory specification"

This reverts commit 0c2d40632e.

* Revert "implib"

This reverts commit d41349d6ed.

* Revert "more macos tinkering"

This reverts commit 829ec35b57.

* Revert "I'm really just throwing everything to the wall and seeing what sticks"

This reverts commit 1a05b027fe.

* Revert "try stripping out all the custom macos test logic again"

This reverts commit cc15a26ce8.

* Revert "try and narrow down the macos build failure cause"

This reverts commit 5fd86833fa.

* Revert "more fiddling with mac test builds"

This reverts commit 0f843c02c9.

* Revert "try disabling an apple-specific build rule"

This reverts commit 45ec66e976.

* back to debug messages

* see if this re-breaks mac

* are these messages actually somehow fixing the issue?

* was not actually fixed

* add debug messages (again)

* debug try 2

* change runtime output dir

* rename gcc to gnu

* expand cmake presets

* fix preset

* change defaults

* altered cmake configuration scripts

* disable /WX on MSVC

* update github actions

* update build presets

* change gnu and clang build directories to enable consistent artifact generation

* add RelWithDebInfo presets and move -Werror flag into presets.json

* use DLU_CONFIG_DIR envvar

* CMakePresets indentation

* temp fix for MSVC debug builds
2024-11-17 19:03:54 -06:00
jadebenn
652f42ccf2 press the enter key once (#1648) 2024-11-17 19:03:09 -06:00
Wincent Holm
fedd039e00 Proposal for observers and deferred implementations (#1599) 2024-11-17 18:46:08 -06:00
jadebenn
84d7c65717 consolidate the messagetype enums into a single namespace (#1647) 2024-11-17 18:39:44 -06:00
David Markowitz
adc9cd2876 feat: Add some save data tests (#1623)
* saving from a test works

* testing works

* Update SavingTests.cpp

* test dServer stuff

* tests

* use dummy database and add missing pure fns

* add more tests

* add more tests

* add rocket tests

* Update BuffComponent.h

* Update test_xml_data.xml

* Update SavingTests.cpp

* update
2024-11-17 16:27:33 -08:00
David Markowitz
008e2d4dce add error reporting for failed charxml (#1642) 2024-11-17 18:17:29 -06:00
David Markowitz
677e7c1097 fix: remove ninjago missions items for completed missions (#1643)
* fix: ninjago missions remove items

fixes an issue where this mission was completed prior to a bug fix, causing the items to remain in the inventory.

Tested that players with the mission completed have the item correctly removed from their inventory.

* Update eCharacterVersion.h
2024-11-17 18:08:36 -06:00
David Markowitz
628ac9807e fix crash (#1644)
tested that sending an empty packet with this messageID no longer crashes the chat server
2024-11-17 18:07:40 -06:00
David Markowitz
9e242995e9 use SQLite types 2024-11-15 01:05:05 -08:00
David Markowitz
0aa1f70540 Use less specific matcher 2024-11-14 12:43:52 -08:00
David Markowitz
de3fe93100 Update WorldServer.cpp (#1645) 2024-11-03 08:17:00 -06:00
David Markowitz
af943278fb Use macros so we can use more properties (#1640)
makes it so we can adjust many more settings since the segfault only happens in windows debug, why remove the functionality for all users?
Tested that windows debug, windows RelWithDebInfo and ubuntu default all build and run without issues (will contact luxaritas about pipe testing)
2024-10-30 09:45:40 -05:00
Gie "Max" Vanommeslaeghe
bfe6900c26 Merge pull request #1639 from DarkflameUniverse/FixPetCrash
fix: nullptr crashes in PetComponent AddDrainImaginationTimer and Deactivate
2024-10-27 22:23:49 +01:00
David Markowitz
0d218fc5c7 fix: PetComponent crashing due to nullptr access
Resolves an issue where item is null but is accessed but not doing that code and instead consulting the EntityManager for a valid Entity, alongside nullifying the m_Owner objectID should the pet be destroyed and timer still exist.

Update PetComponent.cpp

Add nullptr check

Add back timer

Update PetComponent.cpp

speculative fix for a different crash

Why are we accessing something before checking if its null
2024-10-26 21:44:19 -07:00
David Markowitz
102e3556cf feat: add millisecond tracking for racing (#1615)
* add millisecond tracking

Update RacingControlComponent.cpp

* remove const ig?

* is this what you wanted
2024-10-26 22:59:50 -05:00
David Markowitz
33a8efdd22 fix slow code, add bounds checks (#1606)
Tested that players with valid names up to the usual 33 character max are still added to the player container
Tested that you can still team with <= 4 players on a team
Tested that chat server no longer crashes with a bad memberSize variable
asserted that InsertPlayer is indeed much faster now and is no longer a slow point of ChatServer
2024-10-26 22:09:32 -05:00
David Markowitz
8d54db7851 Update WorldServer.cpp (#1633) 2024-09-13 09:45:55 -07:00
David Markowitz
6213aed8e5 fix ag navmesh near burtton (#1626)
tested that pets now correctly try to activate the button instead of standing idly by.
2024-09-13 09:45:46 -07:00
wincent
d57c5101f4 Amend preconditions fix 2024-09-12 15:33:09 +02:00
wincent
6be65569de Fixed mission related preconditions 2024-09-10 12:41:38 +02:00
David Markowitz
94b9731a2b Use the correct bit field for checking whether or not to decrement progress (#1631)
Tested that the cooking mission with johnny umami now no longer allows you to lose progress by deleting items.
2024-08-11 10:26:25 -07:00
David Markowitz
aaf446fe6e feat: Add Inventory Brick and Model groups (#1587)
* Added feature grouping logic

* Add saving of brick buckets

* Add edge case check for max group count

* Use vector for storing groups

* Update InventoryComponent.cpp

* Update InventoryComponent.h

* Update InventoryComponent.h

* fix string log format

* Update GameMessages.cpp
2024-08-01 23:38:21 -07:00
Gie "Max" Vanommeslaeghe
2c70f1503c Merge pull request #1616 from DarkflameUniverse/behavior
fix: add larger behavior fields for saving
2024-07-17 22:24:52 +02:00
Gie "Max" Vanommeslaeghe
49b4748ed3 Merge pull request #1614 from DarkflameUniverse/tea
fix: move mission progression location for racing
2024-07-17 22:24:17 +02:00
Gie "Max" Vanommeslaeghe
ffeb0108d0 Merge pull request #1619 from DarkflameUniverse/shield
fix: echo skill cast down to client for some server skills
2024-07-17 22:23:21 +02:00
David Markowitz
c3f6ef5a1d feat: add admin account creation options from cli (GM level) (#1620)
* add admin account creation options from cli

* use actual gm levels

felt under delivered in previous iteration.

* Update dMasterServer/MasterServer.cpp

Co-authored-by: Daniel Seiler <me@xiphoseer.de>

---------

Co-authored-by: Daniel Seiler <me@xiphoseer.de>
2024-07-03 15:37:19 -07:00
David Markowitz
999995b2fb Merge branch 'main' into shield 2024-07-02 03:14:32 -07:00
Gie "Max" Vanommeslaeghe
84fff7c380 Merge pull request #1621 from DarkflameUniverse/EmosewaMC-patch-10
fix: compiler issue on newer gcc versions
2024-07-02 12:12:30 +02:00
David Markowitz
59c4b35479 Update Preconditions.cpp 2024-07-02 01:55:42 -07:00
David Markowitz
f2d72e7ed5 Update Preconditions.cpp 2024-06-25 21:02:40 -07:00
David Markowitz
b648b43c4d ?? 2024-06-25 20:52:46 -07:00
David Markowitz
2628470482 set shield to false, add sync for done 2024-06-18 14:24:03 -07:00
David Markowitz
f82a82f254 Create 16_big_behaviors.sql 2024-06-17 19:41:27 -07:00
Gie "Max" Vanommeslaeghe
9400ee1dc0 Merge pull request #1586 from DarkflameUniverse/property_behavior_saving
feat: Property Behavior Saving
2024-06-16 12:31:21 +02:00
David Markowitz
54b8c25754 Merge branch 'main' into tea 2024-06-12 19:20:44 -07:00
David Markowitz
b984cd6a0b Merge branch 'main' into property_behavior_saving 2024-06-12 19:17:39 -07:00
Gie "Max" Vanommeslaeghe
bcf1058759 Merge pull request #1595 from DarkflameUniverse/issue-462
fix: prevent moving items between inventories under cetain circumsances
2024-06-11 20:48:09 +02:00
David Markowitz
6ad6e930c7 move mission progression
done now as soon as you cross the finish line on the last lap instead of after you click "rewards"
2024-06-11 02:29:25 -07:00
David Markowitz
fee0238e79 fix: master not using table data, remove 2 noisy logs (#1613)
Tested with logs that queries to get soft and hard cap actually succeed now
Logs about slash command handler command registration and vanity NPC creation in mis matched worlds are now removed.
2024-06-09 15:31:57 -07:00
Wincent Holm
1454fcd003 Fix g++ 14 (#1610)
* Fix g++ 14

* Update thirdparty/CMakeLists.txt

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

---------

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2024-06-06 04:00:44 -05:00
Gie "Max" Vanommeslaeghe
af651f0d63 Merge pull request #1608 from DarkflameUniverse/feat--spectate-command
feat: spectate command
2024-06-04 09:17:18 +02:00
ff38503597 no feedback if empty 2024-06-03 22:51:46 -05:00
3f22bf5cc0 Add an easy way to stop spectating 2024-06-03 22:44:54 -05:00
9d5d2a68ee fix gm serialization 2024-06-03 22:30:57 -05:00
1a14c29c39 add returns, lol 2024-06-03 22:29:21 -05:00
2ef45bd7ee use empty 2024-06-03 22:28:37 -05:00
b56d077892 feat: spectate command 2024-06-03 21:50:12 -05:00
David Markowitz
a54600b41e busting out the multimap ig (#1602) 2024-05-31 13:46:18 -05:00
David Markowitz
342da927f5 fix dimantling items from not the model inventory (#1605) 2024-05-30 23:53:13 -05:00
David Markowitz
01086d05c8 fix: use after free and uninitialized memory (#1603)
* fix use after free and uninitialized memory

* add if check for packet lengths

* move purge down further

Its used in the if check too...
2024-05-30 23:53:03 -05:00
Remco Hofman
cce5755366 Fix Dockerfile vanity COPY (#1604)
Corrected an unintended mistake in the COPY commands for adding the
vanity files to the Docker container, causing only the last file
contents to be added to the file '/app/vanity/*'
2024-05-27 17:46:09 -07:00
TAHuntling
e966d3a644 Chore: split VE script up (#1598)
* Testing Scripts

Testing splitting AgSpaceStuff into AgSpaceStuff and AgShipShake

* fixed inclusions

* Removed DoShake

* cleaning up

* consistent if statements

* Update dScripts/ai/AG/AgShipShake.h

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

---------

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2024-05-27 01:24:48 -05:00
Gie "Max" Vanommeslaeghe
9328021339 Merge pull request #1600 from DarkflameUniverse/add-missing-scripts
fix: add back missing scripts from scripts refactor
2024-05-26 12:02:12 +02:00
Gie "Max" Vanommeslaeghe
d1134fdd62 Merge pull request #1601 from DarkflameUniverse/fix-using-skill-in-race
fix: players using non-car skills in a race
2024-05-26 12:01:54 +02:00
David Markowitz
efa658bc31 fix players using non-car skills in a race 2024-05-25 19:59:15 -07:00
David Markowitz
e59525d2ae Update CppScripts.cpp 2024-05-25 19:32:18 -07:00
David Markowitz
0348db72a5 fiux mission (#1596) 2024-05-25 12:24:02 -05:00
TAHuntling
debc2a96e2 Update CppScripts exclusion list (#1597) 2024-05-25 01:43:32 -07:00
86f335d64b fix type 2024-05-24 21:43:54 -05:00
8ca05241f2 fix: prevent moving items between inventories under cetain circumsances 2024-05-24 21:35:14 -05:00
David Markowitz
8ae1a8ff7c fix stale reference (#1594) 2024-05-24 09:15:30 -05:00
David Markowitz
f0960d48b2 Add more modular saving of config data for items (#1591)
* stubbing for saving item extra data

* add declaration to header

* modularize loading for all possible extra data

* move logic to Item

* remove extra map
2024-05-22 17:06:52 -07:00
David Markowitz
dc430d9758 Add reputation as a repeatable mission reward (#1590)
This reverts commit 7d1a28b492b263aba2008a5984dc0f5e7348a068.

Add stubbing for abbreviations

Reward reputation always if possible
2024-05-22 16:35:45 -07:00
TAHuntling
dea10c6d56 Client commands implementation (#1592)
* Adding Client Commands

Adding list of client commands provided to me by EmosewaMC

* Finished adding client commands
2024-05-22 08:32:24 -05:00
TAHuntling
ed00551982 feat: Help Command Pagination (#1581)
* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Fixed Comments

Now able to do /command help to see info for said command. Additionally this works for aliases. Fixed serialization missing from merge.

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp
2024-05-21 20:02:07 -05:00
TAHuntling
d6cac65a8d fix: Falling Off Edge in Pet Puzzle (#1584)
* FloatFix

* game activity setting

* Update dNavMesh.cpp

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
2024-05-21 20:01:44 -05:00
David Markowitz
d8f079cb1b fix mpc resetting on each world load (#1588) 2024-05-20 02:43:57 -05:00
David Markowitz
db2d4f02b5 preemptive include for windows 2024-05-18 04:16:07 -07:00
David Markowitz
00f36f3f28 missing include for windows 2024-05-18 04:15:07 -07:00
David Markowitz
a50b256689 Update IBehaviors.h 2024-05-18 03:54:09 -07:00
David Markowitz
b3548de7da debug logs and spacing 2024-05-18 03:52:36 -07:00
David Markowitz
387c37505c undo debug changes 2024-05-18 03:39:25 -07:00
David Markowitz
0c4108e730 Add loading from database
yahoo
2024-05-18 03:36:29 -07:00
David Markowitz
fd1c6ab2ea Saving actually works this time 2024-05-18 02:12:23 -07:00
David Markowitz
f2bf9a2a28 Saving to database working 2024-05-18 02:05:55 -07:00
TAHuntling
c8e0bb0db0 feat: Command Sorting (#1580)
* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update SlashCommandHandler.cpp

* Update dGame/dUtilities/SlashCommandHandler.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

---------

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2024-05-16 22:02:30 -07:00
David Markowitz
d9d262d3f1 prevent building in a folder which contains spaces (#1583) 2024-05-16 08:05:57 -05:00
TAHuntling
d0a5678290 chore: CppScripts refactor (#1579)
* Updating CppScripts

Rewrote file to use a lambda map rather than the massive if else chain. Kept the original comments alongside each of the different scripts they were by before.

* add script tests

* Update names

* More Changes to Scripts

* Update CppScripts.cpp

* Removing Unneeded Files

* Update CppScripts.cpp

* Delete tests/dGameTests/dScriptsTests/CMakeLists.txt

* Delete tests/dGameTests/dScriptsTests/dScriptsTests.cpp

* Delete tests/dGameTests/dScriptsTests/CppScriptsOld.cpp

* Delete tests/dGameTests/dScriptsTests/CppScriptsOld.h

* Update CMakeLists.txt

* finishing up

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
2024-05-16 04:50:18 -05:00
David Markowitz
35321b22d9 script fixes (#1577)
fixes an issue where the sirens would not be destroyed correctly
fixes undefined behavior in buff station

ok for real this time

actual fix for mermaids

and for general death_behavior 0 skill stuff
2024-05-16 04:30:32 -05:00
David Markowitz
8837b110ab add include guards (#1569) 2024-05-16 04:30:00 -05:00
David Markowitz
09a8c99f3e fix: mail crash from underflow and document variables (#1582)
* fix mail crash and document variables

* const
2024-05-16 04:29:48 -05:00
Terrev
e3b108e00e fv race place atm (#1570) 2024-05-13 06:18:27 -05:00
David Markowitz
9f382aca42 fix: use after free in mission progression after removing item from inventory (#1567)
that method is cursed.

no longer has ub when deleting an item from the inventory
2024-05-12 07:30:03 -05:00
David Markowitz
4d1395e522 Update CheatDetection.cpp (#1559) 2024-05-10 16:20:42 -05:00
9e36510c6b chore: Bump verion to 2.3.0 (#1564)
fix versions.txt, update cmake version
2024-05-10 15:21:10 -05:00
David Markowitz
2ca61c3e57 feat: Dragonmaw (#1562)
* rigid as heck

* abstract physics creation to separate function

* loading

Update FvRacePillarDServer.cpp

consolidate abcd pillar logic

modularization

Update SimplePhysicsComponent.cpp

Update EntityManager.cpp

Update MovingPlatformComponent.cpp

still need another pass

* geiser works

* columns working finally

* consolidate logic

* constiness

* Update PhantomPhysicsComponent.cpp

* Update PhysicsComponent.cpp

* revert testing code

* add versions info

---------

Co-authored-by: Aaron Kimbre <aronwk.aaron@gmail.com>
2024-05-10 09:22:26 -05:00
07cb19cc30 chore: remove json (#1561)
we can't use it currently due to threadsafety issues, so just going to remove it until we actually need it and will re-add it as a vendored file later due to cmake issues pulling in things
2024-05-02 06:35:55 -05:00
David Markowitz
794b254fe7 remove md5 new (#1560)
tested that sqlite hash is still calculated
2024-05-02 06:35:44 -05:00
Gie "Max" Vanommeslaeghe
ab7f6f0b57 Merge pull request #1558 from DarkflameUniverse/swap-update-order
fix: out of order physics updates
2024-05-01 22:33:45 +02:00
David Markowitz
58cc569c75 fix out of order physics updates
fixes an issue where physics entities were not given a chance to be marked as sleeping, causing a initial sleeping calls to be missed and causing objects that collided with one another to not register new collisions since they were sleeping at the time the new collision fired off.

Tested that Brick Fury now corectly aggros the _first_ spawn of enemies near by to him.
Tested that the turrets in crux prime now correctly shoot the _first_ wave of enemies that spawn.
2024-04-30 23:09:35 -07:00
Daniel Seiler
35c463656d Use volume for mariadb persistence (#1555)
I initially used the bind mount because it's arguably easier to back up and move around than a volume, but turns out with https://github.com/DarkflameUniverse/NexusDashboard/issues/92 it's nothing we can recommend for Docker Desktop on WSL, which unfortunately is the primary setup newcomers will try this with. So changing the default to be a volume should address that (presumably by hosting the volume within the WSL Docker VM, as opposed to the host NTFS filesystem)
2024-04-29 22:51:13 +02:00
3801a97722 feat: add nlohmann/json lib (#1552)
* feat: add nlohmann/json lib

* remove build test off
2024-04-24 21:35:45 -05:00
jadebenn
0367c67c85 chore: move the pet minigame table loading logic out of petcomponent (#1551)
* move the pet minigame table loading logic out of petcomponent

* misc fixes

* actually, using paths is dumb here when they're already char strings. why bother? silly me.

* removed unga bunga reference-casting

* add back in puzzle not found error message

* pre-allocate unordered map and make getter const-correct

* Update dDatabase/CDClientDatabase/CDClientTables/CDTamingBuildPuzzleTable.cpp

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>

---------

Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2024-04-24 10:09:15 -05:00
jadebenn
8fdc212cda chore: Convert heap allocation to optional (#1553)
* chore: Convert heap allocation to optional

* Update dGame/dComponents/PetComponent.h

Default-initialize
2024-04-24 10:09:04 -05:00
99e7349f6c feat: slashcommands for showall, findplayer, get/openhttpmoninfo, and debug world packet (#1545)
* feat: showall, findplayer, get/openhttpmoninfo

http monitor info is planned to be used later, just putting in info that i've since reverse engineered and don't want lost

Additionally add debug world packet for duture dev use

Tested all new commands and variation of command arguments

* fix missing newline at eofs

* address most feedback

* Compormise and use struct with (de)serialize

* remove httpmoninfo commands
2024-04-17 21:47:28 -05:00
jadebenn
fafe2aefad chore: Nitpicking-utils (#1549)
* nit

* GeneralUtils const-correctness and minor fixes

* use copy instead of reference for char iteration loops

* fix typo and reorganize some functions
2024-04-14 23:14:54 -07:00
David Markowitz
5049f215ba chore: Use string to access SQLite columns (#1535)
* use string to access field name

* Update DEVGMCommands.cpp

* corrected column name

* constexpr array

include <array>

Revert "constexpr array"

This reverts commit 1492e8b1773ed5fbbe767c74466ca263178ecdd4.

Revert "include <array>"

This reverts commit 2b7a67e89ad673d420f496be97f9bc51fd2d5e59.

include <array>

constexpr array

---------

Co-authored-by: jadebenn <jonahbenn@yahoo.com>
2024-04-13 23:41:51 -05:00
David Markowitz
3a6123fe36 fix console sound (#1547) 2024-04-11 10:29:49 -05:00
David Markowitz
b8b2b687e2 inherit exception for CppSQLite3Exception (#1544)
catch any exception just in case exception isnt inherited from
2024-04-10 07:32:54 -05:00
d067a8d12f chore: split out slash commands into multiple files (#1539)
* chore: split out slash commands into multiple files
Breakup the monolithic file
don't register slashcommands on startup

* fix typo
2024-04-09 20:15:51 -05:00
David Markowitz
1ee45639af Update GeneralUtils.h (#1541) 2024-04-09 00:20:25 -05:00
jadebenn
db192d2cde chore: Fix use of uninitialized variable in RemoveItemFromInventory (#1540) 2024-04-08 21:50:41 -07:00
David Markowitz
28ce8ac54d remove usage of xmldoc as a ptr (#1538)
resolves a memory leak in BrickDatabase, adds stability to character save doc.

Tested that saving manually via force-save, logout and /crash all saved my position and my removed banana as expected.
The doc was always deleted on character destruction and on any updates, so this is just a semantic change (and now we no longer have new'd tinyxml2::documents on the heap)
2024-04-08 15:13:49 -05:00
David Markowitz
be0a2f6f14 fix jittering (#1537) 2024-04-08 15:13:31 -05:00
David Markowitz
3260a063cb ignore whitespace in try parse (#1536) 2024-04-08 15:13:19 -05:00
feeac2e041 feat: refactor slash commands system into more scalable system (#1510)
* WIP, but working

* Scaffolding

* testing and making it compile again

* move all commands to functions

* renaming to compile

* fix failing tests

idk how these werent failing before.  Seems to have been magic.

* move commandss into their namespace
make help command useful
fix mac error

TODO: remove the multiple not founds/ rework the structure to split into help and handling

* Just need to fill out the fields, but it's all there templated

* Add all aliases, register missing commands

* All help text

* remove test logs

* improvements

pass through added code for optimizations and cleanup as well as reduce the amount of scoping for readability and maintainability

* Update SlashCommandHandler.cpp

* only save command if it is a GM command

* simplify if checks

* remove broken delimiter

* Update SlashCommandHandler.cpp

* Update SlashCommandHandler.cpp

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
2024-04-08 15:11:59 -05:00
jadebenn
18c27b14c8 disable non conforming volatile behavior on MSVC (#1534) 2024-04-05 12:56:23 -05:00
jadebenn
bcfaa6c7fe const return oversight (#1532) 2024-04-05 01:14:52 -07:00
jadebenn
06e7d57e0d chore: Remove dpEntity pointers from collision checking (#1529)
* chore: Remove dpEntity pointers from collision checking

* Update fn documentation in ProximityMonitorComponent.h

* use more idiomatic method to calculate vector index

* feedback

* missed a ranges::find replacement

* adjust for feedback. last changes tonight.

* okay, also remove unneeded include. then sleep.

* for real tho

* update to use unordered_set instead of set
2024-04-05 00:52:26 -05:00
David Markowitz
b340d7c8f9 replace white and blacklist (#1530) 2024-04-05 00:51:40 -05:00
David Markowitz
24de0e5fdb Update GeneralUtils.cpp (#1528)
same check as the header
2024-04-03 19:06:29 -05:00
20408d8dfe chore: remove chat_internal and processes everything over chat connection (#1508)
* WIP

* get rid of redundent case and some formatting issues

* move some things around for cleaner diffs

* remove dead code that does nothing and add connection check

* fix whitespace

* address feedback
2024-03-31 22:27:50 -05:00
David Markowitz
c1c5db6593 update4 fp check (#1524) 2024-03-31 21:46:51 -05:00
David Markowitz
884a41f36a update to current knowledge (#1523)
Should be 100% live accurate as far as logic and bitstream reads goes.

Tested with all valiant weapons and crux prime weapons (drops from dragons) that combat does not desync and that the client reports the same level and amount of skill deserialize issues as before.
2024-03-30 11:16:06 -05:00
David Markowitz
bbc0908989 Update 9_Update_Leaderboard_Storage.sql (#1520) 2024-03-30 08:18:03 -05:00
David Markowitz
5996f3cbf4 fix stewblaster stopping for non-players (#1521)
fixes an issue when stew blaster would stop for non-players and would stand still permanently due to enemy hitboxes being removed.  Tested that stewblaster only stops for players and starts moving when there are no players in the vicinity
2024-03-30 08:17:56 -05:00
jadebenn
150031861d Update README.md (#1518) 2024-03-28 21:32:46 -05:00
jadebenn
9d8e0a9c4a unbreak the stacktraces (#1516) 2024-03-27 06:10:39 +01:00
David Markowitz
bd9b790e1d feat: Add MovingAI pathing for NPCs without combatAI (#1509)
* remove goto

* Update MovementAIComponent.cpp

* convert to PathWaypoint

Easier for usage with paths

* add path parsing

* ref removal, simplification of work

* it works

* Update MovementAIComponent.cpp

* disable pathing for combat

we just need it for npcs for now, combat ai can be done later

* fixed stuttery enemies

wow

* start at ramped up speed

* add pausing and resuming

* Update MovementAIComponent.cpp

* Update MovementAIComponent.h

* Update CMakeLists.txt
2024-03-26 21:06:22 -05:00
David Markowitz
39b81b6263 rename and shorted BehaviorTemplate enum (#1512)
just a renaming of the enum and the value names and deletion of the empty cpp file.  Code compiles still.
2024-03-26 06:35:35 -05:00
David Markowitz
1e09ec92e3 Update PlayerContainer.cpp (#1513)
Prevents a bad actor from possibly spamming the server with sequential IDs and allocating a bunch of memory.

Tested that I can still send and receive friend requests
2024-03-26 06:20:45 -05:00
David Markowitz
2b253a8248 fix: movement ai remove goto, do todo, remove unused call (#1505)
* remove goto

* Update MovementAIComponent.cpp
2024-03-24 22:24:38 -05:00
David Markowitz
3262bc3a86 chore: Remove news in Behavior members (#1504)
* Remove news in behavior members

Tested that GrowingFlowers still have their SkillEvent fired with the correct parameters, gftikitorch works, sharks eating stinky fish still work

* explicitly default move assignment and copy operators/constructors

---------

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>
2024-03-24 21:43:01 -05:00
David Markowitz
3a4e554da9 update switch behavior (#1503)
was using very old code from pre-foss that has not been updated with the new behavior knowledge.  The code has been updated accordingly to what the client expects.

Tested that ice shurikens can now destroy the legs of the skeleton towers in crux prime.  Tested that the following weapons can still do damage to enemies and objects in the world:
surikens of ice
serratorizer
Super Morning Star
Super Dagger
elite long barrel blaster (charge and normal)
Mosaic Wand
2024-03-24 14:01:12 -05:00
jadebenn
35ce8771e5 chore: supress warnings on external library headers and actually get rid of the last old-style casts (#1502)
* chore: supress warnings on external library headers and actually get rid of the last old-style casts

* remove commented out section I forgot

* update cmake required version to 3.25 unless we can find another way to do this

* update readme

* Update CMakeLists.txt
2024-03-17 20:48:09 -05:00
David Markowitz
b9092a3cce update serialization, remove unused variable (#1501)
Tested that players show up as normal on each others screens, tested that money magnet still works with item 8600, tested that gravity still works in Moon Base.
2024-03-10 01:15:43 -06:00
David Markowitz
0b4f70a76b Update StoryBoxInteractServer.cpp (#1500)
Update StoryBoxInteractServer.cpp
2024-03-08 19:29:40 -06:00
David Markowitz
4bc4624bc9 feat: add further MovementAI skeleton (#1499)
* add movement ai skeleton

Zone loading code is tested to load and read the correct values using logs.  other ldf data is unaffected as I walked around crux and dragons/apes can still spawn and be killed.

* format
2024-03-08 19:29:01 -06:00
jadebenn
3a6313a3ba chore: Table Loading Improvements (#1492)
* Assorted pet improvements

* remove unecessary include

* updates to address some feedback

* fixed database code for testing

* messinng around with tables

* updated to address feedback

* fix world hang

* Remove at() in CDLootTableTable.cpp

* Uncapitalize LOT variable

* Uncapitalize LOT variable
2024-03-06 23:45:24 -06:00
jadebenn
6e3b5acede chore: Less verbose name for enum underlying type casts (#1494)
* Less verbose name for enum underlying type casts

* Remove redundant call
2024-03-06 23:45:04 -06:00
David Markowitz
fe4b29f643 fix: commendation vendor cant accept missions (#1497)
* fix: incorrect serialization for commendation

* Update VendorComponent.h
2024-03-06 19:50:21 -06:00
David Markowitz
fcb89b3c7a Remove multiple Script syntax (#1496) 2024-03-06 19:49:29 -06:00
David Markowitz
1a0aaf3123 add info to debug logs (#1495) 2024-03-06 19:46:16 -06:00
jadebenn
9a26ba0a72 feat: Provide SerializeEntity constant reference overload (#1491) 2024-03-06 19:23:24 -06:00
jadebenn
6c9c826e19 chore: Set default symbol visibility to hidden in CMAKE (#1490)
* set default symbol visibility to hidden in CMAKE

* Update CMakeLists.txt with additional comments

* whoops, wrong comment type
2024-03-06 07:49:40 -06:00
Daniel Seiler
554a9a6806 fix: Dissolve more CMake dependencies (#1387)
* fix: more include changes

* fix: remove dZoneManager from global include

* fix: dDatabase

* fix: dCommon

* fix: object libs

* fix: rebase

* fix: bcrypt

* wip: try simplified connector build

* fix: update dockerfile

* fix: mariadb C/C++ on apple

* feat: Move scripts to CMAKE_MODULE_PATH

* fix: dPropertyBehaviors

* fix: macos?

* fix: Dockerfile

* fix: macos?

* fix: macos?

* fix: macos?

* fix: macos?

* fix: macos?

* try: install_name_tool

* fix not building on unix

* fix include paths

* Remove code changes

Will fix in another PR.

* format pass

remove 2 more included directories.
remove commented out code
add status to messages

* comments and format

surround include directories with quotes
remove commented out code
remove debug messages

* Update CMakeLists.txt

---------

Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
Co-authored-by: David Markowitz <39972741+EmosewaMC@users.noreply.github.com>
2024-03-05 20:13:24 -06:00
c4c1e93dc8 fix: plaques would crash when interacting with no data provided (#1486)
Also docs
2024-03-04 06:00:34 -06:00
David Markowitz
15504e693b fix include paths (#1488) 2024-03-03 19:06:19 -06:00
Gie "Max" Vanommeslaeghe
7d626dc31b Merge pull request #1487 from DarkflameUniverse/voidptr
fix: remove void*
2024-03-02 09:26:31 +01:00
David Markowitz
6df6e3e313 remove void* 2024-03-02 00:25:16 -08:00
jadebenn
4ffdf851c6 Delete unused cpp file (#1485) 2024-03-01 23:32:05 -06:00
43707952d2 feat: move all ldf config to be in xml (#1482)
* feat: move all ldf config to be in xml
cleanup dev-tribute.xml
add comments to atm.xml
remove custom script tag in favor of ldfconfig for it

* replace sto* calls with tryParse's

* remove unesessary .has_value() calls and check for null_lot

* remove member variable naming that on on-member vars

* move max's vendor inventory to be configurable via vanity

* Consolidate triplecated vendor code

* don't write name if one is not given

* Updates to vanity xml's and demo for later docs

* rename vars
2024-02-28 17:16:47 -06:00
David Markowitz
ef3fdba621 fix: FrameStats serialization (#1481)
* fix serialization

Was incorrect before.  The only flags are if any data in the FrameStats has changed, you write them again.  Velocities also do not use dirty flags for their values, they use a flag to determine if their velocity if zero or non-zero.  if any velocity changes, re-write FrameStats.

Tested that 2 players can see each other move as before, enemies move as before and players racing is identical as before.

* Update HavokVehiclePhysicsComponent.cpp
2024-02-27 23:40:26 -06:00
398426545c fix: default chat to the correct port when no option is given (#1484) 2024-02-27 15:56:58 -06:00
David Markowitz
366a80ffd2 comments from movementAI branch (#1483)
tests

tested that red green and yellow bots waved when interacted with
tested that construction robot races when interacted with
wandering vendor does nothing before and after, but script is ready for use when npcs are implemented.

add scripts for robot city
2024-02-27 10:07:14 -06:00
David Markowitz
c9a8be4fb9 Remove extra speed class (#1480)
Speed is used in more waypoints than not so we may as well reduce repeated references.

tested that the data is still loaded as normal in avant gardens

Update Zone.cpp
2024-02-27 08:40:49 -06:00
jadebenn
424d54b98c squash commits (#1479) 2024-02-27 01:29:51 -06:00
jadebenn
b261e63233 chore: Change entity and component logic to use bitstream references (#1468)
* chore: Change entity and component logic to use bitstream references

* merge
2024-02-27 01:25:44 -06:00
jadebenn
75544e3eec chore: Change dServer and related code to use BitStream references (#1476) 2024-02-26 23:43:33 -06:00
jadebenn
9e0dd05d42 chore: Convert LeaderboardManager to use BitStream refs (#1469) 2024-02-26 23:25:45 -06:00
jadebenn
27d20dd8fa Convert AMFSerialize to use bitstream references (#1466) 2024-02-26 23:11:56 -06:00
jadebenn
4b0079c817 chore: Convert DoClientProjectileImpact to use bitstream refs (#1471) 2024-02-26 22:16:19 -06:00
jadebenn
30b9ef8ab2 chore: Change Mail to use BitStream references (#1474) 2024-02-26 22:01:18 -06:00
jadebenn
7235423c7b Convert game message bit stream raw pointers to references (#1465) 2024-02-26 08:17:22 -06:00
jadebenn
94a467b361 chore: Change LDFFormat to use BitStream references (#1467) 2024-02-26 08:15:29 -06:00
jadebenn
c3743877df chore: Change EchoStartSkill to use BitStream reference (#1472) 2024-02-26 08:09:45 -06:00
jadebenn
ab937055e7 chore: Convert EchoSyncSkill to use BitStream references (#1473) 2024-02-26 08:08:56 -06:00
jadebenn
5c1ed332c4 chore: Change AuthServer to use BitStream references (#1475) 2024-02-26 08:06:02 -06:00
jadebenn
95d687846a chore: Remove unnecessary heap allocations (#1478) 2024-02-25 19:35:07 -06:00
192c8cf974 feat: refactor vanity (#1477)
* feat: refactor vanity
cleanup code to be generalized for objects
remove unused party feature
add fallback to data to text
Allow for better organizing data in multiple files
remove special case flag values in favor of config data
general cleanup and fixes

* newline at eof's
2024-02-25 16:59:10 -06:00
David Markowitz
cf706d4974 Remove ag special case patch (#1462)
Tested that revision was never the poison value in any lvl file when starting zone 1100.
2024-02-25 13:56:01 +00:00
e729c7f846 feat: achievement vendor and vendor feedback (#1461)
* Groundwork

* movie buying logic out of gm handler
make transaction result more useful

* Full implementation
Cleanup and fix some calls in gamemessages

* Load the component in the entity
Patch Auth

* new line at eof

* cache lookups

* remove sort

* fix includes
2024-02-25 01:47:05 -06:00
David Markowitz
1328850a8d buffRemoval (#1464)
Update BuffComponent.cpp
2024-02-25 01:01:28 -06:00
jadebenn
721ea78bb4 Update Amf3.h member naming scheme (#1463) 2024-02-24 23:03:59 -06:00
jadebenn
5ae8fd8e0e chore: Remove anonymous namespace from GeneralUtils.h (#1460)
* remove anonymous namespace from GeneralUtils.h

* Put helper functions in nested details namespace to hide from hinting

* rename implementation functions to use lower case, leading underscore and move definitions to source file
2024-02-24 04:30:02 -06:00
David Markowitz
f38537aece fix: incorrectly inverted statement (#1459)
if we DONT find it, we want to kill/delete it.  not the other way around where if we find it we try to delete it again.

tested that you no longer crash when trying to login
tested that bird monument issues are fixed
2024-02-20 05:51:02 -06:00
jadebenn
b6af92ef81 refactor: Rewrite BehaviorMessage classes to use member initialization, preferred member naming conventions, and const-ref getters (#1456)
* Split out BehaviorMessage class changes from PR #1452

* remove <string_view> inclusion in ActionContext.h

* add the arguments nullptr check back in

* remove redundant std::string constructor calls

* Update AddStripMessage.cpp - change push_back to emplace_back
2024-02-18 00:38:26 -06:00
David Markowitz
c7b3d9e817 close trade window (#1457) 2024-02-11 21:00:39 -06:00
David Markowitz
c3fbc87f9e remove copy pasted logic (#1446)
tested that the ninjago platforms and fire still works, tested that point of interest work as well

Update PhantomPhysicsComponent.cpp
2024-02-11 14:36:15 -06:00
David Markowitz
dfb2fd93b4 chore: use ranges in EntityManager and touch up (#1451)
* EntityManager: ranges and cleanup

Use LWOOBJID for ghosting entities
use ranges::views::values for associative container iteration
remove dead code
comment magic numbers
little bit of optimization (not enough to be game changing or take the time to measure, they are free speedups anyways, we take those)
use cstdint types

* use size_t

* use lwoobjid for ghost candidate
2024-02-11 14:28:25 -06:00
David Markowitz
ddaac276fe fix: Remove hard coded groups for spawners (#1454)
* fix macros not trimming newline

* Remove hardcoded spawner groups

Was just missing an inline script implementation and using the wrong name
2024-02-11 00:38:21 -06:00
David Markowitz
f7e4a32621 Fix no effect playing when picking up item (#1455) 2024-02-11 00:29:05 -06:00
ecaaea3175 chore: make predefined name unique when the name files are not provided (#1453)
Multiple characters would not be allowed to be made since they would both have tha name INVALID, that is no longer the case
2024-02-11 00:08:22 -06:00
jadebenn
29666a1ff7 chore: General cleanup roundup (#1444)
* Moved unrelated changes out of the TryParse PR branch

* const correctness and cstdint type usage

* removing a few "== nullptr"

* amf constexpr, const-correctness, and attrib tagging

* update to account for feedback

* Fixing accidentally included header and hopefully fixing the MacOS issue too

* try reordering the amf3 specializations to fix the MacOS issue again

* Amf3 template class member func instantiation fix

* try including only on macos

* Using if constexpr rather than specialization

* Trying a different solution for the instantiation problem

* Remove #include "dPlatforms.h"
2024-02-10 13:44:40 -06:00
jadebenn
0c1ee0513d refactor: Change TryParse implementation (#1442)
* Changed how the TryParse function works (and also did some general cleanup along the way)

* Update noexcept attributes (verified these are correct)

* Add fp overload for MacOS functionality

* resolving some feedback

* Split out unrelated changes to CleanupRoundup branch

* Update in response to feedback

* the consequences of emo's member variable renaming request

* Revert "the consequences of emo's member variable renaming request"

This reverts commit bf318caeda.

* Fully revert renaming attempt

* Revert "the consequences of emo's member variable renaming request"

This reverts commit bf318caeda.

Fully revert renaming attempt

* Created ClientVersion.h and moved the client version defaults to it

* Fix partial parsing and MacOS floating point errors

* attempting fix to MacOS compiler error

* syntax pass (should be the last commit unless the CI fails)

* ah, wait, forgot to uncomment the preprocessor statements for MacOS. THIS should be the last commit pending CI

* Okay, one last thing I noticed: We were including C headers here. Now they're C++ headers. Pinky swear this is it!

* typo and I am OCD. please let this be the last

* hash is usally but not always noexcept, so the specifier should go

* Address MOST of the feedback

* address the claim codes issue
2024-02-10 05:05:25 -06:00
David Markowitz
62b670d283 remove sha512, move md5 to thirdparty (#1443)
title.

Tested that Auth runs and I can login still.
2024-02-09 09:15:28 -06:00
David Markowitz
d2aeebcd46 chore: Move database storage containers to be translation unit local to allow for safe references (#1434)
* Move CDClientManager to be a namespace

Tested that worlds still load data as expected.  Had no use being a singleton anyways.

* Move cdclient data storage to tu local containers

Allows some data from these containers to be saved on object by reference instead of always needing to copy.

iteration 2

- move all unnamed namespace containers to a singular spot
- use macro for template specialization and variable declaration
- use templates to allow for as little copy paste of types and functions as possible

* remember to use typename!

compiler believes T::StorageType is accessing a member, not a type.

* Update CDClientManager.cpp

* move to cpp?
2024-02-09 07:37:58 -06:00
David Markowitz
dc29f5962d Move CDClientManager to be a namespace (#1431)
Tested that worlds still load data as expected.  Had no use being a singleton anyways.
2024-02-08 23:40:43 -06:00
Gie "Max" Vanommeslaeghe
24f94edfeb Merge pull request #1447 from DarkflameUniverse/dpGrid_speedup
chore: Use vector instead of forward_list for dpGrid for ~50% physics loop speed improvement
2024-02-08 14:54:51 +01:00
David Markowitz
e8aa491904 Merge branch 'main' into dpGrid_speedup 2024-02-08 03:55:36 -08:00
David Markowitz
a88ef0c325 Update dpGrid.cpp 2024-02-04 16:44:40 -08:00
David Markowitz
8e29148137 actually use clamped value 2024-02-04 16:39:00 -08:00
David Markowitz
f2e7d2eaac Use vector instead of forward_list for dpGrid
also swap contains in for find != end on an associative container since we are in c++20 now :)
2024-02-04 06:10:07 -08:00
654 changed files with 18017 additions and 13351 deletions

View File

@@ -73,4 +73,4 @@ cpp_space_around_assignment_operator=insert
cpp_space_pointer_reference_alignment=left cpp_space_pointer_reference_alignment=left
cpp_space_around_ternary_operator=insert cpp_space_around_ternary_operator=insert
cpp_wrap_preserve_blocks=one_liners cpp_wrap_preserve_blocks=one_liners
cpp_indent_comment=fasle cpp_indent_comment=false

View File

@@ -16,12 +16,12 @@ jobs:
os: [ windows-2022, ubuntu-22.04, macos-13 ] os: [ windows-2022, ubuntu-22.04, macos-13 ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Add msbuild to PATH (Windows only) - name: Add msbuild to PATH (Windows only)
if: ${{ matrix.os == 'windows-2022' }} if: ${{ matrix.os == 'windows-2022' }}
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v2
with: with:
vs-version: '[17,18)' vs-version: '[17,18)'
msbuild-architecture: x64 msbuild-architecture: x64
@@ -33,21 +33,19 @@ jobs:
- name: cmake - name: cmake
uses: lukka/run-cmake@v10 uses: lukka/run-cmake@v10
with: with:
configurePreset: "ci-${{matrix.os}}" workflowPreset: "ci-${{matrix.os}}"
buildPreset: "ci-${{matrix.os}}"
testPreset: "ci-${{matrix.os}}"
- name: artifacts - name: artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: build-${{matrix.os}} name: build-${{matrix.os}}
path: | path: |
build/*Server* build/*/*Server*
build/*.ini build/*/*.ini
build/*.so build/*/*.so
build/*.dll build/*/*.dll
build/vanity/ build/*/vanity/
build/navmeshes/ build/*/navmeshes/
build/migrations/ build/*/migrations/
build/*.dcf build/*/*.dcf
!build/*.pdb !build/*/*.pdb
!build/d*/ !build/*/d*/

3
.gitignore vendored
View File

@@ -122,4 +122,7 @@ docker/__pycache__
docker-compose.override.yml docker-compose.override.yml
!*Test.bin !*Test.bin
# CMake scripts
!cmake/* !cmake/*
!cmake/toolchains/*

View File

@@ -1,9 +1,23 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.25)
project(Darkflame) project(Darkflame
HOMEPAGE_URL "https://github.com/DarkflameUniverse/DarkflameServer"
LANGUAGES C CXX
)
# check if the path to the source directory contains a space
if("${CMAKE_SOURCE_DIR}" MATCHES " ")
message(FATAL_ERROR "The server cannot build in the path (" ${CMAKE_SOURCE_DIR} ") because it contains a space. Please move the server to a path without spaces.")
endif()
include(CTest) include(CTest)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Read variables from file # Read variables from file
@@ -52,33 +66,36 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
# Disabled no-register # Disabled no-register
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. # Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
if(UNIX) if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC") add_compile_options("-fPIC")
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0) add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
if(NOT APPLE) # For all except Clang and Apple Clang
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs") if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options("-static-libgcc" "-lstdc++fs")
endif() endif()
if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") add_link_options("-export-dynamic")
endif() endif()
if(${GGDB}) if(${GGDB})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") add_compile_options("-ggdb")
endif() endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
elseif(MSVC) elseif(MSVC)
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
add_compile_options("/wd4267" "/utf-8") # Also disable non-portable MSVC volatile behavior
add_compile_options("/wd4267" "/utf-8" "/volatile:iso" "/Zc:inline")
elseif(WIN32) elseif(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS) add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif() endif()
# Our output dir # Our output dir
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) #set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process
# TODO make this not have to override the build type directories # TODO make this not have to override the build type directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
@@ -90,37 +107,47 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
find_package(MariaDB)
# Create a /resServer directory # Create a /resServer directory
make_directory(${CMAKE_BINARY_DIR}/resServer) make_directory(${CMAKE_BINARY_DIR}/resServer)
# Create a /logs directory # Create a /logs directory
make_directory(${CMAKE_BINARY_DIR}/logs) make_directory(${CMAKE_BINARY_DIR}/logs)
# Get DLU config directory
if(DEFINED ENV{DLU_CONFIG_DIR})
set(DLU_CONFIG_DIR $ENV{DLU_CONFIG_DIR})
else()
set(DLU_CONFIG_DIR ${PROJECT_BINARY_DIR})
endif()
message(STATUS "Variable: DLU_CONFIG_DIR = ${DLU_CONFIG_DIR}")
# Copy resource files on first build # Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf")
message(STATUS "Checking resource file integrity") message(STATUS "Checking resource file integrity")
include(Utils) include(Utils)
UpdateConfigOption(${PROJECT_BINARY_DIR}/authconfig.ini "port" "auth_server_port") UpdateConfigOption(${DLU_CONFIG_DIR}/authconfig.ini "port" "auth_server_port")
UpdateConfigOption(${PROJECT_BINARY_DIR}/chatconfig.ini "port" "chat_server_port") UpdateConfigOption(${DLU_CONFIG_DIR}/chatconfig.ini "port" "chat_server_port")
UpdateConfigOption(${PROJECT_BINARY_DIR}/masterconfig.ini "port" "master_server_port") UpdateConfigOption(${DLU_CONFIG_DIR}/masterconfig.ini "port" "master_server_port")
foreach(resource_file ${RESOURCE_FILES}) foreach(resource_file ${RESOURCE_FILES})
set(file_size 0) set(file_size 0)
if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file}) if(EXISTS ${DLU_CONFIG_DIR}/${resource_file})
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size) file(SIZE ${DLU_CONFIG_DIR}/${resource_file} file_size)
endif() endif()
if(${file_size} EQUAL 0) if(${file_size} EQUAL 0)
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file} ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${DLU_CONFIG_DIR}/${resource_file}
COPYONLY COPYONLY
) )
message(STATUS "Moved " ${resource_file} " to project binary directory") message(STATUS "Moved " ${resource_file} " to DLU config directory")
elseif(resource_file MATCHES ".ini") elseif(resource_file MATCHES ".ini")
message(STATUS "Checking " ${resource_file} " for missing config options") message(STATUS "Checking " ${resource_file} " for missing config options")
file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents) file(READ ${DLU_CONFIG_DIR}/${resource_file} current_file_contents)
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents}) string(REPLACE "\\\n" "" current_file_contents ${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 "") set(parsed_current_file_contents "")
@@ -151,10 +178,10 @@ foreach(resource_file ${RESOURCE_FILES})
set(line_to_add ${line_to_add} ${line}) set(line_to_add ${line_to_add} ${line})
foreach(line_to_append ${line_to_add}) foreach(line_to_append ${line_to_add})
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append}) file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n" ${line_to_append})
endforeach() endforeach()
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n") file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n")
endif() endif()
set(line_to_add "") set(line_to_add "")
@@ -179,7 +206,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip) file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
# Copy vanity files on first build # Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml") set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml")
foreach(file ${VANITY_FILES}) foreach(file ${VANITY_FILES})
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
@@ -202,42 +229,28 @@ foreach(file ${SQL_FILES})
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}) configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
endforeach() endforeach()
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
if (APPLE)
include_directories("/usr/local/include/")
endif()
# Load all of our third party directories
add_subdirectory(thirdparty SYSTEM)
# Create our list of include directories # Create our list of include directories
set(INCLUDED_DIRECTORIES include_directories(
"dCommon"
"dCommon/dClient"
"dCommon/dEnums"
"dChatFilter"
"dGame"
"dGame/dBehaviors"
"dGame/dComponents"
"dGame/dGameMessages"
"dGame/dInventory"
"dGame/dMission"
"dGame/dEntity"
"dGame/dPropertyBehaviors"
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
"dGame/dUtilities"
"dPhysics" "dPhysics"
"dNavigation" "dNavigation"
"dNavigation/dTerrain"
"dZoneManager"
"dDatabase"
"dDatabase/CDClientDatabase"
"dDatabase/CDClientDatabase/CDClientTables"
"dDatabase/GameDatabase"
"dDatabase/GameDatabase/ITables"
"dDatabase/GameDatabase/MySQL"
"dDatabase/GameDatabase/MySQL/Tables"
"dNet" "dNet"
"tests"
"tests/dCommonTests"
"tests/dGameTests"
"tests/dGameTests/dComponentsTests"
SYSTEM
"thirdparty/magic_enum/include/magic_enum" "thirdparty/magic_enum/include/magic_enum"
"thirdparty/raknet/Source" "thirdparty/raknet/Source"
"thirdparty/tinyxml2" "thirdparty/tinyxml2"
@@ -246,47 +259,25 @@ set(INCLUDED_DIRECTORIES
"thirdparty/cpplinq" "thirdparty/cpplinq"
"thirdparty/cpp-httplib" "thirdparty/cpp-httplib"
"thirdparty/MD5" "thirdparty/MD5"
"tests"
"tests/dCommonTests"
"tests/dGameTests"
"tests/dGameTests/dComponentsTests"
) )
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) # Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
# TODO: Should probably not do this.
if(APPLE) if(APPLE)
include_directories("/usr/local/include/") include_directories("/usr/local/include/")
endif() endif()
# Actually include the directories from our list # Set warning flags
foreach(dir ${INCLUDED_DIRECTORIES}) if(MSVC)
include_directories(${PROJECT_SOURCE_DIR}/${dir}) # add_compile_options("/W4")
endforeach() # Want to enable warnings eventually, but WAY too much noise right now
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
if(NOT WIN32) add_compile_options("-Wuninitialized" "-Wold-style-cast")
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt") else()
message(WARNING "Unknown compiler: '${CMAKE_CXX_COMPILER_ID}' - No warning flags enabled.")
endif() endif()
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
# Add linking directories: # Add linking directories:
link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif()
# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
)
file( file(
GLOB HEADERS_DZONEMANAGER GLOB HEADERS_DZONEMANAGER
LIST_DIRECTORIES false LIST_DIRECTORIES false
@@ -321,7 +312,7 @@ add_subdirectory(dPhysics)
add_subdirectory(dServer) add_subdirectory(dServer)
# Create a list of common libraries shared between all binaries # Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum" "MD5") set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum")
# Add platform specific common libraries # Add platform specific common libraries
if(UNIX) if(UNIX)
@@ -343,12 +334,6 @@ target_precompile_headers(
${HEADERS_DZONEMANAGER} ${HEADERS_DZONEMANAGER}
) )
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
target_precompile_headers(
dDatabase PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
)
target_precompile_headers( target_precompile_headers(
dCommon PRIVATE dCommon PRIVATE
${HEADERS_DCOMMON} ${HEADERS_DCOMMON}

View File

@@ -1,128 +1,641 @@
{ {
"version": 3, "version": 6,
"cmakeMinimumRequired": { "cmakeMinimumRequired": {
"major": 3, "major": 3,
"minor": 14, "minor": 25,
"patch": 0 "patch": 0
}, },
"configurePresets": [ "configurePresets": [
{ {
"name": "default", "name": "default",
"displayName": "Default configure step", "displayName": "Default configure step",
"description": "Use 'build' dir and Unix makefiles", "description": "Use 'build' dir and Unix makefiles",
"binaryDir": "${sourceDir}/build", "binaryDir": "${sourceDir}/build",
"generator": "Unix Makefiles" "environment": {
}, "DLU_CONFIG_DIR": "${sourceDir}/build"
{ },
"name": "ci-ubuntu-22.04", "generator": "Unix Makefiles"
"displayName": "CI configure step for Ubuntu",
"description": "Same as default, Used in GitHub actions workflow",
"inherits": "default"
},
{
"name": "ci-macos-13",
"displayName": "CI configure step for MacOS",
"description": "Same as default, Used in GitHub actions workflow",
"inherits": "default"
},
{
"name": "ci-windows-2022",
"displayName": "CI configure step for Windows",
"description": "Set architecture to 64-bit (b/c RakNet)",
"inherits": "default",
"generator": "Visual Studio 17 2022",
"architecture": {
"value": "x64"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "windows-default",
"inherits": "ci-windows-2022",
"displayName": "Windows only Configure Settings",
"description": "Sets build and install directories",
"generator": "Ninja",
"architecture": {
"value": "x64",
"strategy": "external"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default",
"displayName": "Default Build",
"description": "Default Build",
"jobs": 2
},
{
"name": "ci-windows-2022",
"configurePreset": "ci-windows-2022",
"displayName": "Windows CI Build",
"description": "This preset is used by the CI build on windows",
"configuration": "RelWithDebInfo",
"jobs": 2
},
{
"name": "ci-ubuntu-22.04",
"configurePreset": "ci-ubuntu-22.04",
"displayName": "Linux CI Build",
"description": "This preset is used by the CI build on linux",
"jobs": 2
},
{
"name": "ci-macos-13",
"configurePreset": "ci-macos-13",
"displayName": "MacOS CI Build",
"description": "This preset is used by the CI build on MacOS",
"jobs": 2
}
],
"testPresets": [
{
"name": "ci-ubuntu-22.04",
"configurePreset": "ci-ubuntu-22.04",
"displayName": "CI Tests on Linux",
"description": "Runs all tests on a linux configuration",
"execution": {
"jobs": 2
}, },
"output": { {
"outputOnFailure": true "name": "debug-config",
} "hidden": true,
}, "cacheVariables": {
{ "CMAKE_BUILD_TYPE": "Debug"
"name": "ci-macos-13",
"configurePreset": "ci-macos-13",
"displayName": "CI Tests on MacOS",
"description": "Runs all tests on a Mac configuration",
"execution": {
"jobs": 2
},
"output": {
"outputOnFailure": true
}
},
{
"name": "ci-windows-2022",
"configurePreset": "ci-windows-2022",
"displayName": "CI Tests on windows",
"description": "Runs all tests on a windows configuration",
"configuration": "RelWithDebInfo",
"execution": {
"jobs": 2
},
"output": {
"outputOnFailure": true
},
"filter": {
"exclude": {
"name": "((example)|(minigzip))+"
} }
},
{
"name": "relwithdebinfo-config",
"hidden": true,
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "release-config",
"hidden": true,
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "clang-config",
"hidden": true,
"toolchainFile": "${sourceDir}/cmake/toolchains/linux-clang.cmake"
},
{
"name": "gnu-config",
"hidden": true,
"toolchainFile": "${sourceDir}/cmake/toolchains/linux-gnu.cmake"
},
{
"name": "windows-msvc",
"inherits": "default",
"displayName": "[Multi] Windows (MSVC)",
"description": "Set architecture to 64-bit (b/c RakNet)",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/msvc",
"architecture": {
"value": "x64"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows-default",
"inherits": "windows-msvc",
"displayName": "Windows only Configure Settings",
"description": "Sets build and install directories",
"generator": "Ninja",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"architecture": {
"value": "x64"
}
},
{
"name": "linux-config",
"inherits": "default",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "linux-clang-debug",
"inherits": [
"linux-config",
"clang-config",
"debug-config"
],
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
"description": "Create a debug build using the Clang toolchain for Linux",
"binaryDir": "${sourceDir}/build/clang-debug"
},
{
"name": "linux-clang-relwithdebinfo",
"inherits": [
"linux-config",
"clang-config",
"relwithdebinfo-config"
],
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
"description": "Create a release build with debug info using the Clang toolchain for Linux",
"binaryDir": "${sourceDir}/build/clang-relwithdebinfo"
},
{
"name": "linux-clang-release",
"inherits": [
"linux-config",
"clang-config",
"release-config"
],
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
"description": "Create a release build using the Clang toolchain for Linux",
"binaryDir": "${sourceDir}/build/clang-release"
},
{
"name": "linux-gnu-debug",
"inherits": [
"linux-config",
"gnu-config",
"debug-config"
],
"displayName": "[Debug] Linux (GNU)",
"description": "Create a debug build using the GNU toolchain for Linux",
"binaryDir": "${sourceDir}/build/gnu-debug"
},
{
"name": "linux-gnu-relwithdebinfo",
"inherits": [
"linux-config",
"gnu-config",
"relwithdebinfo-config"
],
"displayName": "[RelWithDebInfo] Linux (GNU)",
"description": "Create a release build with debug info using the GNU toolchain for Linux",
"binaryDir": "${sourceDir}/build/gnu-relwithdebinfo"
},
{
"name": "linux-gnu-release",
"inherits": [
"linux-config",
"gnu-config",
"release-config"
],
"displayName": "[Release] Linux (GNU)",
"description": "Create a release build using the GNU toolchain for Linux",
"binaryDir": "${sourceDir}/build/gnu-release"
},
{
"name": "macos",
"inherits": "default",
"displayName": "[Multi] MacOS",
"description": "Create a build for MacOS",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"binaryDir": "${sourceDir}/build/macos"
} }
} ],
] "buildPresets": [
} {
"name": "default",
"configurePreset": "default",
"displayName": "Default Build",
"description": "Default Build",
"jobs": 2
},
{
"name": "windows-msvc-debug",
"inherits": "default",
"configurePreset": "windows-msvc",
"displayName": "[Debug] Windows (MSVC)",
"description": "This preset is used to build in debug mode using the MSVC toolchain on Windows",
"configuration": "Debug"
},
{
"name": "windows-msvc-relwithdebinfo",
"inherits": "default",
"configurePreset": "windows-msvc",
"displayName": "[RelWithDebInfo] Windows (MSVC)",
"description": "This preset is used to build in debug mode using the MSVC toolchain on Windows",
"configuration": "RelWithDebInfo"
},
{
"name": "windows-msvc-release",
"inherits": "default",
"configurePreset": "windows-msvc",
"displayName": "[Release] Windows (MSVC)",
"description": "This preset is used to build in release mode using the MSVC toolchain on Windows",
"configuration": "Release"
},
{
"name": "linux-clang-debug",
"inherits": "default",
"configurePreset": "linux-clang-debug",
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
"description": "This preset is used to build in debug mode using the Clang toolchain on Linux",
"configuration": "Debug"
},
{
"name": "linux-clang-relwithdebinfo",
"inherits": "default",
"configurePreset": "linux-clang-relwithdebinfo",
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
"description": "This preset is used to build in release mode with debug info using the Clang toolchain on Linux",
"configuration": "RelWithDebInfo"
},
{
"name": "linux-clang-release",
"inherits": "default",
"configurePreset": "linux-clang-release",
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
"description": "This preset is used to build in release mode using the Clang toolchain on Linux",
"configuration": "Release"
},
{
"name": "linux-gnu-debug",
"inherits": "default",
"configurePreset": "linux-gnu-debug",
"displayName": "[Debug] Linux (GNU)",
"description": "This preset is used to build in debug mode using the GNU toolchain on Linux",
"configuration": "Debug"
},
{
"name": "linux-gnu-relwithdebinfo",
"inherits": "default",
"configurePreset": "linux-gnu-relwithdebinfo",
"displayName": "[RelWithDebInfo] Linux (GNU)",
"description": "This preset is used to build in release mode with debug info using the GNU toolchain on Linux",
"configuration": "RelWithDebInfo"
},
{
"name": "linux-gnu-release",
"inherits": "default",
"configurePreset": "linux-gnu-release",
"displayName": "[Release] Linux (GNU)",
"description": "This preset is used to build in release mode using the GNU toolchain on Linux",
"configuration": "Release"
},
{
"name": "macos-debug",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[Debug] MacOS",
"description": "This preset is used to build in debug mode on MacOS",
"configuration": "Debug"
},
{
"name": "macos-relwithdebinfo",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[RelWithDebInfo] MacOS",
"description": "This preset is used to build in release mode with debug info on MacOS",
"configuration": "RelWithDebInfo"
},
{
"name": "macos-release",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[Release] MacOS",
"description": "This preset is used to build in release mode on MacOS",
"configuration": "Release"
}
],
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"execution": {
"jobs": 2
},
"output": {
"outputOnFailure": true
}
},
{
"name": "windows-msvc-test",
"inherits": "default",
"configurePreset": "windows-msvc",
"hidden": true,
"filter": {
"exclude": {
"name": "((example)|(minigzip))+"
}
}
},
{
"name": "windows-msvc-debug",
"inherits": "windows-msvc-test",
"configurePreset": "windows-msvc",
"displayName": "[Debug] Windows (MSVC)",
"description": "Runs all tests on a Windows configuration",
"configuration": "Debug"
},
{
"name": "windows-msvc-relwithdebinfo",
"inherits": "windows-msvc-test",
"configurePreset": "windows-msvc",
"displayName": "[RelWithDebInfo] Windows (MSVC)",
"description": "Runs all tests on a Windows configuration",
"configuration": "RelWithDebInfo"
},
{
"name": "windows-msvc-release",
"inherits": "windows-msvc-test",
"configurePreset": "windows-msvc",
"displayName": "[Release] Windows (MSVC)",
"description": "Runs all tests on a Windows configuration",
"configuration": "Release"
},
{
"name": "linux-clang-debug",
"inherits": "default",
"configurePreset": "linux-clang-debug",
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
"description": "Runs all tests on a Linux Clang configuration",
"configuration": "Release"
},
{
"name": "linux-clang-relwithdebinfo",
"inherits": "default",
"configurePreset": "linux-clang-relwithdebinfo",
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
"description": "Runs all tests on a Linux Clang configuration",
"configuration": "RelWithDebInfo"
},
{
"name": "linux-clang-release",
"inherits": "default",
"configurePreset": "linux-clang-release",
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
"description": "Runs all tests on a Linux Clang configuration",
"configuration": "Release"
},
{
"name": "linux-gnu-debug",
"inherits": "default",
"configurePreset": "linux-gnu-debug",
"displayName": "[Debug] Linux (GNU)",
"description": "Runs all tests on a Linux GNU configuration",
"configuration": "Release"
},
{
"name": "linux-gnu-relwithdebinfo",
"inherits": "default",
"configurePreset": "linux-gnu-relwithdebinfo",
"displayName": "[RelWithDebInfo] Linux (GNU)",
"description": "Runs all tests on a Linux GNU configuration",
"configuration": "RelWithDebInfo"
},
{
"name": "linux-gnu-release",
"inherits": "default",
"configurePreset": "linux-gnu-release",
"displayName": "[Release] Linux (GNU)",
"description": "Runs all tests on a Linux GNU configuration",
"configuration": "Release"
},
{
"name": "macos-debug",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[Debug] MacOS",
"description": "Runs all tests on a MacOS configuration",
"configuration": "Debug"
},
{
"name": "macos-relwithdebinfo",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[RelWithDebInfo] MacOS",
"description": "Runs all tests on a MacOS configuration",
"configuration": "RelWithDebInfo"
},
{
"name": "macos-release",
"inherits": "default",
"configurePreset": "macos",
"displayName": "[Release] MacOS",
"description": "Runs all tests on a MacOS configuration",
"configuration": "Release"
}
],
"workflowPresets": [
{
"name": "default",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
}
]
},
{
"name": "windows-msvc-debug",
"displayName": "[Debug] Windows (MSVC)",
"description": "MSVC debug workflow preset for Windows",
"steps": [
{
"type": "configure",
"name": "windows-msvc"
},
{
"type": "build",
"name": "windows-msvc-debug"
},
{
"type": "test",
"name": "windows-msvc-debug"
}
]
},
{
"name": "windows-msvc-relwithdebinfo",
"displayName": "[RelWithDebInfo] Windows (MSVC)",
"description": "MSVC release with debug info workflow preset for Windows",
"steps": [
{
"type": "configure",
"name": "windows-msvc"
},
{
"type": "build",
"name": "windows-msvc-relwithdebinfo"
},
{
"type": "test",
"name": "windows-msvc-relwithdebinfo"
}
]
},
{
"name": "ci-windows-2022",
"displayName": "[Release] Windows (MSVC)",
"description": "CI workflow preset for Windows",
"steps": [
{
"type": "configure",
"name": "windows-msvc"
},
{
"type": "build",
"name": "windows-msvc-release"
},
{
"type": "test",
"name": "windows-msvc-release"
}
]
},
{
"name": "linux-gnu-debug",
"displayName": "[Debug] Linux (GNU)",
"description": "GNU debug workflow preset for Linux",
"steps": [
{
"type": "configure",
"name": "linux-gnu-debug"
},
{
"type": "build",
"name": "linux-gnu-debug"
},
{
"type": "test",
"name": "linux-gnu-debug"
}
]
},
{
"name": "linux-gnu-relwithdebinfo",
"displayName": "[RelWithDebInfo] Linux (GNU)",
"description": "GNU release with debug info workflow preset for Linux",
"steps": [
{
"type": "configure",
"name": "linux-gnu-relwithdebinfo"
},
{
"type": "build",
"name": "linux-gnu-relwithdebinfo"
},
{
"type": "test",
"name": "linux-gnu-relwithdebinfo"
}
]
},
{
"name": "ci-ubuntu-22.04",
"displayName": "[Release] Linux (GNU)",
"description": "CI workflow preset for Ubuntu",
"steps": [
{
"type": "configure",
"name": "linux-gnu-release"
},
{
"type": "build",
"name": "linux-gnu-release"
},
{
"type": "test",
"name": "linux-gnu-release"
}
]
},
{
"name": "linux-clang-debug",
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
"description": "Clang debug workflow preset for Linux",
"steps": [
{
"type": "configure",
"name": "linux-clang-debug"
},
{
"type": "build",
"name": "linux-clang-debug"
},
{
"type": "test",
"name": "linux-clang-debug"
}
]
},
{
"name": "linux-clang-relwithdebinfo",
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
"description": "Clang release with debug info workflow preset for Linux",
"steps": [
{
"type": "configure",
"name": "linux-clang-relwithdebinfo"
},
{
"type": "build",
"name": "linux-clang-relwithdebinfo"
},
{
"type": "test",
"name": "linux-clang-relwithdebinfo"
}
]
},
{
"name": "linux-clang-release",
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
"description": "Clang release workflow preset for Linux",
"steps": [
{
"type": "configure",
"name": "linux-clang-release"
},
{
"type": "build",
"name": "linux-clang-release"
},
{
"type": "test",
"name": "linux-clang-release"
}
]
},
{
"name": "macos-debug",
"displayName": "[Debug] MacOS",
"description": "Release workflow preset for MacOS",
"steps": [
{
"type": "configure",
"name": "macos"
},
{
"type": "build",
"name": "macos-debug"
},
{
"type": "test",
"name": "macos-debug"
}
]
},
{
"name": "macos-relwithdebinfo",
"displayName": "[RelWithDebInfo] MacOS",
"description": "Release with debug info workflow preset for MacOS",
"steps": [
{
"type": "configure",
"name": "macos"
},
{
"type": "build",
"name": "macos-relwithdebinfo"
},
{
"type": "test",
"name": "macos-relwithdebinfo"
}
]
},
{
"name": "ci-macos-13",
"displayName": "[Release] MacOS",
"description": "CI workflow preset for MacOS",
"steps": [
{
"type": "configure",
"name": "macos"
},
{
"type": "build",
"name": "macos-release"
},
{
"type": "test",
"name": "macos-release"
}
]
}
]
}

View File

@@ -1,6 +1,6 @@
PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MAJOR=2
PROJECT_VERSION_MINOR=1 PROJECT_VERSION_MINOR=3
PROJECT_VERSION_PATCH=1 PROJECT_VERSION_PATCH=0
# Debugging # Debugging
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. # Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.

View File

@@ -23,8 +23,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# Grab libraries and load them # Grab libraries and load them
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadbcpp.so /usr/local/lib/ COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /usr/local/lib
RUN ldconfig RUN ldconfig
# Server bins # Server bins
@@ -32,7 +31,7 @@ COPY --from=build /app/build/*Server /app/
# Necessary suplimentary files # Necessary suplimentary files
COPY --from=build /app/build/*.ini /app/configs/ COPY --from=build /app/build/*.ini /app/configs/
COPY --from=build /app/build/vanity/*.* /app/vanity/* COPY --from=build /app/build/vanity/*.* /app/vanity/
COPY --from=build /app/build/navmeshes /app/navmeshes COPY --from=build /app/build/navmeshes /app/navmeshes
COPY --from=build /app/build/migrations /app/migrations COPY --from=build /app/build/migrations /app/migrations
COPY --from=build /app/build/*.dcf /app/ COPY --from=build /app/build/*.dcf /app/
@@ -40,7 +39,7 @@ COPY --from=build /app/build/*.dcf /app/
# backup of config and vanity files to copy to the host incase # backup of config and vanity files to copy to the host incase
# of a mount clobbering the copy from above # of a mount clobbering the copy from above
COPY --from=build /app/build/*.ini /app/default-configs/ COPY --from=build /app/build/*.ini /app/default-configs/
COPY --from=build /app/build/vanity/*.* /app/default-vanity/* COPY --from=build /app/build/vanity/*.* /app/default-vanity/
# needed as the container runs with the root user # needed as the container runs with the root user
# and therefore sudo doesn't exist # and therefore sudo doesn't exist

View File

@@ -51,7 +51,7 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
### Windows packages ### Windows packages
Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed.
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.18**</font> or later!). You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.25**</font> or later!).
### MacOS packages ### MacOS packages
Ensure you have [brew](https://brew.sh) installed. Ensure you have [brew](https://brew.sh) installed.
@@ -73,7 +73,7 @@ sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-serve
``` ```
#### Required CMake version #### Required CMake version
This project uses <font size="4">**CMake version 3.18**</font> or higher and as such you will need to ensure you have this version installed. This project uses <font size="4">**CMake version 3.25**</font> or higher and as such you will need to ensure you have this version installed.
You can check your CMake version by using the following command in a terminal. You can check your CMake version by using the following command in a terminal.
```bash ```bash
cmake --version cmake --version

View File

@@ -6,8 +6,7 @@ mkdir -p build
cd build cd build
# Run cmake to generate make files # Run cmake to generate make files
cmake .. cmake -DCMAKE_BUILD_TYPE="Release" ..
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8' # To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
cmake --build . --config Release $1 cmake --build . --config Release $1

View File

@@ -0,0 +1,17 @@
include(FetchContent)
message(STATUS "Fetching gtest...")
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(GoogleTest)
message(STATUS "gtest fetched and is now ready.")
set(GoogleTest_FOUND TRUE)

View File

@@ -23,14 +23,14 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
set(MARIADB_CONNECTOR_CPP_MSI "mariadb-connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}-win64.msi") set(MARIADB_CONNECTOR_CPP_MSI "mariadb-connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}-win64.msi")
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" ) if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" )
message("Downloading mariadb connector/c") message(STATUS "Downloading mariadb connector/c")
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_C_BUCKET}/Connectors/c/connector-c-${MARIADB_CONNECTOR_C_VERSION}/${MARIADB_CONNECTOR_C_MSI} file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_C_BUCKET}/Connectors/c/connector-c-${MARIADB_CONNECTOR_C_VERSION}/${MARIADB_CONNECTOR_C_MSI}
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}"
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_C_MD5}) EXPECTED_HASH MD5=${MARIADB_CONNECTOR_C_MD5})
endif() endif()
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" ) if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" )
message("Downloading mariadb connector/c++") message(STATUS "Downloading mariadb connector/c++")
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_CPP_BUCKET}/Connectors/cpp/connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}/${MARIADB_CONNECTOR_CPP_MSI} file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_CPP_BUCKET}/Connectors/cpp/connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}/${MARIADB_CONNECTOR_CPP_MSI}
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}"
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_CPP_MD5}) EXPECTED_HASH MD5=${MARIADB_CONNECTOR_CPP_MD5})
@@ -43,27 +43,28 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" MSI_DIR) file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" MSI_DIR)
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
endif() endif()
set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll")
if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}") if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}")
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" MSI_DIR) file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" MSI_DIR)
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
endif() endif()
set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll") set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll")
set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib") set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib")
set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb") set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb")
add_custom_target(mariadb_connector_cpp) add_custom_target(mariadb_connector_cpp)
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll" "${MARIADBCPP_SHARED_LIBRARY_LOCATION}"
"${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll" "${MARIADBC_SHARED_LIBRARY_LOCATION}"
"${PROJECT_BINARY_DIR}") "${PROJECT_BINARY_DIR}")
# MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories, # MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories,
# so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory. # so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory.
# Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable # Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable
add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION}) add_link_options(/DELAYLOAD:${MARIADBCPP_SHARED_LIBRARY_LOCATION})
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin") add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin")
else() # Build from source else() # Build from source
@@ -85,77 +86,61 @@ else() # Build from source
-DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0) -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0)
endif() endif()
set(MARIADBCPP_INSTALL_DIR ${PROJECT_BINARY_DIR}/prefix)
set(MARIADBCPP_LIBRARY_DIR ${PROJECT_BINARY_DIR}/mariadbcpp)
set(MARIADBCPP_PLUGIN_DIR ${MARIADBCPP_LIBRARY_DIR}/plugin)
set(MARIADBCPP_SOURCE_DIR ${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp)
set(MARIADB_INCLUDE_DIR "${MARIADBCPP_SOURCE_DIR}/include")
ExternalProject_Add(mariadb_connector_cpp ExternalProject_Add(mariadb_connector_cpp
SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp PREFIX "${PROJECT_BINARY_DIR}/thirdparty/mariadb-connector-cpp"
CMAKE_ARGS -Wno-dev SOURCE_DIR ${MARIADBCPP_SOURCE_DIR}
-DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN} INSTALL_DIR ${MARIADBCPP_INSTALL_DIR}
-DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory CMAKE_ARGS -Wno-dev
-DINSTALL_PLUGINDIR=plugin -DWITH_UNIT_TESTS=OFF
${MARIADB_EXTRA_CMAKE_ARGS} -DMARIADB_LINK_DYNAMIC=OFF
PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp" -DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN}
BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${MARIADB_CONNECTOR_COMPILE_JOBS} -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
INSTALL_COMMAND "") -DINSTALL_LIBDIR=${MARIADBCPP_LIBRARY_DIR}
-DINSTALL_PLUGINDIR=${MARIADBCPP_PLUGIN_DIR}
ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR) ${MARIADB_EXTRA_CMAKE_ARGS}
BUILD_ALWAYS true
)
if(WIN32) if(WIN32)
set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll) set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll)
set(MARIADB_PLUGIN_SUFFIX .dll) set(MARIADB_PLUGIN_SUFFIX .dll)
set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib") set(MARIADB_IMPLIB_LOCATION "${MARIADBCPP_LIBRARY_DIR}/mariadbcpp.lib")
# When built from source windows only seems to check same folder as exe instead specified folder, so use # When built from source windows only seems to check same folder as exe instead specified folder, so use
# environment variable to force it # environment variable to force it
add_link_options(/DELAYLOAD:mariadbcpp.dll) add_link_options(/DELAYLOAD:mariadbcpp.dll)
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin") add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADBCPP_PLUGIN_DIR}")
else() else()
set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX}) set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX})
set(MARIADB_PLUGIN_SUFFIX .so) set(MARIADB_PLUGIN_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
endif() endif()
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
if(isMultiConfig) if(WIN32)
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}") set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/libmariadb.lib")
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>")
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo")
else()
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}")
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb")
endif() endif()
set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/")
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
${BINARY_DIR}/mariadbcpp/plugin
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${MARIADB_SHARED_LIBRARY_LOCATION}
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX}
${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX}
${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX}
${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX}
${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX}
${BINARY_DIR}/mariadbcpp/plugin)
endif()
# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests.
if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
endif() endif()
# Create mariadb connector library object # Create mariadb connector library object
add_library(mariadbConnCpp SHARED IMPORTED GLOBAL) add_library(MariaDB::ConnCpp SHARED IMPORTED GLOBAL)
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION}) add_dependencies(MariaDB::ConnCpp mariadb_connector_cpp)
set_target_properties(MariaDB::ConnCpp PROPERTIES
IMPORTED_LOCATION "${MARIADBCPP_SHARED_LIBRARY_LOCATION}")
if(WIN32) if(WIN32)
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION}) set_target_properties(MariaDB::ConnCpp PROPERTIES
IMPORTED_IMPLIB "${MARIADB_IMPLIB_LOCATION}")
elseif(APPLE)
set_target_properties(MariaDB::ConnCpp PROPERTIES
IMPORTED_SONAME "libmariadbcpp")
endif() endif()
# Add directories to include lists # Add directories to include lists
target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR}) target_include_directories(MariaDB::ConnCpp SYSTEM INTERFACE ${MARIADB_INCLUDE_DIR})
add_dependencies(mariadbConnCpp mariadb_connector_cpp)
set(MariaDB_FOUND TRUE)

View File

@@ -0,0 +1,14 @@
# Try and find a clang-16 install, falling back to a generic clang install otherwise
find_program(CLANG_C_COMPILER clang-16 | clang REQUIRED)
find_program(CLANG_CXX_COMPILER clang++-16 | clang++ REQUIRED)
# Debug messages
message(DEBUG "CLANG_C_COMPILER = ${CLANG_C_COMPILER}")
message(DEBUG "CLANG_CXX_COMPILER = ${CLANG_CXX_COMPILER}")
# Set compilers to clang (need to cache for VSCode tools to work correctly)
set(CMAKE_C_COMPILER ${CLANG_C_COMPILER} CACHE STRING "Set C compiler")
set(CMAKE_CXX_COMPILER ${CLANG_CXX_COMPILER} CACHE STRING "Set C++ compiler")
# Set linker to lld
add_link_options("-fuse-ld=lld")

View File

@@ -0,0 +1,11 @@
# Try and find a gcc/g++ install
find_program(GNU_C_COMPILER cc | gcc REQUIRED)
find_program(GNU_CXX_COMPILER c++ | g++ REQUIRED)
# Debug messages
message(DEBUG "GNU_C_COMPILER = ${GNU_C_COMPILER}")
message(DEBUG "GNU_CXX_COMPILER = ${GNU_CXX_COMPILER}")
# Set compilers to GNU (need to cache for VSCode tools to work correctly)
set(CMAKE_C_COMPILER ${GNU_C_COMPILER} CACHE STRING "Set C compiler")
set(CMAKE_CXX_COMPILER ${GNU_CXX_COMPILER} CACHE STRING "Set C++ compiler")

View File

@@ -21,8 +21,8 @@
//Auth includes: //Auth includes:
#include "AuthPackets.h" #include "AuthPackets.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eServerMessageType.h" #include "MessageType/Server.h"
#include "eAuthMessageType.h" #include "MessageType/Auth.h"
#include "Game.h" #include "Game.h"
#include "Server.h" #include "Server.h"
@@ -82,11 +82,11 @@ int main(int argc, char** argv) {
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
std::string ourIP = "localhost"; std::string ourIP = "localhost";
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients); const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
GeneralUtils::TryParse(Game::config->GetValue("auth_server_port"), ourPort);
//LU client is hardcoded to use this for auth port, so I'm making it the default.
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("auth_server_port")).value_or(1001);
const auto externalIPString = Game::config->GetValue("external_ip"); const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString; if (!externalIPString.empty()) ourIP = externalIPString;
@@ -102,7 +102,7 @@ int main(int argc, char** argv) {
uint32_t framesSinceLastSQLPing = 0; uint32_t framesSinceLastSQLPing = 0;
AuthPackets::LoadClaimCodes(); AuthPackets::LoadClaimCodes();
Game::logger->Flush(); // once immediately before main loop Game::logger->Flush(); // once immediately before main loop
while (!Game::ShouldShutdown()) { while (!Game::ShouldShutdown()) {
//Check if we're still connected to master: //Check if we're still connected to master:
@@ -166,11 +166,11 @@ void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_USER_PACKET_ENUM) { if (packet->data[0] == ID_USER_PACKET_ENUM) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) {
AuthPackets::HandleHandshake(Game::server, packet); AuthPackets::HandleHandshake(Game::server, packet);
} }
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) { } else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
if (static_cast<eAuthMessageType>(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) { if (static_cast<MessageType::Auth>(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) {
AuthPackets::HandleLoginRequest(Game::server, packet); AuthPackets::HandleLoginRequest(Game::server, packet);
} }
} }

View File

@@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
ExportWordlistToDCF(filepath + ".dcf", true); ExportWordlistToDCF(filepath + ".dcf", true);
} }
if (BinaryIO::DoesFileExist("blacklist.dcf")) { if (BinaryIO::DoesFileExist("blocklist.dcf")) {
ReadWordlistDCF("blacklist.dcf", false); ReadWordlistDCF("blocklist.dcf", false);
} }
//Read player names that are ok as well: //Read player names that are ok as well:
@@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() {
m_DeniedWords.clear(); m_DeniedWords.clear();
} }
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) { void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) {
std::ifstream file(filepath); std::ifstream file(filepath);
if (file) { if (file) {
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line)); if (allowList) m_ApprovedWords.push_back(CalculateHash(line));
else m_DeniedWords.push_back(CalculateHash(line)); else m_DeniedWords.push_back(CalculateHash(line));
} }
} }
} }
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (file) { if (file) {
fileHeader hdr; fileHeader hdr;
@@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
if (hdr.formatVersion == formatVersion) { if (hdr.formatVersion == formatVersion) {
size_t wordsToRead = 0; size_t wordsToRead = 0;
BinaryIO::BinaryRead(file, wordsToRead); BinaryIO::BinaryRead(file, wordsToRead);
if (whiteList) m_ApprovedWords.reserve(wordsToRead); if (allowList) m_ApprovedWords.reserve(wordsToRead);
else m_DeniedWords.reserve(wordsToRead); else m_DeniedWords.reserve(wordsToRead);
size_t word = 0; size_t word = 0;
for (size_t i = 0; i < wordsToRead; ++i) { for (size_t i = 0; i < wordsToRead; ++i) {
BinaryIO::BinaryRead(file, word); BinaryIO::BinaryRead(file, word);
if (whiteList) m_ApprovedWords.push_back(word); if (allowList) m_ApprovedWords.push_back(word);
else m_DeniedWords.push_back(word); else m_DeniedWords.push_back(word);
} }
@@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
return false; return false;
} }
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) { void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowList) {
std::ofstream file(filepath, std::ios::binary | std::ios_base::out); std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
if (file) { if (file) {
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size())); BinaryIO::BinaryWrite(file, size_t(allowList ? m_ApprovedWords.size() : m_DeniedWords.size()));
for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) { for (size_t word : allowList ? m_ApprovedWords : m_DeniedWords) {
BinaryIO::BinaryWrite(file, word); BinaryIO::BinaryWrite(file, word);
} }
@@ -105,10 +105,10 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis
} }
} }
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) { std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList) {
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
if (message.empty()) return { }; if (message.empty()) return { };
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; if (!allowList && m_DeniedWords.empty()) return { { 0, message.length() } };
std::stringstream sMessage(message); std::stringstream sMessage(message);
std::string segment; std::string segment;
@@ -126,16 +126,16 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
size_t hash = CalculateHash(segment); size_t hash = CalculateHash(segment);
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) { if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) {
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) { if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) {
m_UserUnapprovedWordCache.push_back(hash); m_UserUnapprovedWordCache.push_back(hash);
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) { if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) {
m_UserUnapprovedWordCache.push_back(hash); m_UserUnapprovedWordCache.push_back(hash);
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }

View File

@@ -21,10 +21,10 @@ public:
dChatFilter(const std::string& filepath, bool dontGenerateDCF); dChatFilter(const std::string& filepath, bool dontGenerateDCF);
~dChatFilter(); ~dChatFilter();
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); void ReadWordlistPlaintext(const std::string& filepath, bool allowList);
bool ReadWordlistDCF(const std::string& filepath, bool whiteList); bool ReadWordlistDCF(const std::string& filepath, bool allowList);
void ExportWordlistToDCF(const std::string& filepath, bool whiteList); void ExportWordlistToDCF(const std::string& filepath, bool allowList);
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true); std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true);
private: private:
bool m_DontGenerateDCF; bool m_DontGenerateDCF;

View File

@@ -5,10 +5,12 @@ set(DCHATSERVER_SOURCES
) )
add_executable(ChatServer "ChatServer.cpp") add_executable(ChatServer "ChatServer.cpp")
add_library(dChatServer ${DCHATSERVER_SOURCES}) target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter")
target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
add_library(dChatServer ${DCHATSERVER_SOURCES})
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer")
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer) target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)

View File

@@ -1,6 +1,6 @@
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "eChatInternalMessageType.h" #include "MessageType/Chat.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
@@ -13,7 +13,7 @@
// The only thing not auto-handled is instance activities force joining the team on the server. // The only thing not auto-handled is instance activities force joining the team on the server.
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) { void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receivingPlayer); bitStream.Write(receivingPlayer);
//portion that will get routed: //portion that will get routed:
@@ -59,7 +59,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
bitStream.Write(LUWString(ignoredPlayer.playerName, 36)); bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
} }
Game::server->Send(&bitStream, packet->systemAddress, false); Game::server->Send(bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::AddIgnore(Packet* packet) { void ChatIgnoreList::AddIgnore(Packet* packet) {
@@ -131,7 +131,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
bitStream.Write(ignoredPlayerId); bitStream.Write(ignoredPlayerId);
Game::server->Send(&bitStream, packet->systemAddress, false); Game::server->Send(bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::RemoveIgnore(Packet* packet) { void ChatIgnoreList::RemoveIgnore(Packet* packet) {
@@ -167,5 +167,5 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
LUWString playerNameSend(removedIgnoreStr, 33); LUWString playerNameSend(removedIgnoreStr, 33);
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
Game::server->Send(&bitStream, packet->systemAddress, false); Game::server->Send(bitStream, packet->systemAddress, false);
} }

View File

@@ -13,12 +13,12 @@
#include "dConfig.h" #include "dConfig.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eChatMessageType.h" #include "MessageType/Chat.h"
#include "eChatInternalMessageType.h" #include "MessageType/Client.h"
#include "eClientMessageType.h" #include "MessageType/Game.h"
#include "eGameMessageType.h"
#include "StringifiedEnum.h" #include "StringifiedEnum.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "ChatPackets.h"
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with: //Get from the packet which player we want to do something with:
@@ -60,11 +60,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Now, we need to send the friendlist to the server they came from: //Now, we need to send the friendlist to the server they came from:
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(playerID); bitStream.Write(playerID);
//portion that will get routed: //portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GET_FRIENDS_LIST_RESPONSE);
bitStream.Write<uint8_t>(0); bitStream.Write<uint8_t>(0);
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it. bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
bitStream.Write<uint16_t>(player.friends.size()); bitStream.Write<uint16_t>(player.friends.size());
@@ -355,7 +355,68 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) {
inStream.Read(player.gmLevel); inStream.Read(player.gmLevel);
} }
// the structure the client uses to send this packet is shared in many chat messages
void ChatPacketHandler::HandleWho(Packet* packet) {
CINSTREAM_SKIP_HEADER;
FindPlayerRequest request;
request.Deserialize(inStream);
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
if (!sender) return;
const auto& player = Game::playerContainer.GetPlayerData(request.playerName.GetAsString());
bool online = player;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(request.requestor);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::WHO_RESPONSE);
bitStream.Write<uint8_t>(online);
bitStream.Write(player.zoneID.GetMapID());
bitStream.Write(player.zoneID.GetInstanceID());
bitStream.Write(player.zoneID.GetCloneID());
bitStream.Write(request.playerName);
SystemAddress sysAddr = sender.sysAddr;
SEND_PACKET;
}
void ChatPacketHandler::HandleShowAll(Packet* packet) {
CINSTREAM_SKIP_HEADER;
ShowAllRequest request;
request.Deserialize(inStream);
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
if (!sender) return;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(request.requestor);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::SHOW_ALL_RESPONSE);
bitStream.Write<uint8_t>(!request.displayZoneData && !request.displayIndividualPlayers);
bitStream.Write(Game::playerContainer.GetPlayerCount());
bitStream.Write(Game::playerContainer.GetSimCount());
bitStream.Write<uint8_t>(request.displayIndividualPlayers);
bitStream.Write<uint8_t>(request.displayZoneData);
if (request.displayZoneData || request.displayIndividualPlayers){
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
if (!playerData) continue;
bitStream.Write<uint8_t>(0); // structure packing
if (request.displayIndividualPlayers) bitStream.Write(LUWString(playerData.playerName));
if (request.displayZoneData) {
bitStream.Write(playerData.zoneID.GetMapID());
bitStream.Write(playerData.zoneID.GetInstanceID());
bitStream.Write(playerData.zoneID.GetCloneID());
}
}
}
SystemAddress sysAddr = sender.sysAddr;
SEND_PACKET;
}
// the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages // that are sent to the server. Because of this, there are large gaps of unused data in chat messages
void ChatPacketHandler::HandleChatMessage(Packet* packet) { void ChatPacketHandler::HandleChatMessage(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
@@ -367,7 +428,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
eChatChannel channel; eChatChannel channel;
uint32_t size; uint32_t size;
inStream.IgnoreBytes(4); inStream.IgnoreBytes(4);
inStream.Read(channel); inStream.Read(channel);
inStream.Read(size); inStream.Read(size);
@@ -375,7 +436,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
LUWString message(size); LUWString message(size);
inStream.Read(message); inStream.Read(message);
LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str()); LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str());
switch (channel) { switch (channel) {
@@ -396,7 +457,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
} }
} }
// the structure the client uses to send this packet is shared in many chat messages // the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages // that are sent to the server. Because of this, there are large gaps of unused data in chat messages
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
@@ -423,7 +484,7 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
LUWString message(size); LUWString message(size);
inStream.Read(message); inStream.Read(message);
LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str()); LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str());
const auto& receiver = Game::playerContainer.GetPlayerData(receiverName); const auto& receiver = Game::playerContainer.GetPlayerData(receiverName);
@@ -454,10 +515,10 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) { void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(routeTo.playerID); bitStream.Write(routeTo.playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::PRIVATE_CHAT_MESSAGE);
bitStream.Write(sender.playerID); bitStream.Write(sender.playerID);
bitStream.Write(channel); bitStream.Write(channel);
bitStream.Write<uint32_t>(0); // not used bitStream.Write<uint32_t>(0); // not used
@@ -696,11 +757,11 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) { void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE);
bitStream.Write(LUWString(sender.playerName.c_str())); bitStream.Write(LUWString(sender.playerName.c_str()));
bitStream.Write(sender.playerID); bitStream.Write(sender.playerID);
@@ -711,14 +772,14 @@ void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerD
void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) { void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_INVITE_CONFIRM); bitStream.Write(MessageType::Game::TEAM_INVITE_CONFIRM);
bitStream.Write(bLeaderIsFreeTrial); bitStream.Write(bLeaderIsFreeTrial);
bitStream.Write(i64LeaderID); bitStream.Write(i64LeaderID);
@@ -738,14 +799,14 @@ void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool b
void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) { void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_GET_STATUS_RESPONSE); bitStream.Write(MessageType::Game::TEAM_GET_STATUS_RESPONSE);
bitStream.Write(i64LeaderID); bitStream.Write(i64LeaderID);
bitStream.Write(i64LeaderZoneID); bitStream.Write(i64LeaderZoneID);
@@ -763,14 +824,14 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) { void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_SET_LEADER); bitStream.Write(MessageType::Game::TEAM_SET_LEADER);
bitStream.Write(i64PlayerID); bitStream.Write(i64PlayerID);
@@ -780,14 +841,14 @@ void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i
void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) { void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_ADD_PLAYER); bitStream.Write(MessageType::Game::TEAM_ADD_PLAYER);
bitStream.Write(bIsFreeTrial); bitStream.Write(bIsFreeTrial);
bitStream.Write(bLocal); bitStream.Write(bLocal);
@@ -809,14 +870,14 @@ void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFr
void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) { void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_REMOVE_PLAYER); bitStream.Write(MessageType::Game::TEAM_REMOVE_PLAYER);
bitStream.Write(bDisband); bitStream.Write(bDisband);
bitStream.Write(bIsKicked); bitStream.Write(bIsKicked);
@@ -835,14 +896,14 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) { void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER; CMSGHEADER;
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
bitStream.Write(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG); bitStream.Write(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG);
bitStream.Write(i64PlayerID); bitStream.Write(i64PlayerID);
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) { if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
@@ -869,11 +930,11 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
[bool] - is FTP*/ [bool] - is FTP*/
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(friendData.playerID); bitStream.Write(friendData.playerID);
//portion that will get routed: //portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::UPDATE_FRIEND_NOTIFY);
bitStream.Write<uint8_t>(notifyType); bitStream.Write<uint8_t>(notifyType);
std::string playerName = playerData.playerName.c_str(); std::string playerName = playerData.playerName.c_str();
@@ -906,11 +967,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
} }
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_REQUEST);
bitStream.Write(LUWString(sender.playerName)); bitStream.Write(LUWString(sender.playerName));
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side. bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
@@ -920,11 +981,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
// Portion that will get routed: // Portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_RESPONSE);
bitStream.Write(responseCode); bitStream.Write(responseCode);
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver. // For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.sysAddr != UNASSIGNED_SYSTEM_ADDRESS); bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
@@ -943,11 +1004,11 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) { void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::REMOVE_FRIEND_RESPONSE);
bitStream.Write<uint8_t>(isSuccessful); //isOnline bitStream.Write<uint8_t>(isSuccessful); //isOnline
bitStream.Write(LUWString(personToRemove)); bitStream.Write(LUWString(personToRemove));

View File

@@ -50,6 +50,8 @@ namespace ChatPacketHandler {
void HandleFriendResponse(Packet* packet); void HandleFriendResponse(Packet* packet);
void HandleRemoveFriend(Packet* packet); void HandleRemoveFriend(Packet* packet);
void HandleGMLevelUpdate(Packet* packet); void HandleGMLevelUpdate(Packet* packet);
void HandleWho(Packet* packet);
void HandleShowAll(Packet* packet);
void HandleChatMessage(Packet* packet); void HandleChatMessage(Packet* packet);
void HandlePrivateChatMessage(Packet* packet); void HandlePrivateChatMessage(Packet* packet);

View File

@@ -16,9 +16,8 @@
#include "eConnectionType.h" #include "eConnectionType.h"
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "ChatPacketHandler.h" #include "ChatPacketHandler.h"
#include "eChatMessageType.h" #include "MessageType/Chat.h"
#include "eChatInternalMessageType.h" #include "MessageType/World.h"
#include "eWorldMessageType.h"
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "StringifiedEnum.h" #include "StringifiedEnum.h"
@@ -99,20 +98,17 @@ int main(int argc, char** argv) {
masterPort = masterInfo->port; masterPort = masterInfo->port;
} }
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t ourPort = 1501;
std::string ourIP = "localhost"; std::string ourIP = "localhost";
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients); const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
GeneralUtils::TryParse(Game::config->GetValue("chat_server_port"), ourPort); const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(2005);
const auto externalIPString = Game::config->GetValue("external_ip"); const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString; if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal); Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
bool dontGenerateDCF = false; const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
GeneralUtils::TryParse(Game::config->GetValue("dont_generate_dcf"), dontGenerateDCF);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
Game::playerContainer.Initialize(); Game::playerContainer.Initialize();
@@ -183,185 +179,168 @@ int main(int argc, char** argv) {
} }
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->length < 1) return;
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
LOG("A server has disconnected, erasing their connected players from the list."); LOG("A server has disconnected, erasing their connected players from the list.");
} } else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
LOG("A server is connecting, awaiting user list."); LOG("A server is connecting, awaiting user list.");
} } else if (packet->length < 4 || packet->data[0] != ID_USER_PACKET_ENUM) return; // Nothing left to process or not the right packet type
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue. CINSTREAM;
inStream.SetReadOffset(BYTES_TO_BITS(1));
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { eConnectionType connection;
switch (static_cast<eChatInternalMessageType>(packet->data[3])) { MessageType::Chat chatMessageID;
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
Game::playerContainer.InsertPlayer(packet);
break;
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION: inStream.Read(connection);
Game::playerContainer.RemovePlayer(packet); if (connection != eConnectionType::CHAT) return;
break; inStream.Read(chatMessageID);
case eChatInternalMessageType::MUTE_UPDATE: switch (chatMessageID) {
case MessageType::Chat::GM_MUTE:
Game::playerContainer.MuteUpdate(packet); Game::playerContainer.MuteUpdate(packet);
break; break;
case eChatInternalMessageType::CREATE_TEAM: case MessageType::Chat::CREATE_TEAM:
Game::playerContainer.CreateTeamServer(packet); Game::playerContainer.CreateTeamServer(packet);
break; break;
case eChatInternalMessageType::ANNOUNCEMENT: { case MessageType::Chat::GET_FRIENDS_LIST:
//we just forward this packet to every connected server
CINSTREAM;
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
break;
}
default:
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
eChatMessageType chat_message_type = static_cast<eChatMessageType>(packet->data[3]);
switch (chat_message_type) {
case eChatMessageType::GET_FRIENDS_LIST:
ChatPacketHandler::HandleFriendlistRequest(packet); ChatPacketHandler::HandleFriendlistRequest(packet);
break; break;
case eChatMessageType::GET_IGNORE_LIST: case MessageType::Chat::GET_IGNORE_LIST:
ChatIgnoreList::GetIgnoreList(packet); ChatIgnoreList::GetIgnoreList(packet);
break; break;
case eChatMessageType::ADD_IGNORE: case MessageType::Chat::ADD_IGNORE:
ChatIgnoreList::AddIgnore(packet); ChatIgnoreList::AddIgnore(packet);
break; break;
case eChatMessageType::REMOVE_IGNORE: case MessageType::Chat::REMOVE_IGNORE:
ChatIgnoreList::RemoveIgnore(packet); ChatIgnoreList::RemoveIgnore(packet);
break; break;
case eChatMessageType::TEAM_GET_STATUS: case MessageType::Chat::TEAM_GET_STATUS:
ChatPacketHandler::HandleTeamStatusRequest(packet); ChatPacketHandler::HandleTeamStatusRequest(packet);
break; break;
case eChatMessageType::ADD_FRIEND_REQUEST: case MessageType::Chat::ADD_FRIEND_REQUEST:
//this involves someone sending the initial request, the response is below, response as in from the other player. //this involves someone sending the initial request, the response is below, response as in from the other player.
//We basically just check to see if this player is online or not and route the packet. //We basically just check to see if this player is online or not and route the packet.
ChatPacketHandler::HandleFriendRequest(packet); ChatPacketHandler::HandleFriendRequest(packet);
break; break;
case eChatMessageType::ADD_FRIEND_RESPONSE: case MessageType::Chat::ADD_FRIEND_RESPONSE:
//This isn't the response a server sent, rather it is a player's response to a received request. //This isn't the response a server sent, rather it is a player's response to a received request.
//Here, we'll actually have to add them to eachother's friend lists depending on the response code. //Here, we'll actually have to add them to eachother's friend lists depending on the response code.
ChatPacketHandler::HandleFriendResponse(packet); ChatPacketHandler::HandleFriendResponse(packet);
break; break;
case eChatMessageType::REMOVE_FRIEND: case MessageType::Chat::REMOVE_FRIEND:
ChatPacketHandler::HandleRemoveFriend(packet); ChatPacketHandler::HandleRemoveFriend(packet);
break; break;
case eChatMessageType::GENERAL_CHAT_MESSAGE: case MessageType::Chat::GENERAL_CHAT_MESSAGE:
ChatPacketHandler::HandleChatMessage(packet); ChatPacketHandler::HandleChatMessage(packet);
break; break;
case eChatMessageType::PRIVATE_CHAT_MESSAGE: case MessageType::Chat::PRIVATE_CHAT_MESSAGE:
//This message is supposed to be echo'd to both the sender and the receiver //This message is supposed to be echo'd to both the sender and the receiver
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up. //BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
ChatPacketHandler::HandlePrivateChatMessage(packet); ChatPacketHandler::HandlePrivateChatMessage(packet);
break; break;
case eChatMessageType::TEAM_INVITE: case MessageType::Chat::TEAM_INVITE:
ChatPacketHandler::HandleTeamInvite(packet); ChatPacketHandler::HandleTeamInvite(packet);
break; break;
case eChatMessageType::TEAM_INVITE_RESPONSE: case MessageType::Chat::TEAM_INVITE_RESPONSE:
ChatPacketHandler::HandleTeamInviteResponse(packet); ChatPacketHandler::HandleTeamInviteResponse(packet);
break; break;
case eChatMessageType::TEAM_LEAVE: case MessageType::Chat::TEAM_LEAVE:
ChatPacketHandler::HandleTeamLeave(packet); ChatPacketHandler::HandleTeamLeave(packet);
break; break;
case eChatMessageType::TEAM_SET_LEADER: case MessageType::Chat::TEAM_SET_LEADER:
ChatPacketHandler::HandleTeamPromote(packet); ChatPacketHandler::HandleTeamPromote(packet);
break; break;
case eChatMessageType::TEAM_KICK: case MessageType::Chat::TEAM_KICK:
ChatPacketHandler::HandleTeamKick(packet); ChatPacketHandler::HandleTeamKick(packet);
break; break;
case eChatMessageType::TEAM_SET_LOOT: case MessageType::Chat::TEAM_SET_LOOT:
ChatPacketHandler::HandleTeamLootOption(packet); ChatPacketHandler::HandleTeamLootOption(packet);
break; break;
case eChatMessageType::GMLEVEL_UPDATE: case MessageType::Chat::GMLEVEL_UPDATE:
ChatPacketHandler::HandleGMLevelUpdate(packet); ChatPacketHandler::HandleGMLevelUpdate(packet);
break; break;
case eChatMessageType::LOGIN_SESSION_NOTIFY: case MessageType::Chat::LOGIN_SESSION_NOTIFY:
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE: Game::playerContainer.InsertPlayer(packet);
case eChatMessageType::WORLD_DISCONNECT_REQUEST: break;
case eChatMessageType::WORLD_PROXIMITY_RESPONSE: case MessageType::Chat::GM_ANNOUNCE:{
case eChatMessageType::WORLD_PARCEL_RESPONSE: // we just forward this packet to every connected server
case eChatMessageType::TEAM_MISSED_INVITE_CHECK: inStream.ResetReadPointer();
case eChatMessageType::GUILD_CREATE: Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
case eChatMessageType::GUILD_INVITE: }
case eChatMessageType::GUILD_INVITE_RESPONSE: break;
case eChatMessageType::GUILD_LEAVE: case MessageType::Chat::UNEXPECTED_DISCONNECT:
case eChatMessageType::GUILD_KICK: Game::playerContainer.RemovePlayer(packet);
case eChatMessageType::GUILD_GET_STATUS: break;
case eChatMessageType::GUILD_GET_ALL: case MessageType::Chat::WHO:
case eChatMessageType::SHOW_ALL: ChatPacketHandler::HandleWho(packet);
case eChatMessageType::BLUEPRINT_MODERATED: break;
case eChatMessageType::BLUEPRINT_MODEL_READY: case MessageType::Chat::SHOW_ALL:
case eChatMessageType::PROPERTY_READY_FOR_APPROVAL: ChatPacketHandler::HandleShowAll(packet);
case eChatMessageType::PROPERTY_MODERATION_CHANGED: break;
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED: case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE:
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT: case MessageType::Chat::WORLD_DISCONNECT_REQUEST:
case eChatMessageType::MAIL: case MessageType::Chat::WORLD_PROXIMITY_RESPONSE:
case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST: case MessageType::Chat::WORLD_PARCEL_RESPONSE:
case eChatMessageType::REPUTATION_UPDATE: case MessageType::Chat::TEAM_MISSED_INVITE_CHECK:
case eChatMessageType::SEND_CANNED_TEXT: case MessageType::Chat::GUILD_CREATE:
case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST: case MessageType::Chat::GUILD_INVITE:
case eChatMessageType::CSR_REQUEST: case MessageType::Chat::GUILD_INVITE_RESPONSE:
case eChatMessageType::CSR_REPLY: case MessageType::Chat::GUILD_LEAVE:
case eChatMessageType::GM_KICK: case MessageType::Chat::GUILD_KICK:
case eChatMessageType::GM_ANNOUNCE: case MessageType::Chat::GUILD_GET_STATUS:
case eChatMessageType::WORLD_ROUTE_PACKET: case MessageType::Chat::GUILD_GET_ALL:
case eChatMessageType::GET_ZONE_POPULATIONS: case MessageType::Chat::BLUEPRINT_MODERATED:
case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE: case MessageType::Chat::BLUEPRINT_MODEL_READY:
case eChatMessageType::MATCH_REQUEST: case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL:
case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE: case MessageType::Chat::PROPERTY_MODERATION_CHANGED:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE: case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT: case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT:
case eChatMessageType::UGCC_REQUEST: case MessageType::Chat::MAIL:
case eChatMessageType::WHO: case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST:
case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE: case MessageType::Chat::REPUTATION_UPDATE:
case eChatMessageType::ACHIEVEMENT_NOTIFY: case MessageType::Chat::SEND_CANNED_TEXT:
case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW: case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST:
case eChatMessageType::UNEXPECTED_DISCONNECT: case MessageType::Chat::CSR_REQUEST:
case eChatMessageType::PLAYER_READY: case MessageType::Chat::CSR_REPLY:
case eChatMessageType::GET_DONATION_TOTAL: case MessageType::Chat::GM_KICK:
case eChatMessageType::UPDATE_DONATION: case MessageType::Chat::WORLD_ROUTE_PACKET:
case eChatMessageType::PRG_CSR_COMMAND: case MessageType::Chat::GET_ZONE_POPULATIONS:
case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD: case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE:
case eChatMessageType::UPDATE_FREE_TRIAL_STATUS: case MessageType::Chat::MATCH_REQUEST:
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type); case MessageType::Chat::UGCMANIFEST_REPORT_MISSING_FILE:
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_FILE:
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
case MessageType::Chat::UGCC_REQUEST:
case MessageType::Chat::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
case MessageType::Chat::ACHIEVEMENT_NOTIFY:
case MessageType::Chat::GM_CLOSE_PRIVATE_CHAT_WINDOW:
case MessageType::Chat::PLAYER_READY:
case MessageType::Chat::GET_DONATION_TOTAL:
case MessageType::Chat::UPDATE_DONATION:
case MessageType::Chat::PRG_CSR_COMMAND:
case MessageType::Chat::HEARTBEAT_REQUEST_FROM_WORLD:
case MessageType::Chat::UPDATE_FREE_TRIAL_STATUS:
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID);
break; break;
default: default:
LOG("Unknown CHAT Message id: %i", chat_message_type); LOG("Unknown CHAT Message id: %i", chatMessageID);
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
switch (static_cast<eWorldMessageType>(packet->data[3])) {
case eWorldMessageType::ROUTE_PACKET: {
LOG("Routing packet from world");
break;
}
default:
LOG("Unknown World id: %i", int(packet->data[3]));
}
} }
} }

View File

@@ -9,22 +9,15 @@
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Database.h" #include "Database.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "eGameMasterLevel.h"
#include "ChatPackets.h" #include "ChatPackets.h"
#include "dConfig.h" #include "dConfig.h"
#include "MessageType/Chat.h"
void PlayerContainer::Initialize() { void PlayerContainer::Initialize() {
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends); m_MaxNumberOfBestFriends =
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends); GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends")).value_or(m_MaxNumberOfBestFriends);
} m_MaxNumberOfFriends =
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends")).value_or(m_MaxNumberOfFriends);
PlayerContainer::~PlayerContainer() {
m_Players.clear();
}
PlayerData::PlayerData() {
gmLevel = eGameMasterLevel::CIVILIAN;
} }
TeamData::TeamData() { TeamData::TeamData() {
@@ -43,19 +36,23 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
data.playerID = playerId; data.playerID = playerId;
uint32_t len; uint32_t len;
inStream.Read<uint32_t>(len); if (!inStream.Read<uint32_t>(len)) return;
for (int i = 0; i < len; i++) { if (len > 33) {
char character; inStream.Read<char>(character); LOG("Received a really long player name, probably a fake packet %i.", len);
data.playerName += character; return;
} }
inStream.Read(data.zoneID); data.playerName.resize(len);
inStream.Read(data.muteExpire); inStream.ReadAlignedBytes(reinterpret_cast<unsigned char*>(data.playerName.data()), len);
inStream.Read(data.gmLevel);
if (!inStream.Read(data.zoneID)) return;
if (!inStream.Read(data.muteExpire)) return;
if (!inStream.Read(data.gmLevel)) return;
data.sysAddr = packet->systemAddress; data.sysAddr = packet->systemAddress;
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
m_PlayerCount++;
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID()); LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
@@ -94,6 +91,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
} }
} }
m_PlayerCount--;
LOG("Removed user: %llu", playerID); LOG("Removed user: %llu", playerID);
m_Players.erase(playerID); m_Players.erase(playerID);
@@ -127,6 +125,11 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
size_t membersSize = 0; size_t membersSize = 0;
inStream.Read(membersSize); inStream.Read(membersSize);
if (membersSize >= 4) {
LOG("Tried to create a team with more than 4 players");
return;
}
std::vector<LWOOBJID> members; std::vector<LWOOBJID> members;
members.reserve(membersSize); members.reserve(membersSize);
@@ -145,19 +148,18 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
if (team != nullptr) { if (team != nullptr) {
team->zoneId = zoneId; team->zoneId = zoneId;
UpdateTeamsOnWorld(team, false);
} }
UpdateTeamsOnWorld(team, false);
} }
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) { void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
bitStream.Write(player); bitStream.Write(player);
bitStream.Write(time); bitStream.Write(time);
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) { TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
@@ -359,7 +361,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) { void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
bitStream.Write(team->teamID); bitStream.Write(team->teamID);
bitStream.Write(deleteTeam); bitStream.Write(deleteTeam);
@@ -372,7 +374,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
} }
} }
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
std::u16string PlayerContainer::GetName(LWOOBJID playerID) { std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
@@ -397,7 +399,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
} }
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) { PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
return m_Players[playerID]; return m_Players.contains(playerID) ? m_Players[playerID] : m_Players[LWOOBJID_EMPTY];
} }
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) { PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {

View File

@@ -10,7 +10,7 @@
enum class eGameMasterLevel : uint8_t; enum class eGameMasterLevel : uint8_t;
struct IgnoreData { struct IgnoreData {
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName(name), playerId(id) {} IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {}
inline bool operator==(const std::string& other) const noexcept { inline bool operator==(const std::string& other) const noexcept {
return playerName == other; return playerName == other;
} }
@@ -24,7 +24,6 @@ struct IgnoreData {
}; };
struct PlayerData { struct PlayerData {
PlayerData();
operator bool() const noexcept { operator bool() const noexcept {
return playerID != LWOOBJID_EMPTY; return playerID != LWOOBJID_EMPTY;
} }
@@ -45,7 +44,7 @@ struct PlayerData {
std::string playerName; std::string playerName;
std::vector<FriendData> friends; std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers; std::vector<IgnoreData> ignoredPlayers;
eGameMasterLevel gmLevel; eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN
bool isFTP = false; bool isFTP = false;
}; };
@@ -61,8 +60,6 @@ struct TeamData {
class PlayerContainer { class PlayerContainer {
public: public:
~PlayerContainer();
void Initialize(); void Initialize();
void InsertPlayer(Packet* packet); void InsertPlayer(Packet* packet);
void RemovePlayer(Packet* packet); void RemovePlayer(Packet* packet);
@@ -74,6 +71,9 @@ public:
const PlayerData& GetPlayerData(const std::string& playerName); const PlayerData& GetPlayerData(const std::string& playerName);
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID); PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
PlayerData& GetPlayerDataMutable(const std::string& playerName); PlayerData& GetPlayerDataMutable(const std::string& playerName);
uint32_t GetPlayerCount() { return m_PlayerCount; };
uint32_t GetSimCount() { return m_SimCount; };
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() { return m_Players; };
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members); TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
TeamData* CreateTeam(LWOOBJID leader, bool local = false); TeamData* CreateTeam(LWOOBJID leader, bool local = false);
@@ -96,5 +96,7 @@ private:
std::unordered_map<LWOOBJID, std::u16string> m_Names; std::unordered_map<LWOOBJID, std::u16string> m_Names;
uint32_t m_MaxNumberOfBestFriends = 5; uint32_t m_MaxNumberOfBestFriends = 5;
uint32_t m_MaxNumberOfFriends = 50; uint32_t m_MaxNumberOfFriends = 50;
uint32_t m_PlayerCount = 0;
uint32_t m_SimCount = 0;
}; };

View File

@@ -9,83 +9,63 @@
* AMF3 Deserializer written by EmosewaMC * AMF3 Deserializer written by EmosewaMC
*/ */
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) { std::unique_ptr<AMFBaseValue> AMFDeserialize::Read(RakNet::BitStream& inStream) {
if (!inStream) return nullptr;
AMFBaseValue* returnValue = nullptr;
// Read in the value type from the bitStream // Read in the value type from the bitStream
eAmf marker; eAmf marker;
inStream->Read(marker); inStream.Read(marker);
// Based on the typing, create the value associated with that and return the base value class // Based on the typing, create the value associated with that and return the base value class
switch (marker) { switch (marker) {
case eAmf::Undefined: { case eAmf::Undefined:
returnValue = new AMFBaseValue(); return std::make_unique<AMFBaseValue>();
break; case eAmf::Null:
} return std::make_unique<AMFNullValue>();
case eAmf::False:
case eAmf::Null: { return std::make_unique<AMFBoolValue>(false);
returnValue = new AMFNullValue(); case eAmf::True:
break; return std::make_unique<AMFBoolValue>(true);
} case eAmf::Integer:
return ReadAmfInteger(inStream);
case eAmf::False: { case eAmf::Double:
returnValue = new AMFBoolValue(false); return ReadAmfDouble(inStream);
break; case eAmf::String:
} return ReadAmfString(inStream);
case eAmf::Array:
case eAmf::True: { return ReadAmfArray(inStream);
returnValue = new AMFBoolValue(true);
break;
}
case eAmf::Integer: {
returnValue = ReadAmfInteger(inStream);
break;
}
case eAmf::Double: {
returnValue = ReadAmfDouble(inStream);
break;
}
case eAmf::String: {
returnValue = ReadAmfString(inStream);
break;
}
case eAmf::Array: {
returnValue = ReadAmfArray(inStream);
break;
}
// These values are unimplemented in the live client and will remain unimplemented // These values are unimplemented in the live client and will remain unimplemented
// unless someone modifies the client to allow serializing of these values. // unless someone modifies the client to allow serializing of these values.
case eAmf::XMLDoc: case eAmf::XMLDoc:
[[fallthrough]];
case eAmf::Date: case eAmf::Date:
[[fallthrough]];
case eAmf::Object: case eAmf::Object:
[[fallthrough]];
case eAmf::XML: case eAmf::XML:
[[fallthrough]];
case eAmf::ByteArray: case eAmf::ByteArray:
[[fallthrough]];
case eAmf::VectorInt: case eAmf::VectorInt:
[[fallthrough]];
case eAmf::VectorUInt: case eAmf::VectorUInt:
[[fallthrough]];
case eAmf::VectorDouble: case eAmf::VectorDouble:
[[fallthrough]];
case eAmf::VectorObject: case eAmf::VectorObject:
case eAmf::Dictionary: { [[fallthrough]];
case eAmf::Dictionary:
throw marker; throw marker;
break;
}
default: default:
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker))); throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
break;
} }
return returnValue;
} }
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) { uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
bool byteFlag = true; bool byteFlag = true;
uint32_t actualNumber{}; uint32_t actualNumber{};
uint8_t numberOfBytesRead{}; uint8_t numberOfBytesRead{};
while (byteFlag && numberOfBytesRead < 4) { while (byteFlag && numberOfBytesRead < 4) {
uint8_t byte{}; uint8_t byte{};
inStream->Read(byte); inStream.Read(byte);
// Parse the byte // Parse the byte
if (numberOfBytesRead < 3) { if (numberOfBytesRead < 3) {
byteFlag = byte & static_cast<uint8_t>(1 << 7); byteFlag = byte & static_cast<uint8_t>(1 << 7);
@@ -101,7 +81,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
return actualNumber; return actualNumber;
} }
const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) { const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
auto length = ReadU29(inStream); auto length = ReadU29(inStream);
// Check if this is a reference // Check if this is a reference
bool isReference = length % 2 == 1; bool isReference = length % 2 == 1;
@@ -109,7 +89,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
length = length >> 1; length = length >> 1;
if (isReference) { if (isReference) {
std::string value(length, 0); std::string value(length, 0);
inStream->Read(&value[0], length); inStream.Read(&value[0], length);
// Empty strings are never sent by reference // Empty strings are never sent by reference
if (!value.empty()) accessedElements.push_back(value); if (!value.empty()) accessedElements.push_back(value);
return value; return value;
@@ -119,20 +99,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
} }
} }
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) { std::unique_ptr<AMFDoubleValue> AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
double value; double value;
inStream->Read<double>(value); inStream.Read<double>(value);
return new AMFDoubleValue(value); return std::make_unique<AMFDoubleValue>(value);
} }
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) { std::unique_ptr<AMFArrayValue> AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
auto arrayValue = new AMFArrayValue(); auto arrayValue = std::make_unique<AMFArrayValue>();
// Read size of dense array // Read size of dense array
auto sizeOfDenseArray = (ReadU29(inStream) >> 1); const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
// Then read associative portion // Then read associative portion
while (true) { while (true) {
auto key = ReadString(inStream); const auto key = ReadString(inStream);
// No more associative values when we encounter an empty string key // No more associative values when we encounter an empty string key
if (key.size() == 0) break; if (key.size() == 0) break;
arrayValue->Insert(key, Read(inStream)); arrayValue->Insert(key, Read(inStream));
@@ -144,10 +124,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
return arrayValue; return arrayValue;
} }
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) { std::unique_ptr<AMFStringValue> AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
return new AMFStringValue(ReadString(inStream)); return std::make_unique<AMFStringValue>(ReadString(inStream));
} }
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) { std::unique_ptr<AMFIntValue> AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
return new AMFIntValue(ReadU29(inStream)); return std::make_unique<AMFIntValue>(ReadU29(inStream)); // NOTE: NARROWING CONVERSION FROM UINT TO INT. IS THIS INTENDED?
} }

View File

@@ -1,12 +1,12 @@
#pragma once #pragma once
#include "Amf3.h"
#include "BitStream.h" #include "BitStream.h"
#include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
class AMFBaseValue;
class AMFDeserialize { class AMFDeserialize {
public: public:
/** /**
@@ -15,7 +15,7 @@ public:
* @param inStream inStream to read value from. * @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it. * @return Returns an AMFValue with all the information from the bitStream in it.
*/ */
AMFBaseValue* Read(RakNet::BitStream* inStream); std::unique_ptr<AMFBaseValue> Read(RakNet::BitStream& inStream);
private: private:
/** /**
* @brief Private method to read a U29 integer from a bitstream * @brief Private method to read a U29 integer from a bitstream
@@ -23,7 +23,7 @@ private:
* @param inStream bitstream to read data from * @param inStream bitstream to read data from
* @return The number as an unsigned 29 bit integer * @return The number as an unsigned 29 bit integer
*/ */
uint32_t ReadU29(RakNet::BitStream* inStream); static uint32_t ReadU29(RakNet::BitStream& inStream);
/** /**
* @brief Reads a string from a bitstream * @brief Reads a string from a bitstream
@@ -31,7 +31,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return The read string * @return The read string
*/ */
const std::string ReadString(RakNet::BitStream* inStream); const std::string ReadString(RakNet::BitStream& inStream);
/** /**
* @brief Read an AMFDouble value from a bitStream * @brief Read an AMFDouble value from a bitStream
@@ -39,7 +39,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Double value represented as an AMFValue * @return Double value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream); static std::unique_ptr<AMFDoubleValue> ReadAmfDouble(RakNet::BitStream& inStream);
/** /**
* @brief Read an AMFArray from a bitStream * @brief Read an AMFArray from a bitStream
@@ -47,7 +47,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Array value represented as an AMFValue * @return Array value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream); std::unique_ptr<AMFArrayValue> ReadAmfArray(RakNet::BitStream& inStream);
/** /**
* @brief Read an AMFString from a bitStream * @brief Read an AMFString from a bitStream
@@ -55,7 +55,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return String value represented as an AMFValue * @return String value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream); std::unique_ptr<AMFStringValue> ReadAmfString(RakNet::BitStream& inStream);
/** /**
* @brief Read an AMFInteger from a bitStream * @brief Read an AMFInteger from a bitStream
@@ -63,7 +63,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue * @return Integer value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream); static std::unique_ptr<AMFIntValue> ReadAmfInteger(RakNet::BitStream& inStream);
/** /**
* List of strings read so far saved to be read by reference. * List of strings read so far saved to be read by reference.

View File

@@ -31,54 +31,70 @@ enum class eAmf : uint8_t {
class AMFBaseValue { class AMFBaseValue {
public: public:
virtual eAmf GetValueType() { return eAmf::Undefined; }; [[nodiscard]] constexpr virtual eAmf GetValueType() const noexcept { return eAmf::Undefined; }
AMFBaseValue() {}; constexpr AMFBaseValue() noexcept = default;
virtual ~AMFBaseValue() {}; constexpr virtual ~AMFBaseValue() noexcept = default;
}; };
template<typename ValueType> // AMFValue template class instantiations
template <typename ValueType>
class AMFValue : public AMFBaseValue { class AMFValue : public AMFBaseValue {
public: public:
AMFValue() {}; AMFValue() = default;
AMFValue(ValueType value) { SetValue(value); }; AMFValue(const ValueType value) : m_Data{ value } {}
virtual ~AMFValue() override {};
eAmf GetValueType() override { return eAmf::Undefined; }; virtual ~AMFValue() override = default;
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override;
[[nodiscard]] const ValueType& GetValue() const { return m_Data; }
void SetValue(const ValueType value) { m_Data = value; }
const ValueType& GetValue() { return data; };
void SetValue(ValueType value) { data = value; };
protected: protected:
ValueType data; ValueType m_Data;
}; };
// Explicit template class instantiations
template class AMFValue<std::nullptr_t>;
template class AMFValue<bool>;
template class AMFValue<int32_t>;
template class AMFValue<uint32_t>;
template class AMFValue<std::string>;
template class AMFValue<double>;
// AMFValue template class member function instantiations
template <> [[nodiscard]] constexpr eAmf AMFValue<std::nullptr_t>::GetValueType() const noexcept { return eAmf::Null; }
template <> [[nodiscard]] constexpr eAmf AMFValue<bool>::GetValueType() const noexcept { return m_Data ? eAmf::True : eAmf::False; }
template <> [[nodiscard]] constexpr eAmf AMFValue<int32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<uint32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<std::string>::GetValueType() const noexcept { return eAmf::String; }
template <> [[nodiscard]] constexpr eAmf AMFValue<double>::GetValueType() const noexcept { return eAmf::Double; }
template <typename ValueType>
[[nodiscard]] constexpr eAmf AMFValue<ValueType>::GetValueType() const noexcept { return eAmf::Undefined; }
// As a string this is much easier to write and read from a BitStream. // As a string this is much easier to write and read from a BitStream.
template<> template <>
class AMFValue<const char*> : public AMFBaseValue { class AMFValue<const char*> : public AMFBaseValue {
public: public:
AMFValue() {}; AMFValue() = default;
AMFValue(const char* value) { SetValue(std::string(value)); }; AMFValue(const char* value) { m_Data = value; }
virtual ~AMFValue() override {}; virtual ~AMFValue() override = default;
eAmf GetValueType() override { return eAmf::String; }; [[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::String; }
const std::string& GetValue() { return data; }; [[nodiscard]] const std::string& GetValue() const { return m_Data; }
void SetValue(std::string value) { data = value; }; void SetValue(const std::string& value) { m_Data = value; }
protected: protected:
std::string data; std::string m_Data;
}; };
typedef AMFValue<std::nullptr_t> AMFNullValue; using AMFNullValue = AMFValue<std::nullptr_t>;
typedef AMFValue<bool> AMFBoolValue; using AMFBoolValue = AMFValue<bool>;
typedef AMFValue<int32_t> AMFIntValue; using AMFIntValue = AMFValue<int32_t>;
typedef AMFValue<std::string> AMFStringValue; using AMFStringValue = AMFValue<std::string>;
typedef AMFValue<double> AMFDoubleValue; using AMFDoubleValue = AMFValue<double>;
template<> inline eAmf AMFValue<std::nullptr_t>::GetValueType() { return eAmf::Null; };
template<> inline eAmf AMFValue<bool>::GetValueType() { return this->data ? eAmf::True : eAmf::False; };
template<> inline eAmf AMFValue<int32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<uint32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<std::string>::GetValueType() { return eAmf::String; };
template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; };
/** /**
* The AMFArrayValue object holds 2 types of lists: * The AMFArrayValue object holds 2 types of lists:
@@ -89,37 +105,23 @@ template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; }
* and are not to be deleted by a caller. * and are not to be deleted by a caller.
*/ */
class AMFArrayValue : public AMFBaseValue { class AMFArrayValue : public AMFBaseValue {
using AMFAssociative =
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;
typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative; using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
typedef std::vector<AMFBaseValue*> AMFDense;
public: public:
eAmf GetValueType() override { return eAmf::Array; }; [[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
~AMFArrayValue() override {
for (auto valueToDelete : GetDense()) {
if (valueToDelete) {
delete valueToDelete;
valueToDelete = nullptr;
}
}
for (auto valueToDelete : GetAssociative()) {
if (valueToDelete.second) {
delete valueToDelete.second;
valueToDelete.second = nullptr;
}
}
};
/** /**
* Returns the Associative portion of the object * Returns the Associative portion of the object
*/ */
inline AMFAssociative& GetAssociative() { return this->associative; }; [[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; }
/** /**
* Returns the dense portion of the object * Returns the dense portion of the object
*/ */
inline AMFDense& GetDense() { return this->dense; }; [[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; }
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -135,48 +137,48 @@ public:
* @return The inserted element if the type matched, * @return The inserted element if the type matched,
* or nullptr if a key existed and was not the same type * or nullptr if a key existed and was not the same type
*/ */
template<typename ValueType> template <typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) { [[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
auto element = associative.find(key); const auto element = m_Associative.find(key);
AMFValue<ValueType>* val = nullptr; AMFValue<ValueType>* val = nullptr;
bool found = true; bool found = true;
if (element == associative.end()) { if (element == m_Associative.cend()) {
val = new AMFValue<ValueType>(value); auto newVal = std::make_unique<AMFValue<ValueType>>(value);
associative.insert(std::make_pair(key, val)); val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else { } else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second); val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
}; }
// Associates an array with a string key // Associates an array with a string key
std::pair<AMFBaseValue*, bool> Insert(const std::string& key) { [[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string_view key) {
auto element = associative.find(key); const auto element = m_Associative.find(key);
AMFArrayValue* val = nullptr; AMFArrayValue* val = nullptr;
bool found = true; bool found = true;
if (element == associative.end()) { if (element == m_Associative.cend()) {
val = new AMFArrayValue(); auto newVal = std::make_unique<AMFArrayValue>();
associative.insert(std::make_pair(key, val)); val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else { } else {
val = dynamic_cast<AMFArrayValue*>(element->second); val = dynamic_cast<AMFArrayValue*>(element->second.get());
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
}; }
// Associates an array with an integer key // Associates an array with an integer key
std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) { [[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
AMFArrayValue* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= dense.size()) { if (index >= m_Dense.size()) {
dense.resize(index + 1); m_Dense.resize(index + 1);
val = new AMFArrayValue(); m_Dense.at(index) = std::make_unique<AMFArrayValue>();
dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()), inserted);
}; }
/** /**
* @brief Inserts an AMFValue into the AMFArray key'd by index. * @brief Inserts an AMFValue into the AMFArray key'd by index.
@@ -188,18 +190,16 @@ public:
* @return The inserted element, or nullptr if the type did not match * @return The inserted element, or nullptr if the type did not match
* what was at the index. * what was at the index.
*/ */
template<typename ValueType> template <typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) { [[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
AMFValue<ValueType>* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= this->dense.size()) { if (index >= m_Dense.size()) {
this->dense.resize(index + 1); m_Dense.resize(index + 1);
val = new AMFValue<ValueType>(value); m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
this->dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
}; }
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -210,15 +210,14 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const std::string& key, AMFBaseValue* value) { void Insert(const std::string_view key, std::unique_ptr<AMFBaseValue> value) {
auto element = associative.find(key); const auto element = m_Associative.find(key);
if (element != associative.end() && element->second) { if (element != m_Associative.cend() && element->second) {
delete element->second; element->second = std::move(value);
element->second = value;
} else { } else {
associative.insert(std::make_pair(key, value)); m_Associative.emplace(key, std::move(value));
} }
}; }
/** /**
* Inserts an AMFValue into the associative portion with the given index. * Inserts an AMFValue into the associative portion with the given index.
@@ -229,15 +228,12 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const uint32_t index, AMFBaseValue* value) { void Insert(const size_t index, std::unique_ptr<AMFBaseValue> value) {
if (index < dense.size()) { if (index >= m_Dense.size()) {
AMFDense::iterator itr = dense.begin() + index; m_Dense.resize(index + 1);
if (*itr) delete dense.at(index);
} else {
dense.resize(index + 1);
} }
dense.at(index) = value; m_Dense.at(index) = std::move(value);
}; }
/** /**
* Pushes an AMFValue into the back of the dense portion. * Pushes an AMFValue into the back of the dense portion.
@@ -249,10 +245,10 @@ public:
* *
* @return The inserted pointer, or nullptr should the key already be in use. * @return The inserted pointer, or nullptr should the key already be in use.
*/ */
template<typename ValueType> template <typename ValueType>
inline AMFValue<ValueType>* Push(ValueType value) { [[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) {
return Insert(this->dense.size(), value).first; return Insert(m_Dense.size(), value).first;
}; }
/** /**
* Removes the key from the associative portion * Removes the key from the associative portion
@@ -261,52 +257,47 @@ public:
* *
* @param key The key to remove from the associative portion * @param key The key to remove from the associative portion
*/ */
void Remove(const std::string& key, bool deleteValue = true) { void Remove(const std::string& key, const bool deleteValue = true) {
AMFAssociative::iterator it = this->associative.find(key); const AMFAssociative::const_iterator it = m_Associative.find(key);
if (it != this->associative.end()) { if (it != m_Associative.cend()) {
if (deleteValue) delete it->second; if (deleteValue) m_Associative.erase(it);
this->associative.erase(it);
} }
} }
/** /**
* Pops the last element in the dense portion, deleting it in the process. * Pops the last element in the dense portion, deleting it in the process.
*/ */
void Remove(const uint32_t index) { void Remove(const size_t index) {
if (!this->dense.empty() && index < this->dense.size()) { if (!m_Dense.empty() && index < m_Dense.size()) {
auto itr = this->dense.begin() + index; const auto itr = m_Dense.cbegin() + index;
if (*itr) delete (*itr); m_Dense.erase(itr);
this->dense.erase(itr);
} }
} }
void Pop() { void Pop() {
if (!this->dense.empty()) Remove(this->dense.size() - 1); if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
} }
AMFArrayValue* GetArray(const std::string& key) { [[nodiscard]] AMFArrayValue* GetArray(const std::string_view key) const {
AMFAssociative::const_iterator it = this->associative.find(key); const AMFAssociative::const_iterator it = m_Associative.find(key);
if (it != this->associative.end()) { return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second.get()) : nullptr;
return dynamic_cast<AMFArrayValue*>(it->second); }
}
return nullptr;
};
AMFArrayValue* GetArray(const uint32_t index) { [[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index)); return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()) : nullptr;
}; }
inline AMFArrayValue* InsertArray(const std::string& key) { [[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string_view key) {
return static_cast<AMFArrayValue*>(Insert(key).first); return static_cast<AMFArrayValue*>(Insert(key).first);
}; }
inline AMFArrayValue* InsertArray(const uint32_t index) { [[maybe_unused]] inline AMFArrayValue* InsertArray(const size_t index) {
return static_cast<AMFArrayValue*>(Insert(index).first); return static_cast<AMFArrayValue*>(Insert(index).first);
}; }
inline AMFArrayValue* PushArray() { [[maybe_unused]] inline AMFArrayValue* PushArray() {
return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first); return static_cast<AMFArrayValue*>(Insert(m_Dense.size()).first);
}; }
/** /**
* Gets an AMFValue by the key from the associative portion and converts it * Gets an AMFValue by the key from the associative portion and converts it
@@ -318,18 +309,18 @@ public:
* @return The AMFValue * @return The AMFValue
*/ */
template <typename AmfType> template <typename AmfType>
AMFValue<AmfType>* Get(const std::string& key) const { [[nodiscard]] AMFValue<AmfType>* Get(const std::string_view key) const {
AMFAssociative::const_iterator it = this->associative.find(key); const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != this->associative.end() ? return it != m_Associative.cend() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) : dynamic_cast<AMFValue<AmfType>*>(it->second.get()) :
nullptr; nullptr;
}; }
// Get from the array but dont cast it // Get from the array but dont cast it
AMFBaseValue* Get(const std::string& key) const { [[nodiscard]] AMFBaseValue* Get(const std::string_view key) const {
AMFAssociative::const_iterator it = this->associative.find(key); const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != this->associative.end() ? it->second : nullptr; return it != m_Associative.cend() ? it->second.get() : nullptr;
}; }
/** /**
* @brief Get an AMFValue object at a position in the dense portion. * @brief Get an AMFValue object at a position in the dense portion.
@@ -341,27 +332,28 @@ public:
* @return The casted object, or nullptr. * @return The casted object, or nullptr.
*/ */
template <typename AmfType> template <typename AmfType>
AMFValue<AmfType>* Get(uint32_t index) const { [[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
return index < this->dense.size() ? return index < m_Dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) : dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index).get()) :
nullptr; nullptr;
}; }
// Get from the dense but dont cast it // Get from the dense but dont cast it
AMFBaseValue* Get(const uint32_t index) const { [[nodiscard]] AMFBaseValue* Get(const size_t index) const {
return index < this->dense.size() ? this->dense.at(index) : nullptr; return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
}; }
private: private:
/** /**
* The associative portion. These values are key'd with strings to an AMFValue. * The associative portion. These values are key'd with strings to an AMFValue.
*/ */
AMFAssociative associative; AMFAssociative m_Associative;
/** /**
* The dense portion. These AMFValue's are stored one after * The dense portion. These AMFValue's are stored one after
* another with the most recent addition being at the back. * another with the most recent addition being at the back.
*/ */
AMFDense dense; AMFDense m_Dense;
}; };
#endif //!__AMF3__H__ #endif //!__AMF3__H__

View File

@@ -53,7 +53,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
* A private function to write an value to a RakNet::BitStream * A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
unsigned char b4 = static_cast<unsigned char>(v); unsigned char b4 = static_cast<unsigned char>(v);
if (v < 0x00200000) { if (v < 0x00200000) {
b4 = b4 & 0x7F; b4 = b4 & 0x7F;
@@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b2; unsigned char b2;
v = v >> 7; v = v >> 7;
b2 = static_cast<unsigned char>(v) | 0x80; b2 = static_cast<unsigned char>(v) | 0x80;
bs->Write(b2); bs.Write(b2);
} }
bs->Write(b3); bs.Write(b3);
} }
} else { } else {
unsigned char b1; unsigned char b1;
@@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
v = v >> 7; v = v >> 7;
b1 = static_cast<unsigned char>(v) | 0x80; b1 = static_cast<unsigned char>(v) | 0x80;
bs->Write(b1); bs.Write(b1);
bs->Write(b2); bs.Write(b2);
bs->Write(b3); bs.Write(b3);
} }
bs->Write(b4); bs.Write(b4);
} }
/** /**
* Writes a flag number to a RakNet::BitStream * Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) { void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) {
v = (v << 1) | 0x01; v = (v << 1) | 0x01;
WriteUInt29(bs, v); WriteUInt29(bs, v);
} }
@@ -104,9 +104,9 @@ void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) { void WriteAMFString(RakNet::BitStream& bs, const std::string& str) {
WriteFlagNumber(bs, static_cast<uint32_t>(str.size())); WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
bs->Write(str.c_str(), static_cast<uint32_t>(str.size())); bs.Write(str.c_str(), static_cast<uint32_t>(str.size()));
} }
/** /**
@@ -114,8 +114,8 @@ void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) { void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) {
bs->Write(value); bs.Write(value);
} }
/** /**
@@ -123,8 +123,8 @@ void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) { void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) {
bs->Write(value); bs.Write(value);
} }
/** /**
@@ -132,40 +132,40 @@ void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) { void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) {
bs->Write(value); bs.Write(value);
} }
// Writes an AMFIntegerValue to BitStream // Writes an AMFIntegerValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) { void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
WriteUInt29(this, value.GetValue()); WriteUInt29(*this, value.GetValue());
} }
// Writes an AMFDoubleValue to BitStream // Writes an AMFDoubleValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) { void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
double d = value.GetValue(); double d = value.GetValue();
WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d)); WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d));
} }
// Writes an AMFStringValue to BitStream // Writes an AMFStringValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) { void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
WriteAMFString(this, value.GetValue()); WriteAMFString(*this, value.GetValue());
} }
// Writes an AMFArrayValue to BitStream // Writes an AMFArrayValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) { void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
uint32_t denseSize = value.GetDense().size(); uint32_t denseSize = value.GetDense().size();
WriteFlagNumber(this, denseSize); WriteFlagNumber(*this, denseSize);
auto it = value.GetAssociative().begin(); auto it = value.GetAssociative().begin();
auto end = value.GetAssociative().end(); auto end = value.GetAssociative().end();
while (it != end) { while (it != end) {
WriteAMFString(this, it->first); WriteAMFString(*this, it->first);
this->Write<AMFBaseValue&>(*it->second); this->Write<AMFBaseValue&>(*it->second);
it++; it++;
} }

View File

@@ -30,11 +30,15 @@ foreach(file ${DCOMMON_DCLIENT_SOURCES})
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}") set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
endforeach() endforeach()
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
add_library(dCommon STATIC ${DCOMMON_SOURCES}) add_library(dCommon STATIC ${DCOMMON_SOURCES})
target_include_directories(dCommon
target_link_libraries(dCommon bcrypt dDatabase tinyxml2) PUBLIC "." "dClient" "dEnums"
PRIVATE
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase"
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables"
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase"
"${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include"
)
if (UNIX) if (UNIX)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@@ -65,4 +69,6 @@ else ()
) )
endif () endif ()
target_link_libraries(dCommon ZLIB::ZLIB) target_link_libraries(dCommon
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
INTERFACE dDatabase)

View File

@@ -120,6 +120,8 @@ void CatchUnhandled(int sig) {
if (eptr) std::rethrow_exception(eptr); if (eptr) std::rethrow_exception(eptr);
} catch(const std::exception& e) { } catch(const std::exception& e) {
LOG("Caught exception: '%s'", e.what()); LOG("Caught exception: '%s'", e.what());
} catch (...) {
LOG("Caught unknown exception.");
} }
#ifndef INCLUDE_BACKTRACE #ifndef INCLUDE_BACKTRACE
@@ -199,7 +201,7 @@ void OnTerminate() {
} }
void MakeBacktrace() { void MakeBacktrace() {
struct sigaction sigact; struct sigaction sigact{};
sigact.sa_sigaction = CritErrHdlr; sigact.sa_sigaction = CritErrHdlr;
sigact.sa_flags = SA_RESTART | SA_SIGINFO; sigact.sa_flags = SA_RESTART | SA_SIGINFO;

View File

@@ -8,23 +8,23 @@
#include <map> #include <map>
template <typename T> template <typename T>
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) { static inline size_t MinSize(const size_t size, const std::basic_string_view<T> string) {
if (size == size_t(-1) || size > string.size()) { if (size == SIZE_MAX || size > string.size()) {
return string.size(); return string.size();
} else { } else {
return size; return size;
} }
} }
inline bool IsLeadSurrogate(char16_t c) { inline bool IsLeadSurrogate(const char16_t c) {
return (0xD800 <= c) && (c <= 0xDBFF); return (0xD800 <= c) && (c <= 0xDBFF);
} }
inline bool IsTrailSurrogate(char16_t c) { inline bool IsTrailSurrogate(const char16_t c) {
return (0xDC00 <= c) && (c <= 0xDFFF); return (0xDC00 <= c) && (c <= 0xDFFF);
} }
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) { inline void PushUTF8CodePoint(std::string& ret, const char32_t cp) {
if (cp <= 0x007F) { if (cp <= 0x007F) {
ret.push_back(static_cast<uint8_t>(cp)); ret.push_back(static_cast<uint8_t>(cp));
} else if (cp <= 0x07FF) { } else if (cp <= 0x07FF) {
@@ -46,16 +46,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD; constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
bool _IsSuffixChar(uint8_t c) { bool static _IsSuffixChar(const uint8_t c) {
return (c & 0xC0) == 0x80; return (c & 0xC0) == 0x80;
} }
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
size_t rem = slice.length(); const size_t rem = slice.length();
if (slice.empty()) return false; if (slice.empty()) return false;
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front()); const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
if (rem > 0) { if (rem > 0) {
uint8_t first = bytes[0]; const uint8_t first = bytes[0];
if (first < 0x80) { // 1 byte character if (first < 0x80) { // 1 byte character
out = static_cast<uint32_t>(first & 0x7F); out = static_cast<uint32_t>(first & 0x7F);
slice.remove_prefix(1); slice.remove_prefix(1);
@@ -64,7 +64,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
// middle byte, not valid at start, fall through // middle byte, not valid at start, fall through
} else if (first < 0xE0) { // two byte character } else if (first < 0xE0) { // two byte character
if (rem > 1) { if (rem > 1) {
uint8_t second = bytes[1]; const uint8_t second = bytes[1];
if (_IsSuffixChar(second)) { if (_IsSuffixChar(second)) {
out = (static_cast<uint32_t>(first & 0x1F) << 6) out = (static_cast<uint32_t>(first & 0x1F) << 6)
+ static_cast<uint32_t>(second & 0x3F); + static_cast<uint32_t>(second & 0x3F);
@@ -74,8 +74,8 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
} }
} else if (first < 0xF0) { // three byte character } else if (first < 0xF0) { // three byte character
if (rem > 2) { if (rem > 2) {
uint8_t second = bytes[1]; const uint8_t second = bytes[1];
uint8_t third = bytes[2]; const uint8_t third = bytes[2];
if (_IsSuffixChar(second) && _IsSuffixChar(third)) { if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
out = (static_cast<uint32_t>(first & 0x0F) << 12) out = (static_cast<uint32_t>(first & 0x0F) << 12)
+ (static_cast<uint32_t>(second & 0x3F) << 6) + (static_cast<uint32_t>(second & 0x3F) << 6)
@@ -86,9 +86,9 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
} }
} else if (first < 0xF8) { // four byte character } else if (first < 0xF8) { // four byte character
if (rem > 3) { if (rem > 3) {
uint8_t second = bytes[1]; const uint8_t second = bytes[1];
uint8_t third = bytes[2]; const uint8_t third = bytes[2];
uint8_t fourth = bytes[3]; const uint8_t fourth = bytes[3];
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) { if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
out = (static_cast<uint32_t>(first & 0x07) << 18) out = (static_cast<uint32_t>(first & 0x07) << 18)
+ (static_cast<uint32_t>(second & 0x3F) << 12) + (static_cast<uint32_t>(second & 0x3F) << 12)
@@ -107,7 +107,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
} }
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1> /// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) { bool PushUTF16CodePoint(std::u16string& output, const uint32_t U, const size_t size) {
if (output.length() >= size) return false; if (output.length() >= size) return false;
if (U < 0x10000) { if (U < 0x10000) {
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate. // If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
@@ -120,7 +120,7 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF, // Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
// U' must be less than or equal to 0xFFFFF. That is, U' can be // U' must be less than or equal to 0xFFFFF. That is, U' can be
// represented in 20 bits. // represented in 20 bits.
uint32_t Ut = U - 0x10000; const uint32_t Ut = U - 0x10000;
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and // Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
// 0xDC00, respectively. These integers each have 10 bits free to // 0xDC00, respectively. These integers each have 10 bits free to
@@ -141,25 +141,25 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
} else return false; } else return false;
} }
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) { std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) {
size_t newSize = MinSize(size, string); const size_t newSize = MinSize(size, string);
std::u16string output; std::u16string output;
output.reserve(newSize); output.reserve(newSize);
std::string_view iterator = string; std::string_view iterator = string;
uint32_t c; uint32_t c;
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {} while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
return output; return output;
} }
//! Converts an std::string (ASCII) to UCS-2 / UTF-16 //! Converts an std::string (ASCII) to UCS-2 / UTF-16
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) { std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) {
size_t newSize = MinSize(size, string); const size_t newSize = MinSize(size, string);
std::u16string ret; std::u16string ret;
ret.reserve(newSize); ret.reserve(newSize);
for (size_t i = 0; i < newSize; i++) { for (size_t i = 0; i < newSize; ++i) {
char c = string[i]; const char c = string[i];
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t // Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER); ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
} }
@@ -169,18 +169,18 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8 //! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16> //! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) { std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) {
size_t newSize = MinSize(size, string); const size_t newSize = MinSize(size, string);
std::string ret; std::string ret;
ret.reserve(newSize); ret.reserve(newSize);
for (size_t i = 0; i < newSize; i++) { for (size_t i = 0; i < newSize; ++i) {
char16_t u = string[i]; const char16_t u = string[i];
if (IsLeadSurrogate(u) && (i + 1) < newSize) { if (IsLeadSurrogate(u) && (i + 1) < newSize) {
char16_t next = string[i + 1]; const char16_t next = string[i + 1];
if (IsTrailSurrogate(next)) { if (IsTrailSurrogate(next)) {
i += 1; i += 1;
char32_t cp = 0x10000 const char32_t cp = 0x10000
+ ((static_cast<char32_t>(u) - 0xD800) << 10) + ((static_cast<char32_t>(u) - 0xD800) << 10)
+ (static_cast<char32_t>(next) - 0xDC00); + (static_cast<char32_t>(next) - 0xDC00);
PushUTF8CodePoint(ret, cp); PushUTF8CodePoint(ret, cp);
@@ -195,40 +195,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t
return ret; return ret;
} }
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) { bool GeneralUtils::CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b) {
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); }); return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
} }
// MARK: Bits // MARK: Bits
//! Sets a specific bit in a signed 64-bit integer //! Sets a specific bit in a signed 64-bit integer
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) { int64_t GeneralUtils::SetBit(int64_t value, const uint32_t index) {
return value |= 1ULL << index; return value |= 1ULL << index;
} }
//! Clears a specific bit in a signed 64-bit integer //! Clears a specific bit in a signed 64-bit integer
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) { int64_t GeneralUtils::ClearBit(int64_t value, const uint32_t index) {
return value &= ~(1ULL << index); return value &= ~(1ULL << index);
} }
//! Checks a specific bit in a signed 64-bit integer //! Checks a specific bit in a signed 64-bit integer
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) { bool GeneralUtils::CheckBit(int64_t value, const uint32_t index) {
return value & (1ULL << index); return value & (1ULL << index);
} }
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) { bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) {
size_t start_pos = str.find(from); const size_t start_pos = str.find(from);
if (start_pos == std::string::npos) if (start_pos == std::string::npos)
return false; return false;
str.replace(start_pos, from.length(), to); str.replace(start_pos, from.length(), to);
return true; return true;
} }
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) { std::vector<std::wstring> GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) {
std::vector<std::wstring> vector = std::vector<std::wstring>(); std::vector<std::wstring> vector = std::vector<std::wstring>();
std::wstring current; std::wstring current;
for (const auto& c : str) { for (const wchar_t c : str) {
if (c == delimiter) { if (c == delimiter) {
vector.push_back(current); vector.push_back(current);
current = L""; current = L"";
@@ -237,15 +237,15 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
} }
} }
vector.push_back(current); vector.push_back(std::move(current));
return vector; return vector;
} }
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) { std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) {
std::vector<std::u16string> vector = std::vector<std::u16string>(); std::vector<std::u16string> vector = std::vector<std::u16string>();
std::u16string current; std::u16string current;
for (const auto& c : str) { for (const char16_t c : str) {
if (c == delimiter) { if (c == delimiter) {
vector.push_back(current); vector.push_back(current);
current = u""; current = u"";
@@ -254,17 +254,15 @@ std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str,
} }
} }
vector.push_back(current); vector.push_back(std::move(current));
return vector; return vector;
} }
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) { std::vector<std::string> GeneralUtils::SplitString(const std::string_view str, const char delimiter) {
std::vector<std::string> vector = std::vector<std::string>(); std::vector<std::string> vector = std::vector<std::string>();
std::string current = ""; std::string current = "";
for (size_t i = 0; i < str.length(); i++) { for (const char c : str) {
char c = str[i];
if (c == delimiter) { if (c == delimiter) {
vector.push_back(current); vector.push_back(current);
current = ""; current = "";
@@ -273,53 +271,70 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
} }
} }
vector.push_back(current); vector.push_back(std::move(current));
return vector; return vector;
} }
std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) { std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
uint32_t length; uint32_t length;
inStream->Read<uint32_t>(length); inStream.Read<uint32_t>(length);
std::u16string string; std::u16string string;
for (auto i = 0; i < length; i++) { for (uint32_t i = 0; i < length; ++i) {
uint16_t c; uint16_t c;
inStream->Read(c); inStream.Read(c);
string.push_back(c); string.push_back(c);
} }
return string; return string;
} }
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string_view folder) {
// Because we dont know how large the initial number before the first _ is we need to make it a map like so. // Because we dont know how large the initial number before the first _ is we need to make it a map like so.
std::map<uint32_t, std::string> filenames{}; std::map<uint32_t, std::string> filenames{};
for (auto& t : std::filesystem::directory_iterator(folder)) { for (const auto& t : std::filesystem::directory_iterator(folder)) {
auto filename = t.path().filename().string(); auto filename = t.path().filename().string();
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
filenames.insert(std::make_pair(index, filename)); filenames.emplace(index, std::move(filename));
} }
// Now sort the map by the oldest migration. // Now sort the map by the oldest migration.
std::vector<std::string> sortedFiles{}; std::vector<std::string> sortedFiles{};
auto fileIterator = filenames.begin(); auto fileIterator = filenames.cbegin();
std::map<uint32_t, std::string>::iterator oldest = filenames.begin(); auto oldest = filenames.cbegin();
while (!filenames.empty()) { while (!filenames.empty()) {
if (fileIterator == filenames.end()) { if (fileIterator == filenames.cend()) {
sortedFiles.push_back(oldest->second); sortedFiles.push_back(oldest->second);
filenames.erase(oldest); filenames.erase(oldest);
fileIterator = filenames.begin(); fileIterator = filenames.cbegin();
oldest = filenames.begin(); oldest = filenames.cbegin();
continue; continue;
} }
if (oldest->first > fileIterator->first) oldest = fileIterator; if (oldest->first > fileIterator->first) oldest = fileIterator;
fileIterator++; ++fileIterator;
} }
return sortedFiles; return sortedFiles;
} }
bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) { #if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
// MacOS floating-point parse function specializations
namespace GeneralUtils::details {
template <>
[[nodiscard]] float _parse<float>(const std::string_view str, size_t& parseNum) {
return std::stof(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] double _parse<double>(const std::string_view str, size_t& parseNum) {
return std::stod(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] long double _parse<long double>(const std::string_view str, size_t& parseNum) {
return std::stold(std::string{ str }, &parseNum);
}
} }
#endif

View File

@@ -1,17 +1,21 @@
#pragma once #pragma once
// C++ // C++
#include <stdint.h> #include <charconv>
#include <random> #include <cstdint>
#include <time.h> #include <ctime>
#include <string>
#include <type_traits>
#include <functional> #include <functional>
#include <type_traits> #include <optional>
#include <random>
#include <span>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
#include "BitStream.h" #include "BitStream.h"
#include "NiPoint3.h" #include "NiPoint3.h"
#include "dPlatforms.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
@@ -29,29 +33,31 @@ namespace GeneralUtils {
//! Converts a plain ASCII string to a UTF-16 string //! Converts a plain ASCII string to a UTF-16 string
/*! /*!
\param string The string to convert \param string The string to convert
\param size A size to trim the string to. Default is -1 (No trimming) \param size A size to trim the string to. Default is SIZE_MAX (No trimming)
\return An UTF-16 representation of the string \return An UTF-16 representation of the string
*/ */
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1); std::u16string ASCIIToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
//! Converts a UTF-8 String to a UTF-16 string //! Converts a UTF-8 String to a UTF-16 string
/*! /*!
\param string The string to convert \param string The string to convert
\param size A size to trim the string to. Default is -1 (No trimming) \param size A size to trim the string to. Default is SIZE_MAX (No trimming)
\return An UTF-16 representation of the string \return An UTF-16 representation of the string
*/ */
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1); std::u16string UTF8ToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
//! Internal, do not use namespace details {
bool _NextUTF8Char(std::string_view& slice, uint32_t& out); //! Internal, do not use
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
}
//! Converts a UTF-16 string to a UTF-8 string //! Converts a UTF-16 string to a UTF-8 string
/*! /*!
\param string The string to convert \param string The string to convert
\param size A size to trim the string to. Default is -1 (No trimming) \param size A size to trim the string to. Default is SIZE_MAX (No trimming)
\return An UTF-8 representation of the string \return An UTF-8 representation of the string
*/ */
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1); std::string UTF16ToWTF8(const std::u16string_view string, const size_t size = SIZE_MAX);
/** /**
* Compares two basic strings but does so ignoring case sensitivity * Compares two basic strings but does so ignoring case sensitivity
@@ -59,7 +65,7 @@ namespace GeneralUtils {
* \param b the second string to compare against the first string * \param b the second string to compare against the first string
* @return if the two strings are equal * @return if the two strings are equal
*/ */
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b); bool CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b);
// MARK: Bits // MARK: Bits
@@ -67,9 +73,9 @@ namespace GeneralUtils {
//! Sets a bit on a numerical value //! Sets a bit on a numerical value
template <typename T> template <typename T>
inline void SetBit(T& value, eObjectBits bits) { inline void SetBit(T& value, const eObjectBits bits) {
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type"); static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
auto index = static_cast<size_t>(bits); const auto index = static_cast<size_t>(bits);
if (index > (sizeof(T) * 8) - 1) { if (index > (sizeof(T) * 8) - 1) {
return; return;
} }
@@ -79,9 +85,9 @@ namespace GeneralUtils {
//! Clears a bit on a numerical value //! Clears a bit on a numerical value
template <typename T> template <typename T>
inline void ClearBit(T& value, eObjectBits bits) { inline void ClearBit(T& value, const eObjectBits bits) {
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type"); static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
auto index = static_cast<size_t>(bits); const auto index = static_cast<size_t>(bits);
if (index > (sizeof(T) * 8 - 1)) { if (index > (sizeof(T) * 8 - 1)) {
return; return;
} }
@@ -94,14 +100,14 @@ namespace GeneralUtils {
\param value The value to set the bit for \param value The value to set the bit for
\param index The index of the bit \param index The index of the bit
*/ */
int64_t SetBit(int64_t value, uint32_t index); int64_t SetBit(int64_t value, const uint32_t index);
//! Clears a specific bit in a signed 64-bit integer //! Clears a specific bit in a signed 64-bit integer
/*! /*!
\param value The value to clear the bit from \param value The value to clear the bit from
\param index The index of the bit \param index The index of the bit
*/ */
int64_t ClearBit(int64_t value, uint32_t index); int64_t ClearBit(int64_t value, const uint32_t index);
//! Checks a specific bit in a signed 64-bit integer //! Checks a specific bit in a signed 64-bit integer
/*! /*!
@@ -109,104 +115,151 @@ namespace GeneralUtils {
\param index The index of the bit \param index The index of the bit
\return Whether or not the bit is set \return Whether or not the bit is set
*/ */
bool CheckBit(int64_t value, uint32_t index); bool CheckBit(int64_t value, const uint32_t index);
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); bool ReplaceInString(std::string& str, const std::string_view from, const std::string_view to);
std::u16string ReadWString(RakNet::BitStream* inStream); std::u16string ReadWString(RakNet::BitStream& inStream);
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter); std::vector<std::wstring> SplitString(const std::wstring_view str, const wchar_t delimiter);
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter); std::vector<std::u16string> SplitString(const std::u16string_view str, const char16_t delimiter);
std::vector<std::string> SplitString(const std::string& str, char delimiter); std::vector<std::string> SplitString(const std::string_view str, const char delimiter);
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder); std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
template <typename T> /**
T Parse(const char* value); * Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys
* https://www.reddit.com/r/cpp_questions/comments/12xw3sn/find_stdstring_view_in_unordered_map_with/jhki225/
* https://godbolt.org/z/789xv8Eeq
*/
template <typename... Bases>
struct overload : Bases... {
using is_transparent = void;
using Bases::operator() ... ;
};
template <> struct char_pointer_hash {
inline bool Parse(const char* value) { auto operator()(const char* const ptr) const noexcept {
return std::stoi(value); return std::hash<std::string_view>{}(ptr);
}
template <>
inline int32_t Parse(const char* value) {
return std::stoi(value);
}
template <>
inline int64_t Parse(const char* value) {
return std::stoll(value);
}
template <>
inline float Parse(const char* value) {
return std::stof(value);
}
template <>
inline double Parse(const char* value) {
return std::stod(value);
}
template <>
inline uint16_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint32_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint64_t Parse(const char* value) {
return std::stoull(value);
}
template <>
inline eInventoryType Parse(const char* value) {
return static_cast<eInventoryType>(std::stoul(value));
}
template <>
inline eReplicaComponentType Parse(const char* value) {
return static_cast<eReplicaComponentType>(std::stoul(value));
}
template <typename T>
bool TryParse(const char* value, T& dst) {
try {
dst = Parse<T>(value);
return true;
} catch (...) {
return false;
} }
};
using transparent_string_hash = overload<
std::hash<std::string>,
std::hash<std::string_view>,
char_pointer_hash
>;
// Concept constraining to enum types
template <typename T>
concept Enum = std::is_enum_v<T>;
// Concept constraining to numeric types
template <typename T>
concept Numeric = std::integral<T> || Enum<T> || std::floating_point<T>;
// Concept trickery to enable parsing underlying numeric types
template <Numeric T>
struct numeric_parse { using type = T; };
// If an enum, present an alias to its underlying type for parsing
template <Numeric T> requires Enum<T>
struct numeric_parse<T> { using type = std::underlying_type_t<T>; };
// If a boolean, present an alias to an intermediate integral type for parsing
template <Numeric T> requires std::same_as<T, bool>
struct numeric_parse<T> { using type = uint8_t; };
// Shorthand type alias
template <Numeric T>
using numeric_parse_t = numeric_parse<T>::type;
/**
* For numeric values: Parses a string_view and returns an optional variable depending on the result.
* @param str The string_view to be evaluated
* @returns An std::optional containing the desired value if it is equivalent to the string
*/
template <Numeric T>
[[nodiscard]] std::optional<T> TryParse(std::string_view str) {
numeric_parse_t<T> result;
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
const char* const strEnd = str.data() + str.size();
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
const bool isParsed = parseEnd == strEnd && ec == std::errc{};
return isParsed ? static_cast<T>(result) : std::optional<T>{};
}
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
// MacOS floating-point parse helper function specializations
namespace details {
template <std::floating_point T>
[[nodiscard]] T _parse(const std::string_view str, size_t& parseNum);
}
/**
* For floating-point values: Parses a string_view and returns an optional variable depending on the result.
* Note that this function overload is only included for MacOS, as from_chars will fulfill its purpose otherwise.
* @param str The string_view to be evaluated
* @returns An std::optional containing the desired value if it is equivalent to the string
*/
template <std::floating_point T>
[[nodiscard]] std::optional<T> TryParse(std::string_view str) noexcept
try {
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
size_t parseNum;
const T result = details::_parse<T>(str, parseNum);
const bool isParsed = str.length() == parseNum;
return isParsed ? result : std::optional<T>{};
} catch (...) {
return std::nullopt;
}
#endif
/**
* The TryParse overload for handling NiPoint3 by passing 3 seperate string references
* @param strX The string representing the X coordinate
* @param strY The string representing the Y coordinate
* @param strZ The string representing the Z coordinate
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) {
const auto x = TryParse<float>(strX);
if (!x) return std::nullopt;
const auto y = TryParse<float>(strY);
if (!y) return std::nullopt;
const auto z = TryParse<float>(strZ);
return z ? std::make_optional<NiPoint3>(x.value(), y.value(), z.value()) : std::nullopt;
}
/**
* The TryParse overload for handling NiPoint3 by passing a span of three strings
* @param str The string vector representing the X, Y, and Z coordinates
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::span<const std::string> str) {
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
} }
template <typename T> template <typename T>
T Parse(const std::string& value) { std::u16string to_u16string(const T value) {
return Parse<T>(value.c_str());
}
template <typename T>
bool TryParse(const std::string& value, T& dst) {
return TryParse<T>(value.c_str(), dst);
}
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
template<typename T>
std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value)); return GeneralUtils::ASCIIToUTF16(std::to_string(value));
} }
// From boost::hash_combine // From boost::hash_combine
template <class T> template <class T>
void hash_combine(std::size_t& s, const T& v) { constexpr void hash_combine(std::size_t& s, const T& v) {
std::hash<T> h; std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
} }
@@ -219,7 +272,7 @@ namespace GeneralUtils {
\param max The maximum to generate to \param max The maximum to generate to
*/ */
template <typename T> template <typename T>
inline T GenerateRandomNumber(std::size_t min, std::size_t max) { inline T GenerateRandomNumber(const std::size_t min, const std::size_t max) {
// Make sure it is a numeric type // Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type"); static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
@@ -239,19 +292,17 @@ namespace GeneralUtils {
* @param entry Enum entry to cast * @param entry Enum entry to cast
* @returns The enum entry's value in its underlying type * @returns The enum entry's value in its underlying type
*/ */
template <typename eType> template <Enum eType>
inline constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) { constexpr std::underlying_type_t<eType> ToUnderlying(const eType entry) noexcept {
static_assert(std::is_enum_v<eType>, "Not an enum"); return static_cast<std::underlying_type_t<eType>>(entry);
return static_cast<typename std::underlying_type_t<eType>>(entry);
} }
// on Windows we need to undef these or else they conflict with our numeric limits calls // on Windows we need to undef these or else they conflict with our numeric limits calls
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS // DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
#ifdef _WIN32 #ifdef _WIN32
#undef min #undef min
#undef max #undef max
#endif #endif
template <typename T> template <typename T>
inline T GenerateRandomNumber() { inline T GenerateRandomNumber() {

92
dCommon/Implementation.h Normal file
View File

@@ -0,0 +1,92 @@
#ifndef __IMPLEMENTATION_H__
#define __IMPLEMENTATION_H__
#include <functional>
#include <optional>
/**
* @brief A way to defer the implementation of an action.
*
* @tparam R The result of the action.
* @tparam T The types of the arguments that the implementation requires.
*/
template <typename R, typename... T>
class Implementation {
public:
typedef std::function<std::optional<R>(T...)> ImplementationFunction;
/**
* @brief Sets the implementation of the action.
*
* @param implementation The implementation of the action.
*/
void SetImplementation(const ImplementationFunction& implementation) {
this->implementation = implementation;
}
/**
* @brief Clears the implementation of the action.
*/
void ClearImplementation() {
implementation.reset();
}
/**
* @brief Checks if the implementation is set.
*
* @return true If the implementation is set.
* @return false If the implementation is not set.
*/
bool IsSet() const {
return implementation.has_value();
}
/**
* @brief Executes the implementation if it is set.
*
* @param args The arguments to pass to the implementation.
* @return std::optional<R> The optional result of the implementation. If the result is not set, it indicates that the default action should be taken.
*/
std::optional<R> Execute(T... args) const {
return IsSet() ? implementation.value()(args...) : std::nullopt;
}
/**
* @brief Exectues the implementation if it is set, otherwise returns a default value.
*
* @param args The arguments to pass to the implementation.
* @param defaultValue The default value to return if the implementation is not set or should not be deferred.
*/
R ExecuteWithDefault(T... args, const R& defaultValue) const {
return Execute(args...).value_or(defaultValue);
}
/**
* = operator overload.
*/
Implementation& operator=(const Implementation& other) {
implementation = other.implementation;
return *this;
}
/**
* = operator overload.
*/
Implementation& operator=(const ImplementationFunction& implementation) {
this->implementation = implementation;
return *this;
}
/**
* () operator overload.
*/
std::optional<R> operator()(T... args) {
return !IsSet() ? std::nullopt : implementation(args...);
}
private:
std::optional<ImplementationFunction> implementation;
};
#endif //!__IMPLEMENTATION_H__

View File

@@ -61,33 +61,33 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_S32: { case LDF_TYPE_S32: {
int32_t data; const auto data = GeneralUtils::TryParse<int32_t>(ldfTypeAndValue.second);
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { if (!data) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<int32_t>(key, data); returnValue = new LDFData<int32_t>(key, data.value());
break; break;
} }
case LDF_TYPE_FLOAT: { case LDF_TYPE_FLOAT: {
float data; const auto data = GeneralUtils::TryParse<float>(ldfTypeAndValue.second);
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { if (!data) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<float>(key, data); returnValue = new LDFData<float>(key, data.value());
break; break;
} }
case LDF_TYPE_DOUBLE: { case LDF_TYPE_DOUBLE: {
double data; const auto data = GeneralUtils::TryParse<double>(ldfTypeAndValue.second);
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { if (!data) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<double>(key, data); returnValue = new LDFData<double>(key, data.value());
break; break;
} }
@@ -100,10 +100,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = 0; data = 0;
} else { } else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { const auto dataOptional = GeneralUtils::TryParse<uint32_t>(ldfTypeAndValue.second);
if (!dataOptional) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<uint32_t>(key, data); returnValue = new LDFData<uint32_t>(key, data);
@@ -118,10 +120,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = false; data = false;
} else { } else {
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { const auto dataOptional = GeneralUtils::TryParse<bool>(ldfTypeAndValue.second);
if (!dataOptional) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<bool>(key, data); returnValue = new LDFData<bool>(key, data);
@@ -129,22 +133,22 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_U64: { case LDF_TYPE_U64: {
uint64_t data; const auto data = GeneralUtils::TryParse<uint64_t>(ldfTypeAndValue.second);
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { if (!data) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<uint64_t>(key, data); returnValue = new LDFData<uint64_t>(key, data.value());
break; break;
} }
case LDF_TYPE_OBJID: { case LDF_TYPE_OBJID: {
LWOOBJID data; const auto data = GeneralUtils::TryParse<LWOOBJID>(ldfTypeAndValue.second);
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) { if (!data) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<LWOOBJID>(key, data); returnValue = new LDFData<LWOOBJID>(key, data.value());
break; break;
} }

View File

@@ -31,22 +31,22 @@ public:
virtual ~LDFBaseData() {} virtual ~LDFBaseData() {}
virtual void WriteToPacket(RakNet::BitStream* packet) = 0; virtual void WriteToPacket(RakNet::BitStream& packet) const = 0;
virtual const std::u16string& GetKey() = 0; virtual const std::u16string& GetKey() const = 0;
virtual eLDFType GetValueType() = 0; virtual eLDFType GetValueType() const = 0;
/** Gets a string from the key/value pair /** Gets a string from the key/value pair
* @param includeKey Whether or not to include the key in the data * @param includeKey Whether or not to include the key in the data
* @param includeTypeId Whether or not to include the type id in the data * @param includeTypeId Whether or not to include the type id in the data
* @return The string representation of the data * @return The string representation of the data
*/ */
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0; virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) const = 0;
virtual std::string GetValueAsString() = 0; virtual std::string GetValueAsString() const = 0;
virtual LDFBaseData* Copy() = 0; virtual LDFBaseData* Copy() const = 0;
/** /**
* Given an input string, return the data as a LDF key. * Given an input string, return the data as a LDF key.
@@ -62,17 +62,17 @@ private:
T value; T value;
//! Writes the key to the packet //! Writes the key to the packet
void WriteKey(RakNet::BitStream* packet) { void WriteKey(RakNet::BitStream& packet) const {
packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t)); packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
for (uint32_t i = 0; i < this->key.length(); ++i) { for (uint32_t i = 0; i < this->key.length(); ++i) {
packet->Write<uint16_t>(this->key[i]); packet.Write<uint16_t>(this->key[i]);
} }
} }
//! Writes the value to the packet //! Writes the value to the packet
void WriteValue(RakNet::BitStream* packet) { void WriteValue(RakNet::BitStream& packet) const {
packet->Write<uint8_t>(this->GetValueType()); packet.Write<uint8_t>(this->GetValueType());
packet->Write(this->value); packet.Write(this->value);
} }
public: public:
@@ -90,7 +90,7 @@ public:
/*! /*!
\return The value \return The value
*/ */
const T& GetValue(void) { return this->value; } const T& GetValue(void) const { return this->value; }
//! Sets the value //! Sets the value
/*! /*!
@@ -102,13 +102,13 @@ public:
/*! /*!
\return The value string \return The value string
*/ */
std::string GetValueString(void) { return ""; } std::string GetValueString(void) const { return ""; }
//! Writes the data to a packet //! Writes the data to a packet
/*! /*!
\param packet The packet \param packet The packet
*/ */
void WriteToPacket(RakNet::BitStream* packet) override { void WriteToPacket(RakNet::BitStream& packet) const override {
this->WriteKey(packet); this->WriteKey(packet);
this->WriteValue(packet); this->WriteValue(packet);
} }
@@ -117,13 +117,13 @@ public:
/*! /*!
\return The key \return The key
*/ */
const std::u16string& GetKey(void) override { return this->key; } const std::u16string& GetKey(void) const override { return this->key; }
//! Gets the LDF Type //! Gets the LDF Type
/*! /*!
\return The LDF value type \return The LDF value type
*/ */
eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; } eLDFType GetValueType(void) const override { return LDF_TYPE_UNKNOWN; }
//! Gets the string data //! Gets the string data
/*! /*!
@@ -131,7 +131,7 @@ public:
\param includeTypeId Whether or not to include the type id in the data \param includeTypeId Whether or not to include the type id in the data
\return The string representation of the data \return The string representation of the data
*/ */
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override { std::string GetString(const bool includeKey = true, const bool includeTypeId = true) const override {
if (GetValueType() == -1) { if (GetValueType() == -1) {
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>"; return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
} }
@@ -154,70 +154,70 @@ public:
return stream.str(); return stream.str();
} }
std::string GetValueAsString() override { std::string GetValueAsString() const override {
return this->GetValueString(); return this->GetValueString();
} }
LDFBaseData* Copy() override { LDFBaseData* Copy() const override {
return new LDFData<T>(key, value); return new LDFData<T>(key, value);
} }
inline static T Default = {}; inline static const T Default = {};
}; };
// LDF Types // LDF Types
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) { return LDF_TYPE_UTF_16; }; template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) const { return LDF_TYPE_UTF_16; };
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) { return LDF_TYPE_S32; }; template<> inline eLDFType LDFData<int32_t>::GetValueType(void) const { return LDF_TYPE_S32; };
template<> inline eLDFType LDFData<float>::GetValueType(void) { return LDF_TYPE_FLOAT; }; template<> inline eLDFType LDFData<float>::GetValueType(void) const { return LDF_TYPE_FLOAT; };
template<> inline eLDFType LDFData<double>::GetValueType(void) { return LDF_TYPE_DOUBLE; }; template<> inline eLDFType LDFData<double>::GetValueType(void) const { return LDF_TYPE_DOUBLE; };
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) { return LDF_TYPE_U32; }; template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) const { return LDF_TYPE_U32; };
template<> inline eLDFType LDFData<bool>::GetValueType(void) { return LDF_TYPE_BOOLEAN; }; template<> inline eLDFType LDFData<bool>::GetValueType(void) const { return LDF_TYPE_BOOLEAN; };
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) { return LDF_TYPE_U64; }; template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) const { return LDF_TYPE_U64; };
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) { return LDF_TYPE_OBJID; }; template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) const { return LDF_TYPE_OBJID; };
template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF_TYPE_UTF_8; }; template<> inline eLDFType LDFData<std::string>::GetValueType(void) const { return LDF_TYPE_UTF_8; };
// The specialized version for std::u16string (UTF-16) // The specialized version for std::u16string (UTF-16)
template<> template<>
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) { inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) const {
packet->Write<uint8_t>(this->GetValueType()); packet.Write<uint8_t>(this->GetValueType());
packet->Write<uint32_t>(this->value.length()); packet.Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet->Write<uint16_t>(this->value[i]); packet.Write<uint16_t>(this->value[i]);
} }
} }
// The specialized version for bool // The specialized version for bool
template<> template<>
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) { inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) const {
packet->Write<uint8_t>(this->GetValueType()); packet.Write<uint8_t>(this->GetValueType());
packet->Write<uint8_t>(this->value); packet.Write<uint8_t>(this->value);
} }
// The specialized version for std::string (UTF-8) // The specialized version for std::string (UTF-8)
template<> template<>
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) { inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) const {
packet->Write<uint8_t>(this->GetValueType()); packet.Write<uint8_t>(this->GetValueType());
packet->Write<uint32_t>(this->value.length()); packet.Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet->Write<uint8_t>(this->value[i]); packet.Write<uint8_t>(this->value[i]);
} }
} }
template<> inline std::string LDFData<std::u16string>::GetValueString() { template<> inline std::string LDFData<std::u16string>::GetValueString() const {
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size()); return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
} }
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<int32_t>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<float>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<double>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<double>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<uint32_t>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<uint32_t>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<bool>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<bool>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<uint64_t>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<uint64_t>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<LWOOBJID>::GetValueString() { return std::to_string(this->value); } template<> inline std::string LDFData<LWOOBJID>::GetValueString() const { return std::to_string(this->value); }
template<> inline std::string LDFData<std::string>::GetValueString() { return this->value; } template<> inline std::string LDFData<std::string>::GetValueString() const { return this->value; }
#endif //!__LDFFORMAT__H__ #endif //!__LDFFORMAT__H__

73
dCommon/Observable.h Normal file
View File

@@ -0,0 +1,73 @@
#ifndef __OBSERVABLE_H__
#define __OBSERVABLE_H__
#include <vector>
#include <functional>
/**
* @brief An event which can be observed by multiple observers.
*
* @tparam T The types of the arguments to be passed to the observers.
*/
template <typename... T>
class Observable {
public:
typedef std::function<void(T...)> Observer;
/**
* @brief Adds an observer to the event.
*
* @param observer The observer to add.
*/
void AddObserver(const Observer& observer) {
observers.push_back(observer);
}
/**
* @brief Removes an observer from the event.
*
* @param observer The observer to remove.
*/
void RemoveObserver(const Observer& observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
/**
* @brief Notifies all observers of the event.
*
* @param args The arguments to pass to the observers.
*/
void Notify(T... args) {
for (const auto& observer : observers) {
observer(args...);
}
}
/**
* += operator overload.
*/
Observable& operator+=(const Observer& observer) {
AddObserver(observer);
return *this;
}
/**
* -= operator overload.
*/
Observable& operator-=(const Observer& observer) {
RemoveObserver(observer);
return *this;
}
/**
* () operator overload.
*/
void operator()(T... args) {
Notify(args...);
}
private:
std::vector<Observer> observers;
};
#endif //!__OBSERVABLE_H__

View File

@@ -6,28 +6,14 @@
struct RemoteInputInfo { struct RemoteInputInfo {
RemoteInputInfo() {
m_RemoteInputX = 0;
m_RemoteInputY = 0;
m_IsPowersliding = false;
m_IsModified = false;
}
void operator=(const RemoteInputInfo& other) {
m_RemoteInputX = other.m_RemoteInputX;
m_RemoteInputY = other.m_RemoteInputY;
m_IsPowersliding = other.m_IsPowersliding;
m_IsModified = other.m_IsModified;
}
bool operator==(const RemoteInputInfo& other) { bool operator==(const RemoteInputInfo& other) {
return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified; return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified;
} }
float m_RemoteInputX; float m_RemoteInputX = 0;
float m_RemoteInputY; float m_RemoteInputY = 0;
bool m_IsPowersliding; bool m_IsPowersliding = false;
bool m_IsModified; bool m_IsModified = false;
}; };
struct LocalSpaceInfo { struct LocalSpaceInfo {

View File

@@ -1,6 +1,6 @@
set(DCOMMON_DCLIENT_SOURCES set(DCOMMON_DCLIENT_SOURCES
"AssetManager.cpp"
"PackIndex.cpp" "PackIndex.cpp"
"Pack.cpp" "Pack.cpp"
"AssetManager.cpp"
PARENT_SCOPE PARENT_SCOPE
) )

View File

@@ -0,0 +1,12 @@
#ifndef __CLIENTVERSION_H__
#define __CLIENTVERSION_H__
#include <cstdint>
namespace ClientVersion {
constexpr uint16_t major = 1;
constexpr uint16_t current = 10;
constexpr uint16_t minor = 64;
}
#endif // !__CLIENTVERSION_H__

View File

@@ -1,6 +1,7 @@
#include "dConfig.h" #include "dConfig.h"
#include <sstream> #include <sstream>
#include <algorithm>
#include "BinaryPathFinder.h" #include "BinaryPathFinder.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"

View File

@@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
namespace MessageType {
enum class Auth : uint32_t {
LOGIN_REQUEST = 0,
LOGOUT_REQUEST,
CREATE_NEW_ACCOUNT_REQUEST,
LEGOINTERFACE_AUTH_RESPONSE,
SESSIONKEY_RECEIVED_CONFIRM,
RUNTIME_CONFIG
};
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <cstdint>
namespace MessageType {
//! The Internal Chat Packet Identifiers
enum class Chat : uint32_t {
LOGIN_SESSION_NOTIFY = 0,
GENERAL_CHAT_MESSAGE,
PRIVATE_CHAT_MESSAGE,
USER_CHANNEL_CHAT_MESSAGE,
WORLD_DISCONNECT_REQUEST,
WORLD_PROXIMITY_RESPONSE,
WORLD_PARCEL_RESPONSE,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND,
GET_FRIENDS_LIST,
ADD_IGNORE,
REMOVE_IGNORE,
GET_IGNORE_LIST,
TEAM_MISSED_INVITE_CHECK,
TEAM_INVITE,
TEAM_INVITE_RESPONSE,
TEAM_KICK,
TEAM_LEAVE,
TEAM_SET_LOOT,
TEAM_SET_LEADER,
TEAM_GET_STATUS,
GUILD_CREATE,
GUILD_INVITE,
GUILD_INVITE_RESPONSE,
GUILD_LEAVE,
GUILD_KICK,
GUILD_GET_STATUS,
GUILD_GET_ALL,
SHOW_ALL,
BLUEPRINT_MODERATED,
BLUEPRINT_MODEL_READY,
PROPERTY_READY_FOR_APPROVAL,
PROPERTY_MODERATION_CHANGED,
PROPERTY_BUILDMODE_CHANGED,
PROPERTY_BUILDMODE_CHANGED_REPORT,
MAIL,
WORLD_INSTANCE_LOCATION_REQUEST,
REPUTATION_UPDATE,
SEND_CANNED_TEXT,
GMLEVEL_UPDATE,
CHARACTER_NAME_CHANGE_REQUEST,
CSR_REQUEST,
CSR_REPLY,
GM_KICK,
GM_ANNOUNCE,
GM_MUTE,
ACTIVITY_UPDATE,
WORLD_ROUTE_PACKET,
GET_ZONE_POPULATIONS,
REQUEST_MINIMUM_CHAT_MODE,
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
MATCH_REQUEST,
UGCMANIFEST_REPORT_MISSING_FILE,
UGCMANIFEST_REPORT_DONE_FILE,
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
UGCC_REQUEST,
WHO,
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
ACHIEVEMENT_NOTIFY,
GM_CLOSE_PRIVATE_CHAT_WINDOW,
UNEXPECTED_DISCONNECT,
PLAYER_READY,
GET_DONATION_TOTAL,
UPDATE_DONATION,
PRG_CSR_COMMAND,
HEARTBEAT_REQUEST_FROM_WORLD,
UPDATE_FREE_TRIAL_STATUS,
// CUSTOM DLU MESSAGE ID FOR INTERNAL USE
CREATE_TEAM,
};
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <cstdint>
namespace MessageType {
enum class Client : uint32_t {
LOGIN_RESPONSE = 0,
LOGOUT_RESPONSE,
LOAD_STATIC_ZONE,
CREATE_OBJECT,
CREATE_CHARACTER,
CREATE_CHARACTER_EXTENDED,
CHARACTER_LIST_RESPONSE,
CHARACTER_CREATE_RESPONSE,
CHARACTER_RENAME_RESPONSE,
CHAT_CONNECT_RESPONSE,
AUTH_ACCOUNT_CREATE_RESPONSE,
DELETE_CHARACTER_RESPONSE,
GAME_MSG,
CONNECT_CHAT,
TRANSFER_TO_WORLD,
IMPENDING_RELOAD_NOTIFY,
MAKE_GM_RESPONSE,
HTTP_MONITOR_INFO_RESPONSE,
SLASH_PUSH_MAP_RESPONSE,
SLASH_PULL_MAP_RESPONSE,
SLASH_LOCK_MAP_RESPONSE,
BLUEPRINT_SAVE_RESPONSE,
BLUEPRINT_LUP_SAVE_RESPONSE,
BLUEPRINT_LOAD_RESPONSE_ITEMID,
BLUEPRINT_GET_ALL_DATA_RESPONSE,
MODEL_INSTANTIATE_RESPONSE,
DEBUG_OUTPUT,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND_RESPONSE,
GET_FRIENDS_LIST_RESPONSE,
UPDATE_FRIEND_NOTIFY,
ADD_IGNORE_RESPONSE,
REMOVE_IGNORE_RESPONSE,
GET_IGNORE_LIST_RESPONSE,
TEAM_INVITE,
TEAM_INVITE_INITIAL_RESPONSE,
GUILD_CREATE_RESPONSE,
GUILD_GET_STATUS_RESPONSE,
GUILD_INVITE,
GUILD_INVITE_INITIAL_RESPONSE,
GUILD_INVITE_FINAL_RESPONSE,
GUILD_INVITE_CONFIRM,
GUILD_ADD_PLAYER,
GUILD_REMOVE_PLAYER,
GUILD_LOGIN_LOGOUT,
GUILD_RANK_CHANGE,
GUILD_DATA,
GUILD_STATUS,
MAIL,
DB_PROXY_RESULT,
SHOW_ALL_RESPONSE,
WHO_RESPONSE,
SEND_CANNED_TEXT,
UPDATE_CHARACTER_NAME,
SET_NETWORK_SIMULATOR,
INVALID_CHAT_MESSAGE,
MINIMUM_CHAT_MODE_RESPONSE,
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
CHAT_MODERATION_STRING,
UGC_MANIFEST_RESPONSE,
IN_LOGIN_QUEUE,
SERVER_STATES,
GM_CLOSE_TARGET_CHAT_WINDOW,
GENERAL_TEXT_FOR_LOCALIZATION,
UPDATE_FREE_TRIAL_STATUS,
UGC_DOWNLOAD_FAILED = 120
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
namespace MessageType {
enum class Master : uint32_t {
REQUEST_PERSISTENT_ID = 1,
REQUEST_PERSISTENT_ID_RESPONSE,
REQUEST_ZONE_TRANSFER,
REQUEST_ZONE_TRANSFER_RESPONSE,
SERVER_INFO,
REQUEST_SESSION_KEY,
SET_SESSION_KEY,
SESSION_KEY_RESPONSE,
PLAYER_ADDED,
PLAYER_REMOVED,
CREATE_PRIVATE_ZONE,
REQUEST_PRIVATE_ZONE,
WORLD_READY,
PREP_ZONE,
SHUTDOWN,
SHUTDOWN_RESPONSE,
SHUTDOWN_IMMEDIATE,
SHUTDOWN_UNIVERSE,
AFFIRM_TRANSFER_REQUEST,
AFFIRM_TRANSFER_RESPONSE,
NEW_SESSION_ALERT
};
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <cstdint>
namespace MessageType {
//! The Internal Server Packet Identifiers
enum class Server : uint32_t {
VERSION_CONFIRM = 0,
DISCONNECT_NOTIFY,
GENERAL_NOTIFY
};
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include <cstdint>
#include "magic_enum.hpp"
namespace MessageType {
enum class World : uint32_t {
VALIDATION = 1, // Session info
CHARACTER_LIST_REQUEST,
CHARACTER_CREATE_REQUEST,
LOGIN_REQUEST, // Character selected
GAME_MSG,
CHARACTER_DELETE_REQUEST,
CHARACTER_RENAME_REQUEST,
HAPPY_FLOWER_MODE_NOTIFY,
SLASH_RELOAD_MAP, // Reload map cmp
SLASH_PUSH_MAP_REQUEST, // Push map req cmd
SLASH_PUSH_MAP, // Push map cmd
SLASH_PULL_MAP, // Pull map cmd
LOCK_MAP_REQUEST,
GENERAL_CHAT_MESSAGE, // General chat message
HTTP_MONITOR_INFO_REQUEST,
SLASH_DEBUG_SCRIPTS, // Debug scripts cmd
MODELS_CLEAR,
EXHIBIT_INSERT_MODEL,
LEVEL_LOAD_COMPLETE, // Character data request
TMP_GUILD_CREATE,
ROUTE_PACKET, // Social?
POSITION_UPDATE,
MAIL,
WORD_CHECK, // AllowList word check
STRING_CHECK, // AllowList string check
GET_PLAYERS_IN_ZONE,
REQUEST_UGC_MANIFEST_INFO,
BLUEPRINT_GET_ALL_DATA_REQUEST,
CANCEL_MAP_QUEUE,
HANDLE_FUNNESS,
FAKE_PRG_CSR_MESSAGE,
REQUEST_FREE_TRIAL_REFRESH,
GM_SET_FREE_TRIAL_STATUS,
UI_HELP_TOP_5 = 91
};
}
template <>
struct magic_enum::customize::enum_range<MessageType::World> {
static constexpr int min = 0;
static constexpr int max = 91;
};

View File

@@ -8,7 +8,7 @@
#include <set> #include <set>
#include "BitStream.h" #include "BitStream.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eClientMessageType.h" #include "MessageType/Client.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#pragma warning (disable:4251) //Disables SQL warnings #pragma warning (disable:4251) //Disables SQL warnings
@@ -33,92 +33,90 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
#define CBITSTREAM RakNet::BitStream bitStream; #define CBITSTREAM RakNet::BitStream bitStream;
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); #define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); #define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); #define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GAME_MSG);
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false); #define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); #define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
//=========== TYPEDEFS ========== //=========== TYPEDEFS ==========
typedef int32_t LOT; //!< A LOT using LOT = int32_t; //!< A LOT
typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok) using LWOOBJID = int64_t; //!< An object ID (should be unsigned actually but ok)
typedef int32_t TSkillID; //!< A skill ID using TSkillID = int32_t; //!< A skill ID
typedef uint32_t LWOCLONEID; //!< Used for Clone IDs using LWOCLONEID = uint32_t; //!< Used for Clone IDs
typedef uint16_t LWOMAPID; //!< Used for Map IDs using LWOMAPID = uint16_t; //!< Used for Map IDs
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs using LWOINSTANCEID = uint16_t; //!< Used for Instance IDs
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs using PROPERTYCLONELIST = uint32_t; //!< Used for Property Clone IDs
typedef uint32_t StripId; using StripId = uint32_t;
const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID constexpr LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
const LOT LOT_NULL = -1; //!< A null LOT constexpr LOT LOT_NULL = -1; //!< A null LOT
const int32_t LOOTTYPE_NONE = 0; //!< No loot type available constexpr int32_t LOOTTYPE_NONE = 0; //!< No loot type available
const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority constexpr float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size constexpr uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID constexpr LWOCLONEID LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID constexpr LWOINSTANCEID LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID constexpr LWOMAPID LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID constexpr uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
const float PI = 3.14159f; constexpr float PI = 3.14159f;
//============ STRUCTS ============== //============ STRUCTS ==============
struct LWOSCENEID { struct LWOSCENEID {
public: public:
LWOSCENEID() { m_sceneID = -1; m_layerID = 0; } constexpr LWOSCENEID() noexcept { m_sceneID = -1; m_layerID = 0; }
LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; } constexpr LWOSCENEID(int32_t sceneID) noexcept { m_sceneID = sceneID; m_layerID = 0; }
LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; } constexpr LWOSCENEID(int32_t sceneID, uint32_t layerID) noexcept { m_sceneID = sceneID; m_layerID = layerID; }
LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; } constexpr LWOSCENEID& operator=(const LWOSCENEID& rhs) noexcept { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; } constexpr LWOSCENEID& operator=(const int32_t rhs) noexcept { m_sceneID = rhs; m_layerID = 0; return *this; }
bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); } constexpr bool operator<(const LWOSCENEID& rhs) const noexcept { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
bool operator<(const int rhs) const { return m_sceneID < rhs; } constexpr bool operator<(const int32_t rhs) const noexcept { return m_sceneID < rhs; }
bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); } constexpr bool operator==(const LWOSCENEID& rhs) const noexcept { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
bool operator==(const int rhs) const { return m_sceneID == rhs; } constexpr bool operator==(const int32_t rhs) const noexcept { return m_sceneID == rhs; }
const int GetSceneID() const { return m_sceneID; } constexpr int32_t GetSceneID() const noexcept { return m_sceneID; }
const unsigned int GetLayerID() const { return m_layerID; } constexpr uint32_t GetLayerID() const noexcept { return m_layerID; }
void SetSceneID(const int sceneID) { m_sceneID = sceneID; } constexpr void SetSceneID(const int32_t sceneID) noexcept { m_sceneID = sceneID; }
void SetLayerID(const unsigned int layerID) { m_layerID = layerID; } constexpr void SetLayerID(const uint32_t layerID) noexcept { m_layerID = layerID; }
private: private:
int m_sceneID; int32_t m_sceneID;
unsigned int m_layerID; uint32_t m_layerID;
}; };
struct LWOZONEID { struct LWOZONEID {
public: public:
const LWOMAPID& GetMapID() const { return m_MapID; } constexpr const LWOMAPID& GetMapID() const noexcept { return m_MapID; }
const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; } constexpr const LWOINSTANCEID& GetInstanceID() const noexcept { return m_InstanceID; }
const LWOCLONEID& GetCloneID() const { return m_CloneID; } constexpr const LWOCLONEID& GetCloneID() const noexcept { return m_CloneID; }
//In order: def constr, constr, assign op //In order: def constr, constr, assign op
LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; } constexpr LWOZONEID() noexcept = default;
LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } constexpr LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) noexcept { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
LWOZONEID(const LWOZONEID& replacement) { *this = replacement; } constexpr LWOZONEID(const LWOZONEID& replacement) noexcept { *this = replacement; }
private: private:
LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc... LWOMAPID m_MapID = LWOMAPID_INVALID; //1000 for VE, 1100 for AG, etc...
LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process. LWOINSTANCEID m_InstanceID = LWOINSTANCEID_INVALID; //Instances host the same world, but on a different dWorld process.
LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds. LWOCLONEID m_CloneID = LWOCLONEID_INVALID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
}; };
const LWOSCENEID LWOSCENEID_INVALID = -1; constexpr LWOSCENEID LWOSCENEID_INVALID = -1;
struct LWONameValue { struct LWONameValue {
uint32_t length = 0; //!< The length of the name uint32_t length = 0; //!< The length of the name
std::u16string name; //!< The name std::u16string name; //!< The name
LWONameValue(void) {} LWONameValue() = default;
LWONameValue(const std::u16string& name) { LWONameValue(const std::u16string& name) {
this->name = name; this->name = name;
this->length = static_cast<uint32_t>(name.length()); this->length = static_cast<uint32_t>(name.length());
} }
~LWONameValue(void) {}
}; };
struct FriendData { struct FriendData {

View File

@@ -1,15 +0,0 @@
#ifndef __EAUTHMESSAGETYPE__H__
#define __EAUTHMESSAGETYPE__H__
#include <cstdint>
enum class eAuthMessageType : uint32_t {
LOGIN_REQUEST = 0,
LOGOUT_REQUEST,
CREATE_NEW_ACCOUNT_REQUEST,
LEGOINTERFACE_AUTH_RESPONSE,
SESSIONKEY_RECEIVED_CONFIRM,
RUNTIME_CONFIG
};
#endif //!__EAUTHMESSAGETYPE__H__

View File

@@ -15,7 +15,8 @@ enum class eCharacterVersion : uint32_t {
// Fixes vault size value // Fixes vault size value
VAULT_SIZE, VAULT_SIZE,
// Fixes speed base value in level component // Fixes speed base value in level component
UP_TO_DATE, // will become SPEED_BASE SPEED_BASE,
UP_TO_DATE, // will become NJ_JAYMISSIONS
}; };
#endif //!__ECHARACTERVERSION__H__ #endif //!__ECHARACTERVERSION__H__

View File

@@ -1,31 +0,0 @@
#ifndef __ECHATINTERNALMESSAGETYPE__H__
#define __ECHATINTERNALMESSAGETYPE__H__
#include <cstdint>
enum eChatInternalMessageType : uint32_t {
PLAYER_ADDED_NOTIFICATION = 0,
PLAYER_REMOVED_NOTIFICATION,
ADD_FRIEND,
ADD_BEST_FRIEND,
ADD_TO_TEAM,
ADD_BLOCK,
REMOVE_FRIEND,
REMOVE_BLOCK,
REMOVE_FROM_TEAM,
DELETE_TEAM,
REPORT,
PRIVATE_CHAT,
PRIVATE_CHAT_RESPONSE,
ANNOUNCEMENT,
MAIL_COUNT_UPDATE,
MAIL_SEND_NOTIFY,
REQUEST_USER_LIST,
FRIEND_LIST,
ROUTE_TO_PLAYER,
TEAM_UPDATE,
MUTE_UPDATE,
CREATE_TEAM,
};
#endif //!__ECHATINTERNALMESSAGETYPE__H__

View File

@@ -1,78 +0,0 @@
#ifndef __ECHATMESSAGETYPE__H__
#define __ECHATMESSAGETYPE__H__
#include <cstdint>
//! The Internal Chat Packet Identifiers
enum class eChatMessageType :uint32_t {
LOGIN_SESSION_NOTIFY = 0,
GENERAL_CHAT_MESSAGE,
PRIVATE_CHAT_MESSAGE,
USER_CHANNEL_CHAT_MESSAGE,
WORLD_DISCONNECT_REQUEST,
WORLD_PROXIMITY_RESPONSE,
WORLD_PARCEL_RESPONSE,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND,
GET_FRIENDS_LIST,
ADD_IGNORE,
REMOVE_IGNORE,
GET_IGNORE_LIST,
TEAM_MISSED_INVITE_CHECK,
TEAM_INVITE,
TEAM_INVITE_RESPONSE,
TEAM_KICK,
TEAM_LEAVE,
TEAM_SET_LOOT,
TEAM_SET_LEADER,
TEAM_GET_STATUS,
GUILD_CREATE,
GUILD_INVITE,
GUILD_INVITE_RESPONSE,
GUILD_LEAVE,
GUILD_KICK,
GUILD_GET_STATUS,
GUILD_GET_ALL,
SHOW_ALL,
BLUEPRINT_MODERATED,
BLUEPRINT_MODEL_READY,
PROPERTY_READY_FOR_APPROVAL,
PROPERTY_MODERATION_CHANGED,
PROPERTY_BUILDMODE_CHANGED,
PROPERTY_BUILDMODE_CHANGED_REPORT,
MAIL,
WORLD_INSTANCE_LOCATION_REQUEST,
REPUTATION_UPDATE,
SEND_CANNED_TEXT,
GMLEVEL_UPDATE,
CHARACTER_NAME_CHANGE_REQUEST,
CSR_REQUEST,
CSR_REPLY,
GM_KICK,
GM_ANNOUNCE,
GM_MUTE,
ACTIVITY_UPDATE,
WORLD_ROUTE_PACKET,
GET_ZONE_POPULATIONS,
REQUEST_MINIMUM_CHAT_MODE,
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
MATCH_REQUEST,
UGCMANIFEST_REPORT_MISSING_FILE,
UGCMANIFEST_REPORT_DONE_FILE,
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
UGCC_REQUEST,
WHO,
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
ACHIEVEMENT_NOTIFY,
GM_CLOSE_PRIVATE_CHAT_WINDOW,
UNEXPECTED_DISCONNECT,
PLAYER_READY,
GET_DONATION_TOTAL,
UPDATE_DONATION,
PRG_CSR_COMMAND,
HEARTBEAT_REQUEST_FROM_WORLD,
UPDATE_FREE_TRIAL_STATUS
};
#endif //!__ECHATMESSAGETYPE__H__

View File

@@ -1,76 +0,0 @@
#ifndef __ECLIENTMESSAGETYPE__H__
#define __ECLIENTMESSAGETYPE__H__
#include <cstdint>
enum class eClientMessageType : uint32_t {
LOGIN_RESPONSE = 0,
LOGOUT_RESPONSE,
LOAD_STATIC_ZONE,
CREATE_OBJECT,
CREATE_CHARACTER,
CREATE_CHARACTER_EXTENDED,
CHARACTER_LIST_RESPONSE,
CHARACTER_CREATE_RESPONSE,
CHARACTER_RENAME_RESPONSE,
CHAT_CONNECT_RESPONSE,
AUTH_ACCOUNT_CREATE_RESPONSE,
DELETE_CHARACTER_RESPONSE,
GAME_MSG,
CONNECT_CHAT,
TRANSFER_TO_WORLD,
IMPENDING_RELOAD_NOTIFY,
MAKE_GM_RESPONSE,
HTTP_MONITOR_INFO_RESPONSE,
SLASH_PUSH_MAP_RESPONSE,
SLASH_PULL_MAP_RESPONSE,
SLASH_LOCK_MAP_RESPONSE,
BLUEPRINT_SAVE_RESPONSE,
BLUEPRINT_LUP_SAVE_RESPONSE,
BLUEPRINT_LOAD_RESPONSE_ITEMID,
BLUEPRINT_GET_ALL_DATA_RESPONSE,
MODEL_INSTANTIATE_RESPONSE,
DEBUG_OUTPUT,
ADD_FRIEND_REQUEST,
ADD_FRIEND_RESPONSE,
REMOVE_FRIEND_RESPONSE,
GET_FRIENDS_LIST_RESPONSE,
UPDATE_FRIEND_NOTIFY,
ADD_IGNORE_RESPONSE,
REMOVE_IGNORE_RESPONSE,
GET_IGNORE_LIST_RESPONSE,
TEAM_INVITE,
TEAM_INVITE_INITIAL_RESPONSE,
GUILD_CREATE_RESPONSE,
GUILD_GET_STATUS_RESPONSE,
GUILD_INVITE,
GUILD_INVITE_INITIAL_RESPONSE,
GUILD_INVITE_FINAL_RESPONSE,
GUILD_INVITE_CONFIRM,
GUILD_ADD_PLAYER,
GUILD_REMOVE_PLAYER,
GUILD_LOGIN_LOGOUT,
GUILD_RANK_CHANGE,
GUILD_DATA,
GUILD_STATUS,
MAIL,
DB_PROXY_RESULT,
SHOW_ALL_RESPONSE,
WHO_RESPONSE,
SEND_CANNED_TEXT,
UPDATE_CHARACTER_NAME,
SET_NETWORK_SIMULATOR,
INVALID_CHAT_MESSAGE,
MINIMUM_CHAT_MODE_RESPONSE,
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
CHAT_MODERATION_STRING,
UGC_MANIFEST_RESPONSE,
IN_LOGIN_QUEUE,
SERVER_STATES,
GM_CLOSE_TARGET_CHAT_WINDOW,
GENERAL_TEXT_FOR_LOCALIZATION,
UPDATE_FREE_TRIAL_STATUS,
UGC_DOWNLOAD_FAILED = 120
};
#endif //!__ECLIENTMESSAGETYPE__H__

View File

@@ -5,8 +5,7 @@ enum class eConnectionType : uint16_t {
SERVER = 0, SERVER = 0,
AUTH, AUTH,
CHAT, CHAT,
CHAT_INTERNAL, WORLD = 4,
WORLD,
CLIENT, CLIENT,
MASTER MASTER
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,9 @@
#define __EINVENTORYTYPE__H__ #define __EINVENTORYTYPE__H__
#include <cstdint> #include <cstdint>
#include "magic_enum.hpp"
static const uint8_t NUMBER_OF_INVENTORIES = 17; static const uint8_t NUMBER_OF_INVENTORIES = 17;
/** /**
* Represents the different types of inventories an entity may have * Represents the different types of inventories an entity may have
@@ -56,4 +59,10 @@ public:
}; };
}; };
template <>
struct magic_enum::customize::enum_range<eInventoryType> {
static constexpr int min = 0;
static constexpr int max = 16;
};
#endif //!__EINVENTORYTYPE__H__ #endif //!__EINVENTORYTYPE__H__

View File

@@ -1,36 +0,0 @@
#ifndef __EMASTERMESSAGETYPE__H__
#define __EMASTERMESSAGETYPE__H__
#include <cstdint>
enum class eMasterMessageType : uint32_t {
REQUEST_PERSISTENT_ID = 1,
REQUEST_PERSISTENT_ID_RESPONSE,
REQUEST_ZONE_TRANSFER,
REQUEST_ZONE_TRANSFER_RESPONSE,
SERVER_INFO,
REQUEST_SESSION_KEY,
SET_SESSION_KEY,
SESSION_KEY_RESPONSE,
PLAYER_ADDED,
PLAYER_REMOVED,
CREATE_PRIVATE_ZONE,
REQUEST_PRIVATE_ZONE,
WORLD_READY,
PREP_ZONE,
SHUTDOWN,
SHUTDOWN_RESPONSE,
SHUTDOWN_IMMEDIATE,
SHUTDOWN_UNIVERSE,
AFFIRM_TRANSFER_REQUEST,
AFFIRM_TRANSFER_RESPONSE,
NEW_SESSION_ALERT
};
#endif //!__EMASTERMESSAGETYPE__H__

View File

@@ -0,0 +1,11 @@
#ifndef EPROPERTYSORTTYPE_H
#define EPROPERTYSORTTYPE_H
enum ePropertySortType : int32_t {
SORT_TYPE_FRIENDS = 0,
SORT_TYPE_REPUTATION = 1,
SORT_TYPE_RECENT = 3,
SORT_TYPE_FEATURED = 5
};
#endif //!EPROPERTYSORTTYPE_H

View File

@@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
INTERACTION_MANAGER, INTERACTION_MANAGER,
DONATION_VENDOR, DONATION_VENDOR,
COMBAT_MEDIATOR, COMBAT_MEDIATOR,
COMMENDATION_VENDOR, ACHIEVEMENT_VENDOR,
GATE_RUSH_CONTROL, GATE_RUSH_CONTROL,
RAIL_ACTIVATOR, RAIL_ACTIVATOR,
ROLLER, ROLLER,

View File

@@ -0,0 +1,21 @@
#ifndef __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
#define __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
#include <cstdint>
enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t {
SUCCESS,
FAIL_GENERIC,
FAIL_INV_FULL,
FAIL_ITEM_NOT_FOUND,
FAIL_CANT_MOVE_TO_THAT_INV_TYPE,
FAIL_NOT_NEAR_BANK,
FAIL_CANT_SWAP_ITEMS,
FAIL_SOURCE_TYPE,
FAIL_WRONG_DEST_TYPE,
FAIL_SWAP_DEST_TYPE,
FAIL_CANT_MOVE_THINKING_HAT,
FAIL_DISMOUNT_BEFORE_MOVING
};
#endif //!__EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__

View File

@@ -1,12 +0,0 @@
#ifndef __ESERVERMESSAGETYPE__H__
#define __ESERVERMESSAGETYPE__H__
#include <cstdint>
//! The Internal Server Packet Identifiers
enum class eServerMessageType : uint32_t {
VERSION_CONFIRM = 0,
DISCONNECT_NOTIFY,
GENERAL_NOTIFY
};
#endif //!__ESERVERMESSAGETYPE__H__

View File

@@ -0,0 +1,15 @@
#ifndef __EVENDORTRANSACTIONRESULT__
#define __EVENDORTRANSACTIONRESULT__
#include <cstdint>
enum class eVendorTransactionResult : uint32_t {
SELL_SUCCESS = 0,
SELL_FAIL,
PURCHASE_SUCCESS,
PURCHASE_FAIL,
DONATION_FAIL,
DONATION_FULL
};
#endif // !__EVENDORTRANSACTIONRESULT__

View File

@@ -0,0 +1,59 @@
#ifndef __EWAYPOINTCOMMANDTYPES__H__
#define __EWAYPOINTCOMMANDTYPES__H__
#include <cstdint>
enum class eWaypointCommandType : uint32_t {
INVALID,
BOUNCE,
STOP,
GROUP_EMOTE,
SET_VARIABLE,
CAST_SKILL,
EQUIP_INVENTORY,
UNEQUIP_INVENTORY,
DELAY,
EMOTE,
TELEPORT,
PATH_SPEED,
REMOVE_NPC,
CHANGE_WAYPOINT,
DELETE_SELF,
KILL_SELF,
SPAWN_OBJECT,
PLAY_SOUND,
};
class WaypointCommandType {
public:
static eWaypointCommandType StringToWaypointCommandType(std::string commandString) {
const std::map<std::string, eWaypointCommandType> WaypointCommandTypeMap = {
{"bounce", eWaypointCommandType::BOUNCE},
{"stop", eWaypointCommandType::STOP},
{"groupemote", eWaypointCommandType::GROUP_EMOTE},
{"setvar", eWaypointCommandType::SET_VARIABLE},
{"castskill", eWaypointCommandType::CAST_SKILL},
{"eqInvent", eWaypointCommandType::EQUIP_INVENTORY},
{"unInvent", eWaypointCommandType::UNEQUIP_INVENTORY},
{"delay", eWaypointCommandType::DELAY},
{"femote", eWaypointCommandType::EMOTE},
{"emote", eWaypointCommandType::EMOTE},
{"teleport", eWaypointCommandType::TELEPORT},
{"pathspeed", eWaypointCommandType::PATH_SPEED},
{"removeNPC", eWaypointCommandType::REMOVE_NPC},
{"changeWP", eWaypointCommandType::CHANGE_WAYPOINT},
{"DeleteSelf", eWaypointCommandType::DELETE_SELF},
{"killself", eWaypointCommandType::KILL_SELF},
{"removeself", eWaypointCommandType::DELETE_SELF},
{"spawnOBJ", eWaypointCommandType::SPAWN_OBJECT},
{"playSound", eWaypointCommandType::PLAY_SOUND},
};
auto intermed = WaypointCommandTypeMap.find(commandString);
return (intermed != WaypointCommandTypeMap.end()) ? intermed->second : eWaypointCommandType::INVALID;
};
};
#endif //!__EWAYPOINTCOMMANDTYPES__H__

View File

@@ -1,51 +0,0 @@
#ifndef __EWORLDMESSAGETYPE__H__
#define __EWORLDMESSAGETYPE__H__
#include <cstdint>
#include "magic_enum.hpp"
enum class eWorldMessageType : uint32_t {
VALIDATION = 1, // Session info
CHARACTER_LIST_REQUEST,
CHARACTER_CREATE_REQUEST,
LOGIN_REQUEST, // Character selected
GAME_MSG,
CHARACTER_DELETE_REQUEST,
CHARACTER_RENAME_REQUEST,
HAPPY_FLOWER_MODE_NOTIFY,
SLASH_RELOAD_MAP, // Reload map cmp
SLASH_PUSH_MAP_REQUEST, // Push map req cmd
SLASH_PUSH_MAP, // Push map cmd
SLASH_PULL_MAP, // Pull map cmd
LOCK_MAP_REQUEST,
GENERAL_CHAT_MESSAGE, // General chat message
HTTP_MONITOR_INFO_REQUEST,
SLASH_DEBUG_SCRIPTS, // Debug scripts cmd
MODELS_CLEAR,
EXHIBIT_INSERT_MODEL,
LEVEL_LOAD_COMPLETE, // Character data request
TMP_GUILD_CREATE,
ROUTE_PACKET, // Social?
POSITION_UPDATE,
MAIL,
WORD_CHECK, // Whitelist word check
STRING_CHECK, // Whitelist string check
GET_PLAYERS_IN_ZONE,
REQUEST_UGC_MANIFEST_INFO,
BLUEPRINT_GET_ALL_DATA_REQUEST,
CANCEL_MAP_QUEUE,
HANDLE_FUNNESS,
FAKE_PRG_CSR_MESSAGE,
REQUEST_FREE_TRIAL_REFRESH,
GM_SET_FREE_TRIAL_STATUS,
UI_HELP_TOP_5 = 91
};
template <>
struct magic_enum::customize::enum_range<eWorldMessageType> {
static constexpr int min = 0;
static constexpr int max = 91;
};
#endif //!__EWORLDMESSAGETYPE__H__

View File

@@ -25,6 +25,7 @@
#include "CDScriptComponentTable.h" #include "CDScriptComponentTable.h"
#include "CDSkillBehaviorTable.h" #include "CDSkillBehaviorTable.h"
#include "CDZoneTableTable.h" #include "CDZoneTableTable.h"
#include "CDTamingBuildPuzzleTable.h"
#include "CDVendorComponentTable.h" #include "CDVendorComponentTable.h"
#include "CDActivitiesTable.h" #include "CDActivitiesTable.h"
#include "CDPackageComponentTable.h" #include "CDPackageComponentTable.h"
@@ -39,8 +40,7 @@
#include "CDFeatureGatingTable.h" #include "CDFeatureGatingTable.h"
#include "CDRailActivatorComponent.h" #include "CDRailActivatorComponent.h"
#include "CDRewardCodesTable.h" #include "CDRewardCodesTable.h"
#include "CDPetComponentTable.h"
#include <exception>
#ifndef CDCLIENT_CACHE_ALL #ifndef CDCLIENT_CACHE_ALL
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory. // Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
@@ -54,15 +54,60 @@
#define CDCLIENT_DONT_CACHE_TABLE(x) #define CDCLIENT_DONT_CACHE_TABLE(x)
#endif #endif
class CDClientConnectionException : public std::exception { // Using a macro to reduce repetitive code and issues from copy and paste.
public: // As a note, ## in a macro is used to concatenate two tokens together.
virtual const char* what() const throw() {
return "CDClientDatabase is not connected!"; #define SPECIALIZE_TABLE_STORAGE(table) \
} template<> typename table::StorageType& CDClientManager::GetEntriesMutable<table>() { return table##Entries; };
};
#define DEFINE_TABLE_STORAGE(table) namespace { table::StorageType table##Entries; }; SPECIALIZE_TABLE_STORAGE(table)
DEFINE_TABLE_STORAGE(CDActivityRewardsTable);
DEFINE_TABLE_STORAGE(CDActivitiesTable);
DEFINE_TABLE_STORAGE(CDAnimationsTable);
DEFINE_TABLE_STORAGE(CDBehaviorParameterTable);
DEFINE_TABLE_STORAGE(CDBehaviorTemplateTable);
DEFINE_TABLE_STORAGE(CDBrickIDTableTable);
DEFINE_TABLE_STORAGE(CDComponentsRegistryTable);
DEFINE_TABLE_STORAGE(CDCurrencyTableTable);
DEFINE_TABLE_STORAGE(CDDestructibleComponentTable);
DEFINE_TABLE_STORAGE(CDEmoteTableTable);
DEFINE_TABLE_STORAGE(CDFeatureGatingTable);
DEFINE_TABLE_STORAGE(CDInventoryComponentTable);
DEFINE_TABLE_STORAGE(CDItemComponentTable);
DEFINE_TABLE_STORAGE(CDItemSetSkillsTable);
DEFINE_TABLE_STORAGE(CDItemSetsTable);
DEFINE_TABLE_STORAGE(CDLevelProgressionLookupTable);
DEFINE_TABLE_STORAGE(CDLootMatrixTable);
DEFINE_TABLE_STORAGE(CDLootTableTable);
DEFINE_TABLE_STORAGE(CDMissionEmailTable);
DEFINE_TABLE_STORAGE(CDMissionNPCComponentTable);
DEFINE_TABLE_STORAGE(CDMissionTasksTable);
DEFINE_TABLE_STORAGE(CDMissionsTable);
DEFINE_TABLE_STORAGE(CDMovementAIComponentTable);
DEFINE_TABLE_STORAGE(CDObjectSkillsTable);
DEFINE_TABLE_STORAGE(CDObjectsTable);
DEFINE_TABLE_STORAGE(CDPhysicsComponentTable);
DEFINE_TABLE_STORAGE(CDPackageComponentTable);
DEFINE_TABLE_STORAGE(CDPetComponentTable);
DEFINE_TABLE_STORAGE(CDProximityMonitorComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyEntranceComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyTemplateTable);
DEFINE_TABLE_STORAGE(CDRailActivatorComponentTable);
DEFINE_TABLE_STORAGE(CDRarityTableTable);
DEFINE_TABLE_STORAGE(CDRebuildComponentTable);
DEFINE_TABLE_STORAGE(CDRewardCodesTable);
DEFINE_TABLE_STORAGE(CDRewardsTable);
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable);
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
DEFINE_TABLE_STORAGE(CDZoneTableTable);
void CDClientManager::LoadValuesFromDatabase() { void CDClientManager::LoadValuesFromDatabase() {
if (!CDClientDatabase::isConnected) throw CDClientConnectionException(); if (!CDClientDatabase::isConnected) {
throw std::runtime_error{ "CDClientDatabase is not connected!" };
}
CDActivityRewardsTable::Instance().LoadValuesFromDatabase(); CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
CDActivitiesTable::Instance().LoadValuesFromDatabase(); CDActivitiesTable::Instance().LoadValuesFromDatabase();
@@ -102,6 +147,7 @@ void CDClientManager::LoadValuesFromDatabase() {
CDRewardsTable::Instance().LoadValuesFromDatabase(); CDRewardsTable::Instance().LoadValuesFromDatabase();
CDScriptComponentTable::Instance().LoadValuesFromDatabase(); CDScriptComponentTable::Instance().LoadValuesFromDatabase();
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase(); CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase();
CDVendorComponentTable::Instance().LoadValuesFromDatabase(); CDVendorComponentTable::Instance().LoadValuesFromDatabase();
CDZoneTableTable::Instance().LoadValuesFromDatabase(); CDZoneTableTable::Instance().LoadValuesFromDatabase();
} }

View File

@@ -1,18 +1,12 @@
#pragma once #ifndef __CDCLIENTMANAGER__H__
#define __CDCLIENTMANAGER__H__
#include "CDTable.h"
#include "Singleton.h"
#define UNUSED_TABLE(v) #define UNUSED_TABLE(v)
/** /**
* Initialize the CDClient tables so they are all loaded into memory. * Initialize the CDClient tables so they are all loaded into memory.
*/ */
class CDClientManager : public Singleton<CDClientManager> { namespace CDClientManager {
public:
CDClientManager() = default;
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
void LoadValuesFromDefaults(); void LoadValuesFromDefaults();
@@ -23,7 +17,28 @@ public:
* @return A pointer to the requested table. * @return A pointer to the requested table.
*/ */
template<typename T> template<typename T>
T* GetTable() { T* GetTable();
return &T::Instance();
} /**
* Fetch a table from CDClient
* Note: Calling this function without a template specialization in CDClientManager.cpp will cause a linker error.
*
* @tparam Table type to fetch
* @return A pointer to the requested table.
*/
template<typename T>
typename T::StorageType& GetEntriesMutable();
}; };
// These are included after the CDClientManager namespace declaration as CDTable as of Jan 29 2024 relies on CDClientManager in Templated code.
#include "CDTable.h"
#include "Singleton.h"
template<typename T>
T* CDClientManager::GetTable() {
return &T::Instance();
};
#endif //!__CDCLIENTMANAGER__H__

View File

@@ -1,5 +1,6 @@
#include "CDActivitiesTable.h" #include "CDActivitiesTable.h"
void CDActivitiesTable::LoadValuesFromDatabase() { void CDActivitiesTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; uint32_t size = 0;
@@ -13,7 +14,8 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
@@ -39,7 +41,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1); entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f); entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -48,7 +50,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) { std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
std::vector<CDActivities> data = cpplinq::from(this->entries) std::vector<CDActivities> data = cpplinq::from(GetEntries())
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

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

View File

@@ -1,5 +1,6 @@
#include "CDActivityRewardsTable.h" #include "CDActivityRewardsTable.h"
void CDActivityRewardsTable::LoadValuesFromDatabase() { void CDActivityRewardsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
@@ -14,7 +15,8 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
@@ -28,7 +30,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1); entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -37,7 +39,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) { std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
std::vector<CDActivityRewards> data = cpplinq::from(this->entries) std::vector<CDActivityRewards> data = cpplinq::from(GetEntries())
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

@@ -13,15 +13,9 @@ struct CDActivityRewards {
std::string description; //!< The description std::string description; //!< The description
}; };
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable> { class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable, std::vector<CDActivityRewards>> {
private:
std::vector<CDActivityRewards> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate); std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
std::vector<CDActivityRewards> GetEntries() const;
}; };

View File

@@ -5,6 +5,7 @@
void CDAnimationsTable::LoadValuesFromDatabase() { void CDAnimationsTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
auto& animations = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
DluAssert(!animation_type.empty()); DluAssert(!animation_type.empty());
@@ -24,7 +25,7 @@ void CDAnimationsTable::LoadValuesFromDatabase() {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -35,6 +36,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery(); auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (tableData.eof()) return false; if (tableData.eof()) return false;
auto& animations = GetEntriesMutable();
do { do {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
@@ -55,7 +57,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} while (!tableData.eof()); } while (!tableData.eof());
@@ -68,15 +70,17 @@ void CDAnimationsTable::CacheAnimations(const CDAnimationKey animationKey) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?"); auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
query.bind(1, static_cast<int32_t>(animationKey.second)); query.bind(1, static_cast<int32_t>(animationKey.second));
query.bind(2, animationKey.first.c_str()); query.bind(2, animationKey.first.c_str());
auto& animations = GetEntriesMutable();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (!CacheData(query)) { if (!CacheData(query)) {
this->animations[animationKey]; animations[animationKey];
} }
} }
void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) { void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
auto animationEntryCached = this->animations.find(CDAnimationKey("", animationGroupID)); auto& animations = GetEntriesMutable();
if (animationEntryCached != this->animations.end()) { auto animationEntryCached = animations.find(CDAnimationKey("", animationGroupID));
if (animationEntryCached != animations.end()) {
return; return;
} }
@@ -85,28 +89,29 @@ void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
// Cache the query so we don't run the query again. // Cache the query so we don't run the query again.
CacheData(query); CacheData(query);
this->animations[CDAnimationKey("", animationGroupID)]; animations[CDAnimationKey("", animationGroupID)];
} }
CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) { std::optional<CDAnimation> CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
auto& animations = GetEntriesMutable();
CDAnimationKey animationKey(animationType, animationGroupID); CDAnimationKey animationKey(animationType, animationGroupID);
auto animationEntryCached = this->animations.find(animationKey); auto animationEntryCached = animations.find(animationKey);
if (animationEntryCached == this->animations.end()) { if (animationEntryCached == animations.end()) {
this->CacheAnimations(animationKey); this->CacheAnimations(animationKey);
} }
auto animationEntry = this->animations.find(animationKey); auto animationEntry = animations.find(animationKey);
// If we have only one animation, return it regardless of the chance to play. // If we have only one animation, return it regardless of the chance to play.
if (animationEntry->second.size() == 1) { if (animationEntry->second.size() == 1) {
return CDAnimationLookupResult(animationEntry->second.front()); return animationEntry->second.front();
} }
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1); auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
for (auto& animationEntry : animationEntry->second) { for (auto& animationEntry : animationEntry->second) {
randomAnimation -= animationEntry.chance_to_play; randomAnimation -= animationEntry.chance_to_play;
// This is how the client gets the random animation. // This is how the client gets the random animation.
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry); if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return animationEntry;
} }
return CDAnimationLookupResult(); return std::nullopt;
} }

View File

@@ -2,6 +2,11 @@
#include "CDTable.h" #include "CDTable.h"
#include <list> #include <list>
#include <optional>
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
struct CDAnimation { struct CDAnimation {
// uint32_t animationGroupID; // uint32_t animationGroupID;
@@ -20,12 +25,7 @@ struct CDAnimation {
UNUSED_COLUMN(float blendTime;) //!< The blend time UNUSED_COLUMN(float blendTime;) //!< The blend time
}; };
typedef LookupResult<CDAnimation> CDAnimationLookupResult; class CDAnimationsTable : public CDTable<CDAnimationsTable, std::map<CDAnimationKey, std::list<CDAnimation>>> {
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
/** /**
@@ -38,7 +38,7 @@ public:
* @param animationGroupID The animationGroupID to lookup * @param animationGroupID The animationGroupID to lookup
* @return CDAnimationLookupResult * @return CDAnimationLookupResult
*/ */
[[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID); [[nodiscard]] std::optional<CDAnimation> GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
/** /**
* Cache a full AnimationGroup by its ID. * Cache a full AnimationGroup by its ID.
@@ -58,10 +58,4 @@ private:
* @return false * @return false
*/ */
bool CacheData(CppSQLite3Statement& queryToCache); bool CacheData(CppSQLite3Statement& queryToCache);
/**
* Each animation is key'd by its animationName and its animationGroupID. Each
* animation has a possible list of animations. This is because there can be animations have a percent chance to play so one is selected at random.
*/
std::map<CDAnimationKey, std::list<CDAnimation>> animations;
}; };

View File

@@ -1,6 +1,10 @@
#include "CDBehaviorParameterTable.h" #include "CDBehaviorParameterTable.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"
namespace {
std::unordered_map<std::string, uint32_t> m_ParametersList;
};
uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) { uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
uint64_t key = behaviorID; uint64_t key = behaviorID;
key <<= 31U; key <<= 31U;
@@ -11,6 +15,7 @@ uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
void CDBehaviorParameterTable::LoadValuesFromDatabase() { void CDBehaviorParameterTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
uint32_t behaviorID = tableData.getIntField("behaviorID", -1); uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", "")); auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
@@ -24,7 +29,7 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
uint64_t hash = GetKey(behaviorID, parameterId); uint64_t hash = GetKey(behaviorID, parameterId);
float value = tableData.getFloatField("value", -1.0f); float value = tableData.getFloatField("value", -1.0f);
m_Entries.insert(std::make_pair(hash, value)); entries.insert(std::make_pair(hash, value));
tableData.nextRow(); tableData.nextRow();
} }
@@ -32,22 +37,24 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
} }
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
auto parameterID = this->m_ParametersList.find(name); auto parameterID = m_ParametersList.find(name);
if (parameterID == this->m_ParametersList.end()) return defaultValue; if (parameterID == m_ParametersList.end()) return defaultValue;
auto hash = GetKey(behaviorID, parameterID->second); auto hash = GetKey(behaviorID, parameterID->second);
// Search for specific parameter // Search for specific parameter
auto it = m_Entries.find(hash); auto& entries = GetEntriesMutable();
return it != m_Entries.end() ? it->second : defaultValue; auto it = entries.find(hash);
return it != entries.end() ? it->second : defaultValue;
} }
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
auto& entries = GetEntriesMutable();
uint64_t hashBase = behaviorID; uint64_t hashBase = behaviorID;
std::map<std::string, float> returnInfo; std::map<std::string, float> returnInfo;
for (auto& [parameterString, parameterId] : m_ParametersList) { for (auto& [parameterString, parameterId] : m_ParametersList) {
uint64_t hash = GetKey(hashBase, parameterId); uint64_t hash = GetKey(hashBase, parameterId);
auto infoCandidate = m_Entries.find(hash); auto infoCandidate = entries.find(hash);
if (infoCandidate != m_Entries.end()) { if (infoCandidate != entries.end()) {
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second)); returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
} }
} }

View File

@@ -5,12 +5,10 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> { typedef uint64_t BehaviorParameterHash;
private: typedef float BehaviorParameterValue;
typedef uint64_t BehaviorParameterHash;
typedef float BehaviorParameterValue; class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable, std::unordered_map<BehaviorParameterHash, BehaviorParameterValue>> {
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();

View File

@@ -1,5 +1,9 @@
#include "CDBehaviorTemplateTable.h" #include "CDBehaviorTemplateTable.h"
namespace {
std::unordered_set<std::string> m_EffectHandles;
};
void CDBehaviorTemplateTable::LoadValuesFromDatabase() { void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
@@ -13,11 +17,9 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDBehaviorTemplate entry; CDBehaviorTemplate entry;
entry.behaviorID = tableData.getIntField("behaviorID", -1); entry.behaviorID = tableData.getIntField("behaviorID", -1);
@@ -31,30 +33,17 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first; entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
} }
this->entries.push_back(entry); entries.insert(std::make_pair(entry.behaviorID, entry));
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
} }
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
const std::vector<CDBehaviorTemplate>& CDBehaviorTemplateTable::GetEntries() const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) { const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto entry = this->entriesMappedByBehaviorID.find(behaviorID); auto& entries = GetEntriesMutable();
if (entry == this->entriesMappedByBehaviorID.end()) { auto entry = entries.find(behaviorID);
if (entry == entries.end()) {
CDBehaviorTemplate entryToReturn; CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0; entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end(); entryToReturn.effectHandle = m_EffectHandles.end();

View File

@@ -12,19 +12,9 @@ struct CDBehaviorTemplate {
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
}; };
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable, std::unordered_map<uint32_t, CDBehaviorTemplate>> {
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable> {
private:
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
const std::vector<CDBehaviorTemplate>& GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
}; };

View File

@@ -14,7 +14,8 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
@@ -23,7 +24,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
entry.NDObjectID = tableData.getIntField("NDObjectID", -1); entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1); entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -31,15 +32,9 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) { std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
std::vector<CDBrickIDTable> data = cpplinq::from(GetEntries())
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -4,14 +4,15 @@
void CDComponentsRegistryTable::LoadValuesFromDatabase() { void CDComponentsRegistryTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDComponentsRegistry entry; CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
this->mappedEntries.insert_or_assign(entry.id, 0); entries.insert_or_assign(entry.id, 0);
tableData.nextRow(); tableData.nextRow();
} }
@@ -20,10 +21,11 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
} }
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) { int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
auto exists = mappedEntries.find(id); auto& entries = GetEntriesMutable();
if (exists != mappedEntries.end()) { auto exists = entries.find(id);
auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); if (exists != entries.end()) {
return iter == mappedEntries.end() ? defaultValue : iter->second; auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
return iter == entries.end() ? defaultValue : iter->second;
} }
// Now get the data. Get all components of this entity so we dont do a query for each component // Now get the data. Get all components of this entity so we dont do a query for each component
@@ -38,14 +40,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
tableData.nextRow(); tableData.nextRow();
} }
mappedEntries.insert_or_assign(id, 0); entries.insert_or_assign(id, 0);
auto iter = this->mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
return iter == this->mappedEntries.end() ? defaultValue : iter->second; return iter == entries.end() ? defaultValue : iter->second;
} }

View File

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

View File

@@ -15,7 +15,8 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable");
@@ -27,7 +28,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
entry.maxvalue = tableData.getIntField("maxvalue", -1); entry.maxvalue = tableData.getIntField("maxvalue", -1);
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -35,15 +36,9 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) { std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) {
std::vector<CDCurrencyTable> data = cpplinq::from(GetEntries())
std::vector<CDCurrencyTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -13,7 +13,8 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent");
@@ -34,7 +35,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false;
entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -42,15 +43,9 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) { std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) {
std::vector<CDDestructibleComponent> data = cpplinq::from(GetEntries())
std::vector<CDDestructibleComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDDestructibleComponent>& CDDestructibleComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -20,14 +20,9 @@ struct CDDestructibleComponent {
int32_t difficultyLevel; //!< ??? int32_t difficultyLevel; //!< ???
}; };
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> { class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable, std::vector<CDDestructibleComponent>> {
private:
std::vector<CDDestructibleComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate); std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);
const std::vector<CDDestructibleComponent>& GetEntries(void) const;
}; };

View File

@@ -2,6 +2,7 @@
void CDEmoteTableTable::LoadValuesFromDatabase() { void CDEmoteTableTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDEmoteTable entry; CDEmoteTable entry;
entry.ID = tableData.getIntField("id", -1); entry.ID = tableData.getIntField("id", -1);
@@ -21,6 +22,7 @@ void CDEmoteTableTable::LoadValuesFromDatabase() {
} }
CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) { CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(id); auto itr = entries.find(id);
return itr != entries.end() ? &itr->second : nullptr; return itr != entries.end() ? &itr->second : nullptr;
} }

View File

@@ -26,10 +26,7 @@ struct CDEmoteTable {
std::string gateVersion; std::string gateVersion;
}; };
class CDEmoteTableTable : public CDTable<CDEmoteTableTable> { class CDEmoteTableTable : public CDTable<CDEmoteTableTable, std::map<int, CDEmoteTable>> {
private:
std::map<int, CDEmoteTable> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Returns an emote by ID // Returns an emote by ID

View File

@@ -14,7 +14,8 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating");
@@ -26,7 +27,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
entry.minor = tableData.getIntField("minor", -1); entry.minor = tableData.getIntField("minor", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -35,7 +36,8 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) { std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) {
std::vector<CDFeatureGating> data = cpplinq::from(this->entries) auto& entries = GetEntriesMutable();
std::vector<CDFeatureGating> data = cpplinq::from(entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
@@ -43,6 +45,7 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
} }
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const { bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
auto& entries = GetEntriesMutable();
for (const auto& entry : entries) { for (const auto& entry : entries) {
if (entry.featureName == feature.featureName && feature >= entry) { if (entry.featureName == feature.featureName && feature >= entry) {
return true; return true;
@@ -51,8 +54,3 @@ bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const
return false; return false;
} }
const std::vector<CDFeatureGating>& CDFeatureGatingTable::GetEntries() const {
return this->entries;
}

View File

@@ -17,10 +17,7 @@ struct CDFeatureGating {
} }
}; };
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> { class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable, std::vector<CDFeatureGating>> {
private:
std::vector<CDFeatureGating> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -28,6 +25,4 @@ public:
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate); std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
bool FeatureUnlocked(const CDFeatureGating& feature) const; bool FeatureUnlocked(const CDFeatureGating& feature) const;
const std::vector<CDFeatureGating>& GetEntries(void) const;
}; };

View File

@@ -14,7 +14,8 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent");
@@ -25,7 +26,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
entry.count = tableData.getIntField("count", -1); entry.count = tableData.getIntField("count", -1);
entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false; entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false;
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -33,15 +34,9 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) { std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) {
std::vector<CDInventoryComponent> data = cpplinq::from(GetEntries())
std::vector<CDInventoryComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDInventoryComponent>& CDInventoryComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -10,14 +10,9 @@ struct CDInventoryComponent {
bool equip; //!< Whether or not to equip the item bool equip; //!< Whether or not to equip the item
}; };
class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable> { class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable, std::vector<CDInventoryComponent>> {
private:
std::vector<CDInventoryComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate); std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate);
const std::vector<CDInventoryComponent>& GetEntries() const;
}; };

View File

@@ -17,6 +17,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDItemComponent entry; CDItemComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
@@ -62,7 +63,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
this->entries.insert(std::make_pair(entry.id, entry)); entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
@@ -70,8 +71,9 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
} }
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) { const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) {
const auto& it = this->entries.find(skillID); auto& entries = GetEntriesMutable();
if (it != this->entries.end()) { const auto& it = entries.find(skillID);
if (it != entries.end()) {
return it->second; return it->second;
} }
@@ -129,12 +131,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skill
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
this->entries.insert(std::make_pair(entry.id, entry)); entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
const auto& it2 = this->entries.find(skillID); const auto& it2 = entries.find(skillID);
if (it2 != this->entries.end()) { if (it2 != entries.end()) {
return it2->second; return it2->second;
} }

View File

@@ -49,10 +49,7 @@ struct CDItemComponent {
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
}; };
class CDItemComponentTable : public CDTable<CDItemComponentTable> { class CDItemComponentTable : public CDTable<CDItemComponentTable, std::map<uint32_t, CDItemComponent>> {
private:
std::map<uint32_t, CDItemComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent); static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);

View File

@@ -14,7 +14,8 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills");
@@ -24,7 +25,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
entry.SkillID = tableData.getIntField("SkillID", -1); entry.SkillID = tableData.getIntField("SkillID", -1);
entry.SkillCastType = tableData.getIntField("SkillCastType", -1); entry.SkillCastType = tableData.getIntField("SkillCastType", -1);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -32,22 +33,17 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
} }
std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) { std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) {
std::vector<CDItemSetSkills> data = cpplinq::from(GetEntries())
std::vector<CDItemSetSkills> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
return this->entries;
}
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) { std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) {
std::vector<CDItemSetSkills> toReturn; std::vector<CDItemSetSkills> toReturn;
for (CDItemSetSkills entry : this->entries) { for (const auto& entry : GetEntries()) {
if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry); if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry);
if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed. if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed.
} }

View File

@@ -9,16 +9,11 @@ struct CDItemSetSkills {
uint32_t SkillCastType; //!< The skill cast type uint32_t SkillCastType; //!< The skill cast type
}; };
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> { class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable, std::vector<CDItemSetSkills>> {
private:
std::vector<CDItemSetSkills> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate); std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);
const std::vector<CDItemSetSkills>& GetEntries() const;
std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID); std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID);
}; };

View File

@@ -14,7 +14,8 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets");
@@ -36,7 +37,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
entry.kitID = tableData.getIntField("kitID", -1); entry.kitID = tableData.getIntField("kitID", -1);
entry.priority = tableData.getFloatField("priority", -1.0f); entry.priority = tableData.getFloatField("priority", -1.0f);
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -45,14 +46,9 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) { std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) {
std::vector<CDItemSets> data = cpplinq::from(this->entries) std::vector<CDItemSets> data = cpplinq::from(GetEntries())
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDItemSets>& CDItemSetsTable::GetEntries() const {
return this->entries;
}

View File

@@ -21,15 +21,10 @@ struct CDItemSets {
float priority; //!< The priority float priority; //!< The priority
}; };
class CDItemSetsTable : public CDTable<CDItemSetsTable> { class CDItemSetsTable : public CDTable<CDItemSetsTable, std::vector<CDItemSets>> {
private:
std::vector<CDItemSets> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate); std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);
const std::vector<CDItemSets>& GetEntries(void) const;
}; };

View File

@@ -14,7 +14,8 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup");
@@ -24,7 +25,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
entry.requiredUScore = tableData.getIntField("requiredUScore", -1); entry.requiredUScore = tableData.getIntField("requiredUScore", -1);
entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", ""); entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", "");
this->entries.push_back(entry); entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -33,14 +34,9 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) { std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) {
std::vector<CDLevelProgressionLookup> data = cpplinq::from(this->entries) std::vector<CDLevelProgressionLookup> data = cpplinq::from(GetEntries())
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
return this->entries;
}

View File

@@ -9,15 +9,10 @@ struct CDLevelProgressionLookup {
std::string BehaviorEffect; //!< The behavior effect attached to this std::string BehaviorEffect; //!< The behavior effect attached to this
}; };
class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable> { class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable, std::vector<CDLevelProgressionLookup>> {
private:
std::vector<CDLevelProgressionLookup> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate); std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate);
const std::vector<CDLevelProgressionLookup>& GetEntries() const;
}; };

View File

@@ -25,7 +25,8 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
} }
// Reserve the size // Reserve the size
this->entries.reserve(size); auto& entries = GetEntriesMutable();
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
@@ -33,14 +34,15 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
CDLootMatrix entry; CDLootMatrix entry;
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
this->entries[lootMatrixIndex].push_back(ReadRow(tableData)); entries[lootMatrixIndex].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
} }
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) { const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto itr = this->entries.find(matrixId); auto& entries = GetEntriesMutable();
if (itr != this->entries.end()) { auto itr = entries.find(matrixId);
if (itr != entries.end()) {
return itr->second; return itr->second;
} }
@@ -49,10 +51,10 @@ const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto tableData = query.execQuery(); auto tableData = query.execQuery();
while (!tableData.eof()) { while (!tableData.eof()) {
this->entries[matrixId].push_back(ReadRow(tableData)); entries[matrixId].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
return this->entries[matrixId]; return entries[matrixId];
} }

View File

@@ -16,7 +16,7 @@ struct CDLootMatrix {
typedef uint32_t LootMatrixIndex; typedef uint32_t LootMatrixIndex;
typedef std::vector<CDLootMatrix> LootMatrixEntries; typedef std::vector<CDLootMatrix> LootMatrixEntries;
class CDLootMatrixTable : public CDTable<CDLootMatrixTable> { class CDLootMatrixTable : public CDTable<CDLootMatrixTable, std::unordered_map<LootMatrixIndex, LootMatrixEntries>> {
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -24,6 +24,5 @@ public:
const LootMatrixEntries& GetMatrix(uint32_t matrixId); const LootMatrixEntries& GetMatrix(uint32_t matrixId);
private: private:
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const; CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
}; };

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