Compare commits

...

130 Commits

Author SHA1 Message Date
dependabot[bot]
9b3f9f356d
Bump golang.org/x/crypto in /utils/scripts/build/should-release (#5032)
Some checks failed
Build / Linux (push) Has been cancelled
Build / Windows (push) Has been cancelled
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.36.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.36.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 19:44:17 +01:00
brainiac
e42dc2e1d2
Add Github Actions support (#5031)
Some checks failed
Build / Linux (push) Has been cancelled
Build / Windows (push) Has been cancelled
Basic support for building linux and windows in pull requests and also
the master branch.

Removes search for local perl on windows. Just always use the packaged
perl until we can switch to a package manager.

Removes drone config file, since that isn't doing anything useful anymore.
2025-11-17 10:21:05 -08:00
m0th
c611a25385
Dev Container Overhaul (#5023)
* Cleanup & Reorganize Makefile for Dev Containers

* Fix Makefile & misc fixes

---------

Co-authored-by: m0th <43860202+m0th@users.noreply.github.com>
2025-10-29 22:22:23 -07:00
Vayle
f74efcaa5f
[Bug Fix] Enhance SummonItemIntoInventory() to support stacking of items (#5022)
* Initial plan

* Initial plan

* Enhance SummonItemIntoInventory to support stacking

Co-authored-by: Valorith <76063792+Valorith@users.noreply.github.com>

* Update .gitignore

* Revert "Update .gitignore"

This reverts commit 16159398d8a69c53a719a1d54d068bbe0fa5284c.

* Disable PCH for patch sources compiled with -O0

Disables precompiled headers for specific patch source files that are compiled with -O0 on UNIX. This avoids Clang errors caused by __OPTIMIZE__ macro state mismatches between the PCH and translation units.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2025-10-22 22:50:00 -07:00
Jordan Conner
eb4e7d694c
Update client.cpp HandleEnterWorldPacket for UCS Local Address (#5020)
world/client.cpp's EnterWorld will correctly serve a LAN client the eqemu_config.json.world.localaddress based off IsLocalClient. It will then serve a non-LAN client the world.address value. This concept needs to be applied to UCS as that system also receives direct client connections. Inside world/client.cpp HandleEnterWorldPacket is where world sends the client info about UCS connection. This fix specifically handles the issue when you have a server on LAN and want to connect to it via another LAN computer + you have external clients.
2025-10-22 22:37:37 -07:00
Exonintrendo
ecc0d4b5c0
updated crash report url to new hosted spire location (#5024) 2025-10-16 10:22:49 -07:00
Chris Miles
8175ae6187 [Release] 23.10.3 2025-09-17 01:31:48 -05:00
Chris Miles
e8f4ffd628 [Release] 23.10.2 2025-09-17 00:52:31 -05:00
Chris Miles
0447618f7e hotfix: merge fix 2025-09-17 00:50:03 -05:00
Chris Miles
e71ce001ff Hotfix: revert #4996 2025-09-17 00:47:42 -05:00
Alex King
1575a2af40
[Hotfix] Fixed Mail Key Bug (#5015)
* [Hotfix] Fixed Mail Key Bug

* Release
2025-09-16 22:52:57 -04:00
JJ
4b69df646c
[Release] 23.10.0 (#5014)
* Update CHANGELOG.md

* Update version.h

* Update package.json
2025-09-16 11:35:03 -04:00
Alex King
044b9c1420
[Repositories] Convert Mail Key to Repositories (#5007)
* [Repositories] Convert Mail Key to Repositories

* Update shareddb.cpp

---------

Co-authored-by: JJ <3617814+joligario@users.noreply.github.com>
2025-09-15 14:23:48 -04:00
Alex King
0bbb5b90e7
[Repositories] Convert Total Time Played to Repositories (#5008) 2025-09-15 09:14:59 -04:00
Alex King
6506ad5b51
[Quest API] Add EVENT_CHARM_START and EVENT_CHARM_END (#5013) 2025-09-15 09:14:46 -04:00
Alex King
dcaa0ecdaa
[Quest API] Add Identifiers to Get/Modify NPC Stat Methods (#5012) 2025-09-15 09:14:29 -04:00
Mitch Freeman
9b143132be
[Bug Fix] Fix Several Evolving Item Bugs (#4992)
* Add sending evolving items via parcels
Send, retrieve and inspect tested ok

* Sell evolving items to a merchant and purchase tested ok.

* Fix a problem with potions and quantity
2025-09-07 22:51:39 -04:00
Mitch Freeman
231bf8b4ec
Update database_update_manifest.cpp (#5011) 2025-09-07 19:13:00 -04:00
Alex King
dee58f9a91
[Repositories] Convert Shared Bank Platinum to Repositories (#5006) 2025-09-01 21:39:24 -04:00
Alex King
1eb89edbbd
[Repositories] Convert Item Loading to Repositories (#4998) 2025-08-30 16:39:23 -04:00
Alex King
e015d0d67e
[Repositories] Convert Damage Shield Types to Repositories (#4995)
* [Repositories] Convert Damage Shield Types to Repositories

* Remove max spell ID
2025-08-30 16:23:33 -04:00
Alex King
ba78394ce9
[Repositories] Convert Spell Loading to Repositories (#4996) 2025-08-30 15:42:04 -04:00
Alex King
060f6e377d
[Constants] Convert SE Defines to SpellEffect Namespace (#4999) 2025-08-30 15:33:19 -04:00
Alex King
92c8b0e585
[Constants] Change Race Changes to Race Namespace (#5000) 2025-08-30 15:33:11 -04:00
Alex King
33df8ea665
[Repositories] Convert Character Inspect Messages to Repositories (#4997) 2025-08-30 14:42:40 -04:00
Alex King
9668074d94
[Bug Fix] Fix Recipe Inspect Bug (#4994) 2025-08-30 13:56:14 -04:00
Alex King
822a5dcac4
[Cleanup] Cleanup #show ip_lookup Message (#5005)
* [Cleanup] Cleanup #show ip_lookup Message

* Test

* Update clientlist.cpp
2025-08-30 13:05:18 -04:00
Alex King
0c65a4febe
[Cleanup] Fix #set race 0 Message (#5004) 2025-08-29 20:08:03 -04:00
Alex King
02f66de679
[Cleanup] Remove Unused errorname Variable (#5001) 2025-08-29 12:02:11 -04:00
Alex King
145111f11e
[Bug Fix] Fix Task Reloading (#5002) 2025-08-29 06:52:51 -04:00
Alex King
a4e47d9180
[Pets] Add Pet Constants and Methods (#4987)
* [Pets] Add Pet Constants and Methods

* Remove GetID

* GetPetTypeName()

* Cleanup
2025-08-17 01:00:31 -04:00
Alex King
207ee2daa0
[Database] Add heal_amount to character_stats_record (#4986)
* [Database] Add heal_amount to character_stats_record

* Update version.h
2025-08-16 21:35:55 -04:00
Alex King
1fe5d9fa4f
[Commands] Add #task complete Saylink to #task show (#4985) 2025-08-16 21:35:38 -04:00
Alex King
ed3f6c2a40
[Cleanup] Fix Issues with Strings::Commify and Mob::SendStatsWindow (#4984) 2025-08-16 21:35:13 -04:00
Alex King
adb3196ca5
[Cleanup] Add #npcedit npc_tint_id Help Message (#4982)
* [Cleanup] Add #npcedit npc_tint_id Help Message

* Update npcedit.cpp

* Update npcedit.cpp
2025-08-16 21:34:55 -04:00
Alex King
e13b133ac8
[Quest API] Add GetNPCTintIndex() to Perl/Lua (#4983) 2025-08-16 21:34:39 -04:00
Alex King
d475428157
[Quest API] Add GetKeyRing() to Perl/Lua (#4980) 2025-08-16 21:34:28 -04:00
Alex King
00b66ce432
[Commands] Add #find account Subcommand (#4981)
Credit goes to https://github.com/The-Heroes-Journey-EQEMU/Server/pull/281
2025-08-16 21:34:16 -04:00
Alex
4d12dd5c43
[Code] Remove Attributions (#4988) 2025-08-15 23:36:35 -05:00
regneq
c4f408bffc
[Bug Fix] Fix Race 474 for Titanium (#4979) 2025-08-11 16:49:59 -04:00
Alex King
d876c6df2a
[Bug Fix] Fix #show recipe uint16 Cap (#4978) 2025-08-11 14:06:13 -04:00
Alex King
d142e1ca81
[Hotfix] Fix Quest Ownership Edge Case (#4977)
* [Hotfix] Fix Quest Ownership Edge Case

* Push
2025-08-02 22:09:30 -05:00
Chris Miles
d9f4d49ef4
[Release] 23.9.0 (#4976) 2025-08-02 20:11:29 -05:00
Alex King
0a1df5bbb6
[Quest API] Add GetTimers() and GetPausedTimers() to Perl/Lua (#4965)
* [Quest API] Add GetTimers() and GetPausedTimers() to Perl/Lua

* Push
2025-08-02 19:17:56 -05:00
dependabot[bot]
41f3d7ff31
Bump golang.org/x/oauth2 in /utils/scripts/build/should-release (#4967)
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.0.0-20180821212333-d2e6202438be to 0.27.0.
- [Commits](https://github.com/golang/oauth2/commits/v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.27.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-02 19:16:57 -05:00
solar
0afef19d26
[Loginserver] Fix Legacy World When Using Local DB (#4970)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 19:16:35 -05:00
Alex King
e9be2d76c3
[Commands] Add #show keyring Subcommand (#4973) 2025-08-02 19:15:44 -05:00
solar
ffa813b92c
[Build] Fix Linking with GCC (#4969)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 19:15:11 -05:00
solar
909de47acd
fix player movement deltas (jumping, turning) (#4975)
Co-authored-by: solar <solar@heliacal.net>
2025-08-02 10:32:30 -04:00
regneq
73a5f11e17
[Bug Fix] [Bug Fix] Show player count on the server list status. (#4971) 2025-07-30 19:39:55 -04:00
Alex King
9544e100c3
[Bug Fix] Fix Hero's Forge Ingame and Character Select (#4966) 2025-07-30 19:39:29 -04:00
Chris Miles
f3232cdc3a
[Database] Add Indexes to NPC's Spawns Loot (#4972) 2025-07-30 09:37:23 -04:00
Bemvaras
b8884d6572
[Quest API] Add GetMemberRole() to Perl/Lua (#4963)
* Add group member role retrieval

* Expose group member role to Lua

* Cleanup

* Cleanup

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2025-07-10 15:09:04 -04:00
Alex King
323a0c0b27
[Feature] Zone Scripting (#4908)
* [Feature] Add Zone Scripting Capabilities

* Push

* Update zone.cpp

* Fix crashes

* Lua

* Add other events, finish Lua

* Add EVENT_ENTER_ZONE

* Final

* Push

* Push

* [Feature] Add Zone Scripting Capabilities

* Push

* Update zone.cpp

* Fix crashes

* Add EVENT_ENTER_ZONE

* Remove duplicates

* Update embparser.cpp
2025-07-10 15:08:08 -04:00
regneq
ab45d4358d
[Bug Fix] Add a missing Froglok starting area for Titanium Startzone. (#4962)
* Add a missing Froglok starting area for Titanium Startzone.

* fix formatting.

* add a missing break.
2025-07-04 12:53:45 -04:00
nytmyr
f7775c7a75
[Bots] Fix FinishBuffing rule (#4961) 2025-06-30 19:54:04 -05:00
Chris Miles
659a960401
[Performance] Clear Wearchange Deduplication Cache (#4960)
* [Performance] Clear Wearchange Deduplication Cache

* Move timers to process loops
2025-06-30 13:57:43 -05:00
Chris Miles
07d484597d
[Build] More Build Speed Improvements (#4959) 2025-06-30 13:09:23 -05:00
nytmyr
fc470d5f83
[Bots] Fix ^cast resurrects (#4958)
- Was failing stack checks and couldn't be casted. Added bypass.
2025-06-29 10:19:00 -04:00
Chris Miles
585ed3bd25 [Release] 23.8.1 2025-06-28 17:29:25 -05:00
Chris Miles
2eb291a461
[Databuckets] Revert Caching Changes of #4917 (#4957)
* [Databuckets] Revert Caching Changes of #4917

* Comment caching tests until addressed later
2025-06-28 17:28:19 -05:00
Alex King
a1421af214
[Bug Fix] Fix Hero Forge on Character Select (#4954) 2025-06-26 19:35:28 -04:00
Alex King
13aad6229f
[Crash Fix] Fix Possible Crashes with Raid Methods (#4955) 2025-06-26 19:35:20 -04:00
Alex King
76d46ceaf0
[Bug Fix] Fix FindCharacter Using content_db (#4956) 2025-06-26 19:35:11 -04:00
Chris Miles
389047c4e2
[Release] 23.8.0 (#4953)
* [Release] 23.8.0

* Changelog

* Update ruletypes.h
2025-06-25 21:12:05 -05:00
Chris Miles
2c6d405b2c [Hotfix] Fix ClientList Singleton Shortcomings of #4942 2025-06-25 15:50:34 -05:00
Fryguy
50ae0f8351
[Corpses] Add corpse entity variables to DB (#4911)
* [Corpses] Add corpse entity variables to DB

- When corpses have entity variables add/remove/modified it will update the database accordingly.
- Corpse loading will pull the database values if they exist.

* Updates per review

* Update version.h

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 15:21:52 -05:00
Alex King
dc261bb203
[Code] ZSList Global to Singleton Cleanup (#4940)
* [Code] ZSList Global to Singleton Cleanup

* Final

* Post merge fixes

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 15:16:44 -05:00
Alex King
643ee56433
[Code] PlayerEventLogs Global to Singleton Cleanup (#4928)
* [Code] PlayerEventLogs Global to Singleton Cleanup

* Fix

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 15:05:33 -05:00
Alex King
c0bb32ed12
[Code] WorldContentServer Global to Singleton Cleanup (#4939) 2025-06-25 14:55:39 -05:00
Alex King
c99bda3f47
[Code] WebInterfaceList Global to Singleton Cleanup (#4935) 2025-06-25 14:49:32 -05:00
Alex King
967a13e692
[Code] WorldEventScheduler and ZoneEventScheduler Global to Singleton Cleanup (#4932) 2025-06-25 14:47:37 -05:00
Alex King
f304f9cc61
[Code] QueryServConnection Global to Singleton Cleanup (#4938)
* [Code] QueryServConnection Global to Singleton Cleanup

* Fix missed file in PR

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:43:01 -05:00
Alex King
004e2ca63f
[Code] AdventureManager Global to Singleton Cleanup (#4931)
* [Code] AdventureManager Global to Singleton Cleanup

* Post merge fix

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:38:24 -05:00
Alex King
128732e05d
[Code] EvolvingItemsManager Global to Singleton Cleanup (#4929)
Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:26:29 -05:00
Alex King
1e6a4dac78
[Code] UCSConnection Global to Singleton Cleanup (#4937)
Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:25:37 -05:00
Alex King
654764685a
[Code] LFGuildManager Global to Singleton Cleanup (#4927)
* [Code] LFGuildManager Global to Singleton Cleanup

* Update lfguild.h

* Update worldserver.cpp

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:19:52 -05:00
Alex King
c5ab35e4af
[Code] SharedTaskManager Global to Singleton Cleanup (#4930)
Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 14:11:40 -05:00
Chris Miles
947795f1d1
[Code] EQEmuLogSys Global to Singleton Cleanup (#4925)
* [Code] EQEmuLogSys Global to Singleton Cleanup

* Post merge fix
2025-06-25 14:05:49 -05:00
Alex King
1153c9ab96
[Code] LoginServerList Global to Singleton Cleanup (#4941) 2025-06-25 13:49:55 -05:00
Alex King
2128b45313
[Code] ClientList Global to Singleton Cleanup (#4942) 2025-06-25 13:49:42 -05:00
Alex King
4f7ff2d6f2
[Code] DatabaseUpdate Global to Singleton Cleanup (#4943)
Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 13:48:18 -05:00
Alex King
b5f1e99d3b
[Code] DiscordManager Global to Singleton Cleanup (#4926)
* [Code] DiscordManager Global to Singleton Cleanup

* Update discord_manager.h

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 13:47:47 -05:00
Chris Miles
83918ce020
[Performance] Wearchange Packet Send Deduplication (#4916)
* [Performance] Wearchange Packet Send Deduplication

* Update mob_appearance.cpp

* Reduce one allocation

* Update mob_appearance.cpp

* Change

* Update mob_appearance.cpp

* Update mob_appearance.cpp

* Update mob_appearance.cpp

* Update mob_appearance.cpp

* Update mob_appearance.cpp

* Wut

* ffs
2025-06-25 13:19:29 -05:00
Alex King
f3aaeff0a9
[Code] PetitionList Global to Singleton Cleanup (#4944)
* [Code] PetitionList Global to Singleton Cleanup

* Update worldserver.cpp

* Update worldserver.cpp
2025-06-25 13:15:21 -05:00
Chris Miles
98eff43346 chore: Update language for clarity and attribution 2025-06-25 13:09:43 -05:00
Bemvaras
46b43a990f
[Quest API] Add CompleteTask and UncompleteTask methods to Perl/Lua (#4921)
* Add quest::uncompletetask to quest API

* Remove CMakeSettings.json (local build config) from PR

* Push

* Final

* Update embparser_api.cpp

* Update questmgr.cpp

* Update lua_client.cpp

* Fix parcel slot duplication for evolving item augments

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-25 13:03:23 -05:00
Chris Miles
ea96cbf885
[Databuckets] Nested Caching (#4917)
* [Databuckets] Nested Caching

* One more

* Update benchmark_databuckets.cpp

* Add caching tests

* Fix tests and scoping

* Update databuckets.cpp

* Fix tests

* Rebase fixes

* [Databuckets] Implement Cache in World (#4920)
2025-06-25 12:47:43 -05:00
regneq
de07870c99
[Fix] Fix breaking changes to Titanium, SoF, SoD patches causes by big bags update (#4922)
* [Fix] Fix breaking change to Titanium patches caused by Big Bags update.

* Fixes for Titanium, SoD, SoF causes by big bag bug.
2025-06-25 12:41:13 -05:00
Chris Miles
b3b228c26c
[Code] PCH Cleanup (#4952)
* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update app-pch.h

* Update CMakeLists.txt

* Split out pch to zone

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update windows-build.ps1

* Update windows-build.ps1

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt
2025-06-25 12:26:38 -05:00
Fryguy
27b5c80c3c
[Quest API] Lua Client Scoped EnableTitleSets (#4914)
Example usage:
```lua
client:EnableTitleSet(reward.title_set)
```
2025-06-25 12:25:35 -05:00
Chris Miles
fb4d003e19
[Player Events] Zone Fetch Settings from QS if Enabled (#4915)
* [Player Events] Zone Fetch Settings from QS if Enabled

* Update zonelist.cpp

* Update zoneserver.cpp
2025-06-25 12:21:35 -05:00
Chris Miles
f025e5741b
[Player Event Logs] Don't Clear Event Data on ETL Events (#4913)
* [Player Event Logs] Don't Clear Event Data on ETL Events

* Migration
2025-06-24 20:15:22 -04:00
Chris Miles
c3f2708f1b
[Player Events] Don't Write Empty Data (#4912)
* [Player Events] Don't Write Empty Data

* Revert "[Player Events] Don't Write Empty Data"

This reverts commit f64a824b33c467697cdd377261745add889db206.

* Update player_events.h

* Augs
2025-06-24 20:14:51 -04:00
Alex King
2e760d6397
[Code] ZoneStore Global to Singleton Cleanup (#4934) 2025-06-23 06:45:06 -04:00
Chris Miles
bac892b582
[API] Add wwmarquee <type> <message> (#4919)
* [API] Implement Console "wwmarquee"

* Fin
2025-06-23 05:25:50 -04:00
Chris Miles
4005b68383
[Code] Optimize PCH Config (Faster Builds) (#4951) 2025-06-22 13:52:23 -05:00
Chris Miles
5ac9dd04e4
[Code] Cleanup Strings Header (#4950)
* [Code] Cleanup Strings Header

* Include optimize
2025-06-22 13:52:13 -05:00
Alex King
f0c041e8b3
[Code] EQ::Random Global to Singleton Cleanup (#4936) 2025-06-22 14:13:58 -04:00
Alex King
2f4a5b56dd
[Code] SkillCaps Global to Singleton Cleanup (#4933) 2025-06-22 14:13:16 -04:00
Alex King
940f97c9ae
[Code] TaskManager Global to Singleton Cleanup (#4945)
* [Code] TaskManager Global to Singleton Cleanup

* Remove checks for existence

* Final
2025-06-22 14:10:48 -04:00
Chris Miles
f8ee664b27
[Code] Remove Lua Rule Constants (#4949) 2025-06-22 13:55:55 -04:00
Chris Miles
df86ad371b
[Code] PathManager Global to Singleton Cleanup (#4924) 2025-06-22 13:50:52 -04:00
Chris Miles
e846bb86b6
[Code] Remove Regex Compile Bloat (#4947) 2025-06-22 02:08:15 -05:00
Chris Miles
3e6a3e2168
[Build] Significantly Improve Build Times Using Unity Builds (#4948) 2025-06-22 02:08:03 -05:00
Alex King
2aebf1a78a
[Code] Remove Unused MZoneShutdown Mutex (#4946) 2025-06-22 01:49:39 -05:00
Chris Miles
1be7e56b86
[Databuckets] Move Databuckets to Common (#4918)
* [Databuckets] Move Databuckets to Common

* Fix linking issue
2025-06-16 16:48:29 -05:00
Chris Miles
a0ff9d67a1
[Fix] Bulk Send Corpses after Idle State (#4910) 2025-06-09 14:31:28 -05:00
Chris Miles
befee1c729
[Quests] Support Multiple Quest, Plugin, and Lua Module Paths (#4906)
* [Quests] Add Support for Multiple Load Paths

* Adjust load paths

* plugin != m_lua_module_directories
2025-06-09 12:49:46 -05:00
nytmyr
3d70063a68
[Doors] Fix door saving for versions (#4905)
* [Doors] Fix door saving for versions

- Door saving wasn't saving to the proper version on `#door save`

* Update doors.cpp

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-06-09 12:47:56 -05:00
JJ
4e28bcf85e
Bump libuv to 1.50.0 (#4898) 2025-06-09 12:40:37 -05:00
JJ
687d10960a
[Logs] Fix output for tasks in logs (#4907) 2025-06-09 12:32:45 -05:00
Chris Miles
567d46c3d6
[Performance] Auto Idle / AFK (#4903)
* [Performance] AFK Client Packet Filtering

* Player feedback

* Update client_packet.cpp

* Fixes

* Streamline updates to SetAFK

* Decouple idling and AFK and manual AFK

* Reset clock timer when we take AFK or idle off

* Exclude bard songs in non combat zones from resetting timer

* GM exclusion adjustments
2025-05-22 13:08:32 -05:00
Chris Miles
53cc2de459
[World API] Input Validation (#4904)
* [World API] Input Validation

* Update eqemu_api_world_data_service.cpp

* Add db ping to player events processor, move back into main thread
2025-05-22 13:08:17 -05:00
Chris Miles
cb866cba31
[Release] 23.7.0 (#4902) 2025-05-19 12:31:37 -05:00
JJ
e2162c08da
[CLI] Add custom database version output (#4901)
* Add custom database version output to CLI from #4892

* Spacing alignment
2025-05-18 11:28:10 -05:00
Chris Miles
e657953b8f
[Netcode] Resend Logic Adjustments (#4900)
* Timeout adjustment

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Stuff

* Update daybreak_connection.h

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp

* Update daybreak_connection.cpp
2025-05-18 11:19:37 -05:00
JJ
eb366e67b7
[CLI] Fix MySQL check in database dumper (#4897) 2025-05-16 18:56:38 -05:00
JJ
5b728a42f7
Update zonelist.h (#4896) 2025-05-16 18:17:38 -04:00
Chris Miles
a1d414d64c
[Netcode] Resend Logic Adjustments (#4895)
* [Netcode] Resend Logic Adjustments

* Update daybreak_connection.h
2025-05-16 16:46:07 -05:00
Chris Miles
907029ed76
[Database] Remove Transaction Wrapped Character Save (#4894) 2025-05-16 16:07:45 -05:00
Chris Miles
894f22fba0
[Fix] Deadlock on failed #copycharacter commands (#4887) 2025-05-16 13:39:34 -05:00
Chris Miles
7ec09d7e0f
[Player Events] Add rule to ignore configured GM commands (#4888) 2025-05-16 13:39:24 -05:00
Chris Miles
c82266790a
[Zone State] Load New Spawn2 Data When Present (#4889) 2025-05-16 13:39:16 -05:00
Chris Miles
ec31fddbae
[Logging] Auto Update Log Category Names (#4890) 2025-05-16 13:39:08 -05:00
Chris Miles
fb49ce2404
[Rules] Auto Update Rule Notes from Source (#4891)
* [Rules] Auto Update Rule Notes from Source

* Update rulesys.cpp
2025-05-16 13:38:59 -05:00
Chris Miles
276b7e238a
[Database] Add Custom Database Migrations for Operators (#4892)
* [Database] Add Custom Database Migrations for Operators

* Changes

* Update database_update_manifest_custom.cpp
2025-05-16 13:38:51 -05:00
Chris Miles
c7a463420b
[World] Fix Rarer Reload Deadlock (#4893) 2025-05-16 13:38:42 -05:00
Chris Miles
a56bb52808
Update README.md 2025-05-15 15:29:05 -05:00
Chris Miles
0bbdb58679 Update README.md 2025-05-15 15:26:07 -05:00
326 changed files with 15266 additions and 11309 deletions

View File

@ -1,6 +1,5 @@
!Makefile base/
base/*.sql !base/*.json
base/*.zip override/
base/db/ repo/
base/maps/ cache/
!base/expansion/Makefile

View File

@ -1,196 +1,127 @@
# Build binaries: make cmake, make build
# One time initial setup (or to reset db): make prep, make inject-mariadb, make maps
# Update custom db edits: make inject-custom
# Start up server: make shared, make login, make world, make zone
# in game, stop combat spam #logs set gmsay 79 0
# in game, stop loot spam #logs set gmsay 69 0
NAME := eqemu-server NAME := eqemu-server
.ONESHELL:
DOCKER_ARGS := --rm --name ${NAME} -v $$PWD:/src -w /src ${NAME}
DOCKER_ARM64_ARGS := --rm --platform linux/arm64 --name ${NAME}-arm64 -v $$PWD:/src -w /src ${NAME}-arm64
.PHONY: build
build:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile build --no-print-directory
exit
endif
cd build$$BUILD_SUFFIX && cmake --build . --config Release --target all --
.PHONY: cmake
cmake:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile cmake --no-print-directory
exit
endif
@echo "working directory: $$PWD"
mkdir -p build$$BUILD_SUFFIX
@cd build$$BUILD_SUFFIX && cmake -DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_TESTS=ON \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache -G Ninja ..
clean:
ifneq (,$(findstring .devcontainer,$$PWD))
@make -C ../ -f .devcontainer/Makefile clean --no-print-directory
endif
rm -rf build
docker-cmake:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile docker-cmake --no-print-directory
exit
endif
@echo "working directory: $$PWD"
git submodule update --init --recursive
docker run ${DOCKER_ARGS} make cmake
docker-build:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile docker-build --no-print-directory
exit
endif
docker run ${DOCKER_ARGS} make build
# Build image if it doesn't exist
docker-image-build:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile docker-image-build --no-print-directory
exit
endif
ifeq ($(shell docker images -q ${NAME} 2> /dev/null),)
@echo "Docker image not found. Building..."
docker build -f Dockerfile.debian.dev -t ${NAME} .
endif
docker-arm-cmake: docker-arm-image-build
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile docker-arm-cmake --no-print-directory
exit
endif
git submodule update --init --recursive
docker run ${DOCKER_ARM64_ARGS} make cmake BUILD_SUFFIX=arm64
docker-arm-build: docker-arm-image-build
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile docker-arm-build --no-print-directory
exit
endif
docker run ${DOCKER_ARM64_ARGS} make build BUILD_SUFFIX=arm64
docker-arm-image-build:
ifeq ($(shell docker images -q ${NAME}-arm64 2> /dev/null),)
@echo "Docker image not found. Building..."
docker build -f Dockerfile.debian.arm.dev -t ${NAME}-arm64 .
endif
docker-clean: clean
.PHONY: prep .PHONY: prep
prep: prep: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile prep --no-print-directory
exit
endif
@echo "Preparing build/bin for usage..." @echo "Preparing build/bin for usage..."
mkdir -p build/bin/assets/patches
cp -R -u -p .devcontainer/base/eqemu_config.json build/bin/eqemu_config.json @echo "Prepping folders..."
cp -R -u -p .devcontainer/base/login.json build/bin/login.json @mkdir -p .devcontainer/override
cp -R -u -p loginserver/login_util/* build/bin/assets/patches/ @mkdir -p .devcontainer/repo
mkdir -p build/bin/assets @mkdir -p .devcontainer/cache
cp -R -u -p utils/patches build/bin/assets/ @mkdir -p build/bin/logs
-unlink build/bin/lua_modules @mkdir -p build/bin/shared
cd build/bin && ln -s quests/lua_modules lua_modules @mkdir -p build/bin/assets
-unlink build/bin/mods
cd build/bin && ln -s quests/mods mods @echo "Applying overrides..."
-unlink build/bin/maps @if [ ! -f .devcontainer/override/eqemu_config.json ]; then cp .devcontainer/base/eqemu_config.json .devcontainer/override/eqemu_config.json; fi
cd build/bin && ln -s ../../base/maps maps @if [ -f build/bin/eqemu_config.json ]; then unlink build/bin/eqemu_config.json; fi
mkdir -p build/bin/logs cd build/bin && ln -s ../../.devcontainer/override/eqemu_config.json eqemu_config.json
mkdir -p build/bin/shared @if [ ! -f .devcontainer/override/login.json ]; then cp .devcontainer/base/login.json .devcontainer/override/login.json; fi
@if [ -f build/bin/login.json ]; then unlink build/bin/login.json; fi
cd build/bin && ln -s ../../.devcontainer/override/login.json login.json
@echo "Cloning repositories..."
cd .devcontainer/repo && if [ ! -d "quests" ]; then cd ../../.devcontainer/repo/ && git clone https://github.com/ProjectEQ/projecteqquests.git quests; fi
cd .devcontainer/repo && if [ ! -d "eqemu-definitions" ]; then cd ../../.devcontainer/repo/ && git clone https://github.com/xackery/eqemu-definitions.git eqemu-definitions; fi
cd .devcontainer/repo && if [ ! -d "maps" ]; then cd ../../ && make maps; fi
@if [ -d build/bin/quests ]; then unlink build/bin/quests; fi
cd build/bin && ln -s ../../.devcontainer/repo/quests quests
@if [ -d build/bin/maps ]; then unlink build/bin/maps; fi
cd build/bin && ln -s ../../.devcontainer/repo/maps maps
@if [ -d build/bin/eqemu-definitions ]; then unlink build/bin/eqemu-definitions; fi
cd build/bin && ln -s ../../.devcontainer/repo/eqemu-definitions eqemu-definitions
@mkdir -p build/bin/quests/mods
@echo "Applying base links..."
cp -R -u -p utils/patches .devcontainer/base/
@if [ -d build/bin/assets/patches ]; then unlink build/bin/assets/patches; fi
cd build/bin/assets && ln -s ../../../.devcontainer/base/patches patches
@if [ -d build/bin/lua_modules ]; then unlink build/bin/lua_modules; fi
cd build/bin && ln -s ../../.devcontainer/repo/quests/lua_modules lua_modules
@if [ -d build/bin/mods ]; then unlink build/bin/mods; fi
cd build/bin && ln -s ../../.devcontainer/repo/quests/mods mods
@if [ -d build/bin/plugins ]; then unlink build/bin/plugins; fi
cd build/bin && ln -s ../../.devcontainer/repo/quests/plugins plugins
@echo "Eqemu is prepared. Edit build/bin/eqemu_config.json to configure." @echo "Eqemu is prepared. Edit build/bin/eqemu_config.json to configure."
maps: is-vscode:
@echo "Downloading maps..." @if [ -z "$$REMOTE_CONTAINERS" ]; then \
@mkdir -p base/maps echo "Not running in VS Code devcontainer"; \
@cd base/maps && wget -nc https://github.com/Akkadius/eqemu-maps/archive/refs/heads/master.zip exit 1; \
@cd base/maps && unzip -o master.zip fi
@cd base/maps && mv eqemu-maps-master/* .
@cd base/maps && rm -rf eqemu-maps-master
@echo "Maps downloaded."
quests: clean: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) rm -rf build
@make -C ../ -f .devcontainer/Makefile quests --no-print-directory
exit .PHONY: maps
endif maps: is-vscode
@cd build/bin && git clone https://github.com/ProjectEQ/projecteqquests.git quests @echo "Downloading maps..."
@mkdir -p .devcontainer/repo/maps
@cd .devcontainer/repo/maps && wget -nc https://github.com/EQEmu/maps/archive/refs/heads/master.zip
@cd .devcontainer/repo/maps && unzip -o master.zip
@cd .devcontainer/repo/maps && mv maps-master/* .
@cd .devcontainer/repo/maps && rm -rf maps-master
@echo "Maps downloaded."
# Runs tests # Runs tests
.PHONY: test .PHONY: test
test: test: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile test --no-print-directory
exit
endif
cd build/bin && ./tests cd build/bin && ./tests
# Runs login binary # Runs login binary
.PHONY: login .PHONY: login
login: login: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile login --no-print-directory
exit
endif
cd build/bin && ./loginserver cd build/bin && ./loginserver
.PHONY: hotfix
hotfix: shared
# Runs shared_memory binary # Runs shared_memory binary
.PHONY: shared .PHONY: shared
shared: shared: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile shared --no-print-directory
exit
endif
cd build/bin && ./shared_memory cd build/bin && ./shared_memory
# Runs zone binary # Runs zone binary
.PHONY: zone .PHONY: zone
zone: zone: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) @find build/bin/logs/zone/ -type f -name 'zone*.log' -exec rm -f {} +
@make -C ../ -f .devcontainer/Makefile zone --no-print-directory
exit
endif
@-rm build/bin/logs/zone/zone*.log
cd build/bin && ./zone cd build/bin && ./zone
check-mariadb: is-vscode
@if ! sudo service mariadb status | grep -q 'active (running)'; then \
sudo service mariadb start; \
fi
# Runs world binary # Runs world binary
.PHONY: world .PHONY: world
world: world: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) @find build/bin/logs/ -type f -name 'world*.log' -exec rm -f {} +
@make -C ../ -f .devcontainer/Makefile world --no-print-directory
exit
endif
@-rm build/bin/logs/world*.log
cd build/bin && ./world cd build/bin && ./world
# Runs ucs binary # Runs ucs binary
.PHONY: ucs .PHONY: ucs
ucs: ucs: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) @find build/bin/logs/ -type f -name 'ucs*.log' -exec rm -f {} +
@make -C ../ -f .devcontainer/Makefile ucs --no-print-directory
exit
endif
@-rm build/bin/logs/ucs*.log
cd build/bin && ./ucs cd build/bin && ./ucs
# Runs queryserv binary # Runs queryserv binary
.PHONY: queryserv .PHONY: queryserv
queryserv: queryserv: is-vscode check-mariadb
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) @find build/bin/logs/ -type f -name 'query_server*.log' -exec rm -f {} +
@make -C ../ -f .devcontainer/Makefile queryserv --no-print-directory
exit
endif
@-rm build/bin/logs/query_server*.log
cd build/bin && ./queryserv cd build/bin && ./queryserv
valgrind-%: reset-content:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) @echo "Resetting content tables in database peq..."
@make -C ../ -f .devcontainer/Makefile valgrind --no-print-directory cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_content.sql"
exit
endif valgrind-%: is-vscode
cd build/bin && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=logs/$*.valgrind.log ./$* cd build/bin && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=logs/$*.valgrind.log ./$*
# Start mariaDB standalone # Start mariaDB standalone
@ -201,30 +132,33 @@ mariadb:
.PHONY: inject-mariadb .PHONY: inject-mariadb
inject-mariadb: inject-mariadb:
-sudo service mariadb start -sudo service mariadb start
-mkdir -p base/db/ -mkdir -p .devcontainer/cache/db/
-sudo mariadb -e 'DROP DATABASE IF EXISTS peq;' -sudo mariadb -e 'DROP DATABASE IF EXISTS peq;'
-sudo mariadb -e 'CREATE DATABASE peq;' -sudo mariadb -e 'CREATE DATABASE peq;'
-sudo mariadb -e "CREATE USER 'peq'@'127.0.0.1' IDENTIFIED BY 'peqpass';" -sudo mariadb -e "CREATE USER IF NOT EXISTS 'peq'@'127.0.0.1' IDENTIFIED BY 'peqpass';"
-sudo mariadb -e "GRANT ALL PRIVILEGES ON *.* TO 'peq'@'127.0.0.1';" -sudo mariadb -e "GRANT ALL PRIVILEGES ON *.* TO 'peq'@'127.0.0.1';"
ifeq (,$(wildcard base/db/db.sql.zip)) ifeq (,$(wildcard .devcontainer/cache/db/db.sql.zip))
@echo "base/db.sql.zip not found. Downloading latest from https://db.projecteq.net/" @echo ".devcontainer/cache/db.sql.zip not found. Downloading database from https://db.eqemu.dev/latest"
wget -nc https://db.projecteq.net/latest -O base/db/db.sql.zip wget -nc https://db.eqemu.dev/latest -O .devcontainer/cache/db/db.sql.zip
-cd base/db && unzip db.sql.zip -cd .devcontainer/cache/db && unzip db.sql.zip
endif endif
@echo "Sourcing db may take a while, please wait..." @echo "Sourcing db may take a while, please wait..."
@cd base/db/peq-dump && sudo mariadb --database peq -e "source create_all_tables.sql"
@cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_content.sql"
@cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_login.sql"
@cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_player.sql"
@# deprecated cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_queryserv.sql"
@cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_state.sql"
@cd .devcontainer/cache/db/peq-dump && sudo mariadb --database peq -e "source create_tables_system.sql"
@echo "MariaDB is now injected." @echo "MariaDB is now injected."
.PHONY: gm-% .PHONY: gm-%
gm-%: gm-%: is-vscode
sudo mariadb --database peq -e "UPDATE account SET status=255 WHERE name = '$*';" sudo mariadb --database peq -e "UPDATE account SET status=255 WHERE name = '$*';"
@echo "Account $* is now a GM. /camp to have it go into effect." @echo "Account $* is now a GM. /camp to have it go into effect."
depends: depends: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile depends --no-print-directory
exit
endif
sudo apt install graphviz pip time sudo apt install graphviz pip time
pip3 install graphviz pip3 install graphviz
mkdir -p build/depends mkdir -p build/depends
@ -241,44 +175,54 @@ endif
@echo "Common..." @echo "Common..."
time python3 build/depends/dependency_graph.py -f png common build/depends/common.dot time python3 build/depends/dependency_graph.py -f png common build/depends/common.dot
backup: backup: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile backup --no-print-directory
exit
endif
@mkdir -p build/bin/backup @mkdir -p build/bin/backup
cd build/bin && ./world database:dump --compress --player-tables --state-tables --system-tables --query-serv-tables cd build/bin && ./world database:dump --compress --player-tables --state-tables --system-tables --query-serv-tables
cpu-zone: restore-%: is-vscode
@if [ -z "$*" ]; then \
echo "Please provide a backup file to restore from. Example: make restore-backup.sql"; \
exit 1; \
fi
@echo "Restoring from backup $*"
@sudo mariadb --database peq -e "$*"
cpu-zone: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile cpu-zone --no-print-directory @echo "This makefile is not intended to be run from the .devcontainer directory."
exit exit
endif endif
@cd build/bin && mkdir -p tmp @cd build/bin && mkdir -p tmp
cd build/bin && CPUPROFILE=prof.out ./zone cd build/bin && CPUPROFILE=prof.out ./zone
pprof-zone: pprof-zone: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile pprof-zone --no-print-directory @echo "This makefile is not intended to be run from the .devcontainer directory."
exit exit
endif endif
cd build/bin && google-pprof --pdf zone prof.out > prof.pdf cd build/bin && google-pprof --pdf zone prof.out > prof.pdf
pprof-web-zone:
pprof-gv-zone: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile pprof-web-zone --no-print-directory @echo "This makefile is not intended to be run from the .devcontainer directory."
exit
endif
cd build/bin && google-pprof --web zone prof.out
pprof-gv-zone:
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile pprof-gv-zone --no-print-directory
exit exit
endif endif
cd build/bin && google-pprof --gv zone prof.out > prof.gv cd build/bin && google-pprof --gv zone prof.out > prof.gv
heap-zone:
heap-zone: is-vscode
ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer) ifeq ($(findstring .devcontainer,$(CURDIR)),.devcontainer)
@make -C ../ -f .devcontainer/Makefile heap-zone --no-print-directory @echo "This makefile is not intended to be run from the .devcontainer directory."
exit exit
endif endif
@cd build/bin && mkdir -p tmp @cd build/bin && mkdir -p tmp
cd build/bin && HEAPPROFILE=prof.out ./zone cd build/bin && HEAPPROFILE=prof.out ./zone
.PHONY: pull
pull:
git pull
@if [ ! -d "quests" ]; then git clone https://github.com/rebuildeq/quests.git quests; fi
cd quests && git pull
@if [ ! -d "eqemu-definitions" ]; then git clone https://github.com/xackery/eqemu-definitions.git eqemu-definitions; fi
cd eqemu-definitions && git pull

View File

@ -40,10 +40,41 @@
"GitHub.copilot", "GitHub.copilot",
"xackery.make-magic", "xackery.make-magic",
"Gruntfuggly.todo-tree", "Gruntfuggly.todo-tree",
"ms-vscode.cmake-tools" "ms-vscode.cmake-tools",
] "sumneko.lua"
],
"settings": {
"Lua.runtime.version": "Lua 5.1",
"Lua.workspace.library": [
"/src/repo/eqemu-definitions"
],
"Lua.diagnostics.disable": [
"lowercase-global"
],
"cmake.statusbar.advanced": {
"kit": {
"visibility": "hidden"
},
"debug": {
"visibility": "hidden"
},
"buildTarget": {
"visibility": "compact"
},
"launch": {
"visibility": "hidden"
},
"ctest": {
"visibility": "icon"
}
}
}
} }
}, },
"mounts": [
"source=${localWorkspaceFolder}/.devcontainer/Makefile,target=/src/Makefile,type=bind,consistency=cached"
],
"workspaceFolder": "/src", "workspaceFolder": "/src",
"workspaceMount": "source=${localWorkspaceFolder},target=/src,type=bind,consistency=cached" "workspaceMount": "source=${localWorkspaceFolder},target=/src,type=bind,consistency=cached"
} }

View File

@ -1,98 +0,0 @@
---
kind: pipeline
type: docker
name: Build Linux
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
limit: 1
volumes:
- name: cache
host:
path: /var/lib/cache-release
steps:
- name: Build Linux X64
image: akkadius/eqemu-server:v14
environment:
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
commands:
- ./utils/scripts/build/linux-build.sh
volumes:
- name: cache
path: /home/eqemu/.ccache/
---
kind: pipeline
type: exec
name: Build Windows
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
limit: 1
platform:
os: windows
arch: amd64
steps:
- name: Build Windows X64
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- .\utils\scripts\build\windows-build.ps1
---
kind: pipeline
type: docker
name: Publish Artifacts to Github
steps:
- name: Upload Artifacts
image: akkadius/eqemu-build-releaser:v3
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GH_RELEASE_GITHUB_API_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- ./utils/scripts/build/should-release/should-release
- rclone config create remote ftp env_auth true > /dev/null
- |
rclone copy remote: --include "eqemu-server*.zip" .
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
- |
rclone delete remote: --include "eqemu-server*.zip"
trigger:
branch:
- master
event:
- push
depends_on:
- Build Windows
- Build Linux

81
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,81 @@
name: Build
on:
push:
branches:
- master
pull_request:
jobs:
linux:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v5
with:
submodules: recursive
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-ccache
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential ninja-build ccache libmariadb-dev libmariadb-dev-compat libboost-all-dev libperl-dev liblua5.1-0-dev libluajit-5.1-dev zlib1g-dev uuid-dev libssl-dev libsodium-dev libmbedtls-dev
- name: Configure
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DEQEMU_BUILD_TESTS=ON \
-DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_LUA=ON \
-DEQEMU_BUILD_PERL=ON \
-DEQEMU_BUILD_CLIENT_FILES=ON
- name: Build
run: cmake --build build --parallel
- name: Test
working-directory: build
run: ./bin/tests
windows:
name: Windows
runs-on: windows-latest
steps:
- name: Checkout source
uses: actions/checkout@v5
with:
submodules: recursive
- name: Enable long paths
run: git config --global core.longpaths true
- name: Setup MSVC environment
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Configure
shell: pwsh
run: |
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
-DEQEMU_BUILD_TESTS=ON `
-DEQEMU_BUILD_LOGIN=ON `
-DEQEMU_BUILD_LUA=ON `
-DEQEMU_BUILD_ZLIB=ON `
-DEQEMU_BUILD_CLIENT_FILES=ON
- name: Build
shell: pwsh
run: cmake --build build --config RelWithDebInfo --target ALL_BUILD -- /m
- name: Test
working-directory: build
run: ./bin/RelWithDebInfo/tests.exe

25
.vscode/settings.json vendored
View File

@ -21,14 +21,6 @@
"${workspaceFolder}/dependencies/zlibng" "${workspaceFolder}/dependencies/zlibng"
], ],
"telemetry.enableTelemetry": false, "telemetry.enableTelemetry": false,
"cmake.buildDirectory": "${workspaceFolder}/build",
"cmake.configureArgs": [
"-DEQEMU_BUILD_LOGIN=ON",
"-DEQEMU_BUILD_TESTS=ON",
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
"-DEQEMU_ADD_PROFILER=ON",
"Ninja"
],
"cmake.skipConfigureIfCachePresent": true, "cmake.skipConfigureIfCachePresent": true,
"cmake.configureOnOpen": false, "cmake.configureOnOpen": false,
"files.associations": { "files.associations": {
@ -115,22 +107,5 @@
"format": "cpp", "format": "cpp",
"ranges": "cpp", "ranges": "cpp",
"span": "cpp" "span": "cpp"
},
"cmake.statusbar.advanced": {
"kit": {
"visibility": "hidden",
},
"debug": {
"visibility": "hidden",
},
"buildTarget": {
"visibility": "hidden",
},
"launch": {
"visibility": "hidden",
},
"ctest": {
"visibility": "icon",
}
} }
} }

View File

@ -1,3 +1,283 @@
## [23.10.3] 9/16/2025
### Hotfix
* Hotfix crashes occurring in #4987. @Akkadius 2025-09-17
## [23.10.2] 9/16/2025
### Hotfix
* Revert #4996 as it was causing critical issues with spells that needs to be further investigated. @Akkadius 2025-09-17
## [23.10.1] 9/16/2025
### Hotfix
* Fixed Mail Key Bug ([#5015](https://github.com/EQEmu/Server/pull/5015)) @Kinglykrab 2025-09-16
## [23.10.0] 9/15/2025
### Build
* Fix Linking with GCC ([#4969](https://github.com/EQEmu/Server/pull/4969)) @solar984 2025-08-03
### Code
* Add #npcedit npc_tint_id Help Message ([#4982](https://github.com/EQEmu/Server/pull/4982)) @Kinglykrab 2025-08-17
* Cleanup #show ip_lookup Message ([#5005](https://github.com/EQEmu/Server/pull/5005)) @Kinglykrab 2025-08-30
* Fix #set race 0 Message ([#5004](https://github.com/EQEmu/Server/pull/5004)) @Kinglykrab 2025-08-30
* Fix Issues with Strings::Commify and Mob::SendStatsWindow ([#4984](https://github.com/EQEmu/Server/pull/4984)) @Kinglykrab 2025-08-17
* Remove Attributions ([#4988](https://github.com/EQEmu/Server/pull/4988)) @KimLS 2025-08-16
* Remove Unused errorname Variable ([#5001](https://github.com/EQEmu/Server/pull/5001)) @Kinglykrab 2025-08-29
### Commands
* Add #find account Subcommand ([#4981](https://github.com/EQEmu/Server/pull/4981)) @Kinglykrab 2025-08-17
* Add #show keyring Subcommand ([#4973](https://github.com/EQEmu/Server/pull/4973)) @Kinglykrab 2025-08-03
* Add #task complete Saylink to #task show ([#4985](https://github.com/EQEmu/Server/pull/4985)) @Kinglykrab 2025-08-17
### Constants
* Change Race Changes to Race Namespace ([#5000](https://github.com/EQEmu/Server/pull/5000)) @Kinglykrab 2025-08-30
* Convert SE Defines to SpellEffect Namespace ([#4999](https://github.com/EQEmu/Server/pull/4999)) @Kinglykrab 2025-08-30
### Database
* Add `heal_amount` to `character_stats_record` ([#4986](https://github.com/EQEmu/Server/pull/4986)) @Kinglykrab 2025-08-17
### Fixes
* Fix #show recipe uint16 Cap ([#4978](https://github.com/EQEmu/Server/pull/4978)) @Kinglykrab 2025-08-11
* Fix Race 474 for Titanium ([#4979](https://github.com/EQEmu/Server/pull/4979)) @regneq 2025-08-11
* Fix Recipe Inspect Bug ([#4994](https://github.com/EQEmu/Server/pull/4994)) @Kinglykrab 2025-08-30
* Fix Several Evolving Item Bugs ([#4992](https://github.com/EQEmu/Server/pull/4992)) @neckkola 2025-09-08
* Fix Task Reloading ([#5002](https://github.com/EQEmu/Server/pull/5002)) @Kinglykrab 2025-08-29
### Loginserver
* Fix Legacy World When Using Local DB ([#4970](https://github.com/EQEmu/Server/pull/4970)) @solar984 2025-08-03
### Pets
* Add Pet Constants and Methods ([#4987](https://github.com/EQEmu/Server/pull/4987)) @Kinglykrab 2025-08-17
### Quest API
* Add EVENT_CHARM_START and EVENT_CHARM_END ([#5013](https://github.com/EQEmu/Server/pull/5013)) @Kinglykrab 2025-09-15
* Add GetKeyRing() to Perl/Lua ([#4980](https://github.com/EQEmu/Server/pull/4980)) @Kinglykrab 2025-08-17
* Add GetNPCTintIndex() to Perl/Lua ([#4983](https://github.com/EQEmu/Server/pull/4983)) @Kinglykrab 2025-08-17
* Add GetTimers() and GetPausedTimers() to Perl/Lua ([#4965](https://github.com/EQEmu/Server/pull/4965)) @Kinglykrab 2025-08-03
* Add Identifiers to Get/Modify NPC Stat Methods ([#5012](https://github.com/EQEmu/Server/pull/5012)) @Kinglykrab 2025-09-15
### Repositories
* Convert Character Inspect Messages to Repositories ([#4997](https://github.com/EQEmu/Server/pull/4997)) @Kinglykrab 2025-08-30
* Convert Damage Shield Types to Repositories ([#4995](https://github.com/EQEmu/Server/pull/4995)) @Kinglykrab 2025-08-30
* Convert Item Loading to Repositories ([#4998](https://github.com/EQEmu/Server/pull/4998)) @Kinglykrab 2025-08-30
* Convert Mail Key to Repositories ([#5007](https://github.com/EQEmu/Server/pull/5007)) @Kinglykrab 2025-09-15
* Convert Shared Bank Platinum to Repositories ([#5006](https://github.com/EQEmu/Server/pull/5006)) @Kinglykrab 2025-09-02
* Convert Spell Loading to Repositories ([#4996](https://github.com/EQEmu/Server/pull/4996)) @Kinglykrab 2025-08-30
* Convert Total Time Played to Repositories ([#5008](https://github.com/EQEmu/Server/pull/5008)) @Kinglykrab 2025-09-15
## [23.9.1] 8/2/2025
### Hotfix
* Fix Quest Ownership Edge Case ([#4977](https://github.com/EQEmu/Server/pull/4977)) @Kinglykrab 2025-08-02
## [23.9.0] 8/2/2025
### Bots
* Fix FinishBuffing rule ([#4961](https://github.com/EQEmu/Server/pull/4961)) @nytmyr 2025-07-01
* Fix ^cast resurrects ([#4958](https://github.com/EQEmu/Server/pull/4958)) @nytmyr 2025-06-29
### Build
* Fix Linking with GCC ([#4969](https://github.com/EQEmu/Server/pull/4969)) @solar984 2025-08-03
* More Build Speed Improvements ([#4959](https://github.com/EQEmu/Server/pull/4959)) @Akkadius 2025-06-30
### Commands
* Add #show keyring Subcommand ([#4973](https://github.com/EQEmu/Server/pull/4973)) @Kinglykrab 2025-08-03
### Database
* Add Indexes to NPC's Spawns Loot ([#4972](https://github.com/EQEmu/Server/pull/4972)) @Akkadius 2025-07-30
### Feature
* Zone Scripting ([#4908](https://github.com/EQEmu/Server/pull/4908)) @Kinglykrab 2025-07-10
### Fixes
* Add a missing Froglok starting area for Titanium Startzone. ([#4962](https://github.com/EQEmu/Server/pull/4962)) @regneq 2025-07-04
* Fix Hero's Forge Ingame and Character Select ([#4966](https://github.com/EQEmu/Server/pull/4966)) @Kinglykrab 2025-07-30
* Show player count on the server list status. ([#4971](https://github.com/EQEmu/Server/pull/4971)) @regneq 2025-07-30
### Loginserver
* Fix Legacy World When Using Local DB ([#4970](https://github.com/EQEmu/Server/pull/4970)) @solar984 2025-08-03
### Performance
* Clear Wearchange Deduplication Cache ([#4960](https://github.com/EQEmu/Server/pull/4960)) @Akkadius 2025-06-30
### Quest API
* Add GetMemberRole() to Perl/Lua ([#4963](https://github.com/EQEmu/Server/pull/4963)) @Barathos 2025-07-10
* Add GetTimers() and GetPausedTimers() to Perl/Lua ([#4965](https://github.com/EQEmu/Server/pull/4965)) @Kinglykrab 2025-08-03
## [23.8.1] 6/28/2025
### Crash Fix
* Fix Possible Crashes with Raid Methods ([#4955](https://github.com/EQEmu/Server/pull/4955)) @Kinglykrab 2025-06-26
### Databuckets
* Revert Caching Changes of #4917 ([#4957](https://github.com/EQEmu/Server/pull/4957)) @Akkadius 2025-06-28
### Fixes
* Fix FindCharacter Using content_db ([#4956](https://github.com/EQEmu/Server/pull/4956)) @Kinglykrab 2025-06-26
* Fix Hero Forge on Character Select ([#4954](https://github.com/EQEmu/Server/pull/4954)) @Kinglykrab 2025-06-26
## [23.8.0] 6/25/2025
### API
* Add wwmarquee <type> <message> ([#4919](https://github.com/EQEmu/Server/pull/4919)) @Akkadius 2025-06-23
### Build
* Significantly Improve Build Times Using Unity Builds ([#4948](https://github.com/EQEmu/Server/pull/4948)) @Akkadius 2025-06-22
### Code
* AdventureManager Global to Singleton Cleanup ([#4931](https://github.com/EQEmu/Server/pull/4931)) @Kinglykrab 2025-06-25
* Cleanup Strings Header ([#4950](https://github.com/EQEmu/Server/pull/4950)) @Akkadius 2025-06-22
* ClientList Global to Singleton Cleanup ([#4942](https://github.com/EQEmu/Server/pull/4942)) @Kinglykrab 2025-06-25
* DatabaseUpdate Global to Singleton Cleanup ([#4943](https://github.com/EQEmu/Server/pull/4943)) @Kinglykrab 2025-06-25
* DiscordManager Global to Singleton Cleanup ([#4926](https://github.com/EQEmu/Server/pull/4926)) @Kinglykrab 2025-06-25
* EQ::Random Global to Singleton Cleanup ([#4936](https://github.com/EQEmu/Server/pull/4936)) @Kinglykrab 2025-06-22
* EQEmuLogSys Global to Singleton Cleanup ([#4925](https://github.com/EQEmu/Server/pull/4925)) @Akkadius 2025-06-25
* EvolvingItemsManager Global to Singleton Cleanup ([#4929](https://github.com/EQEmu/Server/pull/4929)) @Kinglykrab 2025-06-25
* LFGuildManager Global to Singleton Cleanup ([#4927](https://github.com/EQEmu/Server/pull/4927)) @Kinglykrab 2025-06-25
* LoginServerList Global to Singleton Cleanup ([#4941](https://github.com/EQEmu/Server/pull/4941)) @Kinglykrab 2025-06-25
* Optimize PCH Config (Faster Builds) ([#4951](https://github.com/EQEmu/Server/pull/4951)) @Akkadius 2025-06-22
* PCH Cleanup ([#4952](https://github.com/EQEmu/Server/pull/4952)) @Akkadius 2025-06-25
* PathManager Global to Singleton Cleanup ([#4924](https://github.com/EQEmu/Server/pull/4924)) @Akkadius 2025-06-22
* PetitionList Global to Singleton Cleanup ([#4944](https://github.com/EQEmu/Server/pull/4944)) @Kinglykrab 2025-06-25
* PlayerEventLogs Global to Singleton Cleanup ([#4928](https://github.com/EQEmu/Server/pull/4928)) @Kinglykrab 2025-06-25
* QueryServConnection Global to Singleton Cleanup ([#4938](https://github.com/EQEmu/Server/pull/4938)) @Kinglykrab 2025-06-25
* Remove Lua Rule Constants ([#4949](https://github.com/EQEmu/Server/pull/4949)) @Akkadius 2025-06-22
* Remove Regex Compile Bloat ([#4947](https://github.com/EQEmu/Server/pull/4947)) @Akkadius 2025-06-22
* Remove Unused MZoneShutdown Mutex ([#4946](https://github.com/EQEmu/Server/pull/4946)) @Kinglykrab 2025-06-22
* SharedTaskManager Global to Singleton Cleanup ([#4930](https://github.com/EQEmu/Server/pull/4930)) @Kinglykrab 2025-06-25
* SkillCaps Global to Singleton Cleanup ([#4933](https://github.com/EQEmu/Server/pull/4933)) @Kinglykrab 2025-06-22
* TaskManager Global to Singleton Cleanup ([#4945](https://github.com/EQEmu/Server/pull/4945)) @Kinglykrab 2025-06-22
* UCSConnection Global to Singleton Cleanup ([#4937](https://github.com/EQEmu/Server/pull/4937)) @Kinglykrab 2025-06-25
* WebInterfaceList Global to Singleton Cleanup ([#4935](https://github.com/EQEmu/Server/pull/4935)) @Kinglykrab 2025-06-25
* WorldContentServer Global to Singleton Cleanup ([#4939](https://github.com/EQEmu/Server/pull/4939)) @Kinglykrab 2025-06-25
* WorldEventScheduler and ZoneEventScheduler Global to Singleton Cleanup ([#4932](https://github.com/EQEmu/Server/pull/4932)) @Kinglykrab 2025-06-25
* ZSList Global to Singleton Cleanup ([#4940](https://github.com/EQEmu/Server/pull/4940)) @Kinglykrab 2025-06-25
* ZoneStore Global to Singleton Cleanup ([#4934](https://github.com/EQEmu/Server/pull/4934)) @Kinglykrab 2025-06-23
### Corpses
* Add corpse entity variables to DB ([#4911](https://github.com/EQEmu/Server/pull/4911)) @fryguy503 2025-06-25
### Databuckets
* Move Databuckets to Common ([#4918](https://github.com/EQEmu/Server/pull/4918)) @Akkadius 2025-06-16
* Nested Caching ([#4917](https://github.com/EQEmu/Server/pull/4917)) @Akkadius 2025-06-25
### Doors
* Fix door saving for versions ([#4905](https://github.com/EQEmu/Server/pull/4905)) @nytmyr 2025-06-09
### Fixes
* Bulk Send Corpses after Idle State ([#4910](https://github.com/EQEmu/Server/pull/4910)) @Akkadius 2025-06-09
* Fix ClientList Singleton Shortcomings of #4942 @Akkadius 2025-06-25
* Fix breaking changes to Titanium, SoF, SoD patches causes by big bags update ([#4922](https://github.com/EQEmu/Server/pull/4922)) @regneq 2025-06-25
### Logs
* Fix output for tasks in logs ([#4907](https://github.com/EQEmu/Server/pull/4907)) @joligario 2025-06-09
### Performance
* Auto Idle / AFK ([#4903](https://github.com/EQEmu/Server/pull/4903)) @Akkadius 2025-05-22
* Wearchange Packet Send Deduplication ([#4916](https://github.com/EQEmu/Server/pull/4916)) @Akkadius 2025-06-25
### Player Event Logs
* Don't Clear Event Data on ETL Events ([#4913](https://github.com/EQEmu/Server/pull/4913)) @Akkadius 2025-06-25
### Player Events
* Don't Write Empty Data ([#4912](https://github.com/EQEmu/Server/pull/4912)) @Akkadius 2025-06-25
* Zone Fetch Settings from QS if Enabled ([#4915](https://github.com/EQEmu/Server/pull/4915)) @Akkadius 2025-06-25
### Quest API
* Add CompleteTask and UncompleteTask methods to Perl/Lua ([#4921](https://github.com/EQEmu/Server/pull/4921)) @Barathos 2025-06-25
* Lua Client Scoped EnableTitleSets ([#4914](https://github.com/EQEmu/Server/pull/4914)) @fryguy503 2025-06-25
### Quests
* Support Multiple Quest, Plugin, and Lua Module Paths ([#4906](https://github.com/EQEmu/Server/pull/4906)) @Akkadius 2025-06-09
### World API
* Input Validation ([#4904](https://github.com/EQEmu/Server/pull/4904)) @Akkadius 2025-05-22
## [23.7.0] 5/19/2025
### CLI
* Add custom database version output ([#4901](https://github.com/EQEmu/Server/pull/4901)) @joligario 2025-05-18
* Fix MySQL check in database dumper ([#4897](https://github.com/EQEmu/Server/pull/4897)) @joligario 2025-05-16
### Commands
* Add #zonevariable Command ([#4882](https://github.com/EQEmu/Server/pull/4882)) @Kinglykrab 2025-05-15
### Database
* Add Custom Database Migrations for Operators ([#4892](https://github.com/EQEmu/Server/pull/4892)) @Akkadius 2025-05-16
* Remove Transaction Wrapped Character Save ([#4894](https://github.com/EQEmu/Server/pull/4894)) @Akkadius 2025-05-16
### Fixes
* Deadlock on failed #copycharacter commands ([#4887](https://github.com/EQEmu/Server/pull/4887)) @Akkadius 2025-05-16
### Logging
* Auto Update Log Category Names ([#4890](https://github.com/EQEmu/Server/pull/4890)) @Akkadius 2025-05-16
### Netcode
* Resend Logic Adjustments ([#4900](https://github.com/EQEmu/Server/pull/4900)) @Akkadius 2025-05-18
### Player Events
* Add rule to ignore configured GM commands ([#4888](https://github.com/EQEmu/Server/pull/4888)) @Akkadius 2025-05-16
### Rules
* Auto Update Rule Notes from Source ([#4891](https://github.com/EQEmu/Server/pull/4891)) @Akkadius 2025-05-16
### World
* Fix Rarer Reload Deadlock ([#4893](https://github.com/EQEmu/Server/pull/4893)) @Akkadius 2025-05-16
### Zone State
* Load New Spawn2 Data When Present ([#4889](https://github.com/EQEmu/Server/pull/4889)) @Akkadius 2025-05-16
## [23.6.0] 5/14/2025 ## [23.6.0] 5/14/2025
### Bots ### Bots

View File

@ -42,6 +42,7 @@ IF(USE_MAP_MMFS)
ENDIF (USE_MAP_MMFS) ENDIF (USE_MAP_MMFS)
IF(MSVC) IF(MSVC)
add_compile_options(/bigobj)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-DNOMINMAX) ADD_DEFINITIONS(-DNOMINMAX)
ADD_DEFINITIONS(-DCRASH_LOGGING) ADD_DEFINITIONS(-DCRASH_LOGGING)
@ -362,6 +363,8 @@ MESSAGE(STATUS "**************************************************")
#setup server libs and headers #setup server libs and headers
SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour) SET(SERVER_LIBS common ${DATABASE_LIBRARY_LIBS} ${ZLIB_LIBRARY_LIBS} ${Boost_LIBRARIES} uv_a fmt RecastNavigation::Detour)
set(FMT_HEADER_ONLY OFF)
INCLUDE_DIRECTORIES(SYSTEM "${DATABASE_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${DATABASE_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}")
INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}") INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}")

49
CMakePresets.json Normal file
View File

@ -0,0 +1,49 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "linux-debug",
"displayName": "Linux Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"EQEMU_BUILD_LOGIN": "ON",
"EQEMU_BUILD_TESTS": "ON",
"EQEMU_ADD_PROFILER": "ON"
}
},
{
"name": "linux-release",
"displayName": "Linux Release",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"EQEMU_BUILD_LOGIN": "ON"
}
},
{
"name": "win-msvc",
"displayName": "Windows MSVC (VS 2022)",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/{presetName}",
"architecture": { "value": "x64" },
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release",
"EQEMU_BUILD_LOGIN": "ON",
"EQEMU_BUILD_TESTS": "ON"
}
}
]
}

179
README.md
View File

@ -1,83 +1,150 @@
# EQEmulator Core Server <h1 align="center">EQEmulator Server Platform</h1>
| Drone (Linux x64) | Drone (Windows x64) |
|:---:|:---:| <p align="center">
|[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) | <img src="https://github.com/user-attachments/assets/11942e15-b512-402d-a619-0543c7f1151e" style="border-radius: 10px">
</p>
<p align="center">
<b>EQEmulator - A Fan-Made Project Honoring a Legendary MMORPG</b>
</p>
<p align="center">
<a href="https://github.com/eqemu/server/graphs/contributors"><img src="https://img.shields.io/github/contributors/eqemu/server" alt="Contributors"></a>
<a href="https://discord.gg/QHsm7CD"><img src="https://img.shields.io/discord/212663220849213441?label=Discord&amp;logo=discord&amp;color=7289DA" alt="Discord"></a>
<a href="https://docs.eqemu.io"><img src="https://img.shields.io/badge/docs-MkDocs%20Powered-blueviolet" alt="Docs"></a>
<a href="./LICENSE"><img src="https://img.shields.io/github/license/EQEmu/Server" alt="License"></a>
<a href="https://github.com/eqemu/server/releases"><img src="https://img.shields.io/github/v/release/eqemu/server" alt="Latest Release"></a>
<a href="https://github.com/EQEmu/Server/releases"><img src="https://img.shields.io/github/release-date/EQEmu/Server" alt="Release Date"></a>
<img src="https://img.shields.io/github/downloads/eqemu/server/total.svg" alt="Github All Releases"></a>
<a href="http://drone.akkadius.com/EQEmu/Server"><img src="http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg" alt="Build Status"></a>
<img src="https://img.shields.io/github/issues-pr-closed/eqemu/server" alt="GitHub Issues or Pull Requests">
<img src="https://img.shields.io/docker/pulls/akkadius/eqemu-server" alt="Docker Pulls">
<a href="http://drone.akkadius.com/EQEmu/Server"><img src="http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg" alt="Build Status"></a> <img src="https://jb.gg/badges/official-plastic.svg" alt="Official">
</p>
*** ***
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++** <p align="center">
* MySQL/MariaDB is used as the database engine (over 200+ tables) EQEmulator is a <b>passion-driven</b>, <b>open source server emulator</b> project dedicated to preserving and celebrating the legacy of a groundbreaking classic MMORPG.
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events </p>
* Open source database (Project EQ) has content up to expansion OoW (included in server installs)
* Game server environments and databases can be heavily customized to create all new experiences
* Hundreds of Quests/events created and maintained by Project EQ
## Server Installs <p align="center">
| |Windows|Linux| For over two decades and continuing, EQEmulator has served as a <strong>fan tribute</strong>, providing tools and technology that allow players to explore, customize, and experience the legendary game's iconic gameplay in new ways. This project exists solely out of <strong>deep admiration</strong> for the original developers, artists, designers, and visionaries who created one of the most influential online worlds of all time.
|:---:|:---:|:---:| </p>
|**Install Count**|![Windows Install Count](http://analytics.akkadius.com/?install_count&windows_count)|![Linux Install Count](http://analytics.akkadius.com/?install_count&linux_count)|
### > Windows
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-windows/) <p align="center">
We do not claim ownership of the original game or its assets. <strong>All credit and respect belong to the original creators and Daybreak Game Company</strong>, whose work continues to inspire generations of players and developers alike.
</p>
### > Debian/Ubuntu/CentOS/Fedora <p align="center">
EQEmulator has for over 20 years and always will be a <strong>fan-based, non-commercial open-source effort</strong> made by players, for players—preserving the legacy of the game while empowering community-driven creativity, learning and joy that the game and its creators has so strongly inspired in us all.
</p>
* [Install Guide](https://docs.eqemu.io/server/installation/server-installation-linux/) ***
* You can use curl or wget to kick off the installer (whichever your OS has) <h3 align="center">
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh Technical Overview & Reverse Engineering Effort
</h1>
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh <p align="center">EQEmulator represents <strong>over two decades of collaborative reverse engineering</strong>, building the server from the ground up without access to the original source code. This effort was achieved entirely through <strong>community-driven analysis, network protocol decoding, and in-game behavioral research</strong>.</p>
## Supported Clients <h1 align="center">
💡 How We Did It
</h1>
<p align="center">
<img src="https://github.com/user-attachments/assets/b6b48cf7-f64a-4497-9750-71f442a3d132" height="300px">
</p>
<p align="center">
<strong>Reverse Engineering</strong>
Every system, packet, opcode, and game mechanic has been reconstructed through countless hours of live packet sniffing, client disassembly, and in-game experimentation by dedicated contributors over the years.
</p>
<p align="center">
No proprietary code or server sources were ever used.
</p>
<p align="center">
All implementations are the result of clean-room engineering.
</p>
<h1 align="center">
🛠️ Technology Stack
</h1>
<p align="center">
<img src="https://github.com/user-attachments/assets/df5ea809-86c5-439d-a8fa-651fb04ba477" style="border-radius: 10px">
</p>
**C++ Core Engine**
* High-performance networking and gameplay logic built in C++
* Cross-platform support for Linux and Windows
**MySQL / MariaDB Backend**
* Fully structured schema with over 200+ tables
* Supports content customization, expansions, and custom worlds
**Scripting Engine**
* Native support for **Perl** and **Lua** scripting
* Powerfully extendable for quests, NPC behaviors, and custom events
**Open Source Content Database**
* Includes ProjectEQs world data up through *Dragons of Norrath*
* 100% customizable to create entirely new game worlds
<h1 align="center">
🚀 Why It Matters
</h1>
<p align="center">🧬 EQEmulator stands as a <strong>technical preservation project</strong>, ensuring that the magic of classic and custom servers lives on for future generations of players, tinkerers, and game designers.
</p>
> We humbly acknowledge and thank the original developers for creating one of the most influential online experiences in gaming history.
<h1 align="center">
🧑‍💻🖥️ Supported Clients
</h1>
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear| |Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|:---:|:---:|:---:|:---:|:---:| |:---:|:---:|:---:|:---:|:---:|
|<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">| |<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">|
## Bug Reports <img src="http://i.imgur.com/daf1Vjw.png" height="20"> ## 📚 Resources
* Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
reports or feature requests.
* The [EQEmu Forums](http://www.eqemulator.org/forums/) are also a place to submit and get help with bugs.
## Contributions <img src="http://image.flaticon.com/icons/png/512/25/25231.png" width="20"> | Resource | Badges | Link |
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| **EQEmulator Docs** | [![Docs](https://img.shields.io/badge/docs-MkDocs%20Powered-blueviolet)](https://docs.eqemu.io) | [docs.eqemu.io](https://docs.eqemu.io/) |
| **Discord Community**| [![Discord](https://img.shields.io/discord/212663220849213441?label=Discord&logo=discord&color=7289DA)](https://discord.gg/QHsm7CD) | [Join Discord](https://discord.gg/QHsm7CD) |
| **Latest Release** | [![Latest Release](https://img.shields.io/github/v/release/eqemu/server)](https://github.com/eqemu/server/releases) <br> [![Release Date](https://img.shields.io/github/release-date/EQEmu/Server)](https://github.com/EQEmu/Server/releases) <br> [![All Releases](https://img.shields.io/github/downloads/eqemu/server/total.svg)](https://github.com/eqemu/server/releases) | [View Releases](https://github.com/eqemu/server/releases) |
| **License** | [![License](https://img.shields.io/github/license/EQEmu/Server)](./LICENSE) | [View License](./LICENSE) |
| **Build Status** | [![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) | [View Build Status](http://drone.akkadius.com/EQEmu/Server) |
| **Docker Pulls** | [![Docker Pulls](https://img.shields.io/docker/pulls/akkadius/eqemu-server)](https://hub.docker.com/r/akkadius/eqemu-server) | [Docker Hub](https://hub.docker.com/r/akkadius/eqemu-server) |
| **Contributions** | [![GitHub PRs](https://img.shields.io/github/issues-pr-closed/eqemu/server)](https://github.com/eqemu/server/pulls?q=is%3Apr+is%3Aclosed) | [Closed PRs & Issues](https://github.com/eqemu/server/pulls?q=is%3Apr+is%3Aclosed) |
* The preferred way to contribute is to fork the repo and submit a pull request on ## 🛠️ Getting Started
GitHub. If you need help with your changes, you can always post on the forums or
try Discord. You can also post unified diffs (`git diff` should do the trick) on the
[Server Code Submissions](http://www.eqemulator.org/forums/forumdisplay.php?f=669)
forum, although pull requests will be much quicker and easier on all parties.
## Contact <img src="http://gamerescape.com/wp-content/uploads/2015/06/discord.png" height="20"> If you want to set up your own EQEmulator server, please refer to the current [server installation guides](https://docs.eqemu.io/#server-installation). We've had 100,000s of players and developers use our guides to set up their own servers, and we hope you will too!
- Discord Channel: https://discord.gg/QHsm7CD ## 🗂️ Related Repositories
- **User Discord Channel**: `#general`
- **Developer Discord Channel**: `#eqemucoders`
## Resources | Repository | Description |
- [EQEmulator Forums](http://www.eqemulator.org/forums) |--------------------|----------------------------------------------------------------------------------|
- [EQEmulator Wiki](https://docs.eqemu.io/) | [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests) | Official quests and event scripts for ProjectEQ |
| [Maps](https://github.com/Akkadius/EQEmuMaps) | EQEmu-compatible zone maps |
| [Installer Resources](https://github.com/Akkadius/EQEmuInstall) | Scripts and assets for setting up EQEmu servers |
| [Zone Utilities](https://github.com/EQEmu/zone-utilities) | Utilities for parsing, rendering, and manipulating EQ zone files |
## Related Repositories
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
* [Maps](https://github.com/Akkadius/EQEmuMaps)
* [Installer Resources](https://github.com/Akkadius/EQEmuInstall)
* [Zone Utilities](https://github.com/EQEmu/zone-utilities) - Various utilities and libraries for parsing, rendering and manipulating EQ Zone files.
## Other License Info
* The server code and utilities are released under **GPLv3**
* We also include some small libraries for convienence that may be under different licensing
* SocketLib - GPL LibXML
* zlib - zlib license
* MariaDB/MySQL - GPL
* GPL Perl - GPL / ActiveState (under the assumption that this is a free project)
* CPPUnit - GLP StringUtilities - Apache
* LUA - MIT
## Contributors ## Contributors
<a href="https://github.com/EQEmu/server/graphs/contributors"> <a href="https://github.com/EQEmu/server/graphs/contributors">
<img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" /> <img src="https://contributors-img.firebaseapp.com/image?repo=EQEmu/server" />
</a> </a>

View File

@ -38,13 +38,6 @@
#include "../../common/skill_caps.h" #include "../../common/skill_caps.h"
#include "../../common/evolving_items.h" #include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EvolvingItemsManager evolving_items_manager;
void ExportSpells(SharedDatabase *db); void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db);
void ExportBaseData(SharedDatabase *db); void ExportBaseData(SharedDatabase *db);
@ -53,10 +46,10 @@ void ExportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
RegisterExecutablePlatform(ExePlatformClientExport); RegisterExecutablePlatform(ExePlatformClientExport);
LogSys.LoadLogSettingsDefaults(); EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
path.LoadPaths(); PathManager::Instance()->Init();
LogInfo("Client Files Export Utility"); LogInfo("Client Files Export Utility");
if (!EQEmuConfig::LoadConfig()) { if (!EQEmuConfig::LoadConfig()) {
@ -99,8 +92,8 @@ int main(int argc, char **argv)
content_db.SetMySQL(database); content_db.SetMySQL(database);
} }
LogSys.SetDatabase(&database) EQEmuLogSys::Instance()->SetDatabase(&database)
->SetLogPath(path.GetLogPath()) ->SetLogPath(PathManager::Instance()->GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@ -129,14 +122,14 @@ int main(int argc, char **argv)
ExportBaseData(&content_db); ExportBaseData(&content_db);
ExportDBStrings(&database); ExportDBStrings(&database);
LogSys.CloseFileLogs(); EQEmuLogSys::Instance()->CloseFileLogs();
return 0; return 0;
} }
void ExportSpells(SharedDatabase* db) void ExportSpells(SharedDatabase* db)
{ {
std::ofstream file(fmt::format("{}/export/spells_us.txt", path.GetServerPath())); std::ofstream file(fmt::format("{}/export/spells_us.txt", PathManager::Instance()->GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/spells_us.txt to write, skipping."); LogError("Unable to open export/spells_us.txt to write, skipping.");
return; return;
@ -155,7 +148,7 @@ void ExportSpells(SharedDatabase* db)
void ExportSkillCaps(SharedDatabase* db) void ExportSkillCaps(SharedDatabase* db)
{ {
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath())); std::ofstream file(fmt::format("{}/export/SkillCaps.txt", PathManager::Instance()->GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/SkillCaps.txt to write, skipping."); LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return; return;
@ -174,7 +167,7 @@ void ExportSkillCaps(SharedDatabase* db)
void ExportBaseData(SharedDatabase *db) void ExportBaseData(SharedDatabase *db)
{ {
std::ofstream file(fmt::format("{}/export/BaseData.txt", path.GetServerPath())); std::ofstream file(fmt::format("{}/export/BaseData.txt", PathManager::Instance()->GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/BaseData.txt to write, skipping."); LogError("Unable to open export/BaseData.txt to write, skipping.");
return; return;
@ -193,7 +186,7 @@ void ExportBaseData(SharedDatabase *db)
void ExportDBStrings(SharedDatabase *db) void ExportDBStrings(SharedDatabase *db)
{ {
std::ofstream file(fmt::format("{}/export/dbstr_us.txt", path.GetServerPath())); std::ofstream file(fmt::format("{}/export/dbstr_us.txt", PathManager::Instance()->GetServerPath()));
if (!file || !file.is_open()) { if (!file || !file.is_open()) {
LogError("Unable to open export/dbstr_us.txt to write, skipping."); LogError("Unable to open export/dbstr_us.txt to write, skipping.");
return; return;

View File

@ -32,13 +32,6 @@
#include "../../common/events/player_event_logs.h" #include "../../common/events/player_event_logs.h"
#include "../../common/evolving_items.h" #include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EvolvingItemsManager evolving_items_manager;
void ImportSpells(SharedDatabase *db); void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db);
void ImportBaseData(SharedDatabase *db); void ImportBaseData(SharedDatabase *db);
@ -46,10 +39,10 @@ void ImportDBStrings(SharedDatabase *db);
int main(int argc, char **argv) { int main(int argc, char **argv) {
RegisterExecutablePlatform(ExePlatformClientImport); RegisterExecutablePlatform(ExePlatformClientImport);
LogSys.LoadLogSettingsDefaults(); EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
path.LoadPaths(); PathManager::Instance()->Init();
LogInfo("Client Files Import Utility"); LogInfo("Client Files Import Utility");
if(!EQEmuConfig::LoadConfig()) { if(!EQEmuConfig::LoadConfig()) {
@ -92,8 +85,8 @@ int main(int argc, char **argv) {
content_db.SetMySQL(database); content_db.SetMySQL(database);
} }
LogSys.SetDatabase(&database) EQEmuLogSys::Instance()->SetDatabase(&database)
->SetLogPath(path.GetLogPath()) ->SetLogPath(PathManager::Instance()->GetLogPath())
->LoadLogDatabaseSettings() ->LoadLogDatabaseSettings()
->StartFileLogs(); ->StartFileLogs();
@ -102,7 +95,7 @@ int main(int argc, char **argv) {
ImportBaseData(&content_db); ImportBaseData(&content_db);
ImportDBStrings(&database); ImportDBStrings(&database);
LogSys.CloseFileLogs(); EQEmuLogSys::Instance()->CloseFileLogs();
return 0; return 0;
} }
@ -138,7 +131,7 @@ bool IsStringField(int i) {
void ImportSpells(SharedDatabase *db) { void ImportSpells(SharedDatabase *db) {
LogInfo("Importing Spells"); LogInfo("Importing Spells");
std::string file = fmt::format("{}/import/spells_us.txt", path.GetServerPath()); std::string file = fmt::format("{}/import/spells_us.txt", PathManager::Instance()->GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);
@ -228,7 +221,7 @@ void ImportSpells(SharedDatabase *db) {
void ImportSkillCaps(SharedDatabase *db) { void ImportSkillCaps(SharedDatabase *db) {
LogInfo("Importing Skill Caps"); LogInfo("Importing Skill Caps");
std::string file = fmt::format("{}/import/SkillCaps.txt", path.GetServerPath()); std::string file = fmt::format("{}/import/SkillCaps.txt", PathManager::Instance()->GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);
@ -265,7 +258,7 @@ void ImportBaseData(SharedDatabase *db)
{ {
LogInfo("Importing Base Data"); LogInfo("Importing Base Data");
const std::string& file_name = fmt::format("{}/import/BaseData.txt", path.GetServerPath()); const std::string& file_name = fmt::format("{}/import/BaseData.txt", PathManager::Instance()->GetServerPath());
const auto& file_contents = File::GetContents(file_name); const auto& file_contents = File::GetContents(file_name);
if (!file_contents.error.empty()) { if (!file_contents.error.empty()) {
@ -305,7 +298,7 @@ void ImportBaseData(SharedDatabase *db)
void ImportDBStrings(SharedDatabase *db) { void ImportDBStrings(SharedDatabase *db) {
LogInfo("Importing DB Strings"); LogInfo("Importing DB Strings");
std::string file = fmt::format("{}/import/dbstr_us.txt", path.GetServerPath()); std::string file = fmt::format("{}/import/dbstr_us.txt", PathManager::Instance()->GetServerPath());
FILE *f = fopen(file.c_str(), "r"); FILE *f = fopen(file.c_str(), "r");
if(!f) { if(!f) {
LogError("Unable to open {} to read, skipping.", file); LogError("Unable to open {} to read, skipping.", file);

View File

@ -60,10 +60,6 @@ IF(EQEMU_FETCH_MSVC_DEPENDENCIES_VCPKG)
ENDIF() ENDIF()
IF(EQEMU_FETCH_MSVC_DEPENDENCIES_PERL) IF(EQEMU_FETCH_MSVC_DEPENDENCIES_PERL)
#Try to find perl first, (so you can use your active install first)
FIND_PACKAGE(PerlLibs)
IF(NOT PerlLibs_FOUND)
MESSAGE(STATUS "Resolving perl dependencies...") MESSAGE(STATUS "Resolving perl dependencies...")
IF(NOT EXISTS ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_ZIP}) IF(NOT EXISTS ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_ZIP})
@ -91,4 +87,3 @@ IF(EQEMU_FETCH_MSVC_DEPENDENCIES_PERL)
SET(PERL_INCLUDE_PATH ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_DIR}/perl/lib/CORE CACHE PATH "Path to perl include files" FORCE) SET(PERL_INCLUDE_PATH ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_DIR}/perl/lib/CORE CACHE PATH "Path to perl include files" FORCE)
SET(PERL_LIBRARY ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_DIR}/perl/lib/CORE/libperl524.a CACHE FILEPATH "Path to perl library" FORCE) SET(PERL_LIBRARY ${PROJECT_SOURCE_DIR}/perl/${EQEMU_PERL_DIR}/perl/lib/CORE/libperl524.a CACHE FILEPATH "Path to perl library" FORCE)
ENDIF() ENDIF()
ENDIF()

View File

@ -17,6 +17,7 @@ SET(common_sources
database.cpp database.cpp
database_instances.cpp database_instances.cpp
database/database_update_manifest.cpp database/database_update_manifest.cpp
database/database_update_manifest_custom.cpp
database/database_update_manifest_bots.cpp database/database_update_manifest_bots.cpp
database/database_update.cpp database/database_update.cpp
dbcore.cpp dbcore.cpp
@ -103,9 +104,9 @@ SET(common_sources
net/console_server.cpp net/console_server.cpp
net/console_server_connection.cpp net/console_server_connection.cpp
net/crc32.cpp net/crc32.cpp
net/daybreak_connection.cpp
net/eqstream.cpp net/eqstream.cpp
net/packet.cpp net/packet.cpp
net/reliable_stream_connection.cpp
net/servertalk_client_connection.cpp net/servertalk_client_connection.cpp
net/servertalk_legacy_client_connection.cpp net/servertalk_legacy_client_connection.cpp
net/servertalk_server.cpp net/servertalk_server.cpp
@ -602,7 +603,6 @@ SET(common_headers
ipc_mutex.h ipc_mutex.h
ip_util.h ip_util.h
item_data.h item_data.h
item_fieldlist.h
item_instance.h item_instance.h
json_config.h json_config.h
light_source.h light_source.h
@ -670,13 +670,13 @@ SET(common_headers
net/console_server.h net/console_server.h
net/console_server_connection.h net/console_server_connection.h
net/crc32.h net/crc32.h
net/daybreak_connection.h
net/daybreak_pooling.h
net/daybreak_structs.h
net/dns.h net/dns.h
net/endian.h net/endian.h
net/eqstream.h net/eqstream.h
net/packet.h net/packet.h
net/reliable_stream_connection.h
net/reliable_stream_pooling.h
net/reliable_stream_structs.h
net/servertalk_client_connection.h net/servertalk_client_connection.h
net/servertalk_legacy_client_connection.h net/servertalk_legacy_client_connection.h
net/servertalk_common.h net/servertalk_common.h
@ -742,10 +742,6 @@ SOURCE_GROUP(Net FILES
net/console_server_connection.h net/console_server_connection.h
net/crc32.cpp net/crc32.cpp
net/crc32.h net/crc32.h
net/daybreak_connection.cpp
net/daybreak_connection.h
net/daybreak_pooling.h
net/daybreak_structs.h
net/dns.h net/dns.h
net/endian.h net/endian.h
net/eqmq.cpp net/eqmq.cpp
@ -754,6 +750,10 @@ SOURCE_GROUP(Net FILES
net/eqstream.h net/eqstream.h
net/packet.cpp net/packet.cpp
net/packet.h net/packet.h
net/reliable_stream_connection.cpp
net/reliable_stream_connection.h
net/reliable_stream_pooling.h
net/reliable_stream_structs.h
net/servertalk_client_connection.cpp net/servertalk_client_connection.cpp
net/servertalk_client_connection.h net/servertalk_client_connection.h
net/servertalk_legacy_client_connection.cpp net/servertalk_legacy_client_connection.cpp
@ -840,8 +840,13 @@ IF (UNIX)
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0) SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF (UNIX) ENDIF (UNIX)
IF (WIN32 AND EQEMU_BUILD_PCH) IF (EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h) TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/std-pch.h)
# Avoid PCH/__OPTIMIZE__ mismatch when compiling certain patch sources with -O0
# These files are compiled with -O0 on UNIX (see COMPILE_FLAGS above), which
# disables the __OPTIMIZE__ predefined macro. Disabling PCH for them prevents
# Clang from erroring due to macro state differences between the PCH and TU.
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
ENDIF () ENDIF ()
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

View File

@ -27,7 +27,7 @@ WorldContentService *WorldContentService::SetExpansionContext()
// pull expansion from rules // pull expansion from rules
int expansion = RuleI(Expansion, CurrentExpansion); int expansion = RuleI(Expansion, CurrentExpansion);
if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) { if (expansion >= Expansion::Classic && expansion <= Expansion::MaxId) {
content_service.SetCurrentExpansion(expansion); WorldContentService::Instance()->SetCurrentExpansion(expansion);
} }
LogInfo( LogInfo(
@ -41,12 +41,12 @@ WorldContentService *WorldContentService::SetExpansionContext()
std::string WorldContentService::GetCurrentExpansionName() std::string WorldContentService::GetCurrentExpansionName()
{ {
if (content_service.GetCurrentExpansion() == Expansion::EXPANSION_ALL) { if (WorldContentService::Instance()->GetCurrentExpansion() == Expansion::EXPANSION_ALL) {
return "All Expansions"; return "All Expansions";
} }
if (current_expansion >= Expansion::Classic && current_expansion <= Expansion::MaxId) { if (current_expansion >= Expansion::Classic && current_expansion <= Expansion::MaxId) {
return Expansion::ExpansionName[content_service.GetCurrentExpansion()]; return Expansion::ExpansionName[WorldContentService::Instance()->GetCurrentExpansion()];
} }
return "Unknown Expansion"; return "Unknown Expansion";
@ -185,7 +185,7 @@ void WorldContentService::ReloadContentFlags()
SetContentFlags(set_content_flags); SetContentFlags(set_content_flags);
LoadStaticGlobalZoneInstances(); LoadStaticGlobalZoneInstances();
zone_store.LoadZones(*m_content_database); ZoneStore::Instance()->LoadZones(*m_content_database);
} }
Database *WorldContentService::GetDatabase() const Database *WorldContentService::GetDatabase() const
@ -291,7 +291,7 @@ WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1 // instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id) WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
{ {
for (const auto &z: zone_store.GetZones()) { for (const auto &z: ZoneStore::Instance()->GetZones()) {
for (auto &i: m_zone_static_instances) { for (auto &i: m_zone_static_instances) {
if ( if (
z.zoneidnumber == zone_id && z.zoneidnumber == zone_id &&

View File

@ -181,6 +181,12 @@ public:
FindZoneResult FindZone(uint32 zone_id, uint32 instance_id); FindZoneResult FindZone(uint32 zone_id, uint32 instance_id);
bool IsInPublicStaticInstance(uint32 instance_id); bool IsInPublicStaticInstance(uint32 instance_id);
static WorldContentService* Instance()
{
static WorldContentService instance;
return &instance;
}
private: private:
int current_expansion{}; int current_expansion{};
std::vector<ContentFlagsRepository::ContentFlags> content_flags; std::vector<ContentFlagsRepository::ContentFlags> content_flags;
@ -194,6 +200,4 @@ private:
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances; std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
}; };
extern WorldContentService content_service;
#endif //EQEMU_WORLD_CONTENT_SERVICE_H #endif //EQEMU_WORLD_CONTENT_SERVICE_H

View File

@ -23,10 +23,12 @@ void SendCrashReport(const std::string &crash_report)
{ {
// can configure multiple endpoints if need be // can configure multiple endpoints if need be
std::vector<std::string> endpoints = { std::vector<std::string> endpoints = {
"https://spire.akkadius.com/api/v1/analytics/server-crash-report", "https://spire.eqemu.dev/api/v1/analytics/server-crash-report",
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development // "http://localhost:3010/api/v1/analytics/server-crash-report", // development
}; };
EQEmuLogSys* log = EQEmuLogSys::Instance();
auto config = EQEmuConfig::get(); auto config = EQEmuConfig::get();
for (auto &e: endpoints) { for (auto &e: endpoints) {
uri u(e); uri u(e);
@ -68,12 +70,12 @@ void SendCrashReport(const std::string &crash_report)
p["cpus"] = cpus.size(); p["cpus"] = cpus.size();
p["origination_info"] = ""; p["origination_info"] = "";
if (!LogSys.origination_info.zone_short_name.empty()) { if (!log->origination_info.zone_short_name.empty()) {
p["origination_info"] = fmt::format( p["origination_info"] = fmt::format(
"{} ({}) instance_id [{}]", "{} ({}) instance_id [{}]",
LogSys.origination_info.zone_short_name, log->origination_info.zone_short_name,
LogSys.origination_info.zone_long_name, log->origination_info.zone_long_name,
LogSys.origination_info.instance_id log->origination_info.instance_id
); );
} }
@ -294,7 +296,7 @@ void print_trace()
SendCrashReport(crash_report); SendCrashReport(crash_report);
} }
LogSys.CloseFileLogs(); EQEmuLogSys::Instance()->CloseFileLogs();
exit(1); exit(1);
} }

View File

@ -1,19 +1,24 @@
#include "data_bucket.h" #include "../common/data_bucket.h"
#include "zonedb.h" #include "database.h"
#include "mob.h"
#include "client.h"
#include "worldserver.h"
#include <ctime> #include <ctime>
#include <cctype> #include <cctype>
#include "../common/json/json.hpp" #include "../common/json/json.hpp"
using json = nlohmann::json; using json = nlohmann::json;
extern WorldServer worldserver;
const std::string NESTED_KEY_DELIMITER = "."; const std::string NESTED_KEY_DELIMITER = ".";
std::vector<DataBucketsRepository::DataBuckets> g_data_bucket_cache = {}; std::vector<DataBucketsRepository::DataBuckets> g_data_bucket_cache = {};
#if defined(ZONE)
#include "../zone/zonedb.h"
extern ZoneDatabase database;
#elif defined(WORLD)
#include "../world/worlddb.h"
extern WorldDatabase database;
#else
#error "You must define either ZONE or WORLD"
#endif
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time) void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
{ {
auto k = DataBucketKey{ auto k = DataBucketKey{
@ -347,27 +352,6 @@ bool DataBucket::DeleteData(const std::string &bucket_key)
return DeleteData(DataBucketKey{.key = bucket_key}); return DeleteData(DataBucketKey{.key = bucket_key});
} }
// GetDataBuckets bulk loads all data buckets for a mob
bool DataBucket::GetDataBuckets(Mob *mob)
{
const uint32 id = mob->GetMobTypeIdentifier();
if (!id) {
return false;
}
if (mob->IsBot()) {
BulkLoadEntitiesToCache(DataBucketLoadType::Bot, {id});
}
else if (mob->IsClient()) {
uint32 account_id = mob->CastToClient()->AccountID();
BulkLoadEntitiesToCache(DataBucketLoadType::Account, {account_id});
BulkLoadEntitiesToCache(DataBucketLoadType::Client, {id});
}
return true;
}
bool DataBucket::DeleteData(const DataBucketKey &k) bool DataBucket::DeleteData(const DataBucketKey &k)
{ {
bool is_nested_key = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos; bool is_nested_key = k.key.find(NESTED_KEY_DELIMITER) != std::string::npos;

View File

@ -2,11 +2,9 @@
#define EQEMU_DATABUCKET_H #define EQEMU_DATABUCKET_H
#include <string> #include <string>
#include "../common/types.h" #include "types.h"
#include "../common/repositories/data_buckets_repository.h" #include "repositories/data_buckets_repository.h"
#include "mob.h" #include "json/json_archive_single_line.h"
#include "../common/json/json_archive_single_line.h"
#include "../common/servertalk.h"
struct DataBucketKey { struct DataBucketKey {
std::string key; std::string key;
@ -46,8 +44,6 @@ public:
static std::string GetDataExpires(const std::string &bucket_key); static std::string GetDataExpires(const std::string &bucket_key);
static std::string GetDataRemaining(const std::string &bucket_key); static std::string GetDataRemaining(const std::string &bucket_key);
static bool GetDataBuckets(Mob *mob);
// scoped bucket methods // scoped bucket methods
static void SetData(const DataBucketKey &k_); static void SetData(const DataBucketKey &k_);
static bool DeleteData(const DataBucketKey &k); static bool DeleteData(const DataBucketKey &k);

View File

@ -708,6 +708,20 @@ const std::string Database::GetNPCNameByID(uint32 npc_id)
return e.id ? e.name : std::string(); return e.id ? e.name : std::string();
} }
template<typename InputIterator, typename OutputIterator>
inline auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result)
{
for (; first != last; ++first) {
if (*first == '_') {
*result = ' ';
}
else if (isalpha(*first) || *first == '`') {
*result = *first;
}
}
return result;
}
const std::string Database::GetCleanNPCNameByID(uint32 npc_id) const std::string Database::GetCleanNPCNameByID(uint32 npc_id)
{ {
const auto& e = NpcTypesRepository::FindOne(*this, npc_id); const auto& e = NpcTypesRepository::FindOne(*this, npc_id);
@ -1920,6 +1934,7 @@ bool Database::CopyCharacter(
std::vector<std::string> tables_to_zero_id = { std::vector<std::string> tables_to_zero_id = {
"keyring", "keyring",
"data_buckets", "data_buckets",
"character_evolving_items",
"character_instance_safereturns", "character_instance_safereturns",
"character_expedition_lockouts", "character_expedition_lockouts",
"character_instance_lockouts", "character_instance_lockouts",
@ -1951,6 +1966,12 @@ bool Database::CopyCharacter(
) )
); );
if (!results.Success()) {
LogError("Transaction failed [{}] rolling back", results.ErrorMessage());
TransactionRollback();
return false;
}
std::vector<std::string> columns = {}; std::vector<std::string> columns = {};
int column_count = 0; int column_count = 0;
@ -1969,6 +1990,12 @@ bool Database::CopyCharacter(
) )
); );
if (!results.Success()) {
LogError("Transaction failed [{}] rolling back", results.ErrorMessage());
TransactionRollback();
return false;
}
std::vector<std::vector<std::string>> new_rows; std::vector<std::vector<std::string>> new_rows;
for (auto row : results) { for (auto row : results) {
@ -2036,13 +2063,18 @@ bool Database::CopyCharacter(
LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied)); LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied));
if (!insert.ErrorMessage().empty()) { if (!insert.ErrorMessage().empty()) {
LogError("Error copying table [{}] [{}]", table_name, insert.ErrorMessage());
TransactionRollback(); TransactionRollback();
return false; return false;
} }
} }
} }
TransactionCommit(); auto r = TransactionCommit();
if (!r.Success()) {
LogError("Transaction failed [{}] rolling back", r.ErrorMessage());
return false;
}
LogInfo( LogInfo(
"Character [{}] copied to [{}] total rows [{}]", "Character [{}] copied to [{}] total rows [{}]",
@ -2212,7 +2244,7 @@ void Database::PurgeCharacterParcels()
pel.event_data = ss.str(); pel.event_data = ss.str();
pel.created_at = std::time(nullptr); pel.created_at = std::time(nullptr);
player_event_logs.AddToQueue(pel); PlayerEventLogs::Instance()->AddToQueue(pel);
ss.str(""); ss.str("");
ss.clear(); ss.clear();

View File

@ -50,7 +50,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
{ {
std::string version_output = GetMySQLVersion(); std::string version_output = GetMySQLVersion();
return version_output.find("mysql") != std::string::npos && version_output.find("Ver") != std::string::npos; return version_output.find("mysql") != std::string::npos && (version_output.find("Ver") != std::string::npos || version_output.find("from") != std::string::npos);
} }
/** /**
@ -204,7 +204,7 @@ void DatabaseDumpService::DatabaseDump()
} }
if (IsDumpOutputToConsole()) { if (IsDumpOutputToConsole()) {
LogSys.SilenceConsoleLogging(); EQEmuLogSys::Instance()->SilenceConsoleLogging();
} }
LogInfo("MySQL installed [{}]", GetMySQLVersion()); LogInfo("MySQL installed [{}]", GetMySQLVersion());
@ -324,7 +324,7 @@ void DatabaseDumpService::DatabaseDump()
} }
if (!IsDumpOutputToConsole()) { if (!IsDumpOutputToConsole()) {
LogSys.LoadLogSettingsDefaults(); EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
} }
if (!pipe_file.empty()) { if (!pipe_file.empty()) {

View File

@ -7,6 +7,7 @@
#include "../http/httplib.h" #include "../http/httplib.h"
#include "database_update_manifest.cpp" #include "database_update_manifest.cpp"
#include "database_update_manifest_custom.cpp"
#include "database_update_manifest_bots.cpp" #include "database_update_manifest_bots.cpp"
#include "database_dump_service.h" #include "database_dump_service.h"
@ -14,7 +15,7 @@ constexpr int BREAK_LENGTH = 70;
DatabaseVersion DatabaseUpdate::GetDatabaseVersions() DatabaseVersion DatabaseUpdate::GetDatabaseVersions()
{ {
auto results = m_database->QueryDatabase("SELECT `version`, `bots_version` FROM `db_version` LIMIT 1"); auto results = m_database->QueryDatabase("SELECT `version`, `bots_version`, `custom_version` FROM `db_version` LIMIT 1");
if (!results.Success() || !results.RowCount()) { if (!results.Success() || !results.RowCount()) {
LogError("Failed to read from [db_version] table!"); LogError("Failed to read from [db_version] table!");
return DatabaseVersion{}; return DatabaseVersion{};
@ -25,6 +26,7 @@ DatabaseVersion DatabaseUpdate::GetDatabaseVersions()
return DatabaseVersion{ return DatabaseVersion{
.server_database_version = Strings::ToInt(r[0]), .server_database_version = Strings::ToInt(r[0]),
.bots_database_version = Strings::ToInt(r[1]), .bots_database_version = Strings::ToInt(r[1]),
.custom_database_version = Strings::ToInt(r[2]),
}; };
} }
@ -33,6 +35,7 @@ DatabaseVersion DatabaseUpdate::GetBinaryDatabaseVersions()
return DatabaseVersion{ return DatabaseVersion{
.server_database_version = CURRENT_BINARY_DATABASE_VERSION, .server_database_version = CURRENT_BINARY_DATABASE_VERSION,
.bots_database_version = (RuleB(Bots, Enabled) ? CURRENT_BINARY_BOTS_DATABASE_VERSION : 0), .bots_database_version = (RuleB(Bots, Enabled) ? CURRENT_BINARY_BOTS_DATABASE_VERSION : 0),
.custom_database_version = CUSTOM_BINARY_DATABASE_VERSION,
}; };
} }
@ -43,6 +46,7 @@ constexpr int LOOK_BACK_AMOUNT = 10;
// this check will take action // this check will take action
void DatabaseUpdate::CheckDbUpdates() void DatabaseUpdate::CheckDbUpdates()
{ {
InjectCustomVersionColumn();
InjectBotsVersionColumn(); InjectBotsVersionColumn();
auto v = GetDatabaseVersions(); auto v = GetDatabaseVersions();
auto b = GetBinaryDatabaseVersions(); auto b = GetBinaryDatabaseVersions();
@ -59,6 +63,15 @@ void DatabaseUpdate::CheckDbUpdates()
m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `version` = {}", b.server_database_version)); m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `version` = {}", b.server_database_version));
} }
if (UpdateManifest(manifest_entries_custom, v.custom_database_version, b.custom_database_version)) {
LogInfo(
"Updates ran successfully, setting database version to [{}] from [{}]",
b.custom_database_version,
v.custom_database_version
);
m_database->QueryDatabase(fmt::format("UPDATE `db_version` SET `custom_version` = {}", b.custom_database_version));
}
if (b.bots_database_version > 0) { if (b.bots_database_version > 0) {
if (UpdateManifest(bot_manifest_entries, v.bots_database_version, b.bots_database_version)) { if (UpdateManifest(bot_manifest_entries, v.bots_database_version, b.bots_database_version)) {
LogInfo( LogInfo(
@ -141,7 +154,7 @@ bool DatabaseUpdate::UpdateManifest(
std::vector<int> missing_migrations = {}; std::vector<int> missing_migrations = {};
if (version_low != version_high) { if (version_low != version_high) {
LogSys.DisableMySQLErrorLogs(); EQEmuLogSys::Instance()->DisableMySQLErrorLogs();
bool force_interactive = false; bool force_interactive = false;
for (int version = version_low + 1; version <= version_high; ++version) { for (int version = version_low + 1; version <= version_high; ++version) {
for (auto &e: entries) { for (auto &e: entries) {
@ -171,7 +184,7 @@ bool DatabaseUpdate::UpdateManifest(
} }
} }
} }
LogSys.EnableMySQLErrorLogs(); EQEmuLogSys::Instance()->EnableMySQLErrorLogs();
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
if (!missing_migrations.empty() && m_skip_backup) { if (!missing_migrations.empty() && m_skip_backup) {
@ -344,6 +357,16 @@ bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
); );
} }
if (b.custom_database_version > 0) {
LogInfo(
"{:>8} | database [{}] binary [{}] {}",
"Custom",
v.custom_database_version,
b.custom_database_version,
(v.custom_database_version == b.custom_database_version) ? "up to date" : "checking updates"
);
}
LogInfo("{:>8} | [server.auto_database_updates] [<green>true]", "Config"); LogInfo("{:>8} | [server.auto_database_updates] [<green>true]", "Config");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH)); LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
@ -353,7 +376,10 @@ bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
// bots database version is optional, if not enabled then it is always up-to-date // bots database version is optional, if not enabled then it is always up-to-date
bool bots_up_to_date = RuleB(Bots, Enabled) ? v.bots_database_version >= b.bots_database_version : true; bool bots_up_to_date = RuleB(Bots, Enabled) ? v.bots_database_version >= b.bots_database_version : true;
return server_up_to_date && bots_up_to_date; // custom database version is optional, if not enabled then it is always up-to-date
bool custom_up_to_date = v.custom_database_version >= b.custom_database_version;
return server_up_to_date && bots_up_to_date && custom_up_to_date;
} }
// checks to see if there are pending updates // checks to see if there are pending updates
@ -373,3 +399,12 @@ void DatabaseUpdate::InjectBotsVersionColumn()
m_database->QueryDatabase("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version"); m_database->QueryDatabase("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version");
} }
} }
void DatabaseUpdate::InjectCustomVersionColumn()
{
auto results = m_database->QueryDatabase("SHOW COLUMNS FROM `db_version` LIKE 'custom_version'");
if (!results.Success() || results.RowCount() == 0) {
LogInfo("Adding custom_version column to db_version table");
m_database->QueryDatabase("ALTER TABLE `db_version` ADD COLUMN `custom_version` INT(11) UNSIGNED NOT NULL DEFAULT 0");
}
}

View File

@ -17,6 +17,7 @@ struct ManifestEntry {
struct DatabaseVersion { struct DatabaseVersion {
int server_database_version; int server_database_version;
int bots_database_version; int bots_database_version;
int custom_database_version;
}; };
class DatabaseUpdate { class DatabaseUpdate {
@ -32,12 +33,20 @@ public:
DatabaseUpdate *SetContentDatabase(Database *db); DatabaseUpdate *SetContentDatabase(Database *db);
DatabaseUpdate *SetSkipBackup(bool skip); DatabaseUpdate *SetSkipBackup(bool skip);
bool HasPendingUpdates(); bool HasPendingUpdates();
static DatabaseUpdate* Instance()
{
static DatabaseUpdate instance;
return &instance;
}
private: private:
bool m_skip_backup = false; bool m_skip_backup = false;
Database *m_database; Database *m_database;
Database *m_content_database; Database *m_content_database;
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b); static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
void InjectBotsVersionColumn(); void InjectBotsVersionColumn();
void InjectCustomVersionColumn();
}; };

View File

@ -7109,6 +7109,80 @@ ALTER TABLE `npc_types`
ALTER TABLE `character_data` ALTER TABLE `character_data`
CHANGE COLUMN `firstlogon` `ingame` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `xtargets`, CHANGE COLUMN `firstlogon` `ingame` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `xtargets`,
ADD COLUMN `first_login` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `xtargets`; ADD COLUMN `first_login` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `xtargets`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9324,
.description = "2025_06_11_player_event_logs_table.sql",
.check = "SHOW CREATE TABLE `player_event_logs`",
.condition = "missing",
.match = "COMPRESS",
.sql = R"(
ALTER TABLE player_event_logs ROW_FORMAT=COMPRESSED;
CREATE INDEX idx_event_type_char_id ON player_event_logs (event_type_id, character_id);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9325,
.description = "2025_06_10_character_corpses_entity_variables.sql",
.check = "SHOW COLUMNS FROM `character_corpses` LIKE 'entity_variables'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_corpses`
ADD COLUMN `entity_variables` TEXT DEFAULT NULL AFTER `rezzable`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9326,
.description = "2025_07_27_add_indexes_npc_spawns_loot.sql",
.check = "SHOW INDEX FROM npc_types",
.condition = "missing",
.match = "idx_npc_types_loottable_id",
.sql = R"(
ALTER TABLE npc_types
ADD INDEX idx_npc_types_loottable_id (loottable_id);
ALTER TABLE spawnentry
ADD INDEX idx_spawnentry_spawngroup_id (spawngroupID),
ADD INDEX idx_spawnentry_npc_id (npcID);
ALTER TABLE lootdrop_entries
ADD INDEX idx_lootdrop_entries_lootdrop_id (lootdrop_id),
ADD INDEX idx_lootdrop_entries_item_id (item_id);
ALTER TABLE loottable_entries
ADD INDEX idx_loottable_entries_lootdrop_id (lootdrop_id),
ADD INDEX idx_loottable_entries_loottable_id (loottable_id);
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9327,
.description = "2025_08_13_character_stats_record_heal_amount.sql",
.check = "SHOW COLUMNS FROM `character_stats_record` LIKE 'heal_amount'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_stats_record`
ADD COLUMN `heal_amount` int(11) NULL DEFAULT 0 AFTER `spell_damage`;
)"
},
ManifestEntry{
.version = 9328,
.description = "2025_08_22_character_parcel_updates.sql",
.check = "SHOW COLUMNS FROM `character_parcels` LIKE 'evolve_amount'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_parcels`
ADD COLUMN `evolve_amount` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `quantity`;
ALTER TABLE `character_parcels_containers`
ADD COLUMN `evolve_amount` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `quantity`;
)", )",
.content_schema_update = false .content_schema_update = false
}, },

View File

@ -0,0 +1,55 @@
#include "database_update.h"
std::vector<ManifestEntry> manifest_entries_custom = {
ManifestEntry{
.version = 1,
.description = "2025_05_16_new_database_check_test",
.check = "SHOW TABLES LIKE 'new_table'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `new_table` (
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
);
)",
.content_schema_update = false,
},
// Used for testing
// ManifestEntry{
// .version = 9229,
// .description = "new_database_check_test",
// .check = "SHOW TABLES LIKE 'new_table'",
// .condition = "empty",
// .match = "",
// .sql = R"(
//CREATE TABLE `new_table` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table1` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table2` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//CREATE TABLE `new_table3` (
// `id` int NOT NULL AUTO_INCREMENT,
// PRIMARY KEY (`id`)
//);
//)",
// }
};
// see struct definitions for what each field does
// struct ManifestEntry {
// int version{}; // database version of the migration
// std::string description{}; // description of the migration ex: "add_new_table" or "add_index_to_table"
// std::string check{}; // query that checks against the condition
// std::string condition{}; // condition or "match_type" - Possible values [contains|match|missing|empty|not_empty]
// std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
// std::string sql{}; // the SQL DDL that gets ran when the condition is true
// };

View File

@ -160,7 +160,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
(uint32) mysql_insert_id(mysql) (uint32) mysql_insert_id(mysql)
); );
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) { if (EQEmuLogSys::Instance()->log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
if ((strncasecmp(query, "select", 6) == 0)) { if ((strncasecmp(query, "select", 6) == 0)) {
LogMySQLQuery( LogMySQLQuery(
"{0} -- ({1} row{2} returned) ({3}s)", "{0} -- ({1} row{2} returned) ({3}s)",
@ -189,9 +189,9 @@ void DBcore::TransactionBegin()
QueryDatabase("START TRANSACTION"); QueryDatabase("START TRANSACTION");
} }
void DBcore::TransactionCommit() MySQLRequestResult DBcore::TransactionCommit()
{ {
QueryDatabase("COMMIT"); return QueryDatabase("COMMIT");
} }
void DBcore::TransactionRollback() void DBcore::TransactionRollback()

View File

@ -32,7 +32,7 @@ public:
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true); MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
MySQLRequestResult QueryDatabaseMulti(const std::string &query); MySQLRequestResult QueryDatabaseMulti(const std::string &query);
void TransactionBegin(); void TransactionBegin();
void TransactionCommit(); MySQLRequestResult TransactionCommit();
void TransactionRollback(); void TransactionRollback();
std::string Escape(const std::string& s); std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen); uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);

View File

@ -4,7 +4,6 @@
#include <string> #include <string>
#include "../types.h" #include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h" #include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h" #include "../events/player_events.h"

View File

@ -26,7 +26,7 @@ void DiscordManager::ProcessMessageQueue()
continue; continue;
} }
auto webhook = LogSys.GetDiscordWebhooks()[q.first]; auto webhook = EQEmuLogSys::Instance()->GetDiscordWebhooks()[q.first];
std::string message; std::string message;
for (auto &m: q.second) { for (auto &m: q.second) {
@ -68,7 +68,7 @@ void DiscordManager::ProcessMessageQueue()
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e) void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{ {
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id); auto w = PlayerEventLogs::Instance()->GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) { if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w); Discord::SendPlayerEventMessage(e, w);
} }

View File

@ -13,6 +13,12 @@ public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message); void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue(); void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e); void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
static DiscordManager* Instance()
{
static DiscordManager instance;
return &instance;
}
private: private:
std::mutex webhook_queue_lock{}; std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{}; std::map<uint32, std::vector<std::string>> webhook_message_queue{};

View File

@ -451,3 +451,23 @@ bool LDoNTheme::IsValid(uint32 theme_id)
{ {
return ldon_theme_names.find(theme_id) != ldon_theme_names.end(); return ldon_theme_names.find(theme_id) != ldon_theme_names.end();
} }
std::string PetCommand::GetName(uint8 pet_command)
{
return IsValid(pet_command) ? pet_commands[pet_command] : "UNKNOWN PET COMMAND";
}
bool PetCommand::IsValid(uint8 pet_command)
{
return pet_commands.find(pet_command) != pet_commands.end();
}
std::string PetType::GetName(uint8 pet_type)
{
return IsValid(pet_type) ? pet_types[pet_type] : "UNKNOWN PET TYPE";
}
bool PetType::IsValid(uint8 pet_type)
{
return pet_types.find(pet_type) != pet_types.end();
}

View File

@ -792,4 +792,131 @@ namespace BookType {
constexpr uint8 ItemInfo = 2; constexpr uint8 ItemInfo = 2;
} }
namespace PetButton {
constexpr uint8 Sit = 0;
constexpr uint8 Stop = 1;
constexpr uint8 Regroup = 2;
constexpr uint8 Follow = 3;
constexpr uint8 Guard = 4;
constexpr uint8 Taunt = 5;
constexpr uint8 Hold = 6;
constexpr uint8 GreaterHold = 7;
constexpr uint8 Focus = 8;
constexpr uint8 SpellHold = 9;
}
namespace PetButtonState {
constexpr uint8 Off = 0;
constexpr uint8 On = 1;
}
namespace PetCommand {
constexpr uint8 HealthReport = 0; // /pet health or Pet Window
constexpr uint8 Leader = 1; // /pet leader or Pet Window
constexpr uint8 Attack = 2; // /pet attack or Pet Window
constexpr uint8 QAttack = 3; // /pet qattack or Pet Window
constexpr uint8 FollowMe = 4; // /pet follow or Pet Window
constexpr uint8 GuardHere = 5; // /pet guard or Pet Window
constexpr uint8 Sit = 6; // /pet sit or Pet Window
constexpr uint8 SitDown = 7; // /pet sit on
constexpr uint8 StandUp = 8; // /pet sit off
constexpr uint8 Stop = 9; // /pet stop or Pet Window - Not implemented
constexpr uint8 StopOn = 10; // /pet stop on - Not implemented
constexpr uint8 StopOff = 11; // /pet stop off - Not implemented
constexpr uint8 Taunt = 12; // /pet taunt or Pet Window
constexpr uint8 TauntOn = 13; // /pet taunt on
constexpr uint8 TauntOff = 14; // /pet taunt off
constexpr uint8 Hold = 15; // /pet hold or Pet Window, won't add to hate list unless attacking
constexpr uint8 HoldOn = 16; // /pet hold on
constexpr uint8 HoldOff = 17; // /pet hold off
constexpr uint8 GreaterHold = 18; // /pet ghold, will never add to hate list unless told to
constexpr uint8 GreaterHoldOn = 19; // /pet ghold on
constexpr uint8 GreaterHoldOff = 20; // /pet ghold off
constexpr uint8 SpellHold = 21; // /pet no cast or /pet spellhold or Pet Window
constexpr uint8 SpellHoldOn = 22; // /pet spellhold on
constexpr uint8 SpellHoldOff = 23; // /pet spellhold off
constexpr uint8 Focus = 24; // /pet focus or Pet Window
constexpr uint8 FocusOn = 25; // /pet focus on
constexpr uint8 FocusOff = 26; // /pet focus off
constexpr uint8 Feign = 27; // /pet feign
constexpr uint8 BackOff = 28; // /pet back off
constexpr uint8 GetLost = 29; // /pet get lost
constexpr uint8 GuardMe = 30; // Same as /pet follow, but different message in older clients
constexpr uint8 Regroup = 31; // /pet regroup, acts like classic hold
constexpr uint8 RegroupOn = 32; // /pet regroup on
constexpr uint8 RegroupOff = 33; // /pet regroup off
constexpr uint8 Max = 34;
static std::map<uint8, std::string> pet_commands = {
{ PetCommand::HealthReport, "Health Report" },
{ PetCommand::Leader, "Leader" },
{ PetCommand::Attack, "Attack" },
{ PetCommand::QAttack, "QAttack" },
{ PetCommand::FollowMe, "Follow Me" },
{ PetCommand::GuardHere, "Guard Here" },
{ PetCommand::Sit, "Sit" },
{ PetCommand::SitDown, "Sit Down" },
{ PetCommand::StandUp, "Stand Up" },
{ PetCommand::Stop, "Stop" },
{ PetCommand::StopOn, "Stop On" },
{ PetCommand::StopOff, "Stop Off" },
{ PetCommand::Taunt, "Taunt" },
{ PetCommand::TauntOn, "Taunt On" },
{ PetCommand::TauntOff, "Taunt Off" },
{ PetCommand::Hold, "Hold" },
{ PetCommand::HoldOn, "Hold On" },
{ PetCommand::HoldOff, "Hold Off" },
{ PetCommand::GreaterHold, "Greater Hold" },
{ PetCommand::GreaterHoldOn, "Greater Hold On" },
{ PetCommand::GreaterHoldOff, "Greater Hold Off" },
{ PetCommand::SpellHold, "Spell Hold" },
{ PetCommand::SpellHoldOn, "Spell Hold On" },
{ PetCommand::SpellHoldOff, "Spell Hold Off" },
{ PetCommand::Focus, "Focus" },
{ PetCommand::FocusOn, "Focus On" },
{ PetCommand::FocusOff, "Focus Off" },
{ PetCommand::Feign, "Feign" },
{ PetCommand::BackOff, "Back Off" },
{ PetCommand::GetLost, "Get Lost" },
{ PetCommand::GuardMe, "Guard Me" },
{ PetCommand::Regroup, "Regroup" },
{ PetCommand::RegroupOn, "Regroup On" },
{ PetCommand::RegroupOff, "Regroup Off" },
{ PetCommand::Max, "Max" }
};
std::string GetName(uint8 pet_command);
bool IsValid(uint8 pet_command);
}
namespace PetOrder {
constexpr uint8 Follow = 0;
constexpr uint8 Sit = 1;
constexpr uint8 Guard = 2;
constexpr uint8 Feign = 3;
}
namespace PetType {
constexpr uint8 Familiar = 0;
constexpr uint8 Animation = 1;
constexpr uint8 Normal = 2;
constexpr uint8 Charmed = 3;
constexpr uint8 Follow = 4;
constexpr uint8 TargetLock = 5;
constexpr uint8 None = 255;
static std::map<uint8, std::string> pet_types = {
{ PetType::Familiar, "Familiar" },
{ PetType::Animation, "Animation" },
{ PetType::Normal, "Normal" },
{ PetType::Charmed, "Charmed" },
{ PetType::Follow, "Follow" },
{ PetType::TargetLock, "Target Lock" },
{ PetType::None, "None" }
};
std::string GetName(uint8 pet_type);
bool IsValid(uint8 pet_type);
}
#endif /*COMMON_EMU_CONSTANTS_H*/ #endif /*COMMON_EMU_CONSTANTS_H*/

View File

@ -988,7 +988,8 @@ enum StartZoneIndex {
Felwithe, Felwithe,
Akanon, Akanon,
Cabilis, Cabilis,
SharVahl SharVahl,
RatheMtn
}; };
enum FVNoDropFlagRule enum FVNoDropFlagRule

View File

@ -545,13 +545,13 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
uint32 chunksize, used; uint32 chunksize, used;
uint32 length; uint32 length;
if (LogSys.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){ if (EQEmuLogSys::Instance()->log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){ if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()); Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
} }
} }
if (LogSys.log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){ if (EQEmuLogSys::Instance()->log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){ if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
} }

View File

@ -6,7 +6,7 @@
#include <string> #include <string>
#include "emu_versions.h" #include "emu_versions.h"
#include "eq_packet.h" #include "eq_packet.h"
#include "net/daybreak_connection.h" #include "net/reliable_stream_connection.h"
typedef enum { typedef enum {
ESTABLISHED, ESTABLISHED,
@ -33,18 +33,18 @@ struct EQStreamManagerInterfaceOptions
//Login I had trouble getting to recognize compression at all //Login I had trouble getting to recognize compression at all
//but that might be because it was still a bit buggy when i was testing that. //but that might be because it was still a bit buggy when i was testing that.
if (compressed) { if (compressed) {
daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression; reliable_stream_options.encode_passes[0] = EQ::Net::EncodeCompression;
} }
else if (encoded) { else if (encoded) {
daybreak_options.encode_passes[0] = EQ::Net::EncodeXOR; reliable_stream_options.encode_passes[0] = EQ::Net::EncodeXOR;
} }
daybreak_options.port = port; reliable_stream_options.port = port;
} }
int opcode_size; int opcode_size;
bool track_opcode_stats; bool track_opcode_stats;
EQ::Net::DaybreakConnectionManagerOptions daybreak_options; EQ::Net::ReliableStreamConnectionManagerOptions reliable_stream_options;
}; };
class EQStreamManagerInterface class EQStreamManagerInterface
@ -80,7 +80,7 @@ public:
struct Stats struct Stats
{ {
EQ::Net::DaybreakConnectionStats DaybreakStats; EQ::Net::ReliableStreamConnectionStats ReliableStreamStats;
int RecvCount[_maxEmuOpcode]; int RecvCount[_maxEmuOpcode];
int SentCount[_maxEmuOpcode]; int SentCount[_maxEmuOpcode];
}; };

View File

@ -177,6 +177,21 @@ void EQEmuConfig::parse_config()
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString(); SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
LogDir = _root["server"]["directories"].get("logs", "logs/").asString(); LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
auto load_paths = [&](const std::string& key, std::vector<std::string>& target) {
const auto& paths = _root["server"]["directories"][key];
if (paths.isArray()) {
for (const auto& dir : paths) {
if (dir.isString()) {
target.push_back(dir.asString());
}
}
}
};
load_paths("quest_paths", m_quest_directories);
load_paths("plugin_paths", m_plugin_directories);
load_paths("lua_module_paths", m_lua_module_directories);
/** /**
* Logs * Logs
*/ */
@ -421,11 +436,11 @@ void EQEmuConfig::CheckUcsConfigConversion()
LogInfo("Migrating old [eqemu_config] UCS configuration to new configuration"); LogInfo("Migrating old [eqemu_config] UCS configuration to new configuration");
std::string config_file_path = std::filesystem::path{ std::string config_file_path = std::filesystem::path{
path.GetServerPath() + "/eqemu_config.json" PathManager::Instance()->GetServerPath() + "/eqemu_config.json"
}.string(); }.string();
std::string config_file_bak_path = std::filesystem::path{ std::string config_file_bak_path = std::filesystem::path{
path.GetServerPath() + "/eqemu_config.ucs-migrate-json.bak" PathManager::Instance()->GetServerPath() + "/eqemu_config.ucs-migrate-json.bak"
}.string(); }.string();
// copy eqemu_config.json to eqemu_config.json.bak // copy eqemu_config.json to eqemu_config.json.bak

View File

@ -120,6 +120,22 @@ class EQEmuConfig
const std::string &GetUCSHost() const; const std::string &GetUCSHost() const;
uint16 GetUCSPort() const; uint16 GetUCSPort() const;
std::vector<std::string> GetQuestDirectories() const
{
return m_quest_directories;
}
std::vector<std::string> GetPluginsDirectories() const
{
return m_plugin_directories;
}
std::vector<std::string> GetLuaModuleDirectories() const
{
return m_lua_module_directories;
}
// uint16 DynamicCount; // uint16 DynamicCount;
// map<string,uint16> StaticZones; // map<string,uint16> StaticZones;
@ -133,6 +149,11 @@ class EQEmuConfig
Json::Value _root; Json::Value _root;
static std::string ConfigFile; static std::string ConfigFile;
std::vector<std::string> m_quest_directories = {};
std::vector<std::string> m_plugin_directories = {};
std::vector<std::string> m_lua_module_directories = {};
protected:
void parse_config(); void parse_config();
EQEmuConfig() EQEmuConfig()
@ -170,7 +191,7 @@ class EQEmuConfig
std::string file = fmt::format( std::string file = fmt::format(
"{}/{}", "{}/{}",
(file_path.empty() ? path.GetServerPath() : file_path), (file_path.empty() ? PathManager::Instance()->GetServerPath() : file_path),
EQEmuConfig::ConfigFile EQEmuConfig::ConfigFile
); );

View File

@ -537,9 +537,9 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
{ {
EQEmuLogSys::CloseFileLogs(); EQEmuLogSys::CloseFileLogs();
if (!File::Exists(path.GetLogPath())) { if (!File::Exists(PathManager::Instance()->GetLogPath())) {
LogInfo("Logs directory not found, creating [{}]", path.GetLogPath()); LogInfo("Logs directory not found, creating [{}]", PathManager::Instance()->GetLogPath());
File::Makedir(path.GetLogPath()); File::Makedir(PathManager::Instance()->GetLogPath());
} }
/** /**
@ -656,7 +656,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
// If we go through this whole loop and nothing is set to any debug level, there // If we go through this whole loop and nothing is set to any debug level, there
// is no point to create a file or keep anything open // is no point to create a file or keep anything open
if (log_settings[c.log_category_id].log_to_file > 0) { if (log_settings[c.log_category_id].log_to_file > 0) {
LogSys.m_file_logs_enabled = true; m_file_logs_enabled = true;
} }
db_categories.emplace_back(c.log_category_id); db_categories.emplace_back(c.log_category_id);
@ -682,14 +682,33 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings(bool silent_load)
if (is_missing_in_database && !is_deprecated_category) { if (is_missing_in_database && !is_deprecated_category) {
LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i); LogInfo("Automatically adding new log category [{}] ({})", Logs::LogCategoryName[i], i);
auto new_category = LogsysCategoriesRepository::NewEntity(); auto e = LogsysCategoriesRepository::NewEntity();
new_category.log_category_id = i; e.log_category_id = i;
new_category.log_category_description = Strings::Escape(Logs::LogCategoryName[i]); e.log_category_description = Strings::Escape(Logs::LogCategoryName[i]);
new_category.log_to_console = log_settings[i].log_to_console; e.log_to_console = log_settings[i].log_to_console;
new_category.log_to_gmsay = log_settings[i].log_to_gmsay; e.log_to_gmsay = log_settings[i].log_to_gmsay;
new_category.log_to_file = log_settings[i].log_to_file; e.log_to_file = log_settings[i].log_to_file;
new_category.log_to_discord = log_settings[i].log_to_discord; e.log_to_discord = log_settings[i].log_to_discord;
db_categories_to_add.emplace_back(new_category); db_categories_to_add.emplace_back(e);
}
// look to see if the category name is different in the database
auto it = std::find_if(
categories.begin(),
categories.end(),
[i](const auto &c) { return c.log_category_id == i; }
);
if (it != categories.end()) {
if (it->log_category_description != Logs::LogCategoryName[i]) {
LogInfo(
"Updating log category [{}] ({}) to new name [{}]",
it->log_category_description,
i,
Logs::LogCategoryName[i]
);
it->log_category_description = Logs::LogCategoryName[i];
LogsysCategoriesRepository::ReplaceOne(*m_database, *it);
}
} }
} }

View File

@ -194,8 +194,8 @@ namespace Logs {
"Web Interface (Deprecated)", "Web Interface (Deprecated)",
"World Server (Deprecated)", "World Server (Deprecated)",
"Zone Server (Deprecated)", "Zone Server (Deprecated)",
"QueryErr", "MySQL Error",
"Query", "MySQL Query",
"Mercenaries", "Mercenaries",
"Quest Debug", "Quest Debug",
"Legacy Packet Logging (Deprecated)", "Legacy Packet Logging (Deprecated)",
@ -218,8 +218,8 @@ namespace Logs {
"Emergency (Deprecated)", "Emergency (Deprecated)",
"Alert (Deprecated)", "Alert (Deprecated)",
"Notice (Deprecated)", "Notice (Deprecated)",
"AI Scan", "AI Scan Close",
"AI Yell", "AI Yell For Help",
"AI CastBeneficial", "AI CastBeneficial",
"AOE Cast", "AOE Cast",
"Entity Management", "Entity Management",
@ -237,7 +237,7 @@ namespace Logs {
"DialogueWindow", "DialogueWindow",
"HTTP", "HTTP",
"Saylink", "Saylink",
"ChecksumVer", "Checksum Verification",
"CombatRecord", "CombatRecord",
"Hate", "Hate",
"Discord", "Discord",
@ -266,8 +266,6 @@ namespace Logs {
}; };
} }
#include "eqemu_logsys_log_aliases.h"
class Database; class Database;
constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300; constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300;
@ -285,6 +283,12 @@ public:
EQEmuLogSys *LoadLogSettingsDefaults(); EQEmuLogSys *LoadLogSettingsDefaults();
EQEmuLogSys *LoadLogDatabaseSettings(bool silent_load = false); EQEmuLogSys *LoadLogDatabaseSettings(bool silent_load = false);
static EQEmuLogSys *Instance()
{
static EQEmuLogSys instance;
return &instance;
}
/** /**
* @param directory_name * @param directory_name
*/ */
@ -350,7 +354,7 @@ public:
/** /**
* Internally used memory reference for all log settings per category * Internally used memory reference for all log settings per category
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults * These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
* Database loaded via LogSys.SetDatabase(&database)->LoadLogDatabaseSettings(); * Database loaded via EQEmuLogSys::Instance()->SetDatabase(&database)->LoadLogDatabaseSettings();
*/ */
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{}; LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
@ -434,7 +438,7 @@ private:
void InjectTablesIfNotExist(); void InjectTablesIfNotExist();
}; };
extern EQEmuLogSys LogSys; #include "eqemu_logsys_log_aliases.h"
/** /**
template<typename... Args> template<typename... Args>
@ -456,7 +460,7 @@ void OutF(
#define OutF(ls, debug_level, log_category, file, func, line, formatStr, ...) \ #define OutF(ls, debug_level, log_category, file, func, line, formatStr, ...) \
do { \ do { \
ls.Out(debug_level, log_category, file, func, line, fmt::format(formatStr, ##__VA_ARGS__).c_str()); \ ls->Out(debug_level, log_category, file, func, line, fmt::format(formatStr, ##__VA_ARGS__).c_str()); \
} while(0) } while(0)
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -716,7 +716,7 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
); );
for (int i = 0; i < h.augment_ids.size(); i++) { for (int i = 0; i < h.augment_ids.size(); i++) {
if (!Strings::EqualFold(h.augment_names[i], "None")) { if (!h.augment_names[i].empty()) {
const uint8 slot_id = (i + 1); const uint8 slot_id = (i + 1);
handin_items_info += fmt::format( handin_items_info += fmt::format(
"Augment {}: {} ({})\n", "Augment {}: {} ({})\n",
@ -741,7 +741,7 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
); );
for (int i = 0; i < r.augment_ids.size(); i++) { for (int i = 0; i < r.augment_ids.size(); i++) {
if (!Strings::EqualFold(r.augment_names[i], "None")) { if (!r.augment_names[i].empty()) {
const uint8 slot_id = (i + 1); const uint8 slot_id = (i + 1);
return_items_info += fmt::format( return_items_info += fmt::format(
"Augment {}: {} ({})\n", "Augment {}: {} ({})\n",

View File

@ -15,9 +15,9 @@ const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1
// general initialization routine // general initialization routine
void PlayerEventLogs::Init() void PlayerEventLogs::Init()
{ {
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000); m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL); m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
m_database_ping_timer.SetTimer(10 * 1000); // 10 seconds
ValidateDatabaseConnection(); ValidateDatabaseConnection();
@ -195,10 +195,12 @@ void PlayerEventLogs::ProcessBatchQueue()
}; };
// Helper to assign ETL table ID // Helper to assign ETL table ID
auto AssignEtlId = [&]( auto AssignEtlId = [&](
PlayerEventLogsRepository::PlayerEventLogs& r, PlayerEventLogsRepository::PlayerEventLogs& r,
PlayerEvent::EventType type PlayerEvent::EventType type
) { )
{
if (m_etl_settings.contains(type)) { if (m_etl_settings.contains(type)) {
r.etl_table_id = m_etl_settings.at(type).next_id++; r.etl_table_id = m_etl_settings.at(type).next_id++;
} }
@ -406,7 +408,6 @@ void PlayerEventLogs::ProcessBatchQueue()
auto it = event_processors.find(static_cast<PlayerEvent::EventType>(r.event_type_id)); auto it = event_processors.find(static_cast<PlayerEvent::EventType>(r.event_type_id));
if (it != event_processors.end()) { if (it != event_processors.end()) {
it->second(r); // Call the appropriate lambda it->second(r); // Call the appropriate lambda
r.event_data = "{}"; // Clear event data
} }
else { else {
LogPlayerEventsDetail("Non-Implemented ETL routing [{}]", r.event_type_id); LogPlayerEventsDetail("Non-Implemented ETL routing [{}]", r.event_type_id);
@ -508,7 +509,7 @@ bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
} }
// ensure there is a matching webhook to begin with // ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) { if (!EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true; return true;
} }
@ -528,13 +529,27 @@ std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_typ
} }
// ensure there is a matching webhook to begin with // ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) { if (!EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url; return EQEmuLogSys::Instance()->GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
} }
return ""; return "";
} }
void PlayerEventLogs::LoadPlayerEventSettingsFromQS(
const std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings> &settings
)
{
for (const auto &e : settings) {
if (e.id >= PlayerEvent::MAX || e.id < 0) {
continue;
}
m_settings[e.id] = e;
}
LogInfo("Applied [{}] player event log settings from QS", settings.size());
}
// GM_COMMAND | [x] Implemented Formatter // GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter // ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter // AA_GAIN | [x] Implemented Formatter
@ -916,6 +931,10 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess // general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process() void PlayerEventLogs::Process()
{ {
if (m_database_ping_timer.Check()) {
m_database->ping();
}
if (m_process_batch_events_timer.Check() || if (m_process_batch_events_timer.Check() ||
m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) { m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue(); ProcessBatchQueue();

View File

@ -77,6 +77,8 @@ public:
bool IsEventDiscordEnabled(int32_t event_type_id); bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id); std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
void LoadPlayerEventSettingsFromQS(const std::vector<PlayerEventLogSettingsRepository::PlayerEventLogSettings>& settings);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e); static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
struct EtlQueues { struct EtlQueues {
@ -94,6 +96,12 @@ public:
std::vector<PlayerEventAaPurchaseRepository::PlayerEventAaPurchase> aa_purchase; std::vector<PlayerEventAaPurchaseRepository::PlayerEventAaPurchase> aa_purchase;
}; };
static PlayerEventLogs* Instance()
{
static PlayerEventLogs instance;
return &instance;
}
private: private:
struct EtlSettings { struct EtlSettings {
bool enabled; bool enabled;
@ -113,6 +121,7 @@ private:
std::map<PlayerEvent::EventType, EtlSettings> m_etl_settings{}; std::map<PlayerEvent::EventType, EtlSettings> m_etl_settings{};
// timers // timers
Timer m_database_ping_timer; // database ping timer
Timer m_process_batch_events_timer; // events processing timer Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
@ -126,6 +135,4 @@ public:
std::map<PlayerEvent::EventType, EtlSettings> &GetEtlSettings() { return m_etl_settings;} std::map<PlayerEvent::EventType, EtlSettings> &GetEtlSettings() { return m_etl_settings;}
}; };
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H #endif //EQEMU_PLAYER_EVENT_LOGS_H

View File

@ -7,8 +7,16 @@
#include "../rulesys.h" #include "../rulesys.h"
#include "../repositories/player_event_logs_repository.h" #include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent { #define CEREAL_NVP_IF_NONZERO(ar, name) \
if ((name) != 0) ar(cereal::make_nvp(#name, name))
#define CEREAL_NVP_IF_NOT_EMPTY(ar, name) \
if (!(name).empty()) ar(cereal::make_nvp(#name, name))
#define CEREAL_NVP_IF_TRUE(ar, name) \
if ((name)) ar(cereal::make_nvp(#name, name))
namespace PlayerEvent {
enum EventType { enum EventType {
GM_COMMAND = 1, GM_COMMAND = 1,
ZONING, ZONING,
@ -226,6 +234,36 @@ namespace PlayerEvent {
// cereal // cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(to_slot),
CEREAL_NVP(charges)
);
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
CEREAL_NVP_IF_TRUE(ar, attuned);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -285,7 +323,36 @@ namespace PlayerEvent {
// cereal // cereal
template <class Archive> template <class Archive>
void serialize(Archive &ar) void save(Archive& ar) const
{
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id)
);
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_1_name);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_2_name);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_3_name);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_4_name);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_5_name);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
CEREAL_NVP_IF_NOT_EMPTY(ar, augment_6_name);
ar(
CEREAL_NVP(item_name),
CEREAL_NVP(charges)
);
CEREAL_NVP_IF_TRUE(ar, in_bag);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(slot), CEREAL_NVP(slot),
@ -295,7 +362,7 @@ namespace PlayerEvent {
CEREAL_NVP(augment_2_id), CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_2_name), CEREAL_NVP(augment_2_name),
CEREAL_NVP(augment_3_id), CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_1_name), CEREAL_NVP(augment_3_name),
CEREAL_NVP(augment_4_id), CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_4_name), CEREAL_NVP(augment_4_name),
CEREAL_NVP(augment_5_id), CEREAL_NVP(augment_5_id),
@ -444,9 +511,34 @@ namespace PlayerEvent {
uint32 augment_6_id; uint32 augment_6_id;
std::string item_name; std::string item_name;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(CEREAL_NVP(item_name));
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -471,9 +563,34 @@ namespace PlayerEvent {
uint32 augment_6_id; uint32 augment_6_id;
std::string item_name; std::string item_name;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(CEREAL_NVP(item_name));
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -501,9 +618,41 @@ namespace PlayerEvent {
bool attuned; bool attuned;
std::string reason; std::string reason;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges)
);
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(attuned),
CEREAL_NVP(reason)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -521,6 +670,7 @@ namespace PlayerEvent {
} }
}; };
struct LevelGainedEvent { struct LevelGainedEvent {
uint32 from_level; uint32 from_level;
uint8 to_level; uint8 to_level;
@ -571,6 +721,39 @@ namespace PlayerEvent {
// cereal // cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges)
);
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -807,6 +990,36 @@ namespace PlayerEvent {
// cereal // cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -886,10 +1099,44 @@ namespace PlayerEvent {
uint64 total_cost; uint64 total_cost;
uint64 player_money_balance; uint64 player_money_balance;
// cereal // cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
CEREAL_NVP(price),
CEREAL_NVP(quantity),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -928,10 +1175,43 @@ namespace PlayerEvent {
uint64 total_cost; uint64 total_cost;
uint64 player_money_balance; uint64 player_money_balance;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(price),
CEREAL_NVP(quantity),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -1083,9 +1363,36 @@ namespace PlayerEvent {
bool attuned; bool attuned;
uint32 guild_favor; uint32 guild_favor;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
CEREAL_NVP_IF_NONZERO(ar, charges);
CEREAL_NVP_IF_TRUE(ar, attuned);
ar(CEREAL_NVP(guild_favor));
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -1095,6 +1402,8 @@ namespace PlayerEvent {
CEREAL_NVP(augment_4_id), CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id), CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id), CEREAL_NVP(augment_6_id),
CEREAL_NVP(charges),
CEREAL_NVP(attuned),
CEREAL_NVP(guild_favor) CEREAL_NVP(guild_favor)
); );
} }
@ -1127,9 +1436,38 @@ namespace PlayerEvent {
std::string from_player_name; std::string from_player_name;
uint32 sent_date; uint32 sent_date;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(quantity),
CEREAL_NVP(from_player_name),
CEREAL_NVP(sent_date)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -1160,9 +1498,40 @@ namespace PlayerEvent {
std::string to_player_name; std::string to_player_name;
uint32 sent_date; uint32 sent_date;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
CEREAL_NVP_IF_NONZERO(ar, charges);
ar(
CEREAL_NVP(quantity),
CEREAL_NVP(from_player_name),
CEREAL_NVP(to_player_name),
CEREAL_NVP(sent_date)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -1195,9 +1564,40 @@ namespace PlayerEvent {
std::string from_name; std::string from_name;
std::string note; std::string note;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(CEREAL_NVP(item_id));
CEREAL_NVP_IF_NONZERO(ar, augment_1_id);
CEREAL_NVP_IF_NONZERO(ar, augment_2_id);
CEREAL_NVP_IF_NONZERO(ar, augment_3_id);
CEREAL_NVP_IF_NONZERO(ar, augment_4_id);
CEREAL_NVP_IF_NONZERO(ar, augment_5_id);
CEREAL_NVP_IF_NONZERO(ar, augment_6_id);
ar(
CEREAL_NVP(quantity),
CEREAL_NVP(char_id),
CEREAL_NVP(from_name),
CEREAL_NVP(note),
CEREAL_NVP(sent_date)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(item_id), CEREAL_NVP(item_id),
@ -1300,9 +1700,41 @@ namespace PlayerEvent {
uint32 quantity; uint32 quantity;
uint32 permission; uint32 permission;
// cereal
template <class Archive> template <class Archive>
void serialize(Archive& ar) void serialize(Archive& ar)
{
if constexpr (Archive::is_saving::value) {
save(ar);
}
else {
load(ar);
}
}
template <class Archive>
void save(Archive& ar) const
{
ar(
CEREAL_NVP(char_id),
CEREAL_NVP(guild_id),
CEREAL_NVP(item_id)
);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_one);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_two);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_three);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_four);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_five);
CEREAL_NVP_IF_NONZERO(ar, aug_slot_six);
ar(
CEREAL_NVP(quantity),
CEREAL_NVP(permission)
);
}
template <class Archive>
void load(Archive& ar)
{ {
ar( ar(
CEREAL_NVP(char_id), CEREAL_NVP(char_id),
@ -1314,7 +1746,8 @@ namespace PlayerEvent {
CEREAL_NVP(aug_slot_four), CEREAL_NVP(aug_slot_four),
CEREAL_NVP(aug_slot_five), CEREAL_NVP(aug_slot_five),
CEREAL_NVP(aug_slot_six), CEREAL_NVP(aug_slot_six),
CEREAL_NVP(quantity) CEREAL_NVP(quantity),
CEREAL_NVP(permission)
); );
} }
}; };
@ -1323,10 +1756,10 @@ namespace PlayerEvent {
#endif //EQEMU_PLAYER_EVENTS_H #endif //EQEMU_PLAYER_EVENTS_H
#define RecordPlayerEventLog(event_type, event_data) do {\ #define RecordPlayerEventLog(event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\ if (PlayerEventLogs::Instance()->IsEventEnabled(event_type)) {\
if (RuleB(Logging, PlayerEventsQSProcess)) {\ if (RuleB(Logging, PlayerEventsQSProcess)) {\
QServ->SendPacket(\ QServ->SendPacket(\
player_event_logs.RecordEvent(\ PlayerEventLogs::Instance()->RecordEvent(\
event_type,\ event_type,\
GetPlayerEvent(),\ GetPlayerEvent(),\
event_data\ event_data\
@ -1335,7 +1768,7 @@ namespace PlayerEvent {
} \ } \
else { \ else { \
worldserver.SendPacket(\ worldserver.SendPacket(\
player_event_logs.RecordEvent(\ PlayerEventLogs::Instance()->RecordEvent(\
event_type,\ event_type,\
GetPlayerEvent(),\ GetPlayerEvent(),\
event_data\ event_data\
@ -1346,10 +1779,10 @@ namespace PlayerEvent {
} while (0) } while (0)
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\ #define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\ if (PlayerEventLogs::Instance()->IsEventEnabled(event_type)) {\
if (RuleB(Logging, PlayerEventsQSProcess)) {\ if (RuleB(Logging, PlayerEventsQSProcess)) {\
QServ->SendPacket(\ QServ->SendPacket(\
player_event_logs.RecordEvent(\ PlayerEventLogs::Instance()->RecordEvent(\
event_type,\ event_type,\
(c)->GetPlayerEvent(),\ (c)->GetPlayerEvent(),\
event_data\ event_data\
@ -1358,7 +1791,7 @@ namespace PlayerEvent {
}\ }\
else {\ else {\
worldserver.SendPacket(\ worldserver.SendPacket(\
player_event_logs.RecordEvent(\ PlayerEventLogs::Instance()->RecordEvent(\
event_type,\ event_type,\
(c)->GetPlayerEvent(),\ (c)->GetPlayerEvent(),\
event_data\ event_data\

View File

@ -21,8 +21,8 @@ void EvolvingItemsManager::LoadEvolvingItems() const
results.begin(), results.begin(),
results.end(), results.end(),
std::inserter( std::inserter(
evolving_items_manager.GetEvolvingItemsCache(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache(),
evolving_items_manager.GetEvolvingItemsCache().end() EvolvingItemsManager::Instance()->GetEvolvingItemsCache().end()
), ),
[](const ItemsEvolvingDetailsRepository::ItemsEvolvingDetails &x) { [](const ItemsEvolvingDetailsRepository::ItemsEvolvingDetails &x) {
return std::make_pair(x.item_id, x); return std::make_pair(x.item_id, x);
@ -42,13 +42,13 @@ void EvolvingItemsManager::SetContentDatabase(Database *db)
double EvolvingItemsManager::CalculateProgression(const uint64 current_amount, const uint32 item_id) double EvolvingItemsManager::CalculateProgression(const uint64 current_amount, const uint32 item_id)
{ {
if (!evolving_items_manager.GetEvolvingItemsCache().contains(item_id)) { if (!EvolvingItemsManager::Instance()->GetEvolvingItemsCache().contains(item_id)) {
return 0; return 0;
} }
return evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount > 0 return EvolvingItemsManager::Instance()->GetEvolvingItemsCache().at(item_id).required_amount > 0
? static_cast<double>(current_amount) ? static_cast<double>(current_amount)
/ static_cast<double>(evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount) * 100 / static_cast<double>(EvolvingItemsManager::Instance()->GetEvolvingItemsCache().at(item_id).required_amount) * 100
: 0; : 0;
} }
@ -73,7 +73,11 @@ void EvolvingItemsManager::DoLootChecks(const uint32 char_id, const uint16 slot_
e.character_id = char_id; e.character_id = char_id;
e.item_id = inst.GetID(); e.item_id = inst.GetID();
e.equipped = inst.GetEvolveEquipped(); e.equipped = inst.GetEvolveEquipped();
e.final_item_id = evolving_items_manager.GetFinalItemID(inst); e.final_item_id = EvolvingItemsManager::Instance()->GetFinalItemID(inst);
if (inst.GetEvolveCurrentAmount() > 0) {
e.current_amount = inst.GetEvolveCurrentAmount();
inst.CalculateEvolveProgression();
}
auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e); auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e);
e.id = r.id; e.id = r.id;
@ -96,20 +100,20 @@ uint32 EvolvingItemsManager::GetFinalItemID(const EQ::ItemInstance &inst) const
} }
const auto start_iterator = std::ranges::find_if( const auto start_iterator = std::ranges::find_if(
evolving_items_manager.GetEvolvingItemsCache().cbegin(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cbegin(),
evolving_items_manager.GetEvolvingItemsCache().cend(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) { [&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID(); return a.second.item_evo_id == inst.GetEvolveLoreID();
} }
); );
if (start_iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) { if (start_iterator == std::end(EvolvingItemsManager::Instance()->GetEvolvingItemsCache())) {
return 0; return 0;
} }
const auto final_id = std::ranges::max_element( const auto final_id = std::ranges::max_element(
start_iterator, start_iterator,
evolving_items_manager.GetEvolvingItemsCache().cend(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&]( [&](
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a, const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a,
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &b const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &b
@ -131,15 +135,15 @@ uint32 EvolvingItemsManager::GetNextEvolveItemID(const EQ::ItemInstance &inst) c
int8 const current_level = inst.GetEvolveLvl(); int8 const current_level = inst.GetEvolveLvl();
const auto iterator = std::ranges::find_if( const auto iterator = std::ranges::find_if(
evolving_items_manager.GetEvolvingItemsCache().cbegin(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cbegin(),
evolving_items_manager.GetEvolvingItemsCache().cend(), EvolvingItemsManager::Instance()->GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) { [&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID() && return a.second.item_evo_id == inst.GetEvolveLoreID() &&
a.second.item_evolve_level == current_level + 1; a.second.item_evolve_level == current_level + 1;
} }
); );
if (iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) { if (iterator == std::end(EvolvingItemsManager::Instance()->GetEvolvingItemsCache())) {
return 0; return 0;
} }
@ -255,8 +259,8 @@ EvolveTransfer EvolvingItemsManager::DetermineTransferResults(
return ets; return ets;
} }
auto evolving_details_inst_from = evolving_items_manager.GetEvolveItemDetails(inst_from.GetID()); auto evolving_details_inst_from = EvolvingItemsManager::Instance()->GetEvolveItemDetails(inst_from.GetID());
auto evolving_details_inst_to = evolving_items_manager.GetEvolveItemDetails(inst_to.GetID()); auto evolving_details_inst_to = EvolvingItemsManager::Instance()->GetEvolveItemDetails(inst_to.GetID());
if (!evolving_details_inst_from.id || !evolving_details_inst_to.id) { if (!evolving_details_inst_from.id || !evolving_details_inst_to.id) {
return ets; return ets;
@ -272,10 +276,10 @@ EvolveTransfer EvolvingItemsManager::DetermineTransferResults(
compatibility = 30; compatibility = 30;
} }
xp = evolving_items_manager.GetTotalEarnedXP(inst_from) * compatibility / 100; xp = EvolvingItemsManager::Instance()->GetTotalEarnedXP(inst_from) * compatibility / 100;
auto results = evolving_items_manager.GetNextItemByXP(inst_to, xp); auto results = EvolvingItemsManager::Instance()->GetNextItemByXP(inst_to, xp);
ets.item_from_id = evolving_items_manager.GetFirstItemInLoreGroup(inst_from.GetEvolveLoreID()); ets.item_from_id = EvolvingItemsManager::Instance()->GetFirstItemInLoreGroup(inst_from.GetEvolveLoreID());
ets.item_from_current_amount = results.from_current_amount; ets.item_from_current_amount = results.from_current_amount;
ets.item_to_id = results.new_item_id; ets.item_to_id = results.new_item_id;
ets.item_to_current_amount = results.new_current_amount; ets.item_to_current_amount = results.new_current_amount;

View File

@ -56,12 +56,15 @@ public:
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails>& GetEvolvingItemsCache() { return m_evolving_items_cache; } std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails>& GetEvolvingItemsCache() { return m_evolving_items_cache; }
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> GetEvolveIDItems(uint32 evolve_id); std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> GetEvolveIDItems(uint32 evolve_id);
static EvolvingItemsManager* Instance()
{
static EvolvingItemsManager instance;
return &instance;
}
private: private:
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> m_evolving_items_cache; std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> m_evolving_items_cache;
Database * m_db; Database * m_db;
Database * m_content_db; Database * m_content_db;
}; };
extern EvolvingItemsManager evolving_items_manager;
#endif //EVOLVING_H #endif //EVOLVING_H

View File

@ -95,12 +95,12 @@ bool IsOfEqualRace(int r1, int r2)
} }
// TODO: add more values // TODO: add more values
switch (r1) { switch (r1) {
case DARK_ELF: case Race::DarkElf:
if (r2 == Race::NeriakCitizen) { if (r2 == Race::NeriakCitizen) {
return true; return true;
} }
break; break;
case BARBARIAN: case Race::Barbarian:
if (r2 == Race::HalasCitizen) { if (r2 == Race::HalasCitizen) {
return true; return true;
} }
@ -116,49 +116,49 @@ bool IsOfIndiffRace(int r1, int r2)
} }
// TODO: add more values // TODO: add more values
switch (r1) { switch (r1) {
case DARK_ELF: case Race::DarkElf:
case OGRE: case Race::Ogre:
case TROLL: case Race::Troll:
if (r2 == OGRE || r2 == TROLL || r2 == DARK_ELF) { if (r2 == Race::Ogre || r2 == Race::Troll || r2 == Race::DarkElf) {
return true; return true;
} }
break; break;
case HUMAN: case Race::Human:
case BARBARIAN: case Race::Barbarian:
case HALF_ELF: case Race::HalfElf:
case GNOME: case Race::Gnome:
case HALFLING: case Race::Halfling:
case WOOD_ELF: case Race::WoodElf:
if (r2 == HUMAN || if (r2 == Race::Human ||
r2 == BARBARIAN || r2 == Race::Barbarian ||
r2 == ERUDITE || r2 == Race::Erudite ||
r2 == HALF_ELF || r2 == Race::HalfElf ||
r2 == GNOME || r2 == Race::Gnome ||
r2 == HALFLING || r2 == Race::Halfling ||
r2 == DWARF || r2 == Race::Dwarf ||
r2 == HIGH_ELF || r2 == Race::HighElf ||
r2 == WOOD_ELF) { r2 == Race::WoodElf) {
return true; return true;
} }
break; break;
case ERUDITE: case Race::Erudite:
if (r2 == HUMAN || r2 == HALF_ELF) { if (r2 == Race::Human || r2 == Race::HalfElf) {
return true; return true;
} }
break; break;
case DWARF: case Race::Dwarf:
if (r2 == HALFLING || r2 == GNOME) { if (r2 == Race::Halfling || r2 == Race::Gnome) {
return true; return true;
} }
break; break;
case HIGH_ELF: case Race::HighElf:
if (r2 == WOOD_ELF) { if (r2 == Race::WoodElf) {
return true; return true;
} }
break; break;
case VAHSHIR: case Race::VahShir:
return true; return true;
case IKSAR: case Race::Iksar:
return false; return false;
} }
return false; return false;

View File

@ -55,7 +55,7 @@ namespace EQ {
EQ_EXCEPT("IPC Mutex", "Could not create mutex."); EQ_EXCEPT("IPC Mutex", "Could not create mutex.");
} }
#else #else
std::string final_name = fmt::format("{}/{}.lock", path.GetSharedMemoryPath(), name); std::string final_name = fmt::format("{}/{}.lock", PathManager::Instance()->GetSharedMemoryPath(), name);
#ifdef __DARWIN #ifdef __DARWIN
#if __DARWIN_C_LEVEL < 200809L #if __DARWIN_C_LEVEL < 200809L

View File

@ -438,7 +438,7 @@ namespace EQ
//uint32 Unk054 {}; //uint32 Unk054 {};
int16 MaxCharges {}; // Maximum charges items can hold: -1 if not a chargeable item int16 MaxCharges {}; // Maximum charges items can hold: -1 if not a chargeable item
uint8 ItemType {}; // Item Type/Skill (itemClass* from above) uint8 ItemType {}; // Item Type/Skill (itemClass* from above)
int32 SubType {}; // Some items have sub types that can be used for other things (unbreakable fishing poles, SE_FFItemClass) int32 SubType {}; // Some items have sub types that can be used for other things (unbreakable fishing poles, SpellEffect::FFItemClass)
uint8 Material {}; // Item material type uint8 Material {}; // Item material type
uint32 HerosForgeModel {};// Hero's Forge Armor Model Type (2-13?) uint32 HerosForgeModel {};// Hero's Forge Armor Model Type (2-13?)
float SellRate {}; // Sell rate float SellRate {}; // Sell rate

View File

@ -1,206 +0,0 @@
/*
These fields must be in the order of how they are serialized!
*/
F(itemclass)
F(name)
F(lore)
F(idfile)
F(id)
F(weight)
F(norent)
F(nodrop)
F(size)
F(slots)
F(price)
F(icon)
F(UNK012)
F(UNK013)
F(benefitflag)
F(tradeskills)
F(cr)
F(dr)
F(pr)
F(mr)
F(fr)
F(astr)
F(asta)
F(aagi)
F(adex)
F(acha)
F(aint)
F(awis)
F(hp)
F(mana)
F(ac)
F(deity)
F(skillmodvalue)
F(UNK033)
F(skillmodmax)
F(skillmodtype)
F(banedmgrace)
F(banedmgamt)
F(banedmgbody)
F(magic)
F(casttime_)
F(reqlevel)
F(bardtype)
F(bardvalue)
F(light)
F(delay)
F(reclevel)
F(recskill)
F(elemdmgtype)
F(elemdmgamt)
F(range)
F(damage)
F(color)
F(classes)
F(races)
F(UNK054)
F(maxcharges)
F(itemtype)
F(material)
F(herosforgemodel)
F(sellrate)
F(UNK059)
F(casttime)
F(elitematerial)
F(procrate)
F(combateffects)
F(shielding)
F(stunresist)
F(strikethrough)
F(extradmgskill)
F(extradmgamt)
F(spellshield)
F(avoidance)
F(accuracy)
F(charmfileid)
F(factionmod1)
F(factionmod2)
F(factionmod3)
F(factionmod4)
F(factionamt1)
F(factionamt2)
F(factionamt3)
F(factionamt4)
F(charmfile)
F(augtype)
F(augslot1type)
F(augslot1visible)
F(augslot2type)
F(augslot2visible)
F(augslot3type)
F(augslot3visible)
F(augslot4type)
F(augslot4visible)
F(augslot5type)
F(augslot5visible)
F(augslot6type)
F(augslot6visible)
F(ldontheme)
F(ldonprice)
F(ldonsold)
F(bagtype)
F(bagslots)
F(bagsize)
F(bagwr)
F(book)
F(booktype)
F(filename)
F(banedmgraceamt)
F(augrestrict)
F(loregroup)
F(pendingloreflag)
F(artifactflag)
F(summonedflag)
F(favor)
F(fvnodrop)
F(endur)
F(dotshielding)
F(attack)
F(regen)
F(manaregen)
F(enduranceregen)
F(haste)
F(damageshield)
F(recastdelay)
F(recasttype)
F(guildfavor)
F(augdistiller)
F(UNK123)
F(UNK124)
F(attuneable)
F(nopet)
F(UNK127)
F(pointtype)
F(potionbelt)
F(potionbeltslots)
F(stacksize)
F(notransfer)
F(stackable)
F(UNK134)
F(clickeffect)
F(clicktype)
F(clicklevel)
F(clicklevel2)
F(proceffect)
F(proctype)
F(proclevel)
F(proclevel2)
F(worneffect)
F(worntype)
F(wornlevel)
F(wornlevel2)
F(focuseffect)
F(focustype)
F(focuslevel)
F(focuslevel2)
F(scrolleffect)
F(scrolltype)
F(scrolllevel)
F(scrolllevel2)
F(bardeffect)
F(bardeffecttype)
F(bardlevel2)
F(bardlevel)
F(questitemflag)
F(svcorruption)
F(purity)
F(evoitem)
F(evoid)
F(evolvinglevel)
F(evomax)
F(backstabdmg)
F(dsmitigation)
F(heroic_str)
F(heroic_int)
F(heroic_wis)
F(heroic_agi)
F(heroic_dex)
F(heroic_sta)
F(heroic_cha)
F(heroic_mr)
F(heroic_fr)
F(heroic_cr)
F(heroic_dr)
F(heroic_pr)
F(heroic_svcorrup)
F(healamt)
F(spelldmg)
F(ldonsellbackrate)
F(scriptfileid)
F(expendablearrow)
F(clairvoyance)
F(clickname)
F(procname)
F(wornname)
F(focusname)
F(scrollname)
F(subtype)

View File

@ -574,7 +574,7 @@ EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
{ {
// Not a Hero Forge item. // Not a Hero Forge item.
if (m_ornament_hero_model == 0 || material_slot < 0) { if (m_ornament_hero_model == 0) {
return 0; return 0;
} }
@ -1799,7 +1799,7 @@ std::vector<std::string> EQ::ItemInstance::GetAugmentNames() const
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) { for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
const auto augment = GetAugment(slot_id); const auto augment = GetAugment(slot_id);
augment_names.push_back(augment ? augment->GetItem()->Name : "None"); augment_names.push_back(augment ? augment->GetItem()->Name : "");
} }
return augment_names; return augment_names;

View File

@ -335,7 +335,7 @@ namespace EQ
void SetEvolveAddToCurrentAmount(const uint64 in) const { m_evolving_details.current_amount += in; } void SetEvolveAddToCurrentAmount(const uint64 in) const { m_evolving_details.current_amount += in; }
void SetEvolveFinalItemID(const uint32 in) const { m_evolving_details.final_item_id = in; } void SetEvolveFinalItemID(const uint32 in) const { m_evolving_details.final_item_id = in; }
bool TransferOwnership(Database& db, const uint32 to_char_id) const; bool TransferOwnership(Database& db, const uint32 to_char_id) const;
void CalculateEvolveProgression() const { m_evolving_details.progression = evolving_items_manager.CalculateProgression(GetEvolveCurrentAmount(), GetID()); } void CalculateEvolveProgression() const { m_evolving_details.progression = EvolvingItemsManager::Instance()->CalculateProgression(GetEvolveCurrentAmount(), GetID()); }
protected: protected:
////////////////////////// //////////////////////////

View File

@ -1,11 +1,11 @@
#include "eqstream.h" #include "eqstream.h"
#include "../eqemu_logsys.h" #include "../eqemu_logsys.h"
EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_daybreak(options.daybreak_options) EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_reliable_stream(options.reliable_stream_options)
{ {
m_daybreak.OnNewConnection(std::bind(&EQStreamManager::DaybreakNewConnection, this, std::placeholders::_1)); m_reliable_stream.OnNewConnection(std::bind(&EQStreamManager::ReliableStreamNewConnection, this, std::placeholders::_1));
m_daybreak.OnConnectionStateChange(std::bind(&EQStreamManager::DaybreakConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_reliable_stream.OnConnectionStateChange(std::bind(&EQStreamManager::ReliableStreamConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_daybreak.OnPacketRecv(std::bind(&EQStreamManager::DaybreakPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); m_reliable_stream.OnPacketRecv(std::bind(&EQStreamManager::ReliableStreamPacketRecv, this, std::placeholders::_1, std::placeholders::_2));
} }
EQ::Net::EQStreamManager::~EQStreamManager() EQ::Net::EQStreamManager::~EQStreamManager()
@ -15,11 +15,11 @@ EQ::Net::EQStreamManager::~EQStreamManager()
void EQ::Net::EQStreamManager::SetOptions(const EQStreamManagerInterfaceOptions &options) void EQ::Net::EQStreamManager::SetOptions(const EQStreamManagerInterfaceOptions &options)
{ {
m_options = options; m_options = options;
auto &opts = m_daybreak.GetOptions(); auto &opts = m_reliable_stream.GetOptions();
opts = options.daybreak_options; opts = options.reliable_stream_options;
} }
void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection) void EQ::Net::EQStreamManager::ReliableStreamNewConnection(std::shared_ptr<ReliableStreamConnection> connection)
{ {
std::shared_ptr<EQStream> stream(new EQStream(this, connection)); std::shared_ptr<EQStream> stream(new EQStream(this, connection));
m_streams.emplace(std::make_pair(connection, stream)); m_streams.emplace(std::make_pair(connection, stream));
@ -28,7 +28,7 @@ void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakCon
} }
} }
void EQ::Net::EQStreamManager::DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to) void EQ::Net::EQStreamManager::ReliableStreamConnectionStateChange(std::shared_ptr<ReliableStreamConnection> connection, DbProtocolStatus from, DbProtocolStatus to)
{ {
auto iter = m_streams.find(connection); auto iter = m_streams.find(connection);
if (iter != m_streams.end()) { if (iter != m_streams.end()) {
@ -42,7 +42,7 @@ void EQ::Net::EQStreamManager::DaybreakConnectionStateChange(std::shared_ptr<Day
} }
} }
void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p) void EQ::Net::EQStreamManager::ReliableStreamPacketRecv(std::shared_ptr<ReliableStreamConnection> connection, const Packet &p)
{ {
auto iter = m_streams.find(connection); auto iter = m_streams.find(connection);
if (iter != m_streams.end()) { if (iter != m_streams.end()) {
@ -53,7 +53,7 @@ void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr<DaybreakConnec
} }
} }
EQ::Net::EQStream::EQStream(EQStreamManagerInterface *owner, std::shared_ptr<DaybreakConnection> connection) EQ::Net::EQStream::EQStream(EQStreamManagerInterface *owner, std::shared_ptr<ReliableStreamConnection> connection)
{ {
m_owner = owner; m_owner = owner;
m_connection = connection; m_connection = connection;
@ -71,7 +71,7 @@ void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
OpcodeManager::EmuToName(p->GetOpcode()), OpcodeManager::EmuToName(p->GetOpcode()),
(*m_opcode_manager)->EmuToEQ(p->GetOpcode()), (*m_opcode_manager)->EmuToEQ(p->GetOpcode()),
p->Size(), p->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "") (EQEmuLogSys::Instance()->IsLogEnabled(Logs::Detail, Logs::PacketServerClient) ? DumpPacketToString(p) : "")
); );
if (m_opcode_manager && *m_opcode_manager) { if (m_opcode_manager && *m_opcode_manager) {
@ -235,7 +235,7 @@ EQStreamState EQ::Net::EQStream::GetState() {
EQ::Net::EQStream::Stats EQ::Net::EQStream::GetStats() const EQ::Net::EQStream::Stats EQ::Net::EQStream::GetStats() const
{ {
Stats ret; Stats ret;
ret.DaybreakStats = m_connection->GetStats(); ret.ReliableStreamStats = m_connection->GetStats();
for (int i = 0; i < _maxEmuOpcode; ++i) { for (int i = 0; i < _maxEmuOpcode; ++i) {
ret.RecvCount[i] = 0; ret.RecvCount[i] = 0;

View File

@ -3,7 +3,7 @@
#include "../eq_packet.h" #include "../eq_packet.h"
#include "../eq_stream_intf.h" #include "../eq_stream_intf.h"
#include "../opcodemgr.h" #include "../opcodemgr.h"
#include "daybreak_connection.h" #include "reliable_stream_connection.h"
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <unordered_map> #include <unordered_map>
@ -23,21 +23,21 @@ namespace EQ
void OnNewConnection(std::function<void(std::shared_ptr<EQStream>)> func) { m_on_new_connection = func; } void OnNewConnection(std::function<void(std::shared_ptr<EQStream>)> func) { m_on_new_connection = func; }
void OnConnectionStateChange(std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } void OnConnectionStateChange(std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
private: private:
DaybreakConnectionManager m_daybreak; ReliableStreamConnectionManager m_reliable_stream;
std::function<void(std::shared_ptr<EQStream>)> m_on_new_connection; std::function<void(std::shared_ptr<EQStream>)> m_on_new_connection;
std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
std::map<std::shared_ptr<DaybreakConnection>, std::shared_ptr<EQStream>> m_streams; std::map<std::shared_ptr<ReliableStreamConnection>, std::shared_ptr<EQStream>> m_streams;
void DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection); void ReliableStreamNewConnection(std::shared_ptr<ReliableStreamConnection> connection);
void DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to); void ReliableStreamConnectionStateChange(std::shared_ptr<ReliableStreamConnection> connection, DbProtocolStatus from, DbProtocolStatus to);
void DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p); void ReliableStreamPacketRecv(std::shared_ptr<ReliableStreamConnection> connection, const Packet &p);
friend class EQStream; friend class EQStream;
}; };
class EQStream : public EQStreamInterface class EQStream : public EQStreamInterface
{ {
public: public:
EQStream(EQStreamManagerInterface *parent, std::shared_ptr<DaybreakConnection> connection); EQStream(EQStreamManagerInterface *parent, std::shared_ptr<ReliableStreamConnection> connection);
~EQStream(); ~EQStream();
virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req = true); virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req = true);
@ -67,7 +67,7 @@ namespace EQ
virtual EQStreamManagerInterface* GetManager() const; virtual EQStreamManagerInterface* GetManager() const;
private: private:
EQStreamManagerInterface *m_owner; EQStreamManagerInterface *m_owner;
std::shared_ptr<DaybreakConnection> m_connection; std::shared_ptr<ReliableStreamConnection> m_connection;
OpcodeManager **m_opcode_manager; OpcodeManager **m_opcode_manager;
std::deque<std::unique_ptr<EQ::Net::Packet>> m_packet_queue; std::deque<std::unique_ptr<EQ::Net::Packet>> m_packet_queue;
std::unordered_map<int, int> m_packet_recv_count; std::unordered_map<int, int> m_packet_recv_count;

View File

@ -1,4 +1,4 @@
#include "daybreak_connection.h" #include "reliable_stream_connection.h"
#include "../event/event_loop.h" #include "../event/event_loop.h"
#include "../data_verification.h" #include "../data_verification.h"
#include "crc32.h" #include "crc32.h"
@ -12,7 +12,7 @@ constexpr size_t MAX_CLIENT_RECV_BYTES_PER_WINDOW = 140 * 1024;
// buffer pools // buffer pools
SendBufferPool send_buffer_pool; SendBufferPool send_buffer_pool;
EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager() EQ::Net::ReliableStreamConnectionManager::ReliableStreamConnectionManager()
{ {
m_attached = nullptr; m_attached = nullptr;
memset(&m_timer, 0, sizeof(uv_timer_t)); memset(&m_timer, 0, sizeof(uv_timer_t));
@ -21,7 +21,7 @@ EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager()
Attach(EQ::EventLoop::Get().Handle()); Attach(EQ::EventLoop::Get().Handle());
} }
EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts) EQ::Net::ReliableStreamConnectionManager::ReliableStreamConnectionManager(const ReliableStreamConnectionManagerOptions &opts)
{ {
m_attached = nullptr; m_attached = nullptr;
m_options = opts; m_options = opts;
@ -31,12 +31,12 @@ EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager(const DaybreakConn
Attach(EQ::EventLoop::Get().Handle()); Attach(EQ::EventLoop::Get().Handle());
} }
EQ::Net::DaybreakConnectionManager::~DaybreakConnectionManager() EQ::Net::ReliableStreamConnectionManager::~ReliableStreamConnectionManager()
{ {
Detach(); Detach();
} }
void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop) void EQ::Net::ReliableStreamConnectionManager::Attach(uv_loop_t *loop)
{ {
if (!m_attached) { if (!m_attached) {
uv_timer_init(loop, &m_timer); uv_timer_init(loop, &m_timer);
@ -45,7 +45,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop)
auto update_rate = (uint64_t)(1000.0 / m_options.tic_rate_hertz); auto update_rate = (uint64_t)(1000.0 / m_options.tic_rate_hertz);
uv_timer_start(&m_timer, [](uv_timer_t *handle) { uv_timer_start(&m_timer, [](uv_timer_t *handle) {
DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data; ReliableStreamConnectionManager *c = (ReliableStreamConnectionManager*)handle->data;
c->UpdateDataBudget(); c->UpdateDataBudget();
c->Process(); c->Process();
c->ProcessResend(); c->ProcessResend();
@ -71,7 +71,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop)
buf->len = 65536; buf->len = 65536;
}, },
[](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data; ReliableStreamConnectionManager *c = (ReliableStreamConnectionManager*)handle->data;
if (nread < 0 || addr == nullptr) { if (nread < 0 || addr == nullptr) {
return; return;
} }
@ -90,7 +90,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop)
} }
} }
void EQ::Net::DaybreakConnectionManager::Detach() void EQ::Net::ReliableStreamConnectionManager::Detach()
{ {
if (m_attached) { if (m_attached) {
uv_udp_recv_stop(&m_socket); uv_udp_recv_stop(&m_socket);
@ -99,11 +99,11 @@ void EQ::Net::DaybreakConnectionManager::Detach()
} }
} }
void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int port) void EQ::Net::ReliableStreamConnectionManager::Connect(const std::string &addr, int port)
{ {
//todo dns resolution //todo dns resolution
auto connection = std::shared_ptr<DaybreakConnection>(new DaybreakConnection(this, addr, port)); auto connection = std::shared_ptr<ReliableStreamConnection>(new ReliableStreamConnection(this, addr, port));
connection->m_self = connection; connection->m_self = connection;
if (m_on_new_connection) { if (m_on_new_connection) {
@ -113,7 +113,7 @@ void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int po
m_connections.emplace(std::make_pair(std::make_pair(addr, port), connection)); m_connections.emplace(std::make_pair(std::make_pair(addr, port), connection));
} }
void EQ::Net::DaybreakConnectionManager::Process() void EQ::Net::ReliableStreamConnectionManager::Process()
{ {
auto now = Clock::now(); auto now = Clock::now();
auto iter = m_connections.begin(); auto iter = m_connections.begin();
@ -177,7 +177,7 @@ void EQ::Net::DaybreakConnectionManager::Process()
} }
} }
void EQ::Net::DaybreakConnectionManager::UpdateDataBudget() void EQ::Net::ReliableStreamConnectionManager::UpdateDataBudget()
{ {
auto outgoing_data_rate = m_options.outgoing_data_rate; auto outgoing_data_rate = m_options.outgoing_data_rate;
if (outgoing_data_rate <= 0.0) { if (outgoing_data_rate <= 0.0) {
@ -196,7 +196,7 @@ void EQ::Net::DaybreakConnectionManager::UpdateDataBudget()
} }
} }
void EQ::Net::DaybreakConnectionManager::ProcessResend() void EQ::Net::ReliableStreamConnectionManager::ProcessResend()
{ {
auto iter = m_connections.begin(); auto iter = m_connections.begin();
while (iter != m_connections.end()) { while (iter != m_connections.end()) {
@ -217,15 +217,15 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend()
} }
} }
void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size) void EQ::Net::ReliableStreamConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size)
{ {
if (m_options.simulated_in_packet_loss && m_options.simulated_in_packet_loss >= m_rand.Int(0, 100)) { if (m_options.simulated_in_packet_loss && m_options.simulated_in_packet_loss >= m_rand.Int(0, 100)) {
return; return;
} }
if (size < DaybreakHeader::size()) { if (size < ReliableStreamHeader::size()) {
if (m_on_error_message) { if (m_on_error_message) {
m_on_error_message(fmt::format("Packet of size {0} which is less than {1}", size, DaybreakHeader::size())); m_on_error_message(fmt::format("Packet of size {0} which is less than {1}", size, ReliableStreamHeader::size()));
} }
return; return;
} }
@ -239,9 +239,9 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi
else { else {
if (data[0] == 0 && data[1] == OP_SessionRequest) { if (data[0] == 0 && data[1] == OP_SessionRequest) {
StaticPacket p((void*)data, size); StaticPacket p((void*)data, size);
auto request = p.GetSerialize<DaybreakConnect>(0); auto request = p.GetSerialize<ReliableStreamConnect>(0);
connection = std::shared_ptr<DaybreakConnection>(new DaybreakConnection(this, request, endpoint, port)); connection = std::shared_ptr<ReliableStreamConnection>(new ReliableStreamConnection(this, request, endpoint, port));
connection->m_self = connection; connection->m_self = connection;
if (m_on_new_connection) { if (m_on_new_connection) {
@ -262,7 +262,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi
} }
} }
std::shared_ptr<EQ::Net::DaybreakConnection> EQ::Net::DaybreakConnectionManager::FindConnectionByEndpoint(std::string addr, int port) std::shared_ptr<EQ::Net::ReliableStreamConnection> EQ::Net::ReliableStreamConnectionManager::FindConnectionByEndpoint(std::string addr, int port)
{ {
auto p = std::make_pair(addr, port); auto p = std::make_pair(addr, port);
auto iter = m_connections.find(p); auto iter = m_connections.find(p);
@ -273,9 +273,9 @@ std::shared_ptr<EQ::Net::DaybreakConnection> EQ::Net::DaybreakConnectionManager:
return nullptr; return nullptr;
} }
void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr, int port) void EQ::Net::ReliableStreamConnectionManager::SendDisconnect(const std::string &addr, int port)
{ {
DaybreakDisconnect header; ReliableStreamDisconnect header;
header.zero = 0; header.zero = 0;
header.opcode = OP_OutOfSession; header.opcode = OP_OutOfSession;
header.connect_code = 0; header.connect_code = 0;
@ -300,7 +300,7 @@ void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr,
} }
//new connection made as server //new connection made as server
EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port) EQ::Net::ReliableStreamConnection::ReliableStreamConnection(ReliableStreamConnectionManager *owner, const ReliableStreamConnect &connect, const std::string &endpoint, int port)
{ {
m_owner = owner; m_owner = owner;
m_last_send = Clock::now(); m_last_send = Clock::now();
@ -327,7 +327,7 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
} }
//new connection made as client //new connection made as client
EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port) EQ::Net::ReliableStreamConnection::ReliableStreamConnection(ReliableStreamConnectionManager *owner, const std::string &endpoint, int port)
{ {
m_owner = owner; m_owner = owner;
m_last_send = Clock::now(); m_last_send = Clock::now();
@ -349,11 +349,11 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner
m_outgoing_budget = owner->m_options.outgoing_data_rate; m_outgoing_budget = owner->m_options.outgoing_data_rate;
} }
EQ::Net::DaybreakConnection::~DaybreakConnection() EQ::Net::ReliableStreamConnection::~ReliableStreamConnection()
{ {
} }
void EQ::Net::DaybreakConnection::Close() void EQ::Net::ReliableStreamConnection::Close()
{ {
if (m_status != StatusDisconnected && m_status != StatusDisconnecting) { if (m_status != StatusDisconnected && m_status != StatusDisconnecting) {
FlushBuffer(); FlushBuffer();
@ -367,17 +367,17 @@ void EQ::Net::DaybreakConnection::Close()
ChangeStatus(StatusDisconnecting); ChangeStatus(StatusDisconnecting);
} }
void EQ::Net::DaybreakConnection::QueuePacket(Packet &p) void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p)
{ {
QueuePacket(p, 0, true); QueuePacket(p, 0, true);
} }
void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream) void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p, int stream)
{ {
QueuePacket(p, stream, true); QueuePacket(p, stream, true);
} }
void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream, bool reliable) void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p, int stream, bool reliable)
{ {
if (*(char*)p.Data() == 0) { if (*(char*)p.Data() == 0) {
DynamicPacket packet; DynamicPacket packet;
@ -390,21 +390,21 @@ void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream, bool reliab
InternalQueuePacket(p, stream, reliable); InternalQueuePacket(p, stream, reliable);
} }
EQ::Net::DaybreakConnectionStats EQ::Net::DaybreakConnection::GetStats() EQ::Net::ReliableStreamConnectionStats EQ::Net::ReliableStreamConnection::GetStats()
{ {
EQ::Net::DaybreakConnectionStats ret = m_stats; EQ::Net::ReliableStreamConnectionStats ret = m_stats;
ret.datarate_remaining = m_outgoing_budget; ret.datarate_remaining = m_outgoing_budget;
ret.avg_ping = m_rolling_ping; ret.avg_ping = m_rolling_ping;
return ret; return ret;
} }
void EQ::Net::DaybreakConnection::ResetStats() void EQ::Net::ReliableStreamConnection::ResetStats()
{ {
m_stats.Reset(); m_stats.Reset();
} }
void EQ::Net::DaybreakConnection::Process() void EQ::Net::ReliableStreamConnection::Process()
{ {
try { try {
auto now = Clock::now(); auto now = Clock::now();
@ -422,7 +422,7 @@ void EQ::Net::DaybreakConnection::Process()
} }
} }
void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p) void EQ::Net::ReliableStreamConnection::ProcessPacket(Packet &p)
{ {
m_last_recv = Clock::now(); m_last_recv = Clock::now();
m_stats.recv_packets++; m_stats.recv_packets++;
@ -458,13 +458,13 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
switch (m_encode_passes[i]) { switch (m_encode_passes[i]) {
case EncodeCompression: case EncodeCompression:
if(temp.GetInt8(0) == 0) if(temp.GetInt8(0) == 0)
Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); Decompress(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size());
else else
Decompress(temp, 1, temp.Length() - 1); Decompress(temp, 1, temp.Length() - 1);
break; break;
case EncodeXOR: case EncodeXOR:
if (temp.GetInt8(0) == 0) if (temp.GetInt8(0) == 0)
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); Decode(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size());
else else
Decode(temp, 1, temp.Length() - 1); Decode(temp, 1, temp.Length() - 1);
break; break;
@ -483,7 +483,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
switch (m_encode_passes[i]) { switch (m_encode_passes[i]) {
case EncodeXOR: case EncodeXOR:
if (temp.GetInt8(0) == 0) if (temp.GetInt8(0) == 0)
Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); Decode(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size());
else else
Decode(temp, 1, temp.Length() - 1); Decode(temp, 1, temp.Length() - 1);
break; break;
@ -502,7 +502,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p)
} }
} }
void EQ::Net::DaybreakConnection::ProcessQueue() void EQ::Net::ReliableStreamConnection::ProcessQueue()
{ {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
auto stream = &m_streams[i]; auto stream = &m_streams[i];
@ -521,7 +521,7 @@ void EQ::Net::DaybreakConnection::ProcessQueue()
} }
} }
void EQ::Net::DaybreakConnection::RemoveFromQueue(int stream, uint16_t seq) void EQ::Net::ReliableStreamConnection::RemoveFromQueue(int stream, uint16_t seq)
{ {
auto s = &m_streams[stream]; auto s = &m_streams[stream];
auto iter = s->packet_queue.find(seq); auto iter = s->packet_queue.find(seq);
@ -532,7 +532,7 @@ void EQ::Net::DaybreakConnection::RemoveFromQueue(int stream, uint16_t seq)
} }
} }
void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Packet &p) void EQ::Net::ReliableStreamConnection::AddToQueue(int stream, uint16_t seq, const Packet &p)
{ {
auto s = &m_streams[stream]; auto s = &m_streams[stream];
auto iter = s->packet_queue.find(seq); auto iter = s->packet_queue.find(seq);
@ -544,7 +544,7 @@ void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Pac
} }
} }
void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) void EQ::Net::ReliableStreamConnection::ProcessDecodedPacket(const Packet &p)
{ {
if (p.GetInt8(0) == 0) { if (p.GetInt8(0) == 0) {
if (p.Length() < 2) { if (p.Length() < 2) {
@ -628,13 +628,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
case OP_SessionRequest: case OP_SessionRequest:
{ {
if (m_status == StatusConnected) { if (m_status == StatusConnected) {
auto request = p.GetSerialize<DaybreakConnect>(0); auto request = p.GetSerialize<ReliableStreamConnect>(0);
if (NetworkToHost(request.connect_code) != m_connect_code) { if (NetworkToHost(request.connect_code) != m_connect_code) {
return; return;
} }
DaybreakConnectReply reply; ReliableStreamConnectReply reply;
reply.zero = 0; reply.zero = 0;
reply.opcode = OP_SessionResponse; reply.opcode = OP_SessionResponse;
reply.connect_code = HostToNetwork(m_connect_code); reply.connect_code = HostToNetwork(m_connect_code);
@ -656,13 +656,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
case OP_SessionResponse: case OP_SessionResponse:
{ {
if (m_status == StatusConnecting) { if (m_status == StatusConnecting) {
auto reply = p.GetSerialize<DaybreakConnectReply>(0); auto reply = p.GetSerialize<ReliableStreamConnectReply>(0);
if (m_connect_code == reply.connect_code) { if (m_connect_code == reply.connect_code) {
m_encode_key = reply.encode_key; m_encode_key = reply.encode_key;
m_crc_bytes = reply.crc_bytes; m_crc_bytes = reply.crc_bytes;
m_encode_passes[0] = (DaybreakEncodeType)reply.encode_pass1; m_encode_passes[0] = (ReliableStreamEncodeType)reply.encode_pass1;
m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2; m_encode_passes[1] = (ReliableStreamEncodeType)reply.encode_pass2;
m_max_packet_size = reply.max_packet_size; m_max_packet_size = reply.max_packet_size;
ChangeStatus(StatusConnected); ChangeStatus(StatusConnected);
@ -686,7 +686,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
return; return;
} }
auto header = p.GetSerialize<DaybreakReliableHeader>(0); auto header = p.GetSerialize<ReliableStreamReliableHeader>(0);
auto sequence = NetworkToHost(header.sequence); auto sequence = NetworkToHost(header.sequence);
auto stream_id = header.opcode - OP_Packet; auto stream_id = header.opcode - OP_Packet;
auto stream = &m_streams[stream_id]; auto stream = &m_streams[stream_id];
@ -703,7 +703,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
RemoveFromQueue(stream_id, sequence); RemoveFromQueue(stream_id, sequence);
SendAck(stream_id, stream->sequence_in); SendAck(stream_id, stream->sequence_in);
stream->sequence_in++; stream->sequence_in++;
StaticPacket next((char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size()); StaticPacket next((char*)p.Data() + ReliableStreamReliableHeader::size(), p.Length() - ReliableStreamReliableHeader::size());
ProcessDecodedPacket(next); ProcessDecodedPacket(next);
} }
@ -715,7 +715,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
case OP_Fragment3: case OP_Fragment3:
case OP_Fragment4: case OP_Fragment4:
{ {
auto header = p.GetSerialize<DaybreakReliableHeader>(0); auto header = p.GetSerialize<ReliableStreamReliableHeader>(0);
auto sequence = NetworkToHost(header.sequence); auto sequence = NetworkToHost(header.sequence);
auto stream_id = header.opcode - OP_Fragment; auto stream_id = header.opcode - OP_Fragment;
auto stream = &m_streams[stream_id]; auto stream = &m_streams[stream_id];
@ -735,22 +735,22 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
stream->sequence_in++; stream->sequence_in++;
if (stream->fragment_total_bytes == 0) { if (stream->fragment_total_bytes == 0) {
auto fragheader = p.GetSerialize<DaybreakReliableFragmentHeader>(0); auto fragheader = p.GetSerialize<ReliableStreamReliableFragmentHeader>(0);
stream->fragment_total_bytes = NetworkToHost(fragheader.total_size); stream->fragment_total_bytes = NetworkToHost(fragheader.total_size);
stream->fragment_current_bytes = 0; stream->fragment_current_bytes = 0;
stream->fragment_packet.Reserve(stream->fragment_total_bytes); stream->fragment_packet.Reserve(stream->fragment_total_bytes);
stream->fragment_packet.PutData( stream->fragment_packet.PutData(
stream->fragment_current_bytes, stream->fragment_current_bytes,
(char*)p.Data() + DaybreakReliableFragmentHeader::size(), p.Length() - DaybreakReliableFragmentHeader::size()); (char*)p.Data() + ReliableStreamReliableFragmentHeader::size(), p.Length() - ReliableStreamReliableFragmentHeader::size());
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableFragmentHeader::size()); stream->fragment_current_bytes += (uint32_t)(p.Length() - ReliableStreamReliableFragmentHeader::size());
} }
else { else {
stream->fragment_packet.PutData( stream->fragment_packet.PutData(
stream->fragment_current_bytes, stream->fragment_current_bytes,
(char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size()); (char*)p.Data() + ReliableStreamReliableHeader::size(), p.Length() - ReliableStreamReliableHeader::size());
stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableHeader::size()); stream->fragment_current_bytes += (uint32_t)(p.Length() - ReliableStreamReliableHeader::size());
if (stream->fragment_current_bytes >= stream->fragment_total_bytes) { if (stream->fragment_current_bytes >= stream->fragment_total_bytes) {
ProcessDecodedPacket(stream->fragment_packet); ProcessDecodedPacket(stream->fragment_packet);
@ -769,7 +769,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
case OP_Ack3: case OP_Ack3:
case OP_Ack4: case OP_Ack4:
{ {
auto header = p.GetSerialize<DaybreakReliableHeader>(0); auto header = p.GetSerialize<ReliableStreamReliableHeader>(0);
auto sequence = NetworkToHost(header.sequence); auto sequence = NetworkToHost(header.sequence);
auto stream_id = header.opcode - OP_Ack; auto stream_id = header.opcode - OP_Ack;
Ack(stream_id, sequence); Ack(stream_id, sequence);
@ -781,7 +781,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
case OP_OutOfOrderAck3: case OP_OutOfOrderAck3:
case OP_OutOfOrderAck4: case OP_OutOfOrderAck4:
{ {
auto header = p.GetSerialize<DaybreakReliableHeader>(0); auto header = p.GetSerialize<ReliableStreamReliableHeader>(0);
auto sequence = NetworkToHost(header.sequence); auto sequence = NetworkToHost(header.sequence);
auto stream_id = header.opcode - OP_OutOfOrderAck; auto stream_id = header.opcode - OP_OutOfOrderAck;
OutOfOrderAck(stream_id, sequence); OutOfOrderAck(stream_id, sequence);
@ -815,13 +815,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
} }
case OP_SessionStatRequest: case OP_SessionStatRequest:
{ {
auto request = p.GetSerialize<DaybreakSessionStatRequest>(0); auto request = p.GetSerialize<ReliableStreamSessionStatRequest>(0);
m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(request.packets_sent); m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(request.packets_sent);
m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(request.packets_recv); m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(request.packets_recv);
m_stats.sync_sent_packets = m_stats.sent_packets; m_stats.sync_sent_packets = m_stats.sent_packets;
m_stats.sync_recv_packets = m_stats.recv_packets; m_stats.sync_recv_packets = m_stats.recv_packets;
DaybreakSessionStatResponse response; ReliableStreamSessionStatResponse response;
response.zero = 0; response.zero = 0;
response.opcode = OP_SessionStatResponse; response.opcode = OP_SessionStatResponse;
response.timestamp = request.timestamp; response.timestamp = request.timestamp;
@ -836,7 +836,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
break; break;
} }
case OP_SessionStatResponse: { case OP_SessionStatResponse: {
auto response = p.GetSerialize<DaybreakSessionStatResponse>(0); auto response = p.GetSerialize<ReliableStreamSessionStatResponse>(0);
m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(response.server_sent); m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(response.server_sent);
m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(response.server_recv); m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(response.server_recv);
m_stats.sync_sent_packets = m_stats.sent_packets; m_stats.sync_sent_packets = m_stats.sent_packets;
@ -858,7 +858,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p)
} }
} }
bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p) bool EQ::Net::ReliableStreamConnection::ValidateCRC(Packet &p)
{ {
if (m_crc_bytes == 0U) { if (m_crc_bytes == 0U) {
return true; return true;
@ -892,7 +892,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p)
return false; return false;
} }
void EQ::Net::DaybreakConnection::AppendCRC(Packet &p) void EQ::Net::ReliableStreamConnection::AppendCRC(Packet &p)
{ {
if (m_crc_bytes == 0U) { if (m_crc_bytes == 0U) {
return; return;
@ -911,7 +911,7 @@ void EQ::Net::DaybreakConnection::AppendCRC(Packet &p)
} }
} }
void EQ::Net::DaybreakConnection::ChangeStatus(DbProtocolStatus new_status) void EQ::Net::ReliableStreamConnection::ChangeStatus(DbProtocolStatus new_status)
{ {
if (m_owner->m_on_connection_state_change) { if (m_owner->m_on_connection_state_change) {
if (auto self = m_self.lock()) { if (auto self = m_self.lock()) {
@ -922,7 +922,7 @@ void EQ::Net::DaybreakConnection::ChangeStatus(DbProtocolStatus new_status)
m_status = new_status; m_status = new_status;
} }
bool EQ::Net::DaybreakConnection::PacketCanBeEncoded(Packet &p) const bool EQ::Net::ReliableStreamConnection::PacketCanBeEncoded(Packet &p) const
{ {
if (p.Length() < 2) { if (p.Length() < 2) {
return false; return false;
@ -941,7 +941,7 @@ bool EQ::Net::DaybreakConnection::PacketCanBeEncoded(Packet &p) const
return true; return true;
} }
void EQ::Net::DaybreakConnection::Decode(Packet &p, size_t offset, size_t length) void EQ::Net::ReliableStreamConnection::Decode(Packet &p, size_t offset, size_t length)
{ {
int key = m_encode_key; int key = m_encode_key;
char *buffer = (char*)p.Data() + offset; char *buffer = (char*)p.Data() + offset;
@ -961,7 +961,7 @@ void EQ::Net::DaybreakConnection::Decode(Packet &p, size_t offset, size_t length
} }
} }
void EQ::Net::DaybreakConnection::Encode(Packet &p, size_t offset, size_t length) void EQ::Net::ReliableStreamConnection::Encode(Packet &p, size_t offset, size_t length)
{ {
int key = m_encode_key; int key = m_encode_key;
char *buffer = (char*)p.Data() + offset; char *buffer = (char*)p.Data() + offset;
@ -1050,7 +1050,7 @@ uint32_t Deflate(const uint8_t* in, uint32_t in_len, uint8_t* out, uint32_t out_
} }
} }
void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t length) void EQ::Net::ReliableStreamConnection::Decompress(Packet &p, size_t offset, size_t length)
{ {
if (length < 2) { if (length < 2) {
return; return;
@ -1075,7 +1075,7 @@ void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t le
p.PutData(offset, new_buffer, new_length); p.PutData(offset, new_buffer, new_length);
} }
void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t length) void EQ::Net::ReliableStreamConnection::Compress(Packet &p, size_t offset, size_t length)
{ {
static thread_local uint8_t new_buffer[2048] = { 0 }; static thread_local uint8_t new_buffer[2048] = { 0 };
uint8_t *buffer = (uint8_t*)p.Data() + offset; uint8_t *buffer = (uint8_t*)p.Data() + offset;
@ -1097,14 +1097,14 @@ void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t leng
p.PutData(offset, new_buffer, new_length); p.PutData(offset, new_buffer, new_length);
} }
void EQ::Net::DaybreakConnection::ProcessResend() void EQ::Net::ReliableStreamConnection::ProcessResend()
{ {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
ProcessResend(i); ProcessResend(i);
} }
} }
void EQ::Net::DaybreakConnection::ProcessResend(int stream) void EQ::Net::ReliableStreamConnection::ProcessResend(int stream)
{ {
if (m_status == DbProtocolStatus::StatusDisconnected) { if (m_status == DbProtocolStatus::StatusDisconnected) {
return; return;
@ -1127,16 +1127,37 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - first_packet.first_sent).count(); auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - first_packet.first_sent).count();
if (time_since_first_sent >= m_owner->m_options.resend_timeout) { if (time_since_first_sent >= m_owner->m_options.resend_timeout) {
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
auto first_sent_ms = std::chrono::duration_cast<std::chrono::milliseconds>(first_packet.first_sent.time_since_epoch()).count();
LogNetClient(
"Closing connection for m_endpoint [{}] m_port [{}] time_since_first_sent [{}] >= m_owner->m_options.resend_timeout [{}] now [{}] first_packet.first_sent [{}]",
m_endpoint,
m_port,
time_since_first_sent,
m_owner->m_options.resend_timeout,
now_ms,
first_sent_ms
);
Close(); Close();
return; return;
} }
if (m_last_ack - now > std::chrono::milliseconds(1000)) {
LogNetClient(
"Resetting m_acked_since_last_resend flag for m_endpoint [{}] m_port [{}]",
m_endpoint,
m_port
);
m_acked_since_last_resend = true;
}
// make sure that the first_packet in the list first_sent time is within the resend_delay and now // make sure that the first_packet in the list first_sent time is within the resend_delay and now
// if it is not, then we need to resend all packets in the list // if it is not, then we need to resend all packets in the list
if (time_since_first_sent <= first_packet.resend_delay && !m_acked_since_last_resend) { if (time_since_first_sent <= first_packet.resend_delay && !m_acked_since_last_resend) {
LogNetClient( LogNetClientDetail(
"Not resending packets for stream [{}] packets [{}] time_first_sent [{}] resend_delay [{}] m_acked_since_last_resend [{}]", "Not resending packets for m_endpoint [{}] m_port [{}] packets [{}] time_first_sent [{}] resend_delay [{}] m_acked_since_last_resend [{}]",
stream, m_endpoint,
m_port,
s->sent_packets.size(), s->sent_packets.size(),
time_since_first_sent, time_since_first_sent,
first_packet.resend_delay, first_packet.resend_delay,
@ -1146,15 +1167,16 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
} }
} }
if (LogSys.IsLogEnabled(Logs::Detail, Logs::Netcode)) { if (EQEmuLogSys::Instance()->IsLogEnabled(Logs::General, Logs::NetClient)) {
size_t total_size = 0; size_t total_size = 0;
for (auto &e: s->sent_packets) { for (auto &e: s->sent_packets) {
total_size += e.second.packet.Length(); total_size += e.second.packet.Length();
} }
LogNetClient( LogNetClientDetail(
"Resending packets for stream [{}] packet count [{}] total packet size [{}] m_acked_since_last_resend [{}]", "Resending packets for m_endpoint [{}] m_port [{}] packet count [{}] total packet size [{}] m_acked_since_last_resend [{}]",
stream, m_endpoint,
m_port,
s->sent_packets.size(), s->sent_packets.size(),
total_size, total_size,
m_acked_since_last_resend m_acked_since_last_resend
@ -1165,9 +1187,12 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
if (m_resend_packets_sent >= MAX_CLIENT_RECV_PACKETS_PER_WINDOW || if (m_resend_packets_sent >= MAX_CLIENT_RECV_PACKETS_PER_WINDOW ||
m_resend_bytes_sent >= MAX_CLIENT_RECV_BYTES_PER_WINDOW) { m_resend_bytes_sent >= MAX_CLIENT_RECV_BYTES_PER_WINDOW) {
LogNetClient( LogNetClient(
"Stopping resend because we hit thresholds m_resend_packets_sent [{}] max [{}] m_resend_bytes_sent [{}] max [{}]", "Stopping resend because we hit thresholds for m_endpoint [{}] m_port [{}] m_resend_packets_sent [{}] max [{}] in_queue [{}] m_resend_bytes_sent [{}] max [{}]",
m_endpoint,
m_port,
m_resend_packets_sent, m_resend_packets_sent,
MAX_CLIENT_RECV_PACKETS_PER_WINDOW, MAX_CLIENT_RECV_PACKETS_PER_WINDOW,
s->sent_packets.size(),
m_resend_bytes_sent, m_resend_bytes_sent,
MAX_CLIENT_RECV_BYTES_PER_WINDOW MAX_CLIENT_RECV_BYTES_PER_WINDOW
); );
@ -1176,7 +1201,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
auto &sp = e.second; auto &sp = e.second;
auto &p = sp.packet; auto &p = sp.packet;
if (p.Length() >= DaybreakHeader::size()) { if (p.Length() >= ReliableStreamHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) { if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++; m_stats.resent_fragments++;
} }
@ -1204,11 +1229,11 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream)
} }
m_acked_since_last_resend = false; m_acked_since_last_resend = false;
m_last_ack = now;
} }
void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq) void EQ::Net::ReliableStreamConnection::Ack(int stream, uint16_t seq)
{ {
auto now = Clock::now(); auto now = Clock::now();
auto s = &m_streams[stream]; auto s = &m_streams[stream];
auto iter = s->sent_packets.begin(); auto iter = s->sent_packets.begin();
@ -1224,15 +1249,17 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
m_rolling_ping = (m_rolling_ping * 2 + round_time) / 3; m_rolling_ping = (m_rolling_ping * 2 + round_time) / 3;
iter = s->sent_packets.erase(iter); iter = s->sent_packets.erase(iter);
m_acked_since_last_resend = true;
} }
else { else {
++iter; ++iter;
} }
} }
m_acked_since_last_resend = true;
m_last_ack = now;
} }
void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq) void EQ::Net::ReliableStreamConnection::OutOfOrderAck(int stream, uint16_t seq)
{ {
auto now = Clock::now(); auto now = Clock::now();
auto s = &m_streams[stream]; auto s = &m_streams[stream];
@ -1247,17 +1274,20 @@ void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq)
s->sent_packets.erase(iter); s->sent_packets.erase(iter);
} }
m_acked_since_last_resend = true;
m_last_ack = now;
} }
void EQ::Net::DaybreakConnection::UpdateDataBudget(double budget_add) void EQ::Net::ReliableStreamConnection::UpdateDataBudget(double budget_add)
{ {
auto outgoing_data_rate = m_owner->m_options.outgoing_data_rate; auto outgoing_data_rate = m_owner->m_options.outgoing_data_rate;
m_outgoing_budget = EQ::ClampUpper(m_outgoing_budget + budget_add, outgoing_data_rate); m_outgoing_budget = EQ::ClampUpper(m_outgoing_budget + budget_add, outgoing_data_rate);
} }
void EQ::Net::DaybreakConnection::SendAck(int stream_id, uint16_t seq) void EQ::Net::ReliableStreamConnection::SendAck(int stream_id, uint16_t seq)
{ {
DaybreakReliableHeader ack; ReliableStreamReliableHeader ack;
ack.zero = 0; ack.zero = 0;
ack.opcode = OP_Ack + stream_id; ack.opcode = OP_Ack + stream_id;
ack.sequence = HostToNetwork(seq); ack.sequence = HostToNetwork(seq);
@ -1268,9 +1298,9 @@ void EQ::Net::DaybreakConnection::SendAck(int stream_id, uint16_t seq)
InternalBufferedSend(p); InternalBufferedSend(p);
} }
void EQ::Net::DaybreakConnection::SendOutOfOrderAck(int stream_id, uint16_t seq) void EQ::Net::ReliableStreamConnection::SendOutOfOrderAck(int stream_id, uint16_t seq)
{ {
DaybreakReliableHeader ack; ReliableStreamReliableHeader ack;
ack.zero = 0; ack.zero = 0;
ack.opcode = OP_OutOfOrderAck + stream_id; ack.opcode = OP_OutOfOrderAck + stream_id;
ack.sequence = HostToNetwork(seq); ack.sequence = HostToNetwork(seq);
@ -1281,9 +1311,9 @@ void EQ::Net::DaybreakConnection::SendOutOfOrderAck(int stream_id, uint16_t seq)
InternalBufferedSend(p); InternalBufferedSend(p);
} }
void EQ::Net::DaybreakConnection::SendDisconnect() void EQ::Net::ReliableStreamConnection::SendDisconnect()
{ {
DaybreakDisconnect disconnect; ReliableStreamDisconnect disconnect;
disconnect.zero = 0; disconnect.zero = 0;
disconnect.opcode = OP_SessionDisconnect; disconnect.opcode = OP_SessionDisconnect;
disconnect.connect_code = HostToNetwork(m_connect_code); disconnect.connect_code = HostToNetwork(m_connect_code);
@ -1292,7 +1322,7 @@ void EQ::Net::DaybreakConnection::SendDisconnect()
InternalSend(out); InternalSend(out);
} }
void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p) void EQ::Net::ReliableStreamConnection::InternalBufferedSend(Packet &p)
{ {
if (p.Length() > 0xFFU) { if (p.Length() > 0xFFU) {
FlushBuffer(); FlushBuffer();
@ -1301,7 +1331,7 @@ void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p)
} }
//we could add this packet to a combined //we could add this packet to a combined
size_t raw_size = DaybreakHeader::size() + (size_t)m_crc_bytes + m_buffered_packets_length + m_buffered_packets.size() + 1 + p.Length(); size_t raw_size = ReliableStreamHeader::size() + (size_t)m_crc_bytes + m_buffered_packets_length + m_buffered_packets.size() + 1 + p.Length();
if (raw_size > m_max_packet_size) { if (raw_size > m_max_packet_size) {
FlushBuffer(); FlushBuffer();
} }
@ -1316,9 +1346,9 @@ void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p)
} }
} }
void EQ::Net::DaybreakConnection::SendConnect() void EQ::Net::ReliableStreamConnection::SendConnect()
{ {
DaybreakConnect connect; ReliableStreamConnect connect;
connect.zero = 0; connect.zero = 0;
connect.opcode = OP_SessionRequest; connect.opcode = OP_SessionRequest;
connect.protocol_version = HostToNetwork(3U); connect.protocol_version = HostToNetwork(3U);
@ -1331,9 +1361,9 @@ void EQ::Net::DaybreakConnection::SendConnect()
InternalSend(p); InternalSend(p);
} }
void EQ::Net::DaybreakConnection::SendKeepAlive() void EQ::Net::ReliableStreamConnection::SendKeepAlive()
{ {
DaybreakHeader keep_alive; ReliableStreamHeader keep_alive;
keep_alive.zero = 0; keep_alive.zero = 0;
keep_alive.opcode = OP_KeepAlive; keep_alive.opcode = OP_KeepAlive;
@ -1343,7 +1373,7 @@ void EQ::Net::DaybreakConnection::SendKeepAlive()
InternalSend(p); InternalSend(p);
} }
void EQ::Net::DaybreakConnection::InternalSend(Packet &p) { void EQ::Net::ReliableStreamConnection::InternalSend(Packet &p) {
if (m_owner->m_options.outgoing_data_rate > 0.0) { if (m_owner->m_options.outgoing_data_rate > 0.0) {
auto new_budget = m_outgoing_budget - (p.Length() / 1024.0); auto new_budget = m_outgoing_budget - (p.Length() / 1024.0);
if (new_budget <= 0.0) { if (new_budget <= 0.0) {
@ -1379,14 +1409,14 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) {
switch (m_encode_passe) { switch (m_encode_passe) {
case EncodeCompression: case EncodeCompression:
if (out.GetInt8(0) == 0) { if (out.GetInt8(0) == 0) {
Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); Compress(out, ReliableStreamHeader::size(), out.Length() - ReliableStreamHeader::size());
} else { } else {
Compress(out, 1, out.Length() - 1); Compress(out, 1, out.Length() - 1);
} }
break; break;
case EncodeXOR: case EncodeXOR:
if (out.GetInt8(0) == 0) { if (out.GetInt8(0) == 0) {
Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); Encode(out, ReliableStreamHeader::size(), out.Length() - ReliableStreamHeader::size());
} else { } else {
Encode(out, 1, out.Length() - 1); Encode(out, 1, out.Length() - 1);
} }
@ -1436,7 +1466,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) {
} }
} }
void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable) void EQ::Net::ReliableStreamConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable)
{ {
if (!reliable) { if (!reliable) {
auto max_raw_size = 0xFFU - m_crc_bytes; auto max_raw_size = 0xFFU - m_crc_bytes;
@ -1450,23 +1480,23 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
} }
auto stream = &m_streams[stream_id]; auto stream = &m_streams[stream_id];
auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size() - 1; // -1 for compress flag auto max_raw_size = m_max_packet_size - m_crc_bytes - ReliableStreamReliableHeader::size() - 1; // -1 for compress flag
size_t length = p.Length(); size_t length = p.Length();
if (length > max_raw_size) { if (length > max_raw_size) {
DaybreakReliableFragmentHeader first_header; ReliableStreamReliableFragmentHeader first_header;
first_header.reliable.zero = 0; first_header.reliable.zero = 0;
first_header.reliable.opcode = OP_Fragment + stream_id; first_header.reliable.opcode = OP_Fragment + stream_id;
first_header.reliable.sequence = HostToNetwork(stream->sequence_out); first_header.reliable.sequence = HostToNetwork(stream->sequence_out);
first_header.total_size = (uint32_t)HostToNetwork((uint32_t)length); first_header.total_size = (uint32_t)HostToNetwork((uint32_t)length);
size_t used = 0; size_t used = 0;
size_t sublen = m_max_packet_size - m_crc_bytes - DaybreakReliableFragmentHeader::size() - 1; // -1 for compress flag size_t sublen = m_max_packet_size - m_crc_bytes - ReliableStreamReliableFragmentHeader::size() - 1; // -1 for compress flag
DynamicPacket first_packet; DynamicPacket first_packet;
first_packet.PutSerialize(0, first_header); first_packet.PutSerialize(0, first_header);
first_packet.PutData(DaybreakReliableFragmentHeader::size(), (char*)p.Data() + used, sublen); first_packet.PutData(ReliableStreamReliableFragmentHeader::size(), (char*)p.Data() + used, sublen);
used += sublen; used += sublen;
DaybreakSentPacket sent; ReliableStreamSentPacket sent;
sent.packet.PutPacket(0, first_packet); sent.packet.PutPacket(0, first_packet);
sent.last_sent = Clock::now(); sent.last_sent = Clock::now();
sent.first_sent = Clock::now(); sent.first_sent = Clock::now();
@ -1483,22 +1513,22 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
while (used < length) { while (used < length) {
auto left = length - used; auto left = length - used;
DynamicPacket packet; DynamicPacket packet;
DaybreakReliableHeader header; ReliableStreamReliableHeader header;
header.zero = 0; header.zero = 0;
header.opcode = OP_Fragment + stream_id; header.opcode = OP_Fragment + stream_id;
header.sequence = HostToNetwork(stream->sequence_out); header.sequence = HostToNetwork(stream->sequence_out);
packet.PutSerialize(0, header); packet.PutSerialize(0, header);
if (left > max_raw_size) { if (left > max_raw_size) {
packet.PutData(DaybreakReliableHeader::size(), (char*)p.Data() + used, max_raw_size); packet.PutData(ReliableStreamReliableHeader::size(), (char*)p.Data() + used, max_raw_size);
used += max_raw_size; used += max_raw_size;
} }
else { else {
packet.PutData(DaybreakReliableHeader::size(), (char*)p.Data() + used, left); packet.PutData(ReliableStreamReliableHeader::size(), (char*)p.Data() + used, left);
used += left; used += left;
} }
DaybreakSentPacket sent; ReliableStreamSentPacket sent;
sent.packet.PutPacket(0, packet); sent.packet.PutPacket(0, packet);
sent.last_sent = Clock::now(); sent.last_sent = Clock::now();
sent.first_sent = Clock::now(); sent.first_sent = Clock::now();
@ -1515,14 +1545,14 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
} }
else { else {
DynamicPacket packet; DynamicPacket packet;
DaybreakReliableHeader header; ReliableStreamReliableHeader header;
header.zero = 0; header.zero = 0;
header.opcode = OP_Packet + stream_id; header.opcode = OP_Packet + stream_id;
header.sequence = HostToNetwork(stream->sequence_out); header.sequence = HostToNetwork(stream->sequence_out);
packet.PutSerialize(0, header); packet.PutSerialize(0, header);
packet.PutPacket(DaybreakReliableHeader::size(), p); packet.PutPacket(ReliableStreamReliableHeader::size(), p);
DaybreakSentPacket sent; ReliableStreamSentPacket sent;
sent.packet.PutPacket(0, packet); sent.packet.PutPacket(0, packet);
sent.last_sent = Clock::now(); sent.last_sent = Clock::now();
sent.first_sent = Clock::now(); sent.first_sent = Clock::now();
@ -1538,7 +1568,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id,
} }
} }
void EQ::Net::DaybreakConnection::FlushBuffer() void EQ::Net::ReliableStreamConnection::FlushBuffer()
{ {
if (m_buffered_packets.empty()) { if (m_buffered_packets.empty()) {
return; return;
@ -1565,7 +1595,7 @@ void EQ::Net::DaybreakConnection::FlushBuffer()
m_buffered_packets_length = 0; m_buffered_packets_length = 0;
} }
EQ::Net::SequenceOrder EQ::Net::DaybreakConnection::CompareSequence(uint16_t expected, uint16_t actual) const EQ::Net::SequenceOrder EQ::Net::ReliableStreamConnection::CompareSequence(uint16_t expected, uint16_t actual) const
{ {
int diff = (int)actual - (int)expected; int diff = (int)actual - (int)expected;

View File

@ -2,8 +2,8 @@
#include "../random.h" #include "../random.h"
#include "packet.h" #include "packet.h"
#include "daybreak_structs.h" #include "reliable_stream_structs.h"
#include "daybreak_pooling.h" #include "reliable_stream_pooling.h"
#include <uv.h> #include <uv.h>
#include <chrono> #include <chrono>
#include <functional> #include <functional>
@ -16,7 +16,7 @@ namespace EQ
{ {
namespace Net namespace Net
{ {
enum DaybreakProtocolOpcode enum ReliableStreamProtocolOpcode
{ {
OP_Padding = 0x00, OP_Padding = 0x00,
OP_SessionRequest = 0x01, OP_SessionRequest = 0x01,
@ -55,7 +55,7 @@ namespace EQ
StatusDisconnected StatusDisconnected
}; };
enum DaybreakEncodeType enum ReliableStreamEncodeType
{ {
EncodeNone = 0, EncodeNone = 0,
EncodeCompression = 1, EncodeCompression = 1,
@ -72,9 +72,9 @@ namespace EQ
typedef std::chrono::steady_clock::time_point Timestamp; typedef std::chrono::steady_clock::time_point Timestamp;
typedef std::chrono::steady_clock Clock; typedef std::chrono::steady_clock Clock;
struct DaybreakConnectionStats struct ReliableStreamConnectionStats
{ {
DaybreakConnectionStats() { ReliableStreamConnectionStats() {
recv_bytes = 0; recv_bytes = 0;
sent_bytes = 0; sent_bytes = 0;
recv_packets = 0; recv_packets = 0;
@ -134,14 +134,14 @@ namespace EQ
uint64_t bytes_before_encode; uint64_t bytes_before_encode;
}; };
class DaybreakConnectionManager; class ReliableStreamConnectionManager;
class DaybreakConnection; class ReliableStreamConnection;
class DaybreakConnection class ReliableStreamConnection
{ {
public: public:
DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port); ReliableStreamConnection(ReliableStreamConnectionManager *owner, const ReliableStreamConnect &connect, const std::string &endpoint, int port);
DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port); ReliableStreamConnection(ReliableStreamConnectionManager *owner, const std::string &endpoint, int port);
~DaybreakConnection(); ~ReliableStreamConnection();
const std::string& RemoteEndpoint() const { return m_endpoint; } const std::string& RemoteEndpoint() const { return m_endpoint; }
int RemotePort() const { return m_port; } int RemotePort() const { return m_port; }
@ -151,23 +151,23 @@ namespace EQ
void QueuePacket(Packet &p, int stream); void QueuePacket(Packet &p, int stream);
void QueuePacket(Packet &p, int stream, bool reliable); void QueuePacket(Packet &p, int stream, bool reliable);
DaybreakConnectionStats GetStats(); ReliableStreamConnectionStats GetStats();
void ResetStats(); void ResetStats();
size_t GetRollingPing() const { return m_rolling_ping; } size_t GetRollingPing() const { return m_rolling_ping; }
DbProtocolStatus GetStatus() const { return m_status; } DbProtocolStatus GetStatus() const { return m_status; }
const DaybreakEncodeType* GetEncodePasses() const { return m_encode_passes; } const ReliableStreamEncodeType* GetEncodePasses() const { return m_encode_passes; }
const DaybreakConnectionManager* GetManager() const { return m_owner; } const ReliableStreamConnectionManager* GetManager() const { return m_owner; }
DaybreakConnectionManager* GetManager() { return m_owner; } ReliableStreamConnectionManager* GetManager() { return m_owner; }
private: private:
DaybreakConnectionManager *m_owner; ReliableStreamConnectionManager *m_owner;
std::string m_endpoint; std::string m_endpoint;
int m_port; int m_port;
uint32_t m_connect_code; uint32_t m_connect_code;
uint32_t m_encode_key; uint32_t m_encode_key;
uint32_t m_max_packet_size; uint32_t m_max_packet_size;
uint32_t m_crc_bytes; uint32_t m_crc_bytes;
DaybreakEncodeType m_encode_passes[2]; ReliableStreamEncodeType m_encode_passes[2];
Timestamp m_last_send; Timestamp m_last_send;
Timestamp m_last_recv; Timestamp m_last_recv;
@ -176,7 +176,7 @@ namespace EQ
std::list<DynamicPacket> m_buffered_packets; std::list<DynamicPacket> m_buffered_packets;
size_t m_buffered_packets_length; size_t m_buffered_packets_length;
std::unique_ptr<char[]> m_combined; std::unique_ptr<char[]> m_combined;
DaybreakConnectionStats m_stats; ReliableStreamConnectionStats m_stats;
Timestamp m_last_session_stats; Timestamp m_last_session_stats;
size_t m_rolling_ping; size_t m_rolling_ping;
Timestamp m_close_time; Timestamp m_close_time;
@ -186,8 +186,9 @@ namespace EQ
size_t m_resend_packets_sent = 0; size_t m_resend_packets_sent = 0;
size_t m_resend_bytes_sent = 0; size_t m_resend_bytes_sent = 0;
bool m_acked_since_last_resend = false; bool m_acked_since_last_resend = false;
Timestamp m_last_ack;
struct DaybreakSentPacket struct ReliableStreamSentPacket
{ {
DynamicPacket packet; DynamicPacket packet;
Timestamp last_sent; Timestamp last_sent;
@ -196,9 +197,9 @@ namespace EQ
size_t resend_delay; size_t resend_delay;
}; };
struct DaybreakStream struct ReliableStream
{ {
DaybreakStream() { ReliableStream() {
sequence_in = 0; sequence_in = 0;
sequence_out = 0; sequence_out = 0;
fragment_current_bytes = 0; fragment_current_bytes = 0;
@ -213,11 +214,11 @@ namespace EQ
uint32_t fragment_current_bytes; uint32_t fragment_current_bytes;
uint32_t fragment_total_bytes; uint32_t fragment_total_bytes;
std::map<uint16_t, DaybreakSentPacket> sent_packets; std::map<uint16_t, ReliableStreamSentPacket> sent_packets;
}; };
DaybreakStream m_streams[4]; ReliableStream m_streams[4];
std::weak_ptr<DaybreakConnection> m_self; std::weak_ptr<ReliableStreamConnection> m_self;
void Process(); void Process();
void ProcessPacket(Packet &p); void ProcessPacket(Packet &p);
@ -250,12 +251,12 @@ namespace EQ
void FlushBuffer(); void FlushBuffer();
SequenceOrder CompareSequence(uint16_t expected, uint16_t actual) const; SequenceOrder CompareSequence(uint16_t expected, uint16_t actual) const;
friend class DaybreakConnectionManager; friend class ReliableStreamConnectionManager;
}; };
struct DaybreakConnectionManagerOptions struct ReliableStreamConnectionManagerOptions
{ {
DaybreakConnectionManagerOptions() { ReliableStreamConnectionManagerOptions() {
max_connection_count = 0; max_connection_count = 0;
keepalive_delay_ms = 9000; keepalive_delay_ms = 9000;
resend_delay_ms = 30; resend_delay_ms = 30;
@ -267,8 +268,8 @@ namespace EQ
connect_stale_ms = 5000; connect_stale_ms = 5000;
crc_length = 2; crc_length = 2;
max_packet_size = 512; max_packet_size = 512;
encode_passes[0] = DaybreakEncodeType::EncodeNone; encode_passes[0] = ReliableStreamEncodeType::EncodeNone;
encode_passes[1] = DaybreakEncodeType::EncodeNone; encode_passes[1] = ReliableStreamEncodeType::EncodeNone;
port = 0; port = 0;
hold_size = 512; hold_size = 512;
hold_length_ms = 50; hold_length_ms = 50;
@ -298,28 +299,28 @@ namespace EQ
double tic_rate_hertz; double tic_rate_hertz;
size_t resend_timeout; size_t resend_timeout;
size_t connection_close_time; size_t connection_close_time;
DaybreakEncodeType encode_passes[2]; ReliableStreamEncodeType encode_passes[2];
int port; int port;
double outgoing_data_rate; double outgoing_data_rate;
}; };
class DaybreakConnectionManager class ReliableStreamConnectionManager
{ {
public: public:
DaybreakConnectionManager(); ReliableStreamConnectionManager();
DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts); ReliableStreamConnectionManager(const ReliableStreamConnectionManagerOptions &opts);
~DaybreakConnectionManager(); ~ReliableStreamConnectionManager();
void Connect(const std::string &addr, int port); void Connect(const std::string &addr, int port);
void Process(); void Process();
void UpdateDataBudget(); void UpdateDataBudget();
void ProcessResend(); void ProcessResend();
void OnNewConnection(std::function<void(std::shared_ptr<DaybreakConnection>)> func) { m_on_new_connection = func; } void OnNewConnection(std::function<void(std::shared_ptr<ReliableStreamConnection>)> func) { m_on_new_connection = func; }
void OnConnectionStateChange(std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } void OnConnectionStateChange(std::function<void(std::shared_ptr<ReliableStreamConnection>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
void OnPacketRecv(std::function<void(std::shared_ptr<DaybreakConnection>, const Packet &)> func) { m_on_packet_recv = func; } void OnPacketRecv(std::function<void(std::shared_ptr<ReliableStreamConnection>, const Packet &)> func) { m_on_packet_recv = func; }
void OnErrorMessage(std::function<void(const std::string&)> func) { m_on_error_message = func; } void OnErrorMessage(std::function<void(const std::string&)> func) { m_on_error_message = func; }
DaybreakConnectionManagerOptions& GetOptions() { return m_options; } ReliableStreamConnectionManagerOptions& GetOptions() { return m_options; }
private: private:
void Attach(uv_loop_t *loop); void Attach(uv_loop_t *loop);
void Detach(); void Detach();
@ -328,18 +329,18 @@ namespace EQ
uv_timer_t m_timer; uv_timer_t m_timer;
uv_udp_t m_socket; uv_udp_t m_socket;
uv_loop_t *m_attached; uv_loop_t *m_attached;
DaybreakConnectionManagerOptions m_options; ReliableStreamConnectionManagerOptions m_options;
std::function<void(std::shared_ptr<DaybreakConnection>)> m_on_new_connection; std::function<void(std::shared_ptr<ReliableStreamConnection>)> m_on_new_connection;
std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; std::function<void(std::shared_ptr<ReliableStreamConnection>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
std::function<void(std::shared_ptr<DaybreakConnection>, const Packet&)> m_on_packet_recv; std::function<void(std::shared_ptr<ReliableStreamConnection>, const Packet&)> m_on_packet_recv;
std::function<void(const std::string&)> m_on_error_message; std::function<void(const std::string&)> m_on_error_message;
std::map<std::pair<std::string, int>, std::shared_ptr<DaybreakConnection>> m_connections; std::map<std::pair<std::string, int>, std::shared_ptr<ReliableStreamConnection>> m_connections;
void ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size); void ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size);
std::shared_ptr<DaybreakConnection> FindConnectionByEndpoint(std::string addr, int port); std::shared_ptr<ReliableStreamConnection> FindConnectionByEndpoint(std::string addr, int port);
void SendDisconnect(const std::string &addr, int port); void SendDisconnect(const std::string &addr, int port);
friend class DaybreakConnection; friend class ReliableStreamConnection;
}; };
} }
} }

View File

@ -8,7 +8,7 @@ namespace EQ
{ {
namespace Net namespace Net
{ {
struct DaybreakHeader struct ReliableStreamHeader
{ {
static size_t size() { return 2; } static size_t size() { return 2; }
uint8_t zero; uint8_t zero;
@ -22,7 +22,7 @@ namespace EQ
} }
}; };
struct DaybreakConnect struct ReliableStreamConnect
{ {
static size_t size() { return 14; } static size_t size() { return 14; }
uint8_t zero; uint8_t zero;
@ -42,7 +42,7 @@ namespace EQ
} }
}; };
struct DaybreakConnectReply struct ReliableStreamConnectReply
{ {
static size_t size() { return 17; } static size_t size() { return 17; }
uint8_t zero; uint8_t zero;
@ -68,7 +68,7 @@ namespace EQ
} }
}; };
struct DaybreakDisconnect struct ReliableStreamDisconnect
{ {
static size_t size() { return 8; } static size_t size() { return 8; }
uint8_t zero; uint8_t zero;
@ -84,7 +84,7 @@ namespace EQ
} }
}; };
struct DaybreakReliableHeader struct ReliableStreamReliableHeader
{ {
static size_t size() { return 4; } static size_t size() { return 4; }
uint8_t zero; uint8_t zero;
@ -100,10 +100,10 @@ namespace EQ
} }
}; };
struct DaybreakReliableFragmentHeader struct ReliableStreamReliableFragmentHeader
{ {
static size_t size() { return 4 + DaybreakReliableHeader::size(); } static size_t size() { return 4 + ReliableStreamReliableHeader::size(); }
DaybreakReliableHeader reliable; ReliableStreamReliableHeader reliable;
uint32_t total_size; uint32_t total_size;
template <class Archive> template <class Archive>
@ -114,7 +114,7 @@ namespace EQ
} }
}; };
struct DaybreakSessionStatRequest struct ReliableStreamSessionStatRequest
{ {
static size_t size() { return 40; } static size_t size() { return 40; }
uint8_t zero; uint8_t zero;
@ -144,7 +144,7 @@ namespace EQ
} }
}; };
struct DaybreakSessionStatResponse struct ReliableStreamSessionStatResponse
{ {
static size_t size() { return 40; } static size_t size() { return 40; }
uint8_t zero; uint8_t zero;

View File

@ -319,7 +319,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
size_t message_len = length; size_t message_len = length;
EQ::Net::StaticPacket packet(&data[0], message_len); EQ::Net::StaticPacket packet(&data[0], message_len);
const auto is_detail_enabled = LogSys.IsLogEnabled(Logs::Detail, Logs::PacketServerToServer); const auto is_detail_enabled = EQEmuLogSys::Instance()->IsLogEnabled(Logs::Detail, Logs::PacketServerToServer);
if (opcode != ServerOP_KeepAlive || is_detail_enabled) { if (opcode != ServerOP_KeepAlive || is_detail_enabled) {
LogPacketServerToServer( LogPacketServerToServer(
"[{:#06x}] Size [{}] {}", "[{:#06x}] Size [{}] {}",

View File

@ -78,7 +78,7 @@ namespace RoF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
@ -117,7 +117,7 @@ namespace RoF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;

View File

@ -81,7 +81,7 @@ namespace RoF2
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
@ -123,7 +123,7 @@ namespace RoF2
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@ -6481,7 +6481,7 @@ namespace RoF2
hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0);
hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber());
hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0; hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0;
if (item->EvolvingItem) { if (item->EvolvingItem && packet_type != ItemPacketParcel && packet_type != ItemPacketMerchant) {
hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword
hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword
} }
@ -6500,6 +6500,7 @@ namespace RoF2
if (item->EvolvingItem > 0) { if (item->EvolvingItem > 0) {
RoF2::structs::EvolvingItem_Struct evotop; RoF2::structs::EvolvingItem_Struct evotop;
inst->CalculateEvolveProgression();
evotop.final_item_id = inst->GetEvolveFinalItemID(); evotop.final_item_id = inst->GetEvolveFinalItemID();
evotop.evolve_level = item->EvolvingLevel; evotop.evolve_level = item->EvolvingLevel;

View File

@ -72,7 +72,7 @@ namespace SoD
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@ -113,7 +113,7 @@ namespace SoD
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@ -3966,12 +3966,12 @@ namespace SoD
SoDSlot = serverSlot - 2; SoDSlot = serverSlot - 2;
} }
else if (serverSlot <= EQ::invbag::GENERAL_BAGS_8_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::GENERAL_BAGS_END && serverSlot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
SoDSlot = serverSlot + 11; SoDSlot = serverSlot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));;
} }
else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (serverSlot <= EQ::invbag::CURSOR_BAG_END && serverSlot >= EQ::invbag::CURSOR_BAG_BEGIN) {
SoDSlot = serverSlot - 9; SoDSlot = serverSlot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) { else if (serverSlot <= EQ::invslot::TRIBUTE_END && serverSlot >= EQ::invslot::TRIBUTE_BEGIN) {
@ -3991,7 +3991,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::BANK_BAGS_END && serverSlot >= EQ::invbag::BANK_BAGS_BEGIN) {
SoDSlot = serverSlot + 1; SoDSlot = serverSlot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));;
} }
else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (serverSlot <= EQ::invslot::SHARED_BANK_END && serverSlot >= EQ::invslot::SHARED_BANK_BEGIN) {
@ -3999,7 +3999,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
SoDSlot = serverSlot + 1; SoDSlot = serverSlot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) { else if (serverSlot <= EQ::invslot::TRADE_END && serverSlot >= EQ::invslot::TRADE_BEGIN) {
@ -4007,7 +4007,7 @@ namespace SoD
} }
else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (serverSlot <= EQ::invbag::TRADE_BAGS_END && serverSlot >= EQ::invbag::TRADE_BAGS_BEGIN) {
SoDSlot = serverSlot; SoDSlot = serverSlot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((serverSlot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) { else if (serverSlot <= EQ::invslot::WORLD_END && serverSlot >= EQ::invslot::WORLD_BEGIN) {
@ -4049,11 +4049,11 @@ namespace SoD
} }
else if (sod_slot <= invbag::GENERAL_BAGS_END && sod_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (sod_slot <= invbag::GENERAL_BAGS_END && sod_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = sod_slot - 11; server_slot = sod_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (sod_slot <= invbag::CURSOR_BAG_END && sod_slot >= invbag::CURSOR_BAG_BEGIN) { else if (sod_slot <= invbag::CURSOR_BAG_END && sod_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = sod_slot + 9; server_slot = sod_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (sod_slot <= invslot::TRIBUTE_END && sod_slot >= invslot::TRIBUTE_BEGIN) { else if (sod_slot <= invslot::TRIBUTE_END && sod_slot >= invslot::TRIBUTE_BEGIN) {
@ -4073,7 +4073,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::BANK_BAGS_END && sod_slot >= invbag::BANK_BAGS_BEGIN) { else if (sod_slot <= invbag::BANK_BAGS_END && sod_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = sod_slot - 1; server_slot = sod_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (sod_slot <= invslot::SHARED_BANK_END && sod_slot >= invslot::SHARED_BANK_BEGIN) { else if (sod_slot <= invslot::SHARED_BANK_END && sod_slot >= invslot::SHARED_BANK_BEGIN) {
@ -4081,7 +4081,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::SHARED_BANK_BAGS_END && sod_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (sod_slot <= invbag::SHARED_BANK_BAGS_END && sod_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = sod_slot - 1; server_slot = sod_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (sod_slot <= invslot::TRADE_END && sod_slot >= invslot::TRADE_BEGIN) { else if (sod_slot <= invslot::TRADE_END && sod_slot >= invslot::TRADE_BEGIN) {
@ -4089,7 +4089,7 @@ namespace SoD
} }
else if (sod_slot <= invbag::TRADE_BAGS_END && sod_slot >= invbag::TRADE_BAGS_BEGIN) { else if (sod_slot <= invbag::TRADE_BAGS_END && sod_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = sod_slot; server_slot = sod_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sod_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (sod_slot <= invslot::WORLD_END && sod_slot >= invslot::WORLD_BEGIN) { else if (sod_slot <= invslot::WORLD_END && sod_slot >= invslot::WORLD_BEGIN) {

View File

@ -71,7 +71,7 @@ namespace SoF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@ -110,7 +110,7 @@ namespace SoF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@ -3355,12 +3355,12 @@ namespace SoF
sof_slot = server_slot - 2; sof_slot = server_slot - 2;
} }
else if (server_slot <= EQ::invbag::GENERAL_BAGS_8_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::GENERAL_BAGS_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
sof_slot = server_slot + 11; sof_slot = server_slot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));;
} }
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) {
sof_slot = server_slot - 9; sof_slot = server_slot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) { else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) {
@ -3380,7 +3380,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) {
sof_slot = server_slot + 1; sof_slot = server_slot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) {
@ -3388,7 +3388,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
sof_slot = server_slot + 1; sof_slot = server_slot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) { else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) {
@ -3396,7 +3396,7 @@ namespace SoF
} }
else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) {
sof_slot = server_slot; sof_slot = server_slot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) { else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) {
@ -3442,11 +3442,11 @@ namespace SoF
} }
else if (sof_slot <= invbag::GENERAL_BAGS_END && sof_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (sof_slot <= invbag::GENERAL_BAGS_END && sof_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = sof_slot - 11; server_slot = sof_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT));;
} }
else if (sof_slot <= invbag::CURSOR_BAG_END && sof_slot >= invbag::CURSOR_BAG_BEGIN) { else if (sof_slot <= invbag::CURSOR_BAG_END && sof_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = sof_slot + 9; server_slot = sof_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (sof_slot <= invslot::TRIBUTE_END && sof_slot >= invslot::TRIBUTE_BEGIN) { else if (sof_slot <= invslot::TRIBUTE_END && sof_slot >= invslot::TRIBUTE_BEGIN) {
@ -3466,7 +3466,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::BANK_BAGS_END && sof_slot >= invbag::BANK_BAGS_BEGIN) { else if (sof_slot <= invbag::BANK_BAGS_END && sof_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = sof_slot - 1; server_slot = sof_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));;
} }
else if (sof_slot <= invslot::SHARED_BANK_END && sof_slot >= invslot::SHARED_BANK_BEGIN) { else if (sof_slot <= invslot::SHARED_BANK_END && sof_slot >= invslot::SHARED_BANK_BEGIN) {
@ -3474,7 +3474,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::SHARED_BANK_BAGS_END && sof_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (sof_slot <= invbag::SHARED_BANK_BAGS_END && sof_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = sof_slot - 1; server_slot = sof_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));;
} }
else if (sof_slot <= invslot::TRADE_END && sof_slot >= invslot::TRADE_BEGIN) { else if (sof_slot <= invslot::TRADE_END && sof_slot >= invslot::TRADE_BEGIN) {
@ -3482,7 +3482,7 @@ namespace SoF
} }
else if (sof_slot <= invbag::TRADE_BAGS_END && sof_slot >= invbag::TRADE_BAGS_BEGIN) { else if (sof_slot <= invbag::TRADE_BAGS_END && sof_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = sof_slot; server_slot = sof_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((sof_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT));;
} }
else if (sof_slot <= invslot::WORLD_END && sof_slot >= invslot::WORLD_BEGIN) { else if (sof_slot <= invslot::WORLD_END && sof_slot >= invslot::WORLD_BEGIN) {

View File

@ -73,7 +73,7 @@ namespace Titanium
auto Config = EQEmuConfig::get(); auto Config = EQEmuConfig::get();
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@ -114,7 +114,7 @@ namespace Titanium
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;
@ -1059,7 +1059,7 @@ namespace Titanium
OUT(spawnid); OUT(spawnid);
OUT_str(charname); OUT_str(charname);
if (emu->race > 473) if (emu->race > 474)
eq->race = 1; eq->race = 1;
else else
OUT(race); OUT(race);
@ -1840,7 +1840,7 @@ namespace Titanium
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq->Race[char_index] = emu_cse->Race; eq->Race[char_index] = emu_cse->Race;
if (eq->Race[char_index] > 473) if (eq->Race[char_index] > 474)
eq->Race[char_index] = 1; eq->Race[char_index] = 1;
for (int index = 0; index < EQ::textures::materialCount; ++index) { for (int index = 0; index < EQ::textures::materialCount; ++index) {
@ -2421,7 +2421,7 @@ namespace Titanium
strcpy(eq->title, emu->title); strcpy(eq->title, emu->title);
// eq->unknown0274 = emu->unknown0274; // eq->unknown0274 = emu->unknown0274;
eq->helm = emu->helm; eq->helm = emu->helm;
if (emu->race > 473) if (emu->race > 474)
eq->race = 1; eq->race = 1;
else else
eq->race = emu->race; eq->race = emu->race;
@ -3596,12 +3596,12 @@ namespace Titanium
else if (server_slot == (EQ::invslot::POSSESSIONS_COUNT + EQ::invslot::slotAmmo)) { else if (server_slot == (EQ::invslot::POSSESSIONS_COUNT + EQ::invslot::slotAmmo)) {
titanium_slot = server_slot - 4; titanium_slot = server_slot - 4;
} }
else if (server_slot <= EQ::invbag::GENERAL_BAGS_8_END && else if (server_slot <= EQ::invbag::GENERAL_BAGS_END &&
server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) { server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot - (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::CURSOR_BAG_BEGIN) {
titanium_slot = server_slot - 20; titanium_slot = server_slot - (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) { else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
@ -3616,21 +3616,21 @@ namespace Titanium
else if (server_slot <= EQ::invslot::BANK_END && server_slot >= EQ::invslot::BANK_BEGIN) { else if (server_slot <= EQ::invslot::BANK_END && server_slot >= EQ::invslot::BANK_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::BANK_BAGS_16_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot - (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) { else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END &&
server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) { server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot - (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::SHARED_BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) { else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
} }
else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) { else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot - (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) - ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((server_slot - EQ::invbag::TRADE_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT));
} }
else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) { else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) {
titanium_slot = server_slot; titanium_slot = server_slot;
@ -3687,10 +3687,10 @@ namespace Titanium
server_slot = titanium_slot + 4; server_slot = titanium_slot + 4;
} }
else if (titanium_slot <= invbag::GENERAL_BAGS_END && titanium_slot >= invbag::GENERAL_BAGS_BEGIN) { else if (titanium_slot <= invbag::GENERAL_BAGS_END && titanium_slot >= invbag::GENERAL_BAGS_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot + (EQ::invbag::GENERAL_BAGS_BEGIN - invbag::GENERAL_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::GENERAL_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (titanium_slot <= invbag::CURSOR_BAG_END && titanium_slot >= invbag::CURSOR_BAG_BEGIN) { else if (titanium_slot <= invbag::CURSOR_BAG_END && titanium_slot >= invbag::CURSOR_BAG_BEGIN) {
server_slot = titanium_slot + 20; server_slot = titanium_slot + (EQ::invbag::CURSOR_BAG_BEGIN - invbag::CURSOR_BAG_BEGIN);
} }
else if (titanium_slot <= invslot::TRIBUTE_END && titanium_slot >= invslot::TRIBUTE_BEGIN) { else if (titanium_slot <= invslot::TRIBUTE_END && titanium_slot >= invslot::TRIBUTE_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
@ -3705,19 +3705,19 @@ namespace Titanium
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::BANK_BAGS_END && titanium_slot >= invbag::BANK_BAGS_BEGIN) { else if (titanium_slot <= invbag::BANK_BAGS_END && titanium_slot >= invbag::BANK_BAGS_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot + (EQ::invbag::BANK_BAGS_BEGIN - invbag::BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (titanium_slot <= invslot::SHARED_BANK_END && titanium_slot >= invslot::SHARED_BANK_BEGIN) { else if (titanium_slot <= invslot::SHARED_BANK_END && titanium_slot >= invslot::SHARED_BANK_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::SHARED_BANK_BAGS_END && titanium_slot >= invbag::SHARED_BANK_BAGS_BEGIN) { else if (titanium_slot <= invbag::SHARED_BANK_BAGS_END && titanium_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot + (EQ::invbag::SHARED_BANK_BAGS_BEGIN - invbag::SHARED_BANK_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::SHARED_BANK_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (titanium_slot <= invslot::TRADE_END && titanium_slot >= invslot::TRADE_BEGIN) { else if (titanium_slot <= invslot::TRADE_END && titanium_slot >= invslot::TRADE_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;
} }
else if (titanium_slot <= invbag::TRADE_BAGS_END && titanium_slot >= invbag::TRADE_BAGS_BEGIN) { else if (titanium_slot <= invbag::TRADE_BAGS_END && titanium_slot >= invbag::TRADE_BAGS_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot + (EQ::invbag::TRADE_BAGS_BEGIN - invbag::TRADE_BAGS_BEGIN) + ((EQ::invbag::SLOT_COUNT - invbag::SLOT_COUNT) * ((titanium_slot - invbag::TRADE_BAGS_BEGIN) / invbag::SLOT_COUNT));
} }
else if (titanium_slot <= invslot::WORLD_END && titanium_slot >= invslot::WORLD_BEGIN) { else if (titanium_slot <= invslot::WORLD_END && titanium_slot >= invslot::WORLD_BEGIN) {
server_slot = titanium_slot; server_slot = titanium_slot;

View File

@ -76,7 +76,7 @@ namespace UF
{ {
//create our opcode manager if we havent already //create our opcode manager if we havent already
if (opcodes == nullptr) { if (opcodes == nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
//load up the opcode manager. //load up the opcode manager.
//TODO: figure out how to support shared memory with multiple patches... //TODO: figure out how to support shared memory with multiple patches...
opcodes = new RegularOpcodeManager(); opcodes = new RegularOpcodeManager();
@ -117,7 +117,7 @@ namespace UF
//we need to go to every stream and replace it's manager. //we need to go to every stream and replace it's manager.
if (opcodes != nullptr) { if (opcodes != nullptr) {
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name); std::string opfile = fmt::format("{}/patch_{}.conf", PathManager::Instance()->GetPatchPath(), name);
if (!opcodes->ReloadOpcodes(opfile.c_str())) { if (!opcodes->ReloadOpcodes(opfile.c_str())) {
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name); LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
return; return;

View File

@ -8,7 +8,7 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
void PathManager::LoadPaths() void PathManager::Init()
{ {
m_server_path = File::FindEqemuConfigPath(); m_server_path = File::FindEqemuConfigPath();
@ -48,10 +48,23 @@ void PathManager::LoadPaths()
return dir; return dir;
}; };
auto load_many_paths_fallback = [&](const std::vector<std::string>& dirs, const std::string& fallback, std::vector<std::string>& target) {
target.clear();
if (!dirs.empty()) {
for (const auto& path : dirs) {
target.push_back(resolve_path(path));
}
} else {
target.push_back(resolve_path(fallback));
}
};
load_many_paths_fallback(c->GetQuestDirectories(), c->QuestDir, m_quests_paths);
load_many_paths_fallback(c->GetPluginsDirectories(), c->PluginDir, m_plugin_paths);
load_many_paths_fallback(c->GetLuaModuleDirectories(), c->LuaModuleDir, m_lua_module_paths);
// resolve all paths
m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"}); m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"});
m_quests_path = resolve_path(c->QuestDir);
m_plugins_path = resolve_path(c->PluginDir);
m_lua_modules_path = resolve_path(c->LuaModuleDir);
m_lua_mods_path = resolve_path("mods"); m_lua_mods_path = resolve_path("mods");
m_patch_path = resolve_path(c->PatchDir); m_patch_path = resolve_path(c->PatchDir);
m_opcode_path = resolve_path(c->OpcodeDir); m_opcode_path = resolve_path(c->OpcodeDir);
@ -62,13 +75,10 @@ void PathManager::LoadPaths()
std::vector<std::pair<std::string, std::string>> paths = { std::vector<std::pair<std::string, std::string>> paths = {
{"server", m_server_path}, {"server", m_server_path},
{"logs", m_log_path}, {"logs", m_log_path},
{"lua mods", m_lua_mods_path},
{"lua_modules", m_lua_modules_path},
{"maps", m_maps_path}, {"maps", m_maps_path},
{"lua mods", m_lua_mods_path},
{"patches", m_patch_path}, {"patches", m_patch_path},
{"opcode", m_opcode_path}, {"opcode", m_opcode_path},
{"plugins", m_plugins_path},
{"quests", m_quests_path},
{"shared_memory", m_shared_memory_path} {"shared_memory", m_shared_memory_path}
}; };
@ -83,6 +93,17 @@ void PathManager::LoadPaths()
LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width); LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width);
} }
} }
auto log_paths = [&](const std::string& label, const std::vector<std::string>& paths) {
if (!paths.empty()) {
LogInfo("{:>{}} > [{:<{}}]", label, name_width - 1, Strings::Join(paths, ";"), path_width);
}
};
log_paths("quests", m_quests_paths);
log_paths("plugins", m_plugin_paths);
log_paths("lua_modules", m_lua_module_paths);
LogInfo("{}", Strings::Repeat("-", break_length)); LogInfo("{}", Strings::Repeat("-", break_length));
} }
@ -96,21 +117,26 @@ const std::string &PathManager::GetMapsPath() const
return m_maps_path; return m_maps_path;
} }
const std::string &PathManager::GetQuestsPath() const
{
return m_quests_path;
}
const std::string &PathManager::GetPluginsPath() const
{
return m_plugins_path;
}
const std::string &PathManager::GetSharedMemoryPath() const const std::string &PathManager::GetSharedMemoryPath() const
{ {
return m_shared_memory_path; return m_shared_memory_path;
} }
std::vector<std::string> PathManager::GetQuestPaths() const
{
return m_quests_paths;
}
std::vector<std::string> PathManager::GetPluginPaths() const
{
return m_plugin_paths;
}
std::vector<std::string> PathManager::GetLuaModulePaths() const
{
return m_lua_module_paths;
}
const std::string &PathManager::GetLogPath() const const std::string &PathManager::GetLogPath() const
{ {
return m_log_path; return m_log_path;
@ -126,11 +152,6 @@ const std::string &PathManager::GetOpcodePath() const
return m_opcode_path; return m_opcode_path;
} }
const std::string &PathManager::GetLuaModulesPath() const
{
return m_lua_modules_path;
}
const std::string &PathManager::GetLuaModsPath() const const std::string &PathManager::GetLuaModsPath() const
{ {
return m_lua_mods_path; return m_lua_mods_path;

View File

@ -3,10 +3,17 @@
#include <string> #include <string>
#include <vector>
class PathManager { class PathManager {
public: public:
void LoadPaths(); void Init();
static PathManager *Instance()
{
static PathManager instance;
return &instance;
}
[[nodiscard]] const std::string &GetLogPath() const; [[nodiscard]] const std::string &GetLogPath() const;
[[nodiscard]] const std::string &GetLuaModsPath() const; [[nodiscard]] const std::string &GetLuaModsPath() const;
@ -14,24 +21,27 @@ public:
[[nodiscard]] const std::string &GetMapsPath() const; [[nodiscard]] const std::string &GetMapsPath() const;
[[nodiscard]] const std::string &GetPatchPath() const; [[nodiscard]] const std::string &GetPatchPath() const;
[[nodiscard]] const std::string &GetOpcodePath() const; [[nodiscard]] const std::string &GetOpcodePath() const;
[[nodiscard]] const std::string &GetPluginsPath() const;
[[nodiscard]] const std::string &GetQuestsPath() const;
[[nodiscard]] const std::string &GetServerPath() const; [[nodiscard]] const std::string &GetServerPath() const;
[[nodiscard]] const std::string &GetSharedMemoryPath() const; [[nodiscard]] const std::string &GetSharedMemoryPath() const;
[[nodiscard]] std::vector<std::string> GetQuestPaths() const;
[[nodiscard]] std::vector<std::string> GetPluginPaths() const;
[[nodiscard]] std::vector<std::string> GetLuaModulePaths() const;
private: private:
std::string m_log_path; std::string m_log_path;
std::string m_lua_mods_path; std::string m_lua_mods_path;
std::string m_lua_modules_path;
std::string m_maps_path; std::string m_maps_path;
std::string m_patch_path; std::string m_patch_path;
std::string m_opcode_path; std::string m_opcode_path;
std::string m_plugins_path;
std::string m_quests_path; std::string m_quests_path;
std::vector<std::string> m_quests_paths;
std::vector<std::string> m_plugin_paths;
std::vector<std::string> m_lua_module_paths;
private:
std::string m_server_path; std::string m_server_path;
std::string m_shared_memory_path; std::string m_shared_memory_path;
}; };
extern PathManager path;
#endif //EQEMU_PATH_MANAGER_H #endif //EQEMU_PATH_MANAGER_H

9
common/pch/app-pch.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "../types.h"
#include "../database.h"
#include "../strings.h"
#include "../eqemu_logsys.h"
#include "../eqemu_logsys_log_aliases.h"
#include "../features.h"
#include "../global_define.h"

View File

@ -1,34 +0,0 @@
// types
#include <limits>
#include <string>
#include <cctype>
#include <sstream>
// containers
#include <iterator>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <list>
#include <vector>
// utilities
#include <iostream>
#include <cassert>
#include <cmath>
#include <memory>
#include <functional>
#include <algorithm>
#include <utility>
#include <tuple>
#include <fstream>
#include <cstdio>
// fmt
#include <fmt/format.h>
// lua
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>

14
common/pch/std-pch.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
// Lightweight, widely used
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <memory>
#include <limits>
#include <cstdint>
#include <cassert>
// fmt
#include <fmt/format.h>

View File

@ -1,6 +1,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include "process.h" #include "process.h"
#include <fmt/format.h>
std::string Process::execute(const std::string &cmd) std::string Process::execute(const std::string &cmd)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -21,103 +21,7 @@
#include "../common/types.h" #include "../common/types.h"
#include <string> #include <string>
namespace Gender {
constexpr uint8 Male = 0;
constexpr uint8 Female = 1;
constexpr uint8 Neuter = 2;
}
//theres a big list straight from the client below.
#define HUMAN 1
#define BARBARIAN 2
#define ERUDITE 3
#define WOOD_ELF 4
#define HIGH_ELF 5
#define DARK_ELF 6
#define HALF_ELF 7
#define DWARF 8
#define TROLL 9
#define OGRE 10
#define HALFLING 11
#define GNOME 12
#define WEREWOLF 14
#define WOLF 42
#define BEAR 43
#define SKELETON 60
#define TIGER 63
#define ELEMENTAL 75
#define ALLIGATOR 91
#define OGGOK_CITIZEN 93
#define EYE_OF_ZOMM 108
#define WOLF_ELEMENTAL 120
#define INVISIBLE_MAN 127
#define IKSAR 128
#define VAHSHIR 130
#define CONTROLLED_BOAT 141
#define MINOR_ILL_OBJ 142
#define TREE 143
#define IKSAR_SKELETON 161
#define FROGLOK 330
// TODO: check all clients for (BYTE) usage of '/who all' class and remove FROGLOK2, if possible (330 - 74 = 256 .. WORD->BYTE conversion loss...)
#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks
#define FAIRY 473
#define DRAKKIN 522 // 32768
#define EMU_RACE_NPC 131069 // was 65533
#define EMU_RACE_PET 131070 // was 65534
#define EMU_RACE_UNKNOWN 131071 // was 65535
// player race values
#define PLAYER_RACE_UNKNOWN 0
#define PLAYER_RACE_HUMAN 1
#define PLAYER_RACE_BARBARIAN 2
#define PLAYER_RACE_ERUDITE 3
#define PLAYER_RACE_WOOD_ELF 4
#define PLAYER_RACE_HIGH_ELF 5
#define PLAYER_RACE_DARK_ELF 6
#define PLAYER_RACE_HALF_ELF 7
#define PLAYER_RACE_DWARF 8
#define PLAYER_RACE_TROLL 9
#define PLAYER_RACE_OGRE 10
#define PLAYER_RACE_HALFLING 11
#define PLAYER_RACE_GNOME 12
#define PLAYER_RACE_IKSAR 13
#define PLAYER_RACE_VAHSHIR 14
#define PLAYER_RACE_FROGLOK 15
#define PLAYER_RACE_DRAKKIN 16
#define PLAYER_RACE_COUNT 16
#define PLAYER_RACE_EMU_NPC 17
#define PLAYER_RACE_EMU_PET 18
#define PLAYER_RACE_EMU_COUNT 19
// player race bits
#define PLAYER_RACE_UNKNOWN_BIT 0
#define PLAYER_RACE_HUMAN_BIT 1
#define PLAYER_RACE_BARBARIAN_BIT 2
#define PLAYER_RACE_ERUDITE_BIT 4
#define PLAYER_RACE_WOOD_ELF_BIT 8
#define PLAYER_RACE_HIGH_ELF_BIT 16
#define PLAYER_RACE_DARK_ELF_BIT 32
#define PLAYER_RACE_HALF_ELF_BIT 64
#define PLAYER_RACE_DWARF_BIT 128
#define PLAYER_RACE_TROLL_BIT 256
#define PLAYER_RACE_OGRE_BIT 512
#define PLAYER_RACE_HALFLING_BIT 1024
#define PLAYER_RACE_GNOME_BIT 2048
#define PLAYER_RACE_IKSAR_BIT 4096
#define PLAYER_RACE_VAHSHIR_BIT 8192
#define PLAYER_RACE_FROGLOK_BIT 16384
#define PLAYER_RACE_DRAKKIN_BIT 32768
#define PLAYER_RACE_ALL_MASK 65535
const char* GetRaceIDName(uint16 race_id); const char* GetRaceIDName(uint16 race_id);
const char* GetPlayerRaceName(uint32 player_race_value);
const char* GetGenderName(uint32 gender_id); const char* GetGenderName(uint32 gender_id);
bool IsPlayerRace(uint16 race_id); bool IsPlayerRace(uint16 race_id);
@ -127,25 +31,13 @@ uint32 GetPlayerRaceValue(uint16 race_id);
uint16 GetPlayerRaceBit(uint16 race_id); uint16 GetPlayerRaceBit(uint16 race_id);
uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value); uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value);
uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit);
float GetRaceGenderDefaultHeight(int race, int gender); float GetRaceGenderDefaultHeight(int race, int gender);
// player race-/gender-based model feature validators namespace Gender {
namespace PlayerAppearance constexpr uint8 Male = 0;
{ constexpr uint8 Female = 1;
bool IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin = true); constexpr uint8 Neuter = 2;
bool IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin = true);
bool IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin = true);
bool IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin = true);
bool IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin = true);
bool IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin = true);
bool IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin = true);
bool IsValidHead(uint16 race_id, uint8 gender_id, uint8 head_value, bool use_luclin = true);
bool IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin = true);
bool IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin = true);
bool IsValidTexture(uint16 race_id, uint8 gender_id, uint8 texture_value, bool use_luclin = true);
bool IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin = true);
} }
namespace Race { namespace Race {
@ -884,8 +776,92 @@ namespace Race {
constexpr uint16 Pegasus3 = 732; constexpr uint16 Pegasus3 = 732;
constexpr uint16 InteractiveObject = 2250; constexpr uint16 InteractiveObject = 2250;
constexpr uint16 Node = 2254; constexpr uint16 Node = 2254;
}
constexpr uint16 ALL_RACES_BITMASK = 65535; namespace RaceBitmask {
constexpr uint16 Unknown = 0;
constexpr uint16 Human = 1;
constexpr uint16 Barbarian = 2;
constexpr uint16 Erudite = 4;
constexpr uint16 WoodElf = 8;
constexpr uint16 HighElf = 16;
constexpr uint16 DarkElf = 32;
constexpr uint16 HalfElf = 64;
constexpr uint16 Dwarf = 128;
constexpr uint16 Troll = 256;
constexpr uint16 Ogre = 512;
constexpr uint16 Halfling = 1024;
constexpr uint16 Gnome = 2048;
constexpr uint16 Iksar = 4096;
constexpr uint16 VahShir = 8192;
constexpr uint16 Froglok = 16384;
constexpr uint16 Drakkin = 32768;
constexpr uint16 All = 65535;
}
namespace RaceIndex {
constexpr uint16 Human = 1;
constexpr uint16 Barbarian = 2;
constexpr uint16 Erudite = 3;
constexpr uint16 WoodElf = 4;
constexpr uint16 HighElf = 5;
constexpr uint16 DarkElf = 6;
constexpr uint16 HalfElf = 7;
constexpr uint16 Dwarf = 8;
constexpr uint16 Troll = 9;
constexpr uint16 Ogre = 10;
constexpr uint16 Halfling = 11;
constexpr uint16 Gnome = 12;
constexpr uint16 Iksar = 13;
constexpr uint16 VahShir = 14;
constexpr uint16 Froglok = 15;
constexpr uint16 Drakkin = 16;
}
namespace RaceAppearance {
bool IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin = true);
bool IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin = true);
bool IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin = true);
bool IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin = true);
bool IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin = true);
bool IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin = true);
bool IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin = true);
bool IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin = true);
bool IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin = true);
bool IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin = true);
constexpr int HumanMale = (Race::Human << 8) | Gender::Male;
constexpr int HumanFemale = (Race::Human << 8) | Gender::Female;
constexpr int BarbarianMale = (Race::Barbarian << 8) | Gender::Male;
constexpr int BarbarianFemale = (Race::Barbarian << 8) | Gender::Female;
constexpr int EruditeMale = (Race::Erudite << 8) | Gender::Male;
constexpr int EruditeFemale = (Race::Erudite << 8) | Gender::Female;
constexpr int WoodElfMale = (Race::WoodElf << 8) | Gender::Male;
constexpr int WoodElfFemale = (Race::WoodElf << 8) | Gender::Female;
constexpr int HighElfMale = (Race::HighElf << 8) | Gender::Male;
constexpr int HighElfFemale = (Race::HighElf << 8) | Gender::Female;
constexpr int DarkElfMale = (Race::DarkElf << 8) | Gender::Male;
constexpr int DarkElfFemale = (Race::DarkElf << 8) | Gender::Female;
constexpr int HalfElfMale = (Race::HalfElf << 8) | Gender::Male;
constexpr int HalfElfFemale = (Race::HalfElf << 8) | Gender::Female;
constexpr int DwarfMale = (Race::Dwarf << 8) | Gender::Male;
constexpr int DwarfFemale = (Race::Dwarf << 8) | Gender::Female;
constexpr int TrollMale = (Race::Troll << 8) | Gender::Male;
constexpr int TrollFemale = (Race::Troll << 8) | Gender::Female;
constexpr int OgreMale = (Race::Ogre << 8) | Gender::Male;
constexpr int OgreFemale = (Race::Ogre << 8) | Gender::Female;
constexpr int HalflingMale = (Race::Halfling << 8) | Gender::Male;
constexpr int HalflingFemale = (Race::Halfling << 8) | Gender::Female;
constexpr int GnomeMale = (Race::Gnome << 8) | Gender::Male;
constexpr int GnomeFemale = (Race::Gnome << 8) | Gender::Female;
constexpr int IksarMale = (Race::Iksar << 8) | Gender::Male;
constexpr int IksarFemale = (Race::Iksar << 8) | Gender::Female;
constexpr int VahShirMale = (Race::VahShir << 8) | Gender::Male;
constexpr int VahShirFemale = (Race::VahShir << 8) | Gender::Female;
constexpr int FroglokMale = (Race::Froglok2 << 8) | Gender::Male;
constexpr int FroglokFemale = (Race::Froglok2 << 8) | Gender::Female;
constexpr int DrakkinMale = (Race::Drakkin << 8) | Gender::Male;
constexpr int DrakkinFemale = (Race::Drakkin << 8) | Gender::Female;
} }
#endif #endif

View File

@ -116,6 +116,12 @@ namespace EQ {
Reseed(); Reseed();
} }
static Random* Instance()
{
static Random instance;
return &instance;
}
private: private:
#ifndef BIASED_INT_DIST #ifndef BIASED_INT_DIST
typedef std::uniform_int_distribution<int>::param_type int_param_t; typedef std::uniform_int_distribution<int>::param_type int_param_t;

View File

@ -70,6 +70,7 @@ public:
uint32_t gm_exp; uint32_t gm_exp;
uint32_t killed_by; uint32_t killed_by;
uint8_t rezzable; uint8_t rezzable;
std::string entity_variables;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@ -131,6 +132,7 @@ public:
"gm_exp", "gm_exp",
"killed_by", "killed_by",
"rezzable", "rezzable",
"entity_variables",
}; };
} }
@ -188,6 +190,7 @@ public:
"gm_exp", "gm_exp",
"killed_by", "killed_by",
"rezzable", "rezzable",
"entity_variables",
}; };
} }
@ -279,6 +282,7 @@ public:
e.gm_exp = 0; e.gm_exp = 0;
e.killed_by = 0; e.killed_by = 0;
e.rezzable = 0; e.rezzable = 0;
e.entity_variables = "";
return e; return e;
} }
@ -366,6 +370,7 @@ public:
e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0; e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0; e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0;
e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0; e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.entity_variables = row[51] ? row[51] : "";
return e; return e;
} }
@ -449,6 +454,7 @@ public:
v.push_back(columns[48] + " = " + std::to_string(e.gm_exp)); v.push_back(columns[48] + " = " + std::to_string(e.gm_exp));
v.push_back(columns[49] + " = " + std::to_string(e.killed_by)); v.push_back(columns[49] + " = " + std::to_string(e.killed_by));
v.push_back(columns[50] + " = " + std::to_string(e.rezzable)); v.push_back(columns[50] + " = " + std::to_string(e.rezzable));
v.push_back(columns[51] + " = '" + Strings::Escape(e.entity_variables) + "'");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -521,6 +527,7 @@ public:
v.push_back(std::to_string(e.gm_exp)); v.push_back(std::to_string(e.gm_exp));
v.push_back(std::to_string(e.killed_by)); v.push_back(std::to_string(e.killed_by));
v.push_back(std::to_string(e.rezzable)); v.push_back(std::to_string(e.rezzable));
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -601,6 +608,7 @@ public:
v.push_back(std::to_string(e.gm_exp)); v.push_back(std::to_string(e.gm_exp));
v.push_back(std::to_string(e.killed_by)); v.push_back(std::to_string(e.killed_by));
v.push_back(std::to_string(e.rezzable)); v.push_back(std::to_string(e.rezzable));
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
} }
@ -685,6 +693,7 @@ public:
e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0; e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0; e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0;
e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0; e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.entity_variables = row[51] ? row[51] : "";
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -760,6 +769,7 @@ public:
e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0; e.gm_exp = row[48] ? static_cast<uint32_t>(strtoul(row[48], nullptr, 10)) : 0;
e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0; e.killed_by = row[49] ? static_cast<uint32_t>(strtoul(row[49], nullptr, 10)) : 0;
e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0; e.rezzable = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.entity_variables = row[51] ? row[51] : "";
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -885,6 +895,7 @@ public:
v.push_back(std::to_string(e.gm_exp)); v.push_back(std::to_string(e.gm_exp));
v.push_back(std::to_string(e.killed_by)); v.push_back(std::to_string(e.killed_by));
v.push_back(std::to_string(e.rezzable)); v.push_back(std::to_string(e.rezzable));
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -958,6 +969,7 @@ public:
v.push_back(std::to_string(e.gm_exp)); v.push_back(std::to_string(e.gm_exp));
v.push_back(std::to_string(e.killed_by)); v.push_back(std::to_string(e.killed_by));
v.push_back(std::to_string(e.rezzable)); v.push_back(std::to_string(e.rezzable));
v.push_back("'" + Strings::Escape(e.entity_variables) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
} }

View File

@ -30,6 +30,7 @@ public:
uint32_t aug_slot_5; uint32_t aug_slot_5;
uint32_t aug_slot_6; uint32_t aug_slot_6;
uint32_t quantity; uint32_t quantity;
uint32_t evolve_amount;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@ -51,6 +52,7 @@ public:
"aug_slot_5", "aug_slot_5",
"aug_slot_6", "aug_slot_6",
"quantity", "quantity",
"evolve_amount",
}; };
} }
@ -68,6 +70,7 @@ public:
"aug_slot_5", "aug_slot_5",
"aug_slot_6", "aug_slot_6",
"quantity", "quantity",
"evolve_amount",
}; };
} }
@ -119,6 +122,7 @@ public:
e.aug_slot_5 = 0; e.aug_slot_5 = 0;
e.aug_slot_6 = 0; e.aug_slot_6 = 0;
e.quantity = 0; e.quantity = 0;
e.evolve_amount = 0;
return e; return e;
} }
@ -166,6 +170,7 @@ public:
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
return e; return e;
} }
@ -209,6 +214,7 @@ public:
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5)); v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_5));
v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6)); v.push_back(columns[9] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[10] + " = " + std::to_string(e.quantity)); v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -241,6 +247,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5)); v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -281,6 +288,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5)); v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
} }
@ -325,6 +333,7 @@ public:
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -360,6 +369,7 @@ public:
e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_5 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.aug_slot_6 = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -445,6 +455,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5)); v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -478,6 +489,7 @@ public:
v.push_back(std::to_string(e.aug_slot_5)); v.push_back(std::to_string(e.aug_slot_5));
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
} }

View File

@ -30,6 +30,7 @@ public:
uint32_t aug_slot_6; uint32_t aug_slot_6;
uint32_t slot_id; uint32_t slot_id;
uint32_t quantity; uint32_t quantity;
uint32_t evolve_amount;
std::string from_name; std::string from_name;
std::string note; std::string note;
time_t sent_date; time_t sent_date;
@ -54,6 +55,7 @@ public:
"aug_slot_6", "aug_slot_6",
"slot_id", "slot_id",
"quantity", "quantity",
"evolve_amount",
"from_name", "from_name",
"note", "note",
"sent_date", "sent_date",
@ -74,6 +76,7 @@ public:
"aug_slot_6", "aug_slot_6",
"slot_id", "slot_id",
"quantity", "quantity",
"evolve_amount",
"from_name", "from_name",
"note", "note",
"UNIX_TIMESTAMP(sent_date)", "UNIX_TIMESTAMP(sent_date)",
@ -128,6 +131,7 @@ public:
e.aug_slot_6 = 0; e.aug_slot_6 = 0;
e.slot_id = 0; e.slot_id = 0;
e.quantity = 0; e.quantity = 0;
e.evolve_amount = 0;
e.from_name = ""; e.from_name = "";
e.note = ""; e.note = "";
e.sent_date = 0; e.sent_date = 0;
@ -178,9 +182,10 @@ public:
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : ""; e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.note = row[12] ? row[12] : ""; e.from_name = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10); e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
return e; return e;
} }
@ -224,9 +229,10 @@ public:
v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6)); v.push_back(columns[8] + " = " + std::to_string(e.aug_slot_6));
v.push_back(columns[9] + " = " + std::to_string(e.slot_id)); v.push_back(columns[9] + " = " + std::to_string(e.slot_id));
v.push_back(columns[10] + " = " + std::to_string(e.quantity)); v.push_back(columns[10] + " = " + std::to_string(e.quantity));
v.push_back(columns[11] + " = '" + Strings::Escape(e.from_name) + "'"); v.push_back(columns[11] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[12] + " = '" + Strings::Escape(e.note) + "'"); v.push_back(columns[12] + " = '" + Strings::Escape(e.from_name) + "'");
v.push_back(columns[13] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")"); v.push_back(columns[13] + " = '" + Strings::Escape(e.note) + "'");
v.push_back(columns[14] + " = FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -259,6 +265,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'"); v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'"); v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -302,6 +309,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'"); v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'"); v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -349,9 +357,10 @@ public:
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : ""; e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.note = row[12] ? row[12] : ""; e.from_name = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10); e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -387,9 +396,10 @@ public:
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0; e.slot_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0; e.quantity = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.from_name = row[11] ? row[11] : ""; e.evolve_amount = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.note = row[12] ? row[12] : ""; e.from_name = row[12] ? row[12] : "";
e.sent_date = strtoll(row[13] ? row[13] : "-1", nullptr, 10); e.note = row[13] ? row[13] : "";
e.sent_date = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -475,6 +485,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'"); v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'"); v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");
@ -511,6 +522,7 @@ public:
v.push_back(std::to_string(e.aug_slot_6)); v.push_back(std::to_string(e.aug_slot_6));
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.quantity)); v.push_back(std::to_string(e.quantity));
v.push_back(std::to_string(e.evolve_amount));
v.push_back("'" + Strings::Escape(e.from_name) + "'"); v.push_back("'" + Strings::Escape(e.from_name) + "'");
v.push_back("'" + Strings::Escape(e.note) + "'"); v.push_back("'" + Strings::Escape(e.note) + "'");
v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")"); v.push_back("FROM_UNIXTIME(" + (e.sent_date > 0 ? std::to_string(e.sent_date) : "null") + ")");

View File

@ -70,6 +70,7 @@ public:
int32_t endurance_regen; int32_t endurance_regen;
int32_t shielding; int32_t shielding;
int32_t spell_damage; int32_t spell_damage;
int32_t heal_amount;
int32_t spell_shielding; int32_t spell_shielding;
int32_t strikethrough; int32_t strikethrough;
int32_t stun_resist; int32_t stun_resist;
@ -154,6 +155,7 @@ public:
"endurance_regen", "endurance_regen",
"shielding", "shielding",
"spell_damage", "spell_damage",
"heal_amount",
"spell_shielding", "spell_shielding",
"strikethrough", "strikethrough",
"stun_resist", "stun_resist",
@ -234,6 +236,7 @@ public:
"endurance_regen", "endurance_regen",
"shielding", "shielding",
"spell_damage", "spell_damage",
"heal_amount",
"spell_shielding", "spell_shielding",
"strikethrough", "strikethrough",
"stun_resist", "stun_resist",
@ -348,6 +351,7 @@ public:
e.endurance_regen = 0; e.endurance_regen = 0;
e.shielding = 0; e.shielding = 0;
e.spell_damage = 0; e.spell_damage = 0;
e.heal_amount = 0;
e.spell_shielding = 0; e.spell_shielding = 0;
e.strikethrough = 0; e.strikethrough = 0;
e.stun_resist = 0; e.stun_resist = 0;
@ -458,29 +462,30 @@ public:
e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0; e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0;
e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0; e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0;
e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0; e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0;
e.spell_shielding = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0; e.heal_amount = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0;
e.strikethrough = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0; e.spell_shielding = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0;
e.stun_resist = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0; e.strikethrough = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0;
e.backstab = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0; e.stun_resist = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0;
e.wind = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0; e.backstab = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0;
e.brass = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0; e.wind = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0;
e.string = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0; e.brass = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0;
e.percussion = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0; e.string = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0;
e.singing = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0; e.percussion = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0;
e.baking = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0; e.singing = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0;
e.alchemy = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0; e.baking = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0;
e.tailoring = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0; e.alchemy = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0;
e.blacksmithing = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0; e.tailoring = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0;
e.fletching = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0; e.blacksmithing = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0;
e.brewing = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0; e.fletching = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0;
e.jewelry = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0; e.brewing = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0;
e.pottery = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0; e.jewelry = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0;
e.research = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0; e.pottery = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0;
e.alcohol = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0; e.research = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0;
e.fishing = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0; e.alcohol = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0;
e.tinkering = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0; e.fishing = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0;
e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); e.tinkering = row[72] ? static_cast<int32_t>(atoi(row[72])) : 0;
e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10);
e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10);
return e; return e;
} }
@ -565,29 +570,30 @@ public:
v.push_back(columns[48] + " = " + std::to_string(e.endurance_regen)); v.push_back(columns[48] + " = " + std::to_string(e.endurance_regen));
v.push_back(columns[49] + " = " + std::to_string(e.shielding)); v.push_back(columns[49] + " = " + std::to_string(e.shielding));
v.push_back(columns[50] + " = " + std::to_string(e.spell_damage)); v.push_back(columns[50] + " = " + std::to_string(e.spell_damage));
v.push_back(columns[51] + " = " + std::to_string(e.spell_shielding)); v.push_back(columns[51] + " = " + std::to_string(e.heal_amount));
v.push_back(columns[52] + " = " + std::to_string(e.strikethrough)); v.push_back(columns[52] + " = " + std::to_string(e.spell_shielding));
v.push_back(columns[53] + " = " + std::to_string(e.stun_resist)); v.push_back(columns[53] + " = " + std::to_string(e.strikethrough));
v.push_back(columns[54] + " = " + std::to_string(e.backstab)); v.push_back(columns[54] + " = " + std::to_string(e.stun_resist));
v.push_back(columns[55] + " = " + std::to_string(e.wind)); v.push_back(columns[55] + " = " + std::to_string(e.backstab));
v.push_back(columns[56] + " = " + std::to_string(e.brass)); v.push_back(columns[56] + " = " + std::to_string(e.wind));
v.push_back(columns[57] + " = " + std::to_string(e.string)); v.push_back(columns[57] + " = " + std::to_string(e.brass));
v.push_back(columns[58] + " = " + std::to_string(e.percussion)); v.push_back(columns[58] + " = " + std::to_string(e.string));
v.push_back(columns[59] + " = " + std::to_string(e.singing)); v.push_back(columns[59] + " = " + std::to_string(e.percussion));
v.push_back(columns[60] + " = " + std::to_string(e.baking)); v.push_back(columns[60] + " = " + std::to_string(e.singing));
v.push_back(columns[61] + " = " + std::to_string(e.alchemy)); v.push_back(columns[61] + " = " + std::to_string(e.baking));
v.push_back(columns[62] + " = " + std::to_string(e.tailoring)); v.push_back(columns[62] + " = " + std::to_string(e.alchemy));
v.push_back(columns[63] + " = " + std::to_string(e.blacksmithing)); v.push_back(columns[63] + " = " + std::to_string(e.tailoring));
v.push_back(columns[64] + " = " + std::to_string(e.fletching)); v.push_back(columns[64] + " = " + std::to_string(e.blacksmithing));
v.push_back(columns[65] + " = " + std::to_string(e.brewing)); v.push_back(columns[65] + " = " + std::to_string(e.fletching));
v.push_back(columns[66] + " = " + std::to_string(e.jewelry)); v.push_back(columns[66] + " = " + std::to_string(e.brewing));
v.push_back(columns[67] + " = " + std::to_string(e.pottery)); v.push_back(columns[67] + " = " + std::to_string(e.jewelry));
v.push_back(columns[68] + " = " + std::to_string(e.research)); v.push_back(columns[68] + " = " + std::to_string(e.pottery));
v.push_back(columns[69] + " = " + std::to_string(e.alcohol)); v.push_back(columns[69] + " = " + std::to_string(e.research));
v.push_back(columns[70] + " = " + std::to_string(e.fishing)); v.push_back(columns[70] + " = " + std::to_string(e.alcohol));
v.push_back(columns[71] + " = " + std::to_string(e.tinkering)); v.push_back(columns[71] + " = " + std::to_string(e.fishing));
v.push_back(columns[72] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); v.push_back(columns[72] + " = " + std::to_string(e.tinkering));
v.push_back(columns[73] + " = FROM_UNIXTIME(" + (e.updated_at > 0 ? std::to_string(e.updated_at) : "null") + ")"); v.push_back(columns[73] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
v.push_back(columns[74] + " = FROM_UNIXTIME(" + (e.updated_at > 0 ? std::to_string(e.updated_at) : "null") + ")");
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -660,6 +666,7 @@ public:
v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.endurance_regen));
v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.shielding));
v.push_back(std::to_string(e.spell_damage)); v.push_back(std::to_string(e.spell_damage));
v.push_back(std::to_string(e.heal_amount));
v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.spell_shielding));
v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.strikethrough));
v.push_back(std::to_string(e.stun_resist)); v.push_back(std::to_string(e.stun_resist));
@ -763,6 +770,7 @@ public:
v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.endurance_regen));
v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.shielding));
v.push_back(std::to_string(e.spell_damage)); v.push_back(std::to_string(e.spell_damage));
v.push_back(std::to_string(e.heal_amount));
v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.spell_shielding));
v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.strikethrough));
v.push_back(std::to_string(e.stun_resist)); v.push_back(std::to_string(e.stun_resist));
@ -870,29 +878,30 @@ public:
e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0; e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0;
e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0; e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0;
e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0; e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0;
e.spell_shielding = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0; e.heal_amount = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0;
e.strikethrough = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0; e.spell_shielding = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0;
e.stun_resist = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0; e.strikethrough = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0;
e.backstab = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0; e.stun_resist = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0;
e.wind = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0; e.backstab = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0;
e.brass = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0; e.wind = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0;
e.string = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0; e.brass = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0;
e.percussion = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0; e.string = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0;
e.singing = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0; e.percussion = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0;
e.baking = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0; e.singing = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0;
e.alchemy = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0; e.baking = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0;
e.tailoring = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0; e.alchemy = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0;
e.blacksmithing = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0; e.tailoring = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0;
e.fletching = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0; e.blacksmithing = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0;
e.brewing = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0; e.fletching = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0;
e.jewelry = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0; e.brewing = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0;
e.pottery = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0; e.jewelry = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0;
e.research = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0; e.pottery = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0;
e.alcohol = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0; e.research = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0;
e.fishing = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0; e.alcohol = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0;
e.tinkering = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0; e.fishing = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0;
e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); e.tinkering = row[72] ? static_cast<int32_t>(atoi(row[72])) : 0;
e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10);
e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10);
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -968,29 +977,30 @@ public:
e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0; e.endurance_regen = row[48] ? static_cast<int32_t>(atoi(row[48])) : 0;
e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0; e.shielding = row[49] ? static_cast<int32_t>(atoi(row[49])) : 0;
e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0; e.spell_damage = row[50] ? static_cast<int32_t>(atoi(row[50])) : 0;
e.spell_shielding = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0; e.heal_amount = row[51] ? static_cast<int32_t>(atoi(row[51])) : 0;
e.strikethrough = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0; e.spell_shielding = row[52] ? static_cast<int32_t>(atoi(row[52])) : 0;
e.stun_resist = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0; e.strikethrough = row[53] ? static_cast<int32_t>(atoi(row[53])) : 0;
e.backstab = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0; e.stun_resist = row[54] ? static_cast<int32_t>(atoi(row[54])) : 0;
e.wind = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0; e.backstab = row[55] ? static_cast<int32_t>(atoi(row[55])) : 0;
e.brass = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0; e.wind = row[56] ? static_cast<int32_t>(atoi(row[56])) : 0;
e.string = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0; e.brass = row[57] ? static_cast<int32_t>(atoi(row[57])) : 0;
e.percussion = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0; e.string = row[58] ? static_cast<int32_t>(atoi(row[58])) : 0;
e.singing = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0; e.percussion = row[59] ? static_cast<int32_t>(atoi(row[59])) : 0;
e.baking = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0; e.singing = row[60] ? static_cast<int32_t>(atoi(row[60])) : 0;
e.alchemy = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0; e.baking = row[61] ? static_cast<int32_t>(atoi(row[61])) : 0;
e.tailoring = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0; e.alchemy = row[62] ? static_cast<int32_t>(atoi(row[62])) : 0;
e.blacksmithing = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0; e.tailoring = row[63] ? static_cast<int32_t>(atoi(row[63])) : 0;
e.fletching = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0; e.blacksmithing = row[64] ? static_cast<int32_t>(atoi(row[64])) : 0;
e.brewing = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0; e.fletching = row[65] ? static_cast<int32_t>(atoi(row[65])) : 0;
e.jewelry = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0; e.brewing = row[66] ? static_cast<int32_t>(atoi(row[66])) : 0;
e.pottery = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0; e.jewelry = row[67] ? static_cast<int32_t>(atoi(row[67])) : 0;
e.research = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0; e.pottery = row[68] ? static_cast<int32_t>(atoi(row[68])) : 0;
e.alcohol = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0; e.research = row[69] ? static_cast<int32_t>(atoi(row[69])) : 0;
e.fishing = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0; e.alcohol = row[70] ? static_cast<int32_t>(atoi(row[70])) : 0;
e.tinkering = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0; e.fishing = row[71] ? static_cast<int32_t>(atoi(row[71])) : 0;
e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); e.tinkering = row[72] ? static_cast<int32_t>(atoi(row[72])) : 0;
e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10);
e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10);
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -1116,6 +1126,7 @@ public:
v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.endurance_regen));
v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.shielding));
v.push_back(std::to_string(e.spell_damage)); v.push_back(std::to_string(e.spell_damage));
v.push_back(std::to_string(e.heal_amount));
v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.spell_shielding));
v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.strikethrough));
v.push_back(std::to_string(e.stun_resist)); v.push_back(std::to_string(e.stun_resist));
@ -1212,6 +1223,7 @@ public:
v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.endurance_regen));
v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.shielding));
v.push_back(std::to_string(e.spell_damage)); v.push_back(std::to_string(e.spell_damage));
v.push_back(std::to_string(e.heal_amount));
v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.spell_shielding));
v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.strikethrough));
v.push_back(std::to_string(e.stun_resist)); v.push_back(std::to_string(e.stun_resist));

View File

@ -15,7 +15,7 @@
#include "../../database.h" #include "../../database.h"
#include "../../strings.h" #include "../../strings.h"
#include <ctime> #include <ctime>
#include <cereal/cereal.hpp>
class BasePlayerEventLogSettingsRepository { class BasePlayerEventLogSettingsRepository {
public: public:
struct PlayerEventLogSettings { struct PlayerEventLogSettings {
@ -25,6 +25,20 @@ public:
int32_t retention_days; int32_t retention_days;
int32_t discord_webhook_id; int32_t discord_webhook_id;
uint8_t etl_enabled; uint8_t etl_enabled;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(id),
CEREAL_NVP(event_name),
CEREAL_NVP(event_enabled),
CEREAL_NVP(retention_days),
CEREAL_NVP(discord_webhook_id),
CEREAL_NVP(etl_enabled)
);
}
}; };
static std::string PrimaryKey() static std::string PrimaryKey()

View File

@ -231,6 +231,21 @@ public:
return UpdateOne(db, corpse); return UpdateOne(db, corpse);
} }
static int UpdateEntityVariables(Database& db, uint32 corpse_id, const std::string& json_string)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `entity_variables` = '{}' WHERE `{}` = {}",
TableName(),
Strings::Escape(json_string),
PrimaryKey(),
corpse_id
)
);
return results.Success() ? results.RowsAffected() : 0;
}
}; };
#endif //EQEMU_CHARACTER_CORPSES_REPOSITORY_H #endif //EQEMU_CHARACTER_CORPSES_REPOSITORY_H

View File

@ -167,6 +167,46 @@ public:
return zone_player_counts; return zone_player_counts;
} }
static std::vector<uint32_t> GetCharacterIDsByAccountID(
Database& db,
uint32_t account_id
)
{
std::vector<uint32_t> character_ids;
auto query = fmt::format(
"SELECT id FROM character_data WHERE account_id = {} AND deleted_at IS NULL",
account_id
);
auto results = db.QueryDatabase(query);
if (results.Success()) {
for (auto row : results) {
if (row[0]) {
character_ids.push_back(static_cast<uint32_t>(std::stoul(row[0])));
}
}
}
return character_ids;
}
static uint32_t GetTotalTimePlayed(Database& db, uint32_t account_id)
{
auto query = fmt::format(
"SELECT SUM(time_played) FROM `character_data` WHERE `account_id` = {}",
account_id
);
auto results = db.QueryDatabase(query);
if (!results.Success()) {
return 0;
}
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
}; };
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H #endif //EQEMU_CHARACTER_DATA_REPOSITORY_H

View File

@ -49,6 +49,7 @@ public:
// these are the base definitions for command_subsettings and can be over-ridden by the database // these are the base definitions for command_subsettings and can be over-ridden by the database
std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = { std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = {
{.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"}, {.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"},
{.parent_command = "find", .sub_command = "account", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaccount"},
{.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"}, {.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"},
{.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"}, {.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"},
{.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"}, {.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"},
@ -142,6 +143,7 @@ public:
{.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"}, {.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"},
{.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"}, {.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"},
{.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"}, {.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"},
{.parent_command = "show", .sub_command = "keyring", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showkeyring"},
{.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"}, {.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"},
{.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"}, {.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"},
{.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"}, {.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"},

View File

@ -14,7 +14,7 @@ namespace ContentFilterCriteria {
table_prefix = table_prefix + "."; table_prefix = table_prefix + ".";
} }
int current_expansion_filter_criteria = content_service.GetCurrentExpansion(); int current_expansion_filter_criteria = WorldContentService::Instance()->GetCurrentExpansion();
if (current_expansion_filter_criteria == Expansion::EXPANSION_ALL) { if (current_expansion_filter_criteria == Expansion::EXPANSION_ALL) {
current_expansion_filter_criteria = Expansion::EXPANSION_FILTER_MAX; current_expansion_filter_criteria = Expansion::EXPANSION_FILTER_MAX;
} }
@ -33,8 +33,8 @@ namespace ContentFilterCriteria {
table_prefix table_prefix
); );
std::vector<std::string> flags_disabled = content_service.GetContentFlagsDisabled(); std::vector<std::string> flags_disabled = WorldContentService::Instance()->GetContentFlagsDisabled();
std::vector<std::string> flags_enabled = content_service.GetContentFlagsEnabled(); std::vector<std::string> flags_enabled = WorldContentService::Instance()->GetContentFlagsEnabled();
std::string flags_in_filter_enabled; std::string flags_in_filter_enabled;
std::string flags_in_filter_disabled; std::string flags_in_filter_disabled;
if (!flags_enabled.empty()) { if (!flags_enabled.empty()) {

View File

@ -43,6 +43,47 @@ public:
* method and encapsulate filters there * method and encapsulate filters there
*/ */
template<typename T1, typename T2, typename T3, typename T4>
static std::vector<std::string> join_tuple(
const std::string &glue,
const std::pair<char, char> &encapsulation,
const std::vector<std::tuple<T1, T2, T3, T4>> &src
)
{
if (src.empty()) {
return {};
}
std::vector<std::string> output;
for (const std::tuple<T1, T2, T3, T4> &src_iter: src) {
output.emplace_back(
fmt::format(
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
encapsulation.first,
std::get<0>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<1>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<2>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<3>(src_iter),
encapsulation.second
)
);
}
return output;
}
// Custom extended repository methods here // Custom extended repository methods here
static std::vector<std::string> GetRuleNames(Database &db, int rule_set_id) static std::vector<std::string> GetRuleNames(Database &db, int rule_set_id)
{ {
@ -87,12 +128,28 @@ public:
return v; return v;
} }
template<typename T>
static std::string
ImplodePair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
{
if (src.empty()) {
return {};
}
std::ostringstream oss;
for (const T &src_iter: src) {
oss << encapsulation.first << src_iter << encapsulation.second << glue;
}
std::string output(oss.str());
output.resize(output.size() - glue.size());
return output;
}
static bool DeleteOrphanedRules(Database& db, std::vector<std::string>& v) static bool DeleteOrphanedRules(Database& db, std::vector<std::string>& v)
{ {
const auto query = fmt::format( const auto query = fmt::format(
"DELETE FROM {} WHERE rule_name IN ({})", "DELETE FROM {} WHERE rule_name IN ({})",
TableName(), TableName(),
Strings::ImplodePair(",", std::pair<char, char>('\'', '\''), v) ImplodePair(",", std::pair<char, char>('\'', '\''), v)
); );
return db.QueryDatabase(query).Success(); return db.QueryDatabase(query).Success();
@ -103,7 +160,7 @@ public:
const auto query = fmt::format( const auto query = fmt::format(
"REPLACE INTO {} (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}", "REPLACE INTO {} (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES {}",
TableName(), TableName(),
Strings::ImplodePair( ImplodePair(
",", ",",
std::pair<char, char>('(', ')'), std::pair<char, char>('(', ')'),
join_tuple(",", std::pair<char, char>('\'', '\''), v) join_tuple(",", std::pair<char, char>('\'', '\''), v)

View File

@ -502,6 +502,19 @@ bool RuleManager::UpdateInjectedRules(Database *db, const std::string &rule_set_
} }
} }
// update rules in the database where the description is different
for (auto &e : RuleValuesRepository::All(*db)) {
auto i = rule_data.find(e.rule_name);
if (i != rule_data.end()) {
// if notes are different, update them
if (i->second.second != nullptr && *i->second.second != e.notes) {
LogInfo("Updating rule [{}] notes to [{}]", i->first, *i->second.second);
e.notes = *i->second.second;
RuleValuesRepository::ReplaceOne(*db, e);
}
}
}
if (injected_rule_entries.size()) { if (injected_rule_entries.size()) {
if (!RuleValuesRepository::InjectRules(*db, injected_rule_entries)) { if (!RuleValuesRepository::InjectRules(*db, injected_rule_entries)) {
return false; return false;

View File

@ -233,6 +233,12 @@ RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0") RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal") RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal")
RULE_BOOL(Character, AlwaysAllowNameChange, false, "Enable this option to allow /changename to work without enabling a name change via scripts.") RULE_BOOL(Character, AlwaysAllowNameChange, false, "Enable this option to allow /changename to work without enabling a name change via scripts.")
RULE_BOOL(Character, EnableAutoAFK, false, "Enable or disable the auto AFK feature, cuts down on packet spam")
RULE_BOOL(Character, AutoIdleFilterPackets, true, "Enable or disable filtering packets when auto AFK is enabled, heavily cuts down on packet spam in zones with lots of players")
RULE_INT(Character, SecondsBeforeIdleCombatZone, 600, "Seconds before a player is considered idle in combat zones (600 = 10 minutes)")
RULE_INT(Character, SecondsBeforeIdleNonCombatZone, 60, "Seconds before a player is considered idle in non-combat zones (60 = 1 minute)")
RULE_INT(Character, SecondsBeforeAFKCombatZone, 1800, "Seconds before a player is considered AFK in combat zones (1800 = 30 minutes)")
RULE_INT(Character, SecondsBeforeAFKNonCombatZone, 600, "Seconds before a player is considered AFK in non-combat zones (600 = 10 minutes)")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)
@ -613,7 +619,7 @@ RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak
RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation") RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation")
RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption") RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption") RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
RULE_BOOL(Combat, UseLiveRiposteMechanics, false, "Set to true to disable SPA 173 SE_RiposteChance from making those with the effect on them immune to enrage, can longer riposte from a riposte.") RULE_BOOL(Combat, UseLiveRiposteMechanics, false, "Set to true to disable SPA 173 SpellEffect::RiposteChance from making those with the effect on them immune to enrage, can longer riposte from a riposte.")
RULE_INT(Combat, FrontalStunImmunityClasses, 0, "Bitmask for Classes than have frontal stun immunity, No Races (0) by default.") RULE_INT(Combat, FrontalStunImmunityClasses, 0, "Bitmask for Classes than have frontal stun immunity, No Races (0) by default.")
RULE_BOOL(Combat, NPCsUseFrontalStunImmunityClasses, false, "Enable or disable NPCs using frontal stun immunity Classes from Combat:FrontalStunImmunityClasses, false by default.") RULE_BOOL(Combat, NPCsUseFrontalStunImmunityClasses, false, "Enable or disable NPCs using frontal stun immunity Classes from Combat:FrontalStunImmunityClasses, false by default.")
RULE_INT(Combat, FrontalStunImmunityRaces, 512, "Bitmask for Races than have frontal stun immunity, Ogre (512) only by default.") RULE_INT(Combat, FrontalStunImmunityRaces, 512, "Bitmask for Races than have frontal stun immunity, Ogre (512) only by default.")
@ -1073,6 +1079,7 @@ RULE_CATEGORY(Logging)
RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp::main:309] Loading variables...") RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp::main:309] Loading variables...")
RULE_BOOL(Logging, WorldGMSayLogging, true, "Relay worldserver logging to zone processes via GM say output") RULE_BOOL(Logging, WorldGMSayLogging, true, "Relay worldserver logging to zone processes via GM say output")
RULE_BOOL(Logging, PlayerEventsQSProcess, false, "Have query server process player events instead of world. Useful when wanting to use a dedicated server and database for processing player events on separate disk") RULE_BOOL(Logging, PlayerEventsQSProcess, false, "Have query server process player events instead of world. Useful when wanting to use a dedicated server and database for processing player events on separate disk")
RULE_STRING(Logging, PlayerEventsIgnoreGMCommands, "help,show", "This is a comma delimited list of commands to ignore when recording GM command player events.")
RULE_INT(Logging, BatchPlayerEventProcessIntervalSeconds, 5, "This is the interval in which player events are processed in world or qs") RULE_INT(Logging, BatchPlayerEventProcessIntervalSeconds, 5, "This is the interval in which player events are processed in world or qs")
RULE_INT(Logging, BatchPlayerEventProcessChunkSize, 10000, "This is the cap of events that can be inserted into the queue before a force flush. This is to keep from hitting MySQL max_allowed_packet and killing the connection") RULE_INT(Logging, BatchPlayerEventProcessChunkSize, 10000, "This is the cap of events that can be inserted into the queue before a force flush. This is to keep from hitting MySQL max_allowed_packet and killing the connection")
RULE_CATEGORY_END() RULE_CATEGORY_END()

View File

@ -275,6 +275,7 @@
// player events // player events
#define ServerOP_QSSendQuery 0x5000 #define ServerOP_QSSendQuery 0x5000
#define ServerOP_PlayerEvent 0x5100 #define ServerOP_PlayerEvent 0x5100
#define ServerOP_SendPlayerEventSettings 0x5101
enum { enum {
CZUpdateType_Character, CZUpdateType_Character,
@ -1778,6 +1779,7 @@ struct BazaarPurchaseMessaging_Struct {
uint32 id; uint32 id;
}; };
#pragma pack() #pragma pack()
#endif #endif

View File

@ -48,7 +48,7 @@ enum class SharedTaskRequestGroupType {
struct ServerSharedTaskRequest_Struct { struct ServerSharedTaskRequest_Struct {
uint32 requested_character_id; uint32 requested_character_id;
uint32 requested_task_id; uint32 requested_task_id;
uint32 requested_npc_type_id; // original task logic passthrough uint32 requested_npc_entity_id; // original task logic passthrough
uint32 accept_time; uint32 accept_time;
}; };

View File

@ -51,19 +51,10 @@
#include "repositories/inventory_repository.h" #include "repositories/inventory_repository.h"
#include "repositories/books_repository.h" #include "repositories/books_repository.h"
#include "repositories/sharedbank_repository.h" #include "repositories/sharedbank_repository.h"
#include "repositories/character_inspect_messages_repository.h"
namespace ItemField #include "repositories/spells_new_repository.h"
{ #include "repositories/damageshieldtypes_repository.h"
enum { #include "repositories/items_repository.h"
source = 0,
#define F(x) x,
#include "item_fieldlist.h"
#undef F
updated,
minstatus,
comment,
};
}
SharedDatabase::SharedDatabase() SharedDatabase::SharedDatabase()
: Database() : Database()
@ -131,68 +122,43 @@ bool SharedDatabase::SetGMFlymode(uint32 account_id, uint8 flymode)
return a.id > 0; return a.id > 0;
} }
uint32 SharedDatabase::GetTotalTimeEntitledOnAccount(uint32 AccountID) { void SharedDatabase::SetMailKey(uint32 character_id, uint32 ip_address, uint32 mail_key)
uint32 EntitledTime = 0;
const std::string query = StringFormat("SELECT `time_played` FROM `character_data` WHERE `account_id` = %u", AccountID);
auto results = QueryDatabase(query);
for (auto& row = results.begin(); row != results.end(); ++row) {
EntitledTime += Strings::ToUnsignedInt(row[0]);
}
return EntitledTime;
}
void SharedDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
{ {
char mail_key[17]; std::string full_mail_key;
if (RuleB(Chat, EnableMailKeyIPVerification) == true) { if (RuleB(Chat, EnableMailKeyIPVerification)) {
sprintf(mail_key, "%08X%08X", IPAddress, MailKey); full_mail_key = fmt::format("{:08X}{:08X}", ip_address, mail_key);
} } else {
else { full_mail_key = fmt::format("{:08X}", mail_key);
sprintf(mail_key, "%08X", MailKey);
} }
const std::string query = StringFormat( auto e = CharacterDataRepository::FindOne(*this, character_id);
"UPDATE character_data SET mailkey = '%s' WHERE id = '%i'", if (!e.id) {
mail_key, CharID LogError("Failed to find character_id [{}] when setting mailkey", character_id);
); return;
}
const auto results = QueryDatabase(query); e.mailkey = full_mail_key;
if (!results.Success()) {
LogError("SharedDatabase::SetMailKey({}, {}) : {}", CharID, mail_key, results.ErrorMessage().c_str()); if (!CharacterDataRepository::UpdateOne(*this, e)) {
LogError("Failed to set mailkey to [{}] for character_id [{}]", full_mail_key, character_id);
} }
} }
SharedDatabase::MailKeys SharedDatabase::GetMailKey(int character_id) SharedDatabase::MailKeys SharedDatabase::GetMailKey(uint32 character_id)
{ {
const std::string query = StringFormat("SELECT `mailkey` FROM `character_data` WHERE `id`='%i' LIMIT 1", character_id); auto e = CharacterDataRepository::FindOne(*this, character_id);
auto results = QueryDatabase(query);
if (!results.Success()) { if (!e.id) {
return MailKeys{ }; return MailKeys{ };
} }
if (!results.RowCount()) {
Log(Logs::General,
Logs::ClientLogin,
"Error: Mailkey for character id [%i] does not exist or could not be found",
character_id
);
return MailKeys{};
}
auto &row = results.begin();
if (row != results.end()) {
std::string mail_key = row[0];
return MailKeys{ return MailKeys{
.mail_key = mail_key.substr(8), .mail_key = e.mailkey.substr(8),
.mail_key_full = mail_key .mail_key_full = e.mailkey
}; };
} }
return MailKeys{};
}
bool SharedDatabase::SaveCursor( bool SharedDatabase::SaveCursor(
uint32 char_id, uint32 char_id,
std::list<EQ::ItemInstance*>::const_iterator& start, std::list<EQ::ItemInstance*>::const_iterator& start,
@ -457,27 +423,20 @@ bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id)
); );
} }
int32 SharedDatabase::GetSharedPlatinum(uint32 account_id) int32 SharedDatabase::GetSharedPlatinum(uint32 account_id)
{ {
const auto query = fmt::format("SELECT sharedplat FROM account WHERE id = {}", account_id); const auto& e = AccountRepository::FindOne(*this, account_id);
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount()) { return e.sharedplat;
return 0;
} }
auto row = results.begin(); bool SharedDatabase::AddSharedPlatinum(uint32 account_id, int amount)
return Strings::ToInt(row[0]); {
} auto e = AccountRepository::FindOne(*this, account_id);
bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) { e.sharedplat += amount;
const std::string query = StringFormat("UPDATE account SET sharedplat = sharedplat + %i WHERE id = %i", amount_to_add, account_id);
const auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
return true; return AccountRepository::UpdateOne(*this, e);
} }
bool SharedDatabase::SetStartingItems( bool SharedDatabase::SetStartingItems(
@ -824,7 +783,7 @@ bool SharedDatabase::GetInventory(Client *c)
e.character_id = char_id; e.character_id = char_id;
e.item_id = item_id; e.item_id = item_id;
e.equipped = inst->GetEvolveEquipped(); e.equipped = inst->GetEvolveEquipped();
e.final_item_id = evolving_items_manager.GetFinalItemID(*inst); e.final_item_id = EvolvingItemsManager::Instance()->GetFinalItemID(*inst);
auto r = CharacterEvolvingItemsRepository::InsertOne(*this, e); auto r = CharacterEvolvingItemsRepository::InsertOne(*this, e);
e.id = r.id; e.id = r.id;
@ -946,25 +905,8 @@ void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id)
void SharedDatabase::GetItemsCount(int32& item_count, uint32& max_id) void SharedDatabase::GetItemsCount(int32& item_count, uint32& max_id)
{ {
item_count = -1; max_id = ItemsRepository::GetMaxId(*this);
max_id = 0; item_count = ItemsRepository::Count(*this);
const std::string query = "SELECT MAX(id), count(*) FROM items";
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0)
return;
auto& row = results.begin();
if (row[0])
max_id = Strings::ToUnsignedInt(row[0]);
if (row[1])
item_count = Strings::ToUnsignedInt(row[1]);
} }
bool SharedDatabase::LoadItems(const std::string &prefix) { bool SharedDatabase::LoadItems(const std::string &prefix) {
@ -974,7 +916,7 @@ bool SharedDatabase::LoadItems(const std::string &prefix) {
const auto Config = EQEmuConfig::get(); const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("items"); EQ::IPCMutex mutex("items");
mutex.Lock(); mutex.Lock();
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("items")); std::string file_name = fmt::format("{}/{}{}", PathManager::Instance()->GetSharedMemoryPath(), prefix, std::string("items"));
items_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name); items_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
items_hash = std::make_unique<EQ::FixedMemoryHashSet<EQ::ItemData>>(static_cast<uint8*>(items_mmf->Get()), items_mmf->Size()); items_hash = std::make_unique<EQ::FixedMemoryHashSet<EQ::ItemData>>(static_cast<uint8*>(items_mmf->Get()), items_mmf->Size());
mutex.Unlock(); mutex.Unlock();
@ -1032,206 +974,204 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
EQ::ItemData item; EQ::ItemData item;
const std::string query = "SELECT source," const auto& l = ItemsRepository::All(*this);
#define F(x) "`"#x"`,"
#include "item_fieldlist.h" if (l.empty()) {
#undef F
"updated, minstatus, comment FROM items ORDER BY id";
auto results = QueryDatabase(query);
if (!results.Success()) {
return; return;
} }
for (auto& row = results.begin(); row != results.end(); ++row) { for (const auto& e : l) {
memset(&item, 0, sizeof(EQ::ItemData)); memset(&item, 0, sizeof(EQ::ItemData));
// Unique Identifier // Unique Identifier
item.ID = Strings::ToUnsignedInt(row[ItemField::id]); item.ID = e.id;
// Minimum Status // Minimum Status
item.MinStatus = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::minstatus])); item.MinStatus = static_cast<uint8>(e.minstatus);
// Name, Lore, and Comment // Name, Lore, and Comment
strn0cpy(item.Name, row[ItemField::name], sizeof(item.Name)); strn0cpy(item.Name, e.Name.c_str(), sizeof(item.Name));
strn0cpy(item.Lore, row[ItemField::lore], sizeof(item.Lore)); strn0cpy(item.Lore, e.lore.c_str(), sizeof(item.Lore));
strn0cpy(item.Comment, row[ItemField::comment], sizeof(item.Comment)); strn0cpy(item.Comment, e.comment.c_str(), sizeof(item.Comment));
// Flags // Flags
item.ArtifactFlag = Strings::ToBool(row[ItemField::artifactflag]); item.ArtifactFlag = e.artifactflag;
item.Attuneable = !disable_attuneable && Strings::ToBool(row[ItemField::attuneable]); item.Attuneable = !disable_attuneable && e.attuneable;
item.BenefitFlag = Strings::ToBool(row[ItemField::benefitflag]); item.BenefitFlag = e.benefitflag;
item.FVNoDrop = Strings::ToBool(row[ItemField::fvnodrop]); item.FVNoDrop = e.fvnodrop;
item.Magic = Strings::ToBool(row[ItemField::magic]); item.Magic = e.magic;
item.NoDrop = disable_no_drop ? static_cast<uint8>(255) : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::nodrop])); item.NoDrop = disable_no_drop ? std::numeric_limits<uint8>::max() : e.nodrop;
item.NoPet = !disable_no_pet && Strings::ToBool(row[ItemField::nopet]); item.NoPet = !disable_no_pet && e.nopet;
item.NoRent = disable_no_rent ? static_cast<uint8>(255) : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::norent])); item.NoRent = disable_no_rent ? std::numeric_limits<uint8>::max() : e.norent;
item.NoTransfer = !disable_no_transfer && Strings::ToBool(row[ItemField::notransfer]); item.NoTransfer = !disable_no_transfer && e.notransfer;
item.PendingLoreFlag = Strings::ToBool(row[ItemField::pendingloreflag]); item.PendingLoreFlag = e.pendingloreflag;
item.QuestItemFlag = Strings::ToBool(row[ItemField::questitemflag]); item.QuestItemFlag = e.questitemflag;
item.Stackable = Strings::ToBool(row[ItemField::stackable]); item.Stackable = e.stackable;
item.Tradeskills = Strings::ToBool(row[ItemField::tradeskills]); item.Tradeskills = e.tradeskills;
item.SummonedFlag = Strings::ToBool(row[ItemField::summonedflag]); item.SummonedFlag = e.summonedflag;
// Lore // Lore
item.LoreGroup = disable_lore ? 0 : Strings::ToInt(row[ItemField::loregroup]); item.LoreGroup = disable_lore ? 0 : e.loregroup;
item.LoreFlag = !disable_lore && item.LoreGroup != 0; item.LoreFlag = !disable_lore && item.LoreGroup != 0;
// Type // Type
item.AugType = Strings::ToUnsignedInt(row[ItemField::augtype]); item.AugType = e.augtype;
item.ItemType = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::itemtype])); item.ItemType = static_cast<uint8>(e.itemtype);
item.SubType = Strings::ToInt(row[ItemField::subtype]); item.SubType = e.subtype;
// Miscellaneous // Miscellaneous
item.ExpendableArrow = static_cast<uint16>(Strings::ToUnsignedInt(row[ItemField::expendablearrow])); item.ExpendableArrow = e.expendablearrow;
item.Light = static_cast<int8>(Strings::ToInt(row[ItemField::light])); item.Light = EQ::Clamp(e.light, -128, 127);
item.MaxCharges = static_cast<int16>(Strings::ToInt(row[ItemField::maxcharges])); item.MaxCharges = e.maxcharges;
item.Size = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::size])); item.Size = static_cast<uint8>(e.size);
item.StackSize = static_cast<int16>(Strings::ToInt(row[ItemField::stacksize])); item.StackSize = e.stacksize;
item.Weight = Strings::ToInt(row[ItemField::weight]); item.Weight = e.weight;
// Potion Belt // Potion Belt
item.PotionBelt = !disable_potion_belt && Strings::ToBool(row[ItemField::potionbelt]); item.PotionBelt = !disable_potion_belt && e.potionbelt;
item.PotionBeltSlots = disable_potion_belt ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::potionbeltslots])); item.PotionBeltSlots = disable_potion_belt ? 0 : static_cast<uint8>(e.potionbeltslots);
// Merchant // Merchant
item.Favor = Strings::ToUnsignedInt(row[ItemField::favor]); item.Favor = e.favor;
item.GuildFavor = Strings::ToUnsignedInt(row[ItemField::guildfavor]); item.GuildFavor = e.guildfavor;
item.Price = Strings::ToUnsignedInt(row[ItemField::price]); item.Price = e.price;
item.SellRate = Strings::ToFloat(row[ItemField::sellrate]); item.SellRate = e.sellrate;
// Display // Display
item.Color = Strings::ToUnsignedInt(row[ItemField::color]); item.Color = e.color;
item.EliteMaterial = Strings::ToUnsignedInt(row[ItemField::elitematerial]); item.EliteMaterial = e.elitematerial;
item.HerosForgeModel = Strings::ToUnsignedInt(row[ItemField::herosforgemodel]); item.HerosForgeModel = e.herosforgemodel;
item.Icon = Strings::ToUnsignedInt(row[ItemField::icon]); item.Icon = e.icon;
strn0cpy(item.IDFile, row[ItemField::idfile], sizeof(item.IDFile)); strn0cpy(item.IDFile, e.idfile.c_str(), sizeof(item.IDFile));
item.Material = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::material])); item.Material = e.material;
// Resists // Resists
item.CR = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::cr]), -128, 127)); item.CR = EQ::Clamp(e.cr, -128, 127);
item.DR = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::dr]), -128, 127)); item.DR = EQ::Clamp(e.dr, -128, 127);
item.FR = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::fr]), -128, 127)); item.FR = EQ::Clamp(e.fr, -128, 127);
item.MR = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::mr]), -128, 127)); item.MR = EQ::Clamp(e.mr, -128, 127);
item.PR = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::pr]), -128, 127)); item.PR = EQ::Clamp(e.pr, -128, 127);
item.SVCorruption = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::svcorruption]), -128, 127)); item.SVCorruption = EQ::Clamp(e.svcorruption, -128, 127);
// Heroic Resists // Heroic Resists
item.HeroicCR = Strings::ToInt(row[ItemField::heroic_cr]); item.HeroicCR = e.heroic_cr;
item.HeroicDR = Strings::ToInt(row[ItemField::heroic_dr]); item.HeroicDR = e.heroic_dr;
item.HeroicFR = Strings::ToInt(row[ItemField::heroic_fr]); item.HeroicFR = e.heroic_fr;
item.HeroicMR = Strings::ToInt(row[ItemField::heroic_mr]); item.HeroicMR = e.heroic_mr;
item.HeroicPR = Strings::ToInt(row[ItemField::heroic_pr]); item.HeroicPR = e.heroic_pr;
item.HeroicSVCorrup = Strings::ToInt(row[ItemField::heroic_svcorrup]); item.HeroicSVCorrup = e.heroic_svcorrup;
// Stats // Stats
item.AAgi = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::aagi]), -128, 127)); item.AAgi = EQ::Clamp(e.aagi, -128, 127);
item.ACha = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::acha]), -128, 127)); item.ACha = EQ::Clamp(e.acha, -128, 127);
item.ADex = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::adex]), -128, 127)); item.ADex = EQ::Clamp(e.adex, -128, 127);
item.AInt = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::aint]), -128, 127)); item.AInt = EQ::Clamp(e.aint, -128, 127);
item.ASta = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::asta]), -128, 127)); item.ASta = EQ::Clamp(e.asta, -128, 127);
item.AStr = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::astr]), -128, 127)); item.AStr = EQ::Clamp(e.astr, -128, 127);
item.AWis = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::awis]), -128, 127)); item.AWis = EQ::Clamp(e.awis, -128, 127);
// Heroic Stats // Heroic Stats
item.HeroicAgi = Strings::ToInt(row[ItemField::heroic_agi]); item.HeroicAgi = e.heroic_agi;
item.HeroicCha = Strings::ToInt(row[ItemField::heroic_cha]); item.HeroicCha = e.heroic_cha;
item.HeroicDex = Strings::ToInt(row[ItemField::heroic_dex]); item.HeroicDex = e.heroic_dex;
item.HeroicInt = Strings::ToInt(row[ItemField::heroic_int]); item.HeroicInt = e.heroic_int;
item.HeroicSta = Strings::ToInt(row[ItemField::heroic_sta]); item.HeroicSta = e.heroic_sta;
item.HeroicStr = Strings::ToInt(row[ItemField::heroic_str]); item.HeroicStr = e.heroic_str;
item.HeroicWis = Strings::ToInt(row[ItemField::heroic_wis]); item.HeroicWis = e.heroic_wis;
// Health, Mana, and Endurance // Health, Mana, and Endurance
item.HP = Strings::ToInt(row[ItemField::hp]); item.HP = e.hp;
item.Regen = Strings::ToInt(row[ItemField::regen]); item.Regen = e.regen;
item.Mana = Strings::ToInt(row[ItemField::mana]); item.Mana = e.mana;
item.ManaRegen = Strings::ToInt(row[ItemField::manaregen]); item.ManaRegen = e.manaregen;
item.Endur = Strings::ToInt(row[ItemField::endur]); item.Endur = e.endur;
item.EnduranceRegen = Strings::ToInt(row[ItemField::enduranceregen]); item.EnduranceRegen = e.enduranceregen;
// Bane Damage // Bane Damage
item.BaneDmgAmt = Strings::ToInt(row[ItemField::banedmgamt]); item.BaneDmgAmt = e.banedmgamt;
item.BaneDmgBody = Strings::ToUnsignedInt(row[ItemField::banedmgbody]); item.BaneDmgBody = e.banedmgbody;
item.BaneDmgRace = Strings::ToUnsignedInt(row[ItemField::banedmgrace]); item.BaneDmgRace = e.banedmgrace;
item.BaneDmgRaceAmt = Strings::ToUnsignedInt(row[ItemField::banedmgraceamt]); item.BaneDmgRaceAmt = e.banedmgraceamt;
// Elemental Damage // Elemental Damage
item.ElemDmgType = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::elemdmgtype])); item.ElemDmgType = static_cast<uint8>(e.elemdmgtype);
item.ElemDmgAmt = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::elemdmgamt])); item.ElemDmgAmt = static_cast<uint8>(e.elemdmgamt);
// Combat // Combat
item.BackstabDmg = Strings::ToUnsignedInt(row[ItemField::backstabdmg]); item.BackstabDmg = e.backstabdmg;
item.Damage = Strings::ToUnsignedInt(row[ItemField::damage]); item.Damage = e.damage;
item.Delay = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::delay])); item.Delay = static_cast<uint8>(e.delay);
item.Range = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::range])); item.Range = static_cast<uint8>(e.range_);
// Combat Stats // Combat Stats
item.AC = Strings::ToInt(row[ItemField::ac]); item.AC = e.ac;
item.Accuracy = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::accuracy]), -128, 127)); item.Accuracy = EQ::Clamp(e.accuracy, -128, 127);
item.Attack = Strings::ToInt(row[ItemField::attack]); item.Attack = e.attack;
item.Avoidance = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::avoidance]), -128, 127)); item.Avoidance = EQ::Clamp(e.avoidance, -128, 127);
item.Clairvoyance = Strings::ToUnsignedInt(row[ItemField::clairvoyance]); item.Clairvoyance = e.clairvoyance;
item.CombatEffects = Strings::IsNumber(row[ItemField::combateffects]) ? static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::combateffects]), -128, 127)) : 0; item.CombatEffects = Strings::IsNumber(e.combateffects) ? static_cast<int8>(EQ::Clamp(Strings::ToInt(e.combateffects), -128, 127)) : 0;
item.DamageShield = Strings::ToInt(row[ItemField::damageshield]); item.DamageShield = e.damageshield;
item.DotShielding = Strings::ToInt(row[ItemField::dotshielding]); item.DotShielding = e.dotshielding;
item.DSMitigation = Strings::ToUnsignedInt(row[ItemField::dsmitigation]); item.DSMitigation = e.dsmitigation;
item.Haste = Strings::ToInt(row[ItemField::haste]); item.Haste = e.haste;
item.HealAmt = Strings::ToInt(row[ItemField::healamt]); item.HealAmt = e.healamt;
item.Purity = Strings::ToUnsignedInt(row[ItemField::purity]); item.Purity = e.purity;
item.Shielding = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::shielding]), -128, 127)); item.Shielding = EQ::Clamp(e.shielding, -128, 127);
item.SpellDmg = Strings::ToInt(row[ItemField::spelldmg]); item.SpellDmg = e.spelldmg;
item.SpellShield = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::spellshield]), -128, 127)); item.SpellShield = EQ::Clamp(e.spellshield, -128, 127);
item.StrikeThrough = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::strikethrough]), -128, 127)); item.StrikeThrough = EQ::Clamp(e.strikethrough, -128, 127);
item.StunResist = static_cast<int8>(EQ::Clamp(Strings::ToInt(row[ItemField::stunresist]), -128, 127)); item.StunResist = EQ::Clamp(e.stunresist, -128, 127);
// Restrictions // Restrictions
item.AugRestrict = Strings::ToUnsignedInt(row[ItemField::augrestrict]); item.AugRestrict = e.augrestrict;
item.Classes = Strings::ToUnsignedInt(row[ItemField::classes]); item.Classes = e.classes;
item.Deity = Strings::ToUnsignedInt(row[ItemField::deity]); item.Deity = e.deity;
item.ItemClass = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::itemclass])); item.ItemClass = static_cast<uint8>(e.itemclass);
item.Races = Strings::ToUnsignedInt(row[ItemField::races]); item.Races = e.races;
item.RecLevel = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::reclevel])); item.RecLevel = static_cast<uint8>(e.reclevel);
item.RecSkill = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::recskill])); item.RecSkill = static_cast<uint8>(e.recskill);
item.ReqLevel = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::reqlevel])); item.ReqLevel = static_cast<uint8>(e.reqlevel);
item.Slots = Strings::ToUnsignedInt(row[ItemField::slots]); item.Slots = e.slots;
// Skill Modifier // Skill Modifier
item.SkillModValue = Strings::ToInt(row[ItemField::skillmodvalue]); item.SkillModValue = e.skillmodvalue;
item.SkillModMax = Strings::ToInt(row[ItemField::skillmodmax]); item.SkillModMax = e.skillmodmax;
item.SkillModType = Strings::ToUnsignedInt(row[ItemField::skillmodtype]); item.SkillModType = e.skillmodtype;
// Extra Damage Skill // Extra Damage Skill
item.ExtraDmgSkill = Strings::ToInt(row[ItemField::extradmgskill]); item.ExtraDmgSkill = e.extradmgskill;
item.ExtraDmgAmt = Strings::ToInt(row[ItemField::extradmgamt]); item.ExtraDmgAmt = e.extradmgamt;
// Bard // Bard
item.BardType = Strings::ToUnsignedInt(row[ItemField::bardtype]); item.BardType = e.bardtype;
item.BardValue = Strings::ToInt(row[ItemField::bardvalue]); item.BardValue = e.bardvalue;
// Faction // Faction
item.FactionAmt1 = Strings::ToInt(row[ItemField::factionamt1]); item.FactionAmt1 = e.factionamt1;
item.FactionMod1 = Strings::ToInt(row[ItemField::factionmod1]); item.FactionMod1 = e.factionmod1;
item.FactionAmt2 = Strings::ToInt(row[ItemField::factionamt2]); item.FactionAmt2 = e.factionamt2;
item.FactionMod2 = Strings::ToInt(row[ItemField::factionmod2]); item.FactionMod2 = e.factionmod2;
item.FactionAmt3 = Strings::ToInt(row[ItemField::factionamt3]); item.FactionAmt3 = e.factionamt3;
item.FactionMod3 = Strings::ToInt(row[ItemField::factionmod3]); item.FactionMod3 = e.factionmod3;
item.FactionAmt4 = Strings::ToInt(row[ItemField::factionamt4]); item.FactionAmt4 = e.factionamt4;
item.FactionMod4 = Strings::ToInt(row[ItemField::factionmod4]); item.FactionMod4 = e.factionmod4;
// Augment // Augment Distiller
item.AugDistiller = Strings::ToUnsignedInt(row[ItemField::augdistiller]); item.AugDistiller = e.augdistiller;
item.AugSlotType[0] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot1type]));
item.AugSlotVisible[0] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot1visible])); // Augment Slots
item.AugSlotType[1] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot2type])); item.AugSlotType[0] = static_cast<uint8>(e.augslot1type);
item.AugSlotVisible[1] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot2visible])); item.AugSlotVisible[0] = static_cast<uint8>(e.augslot1visible);
item.AugSlotType[2] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot3type])); item.AugSlotType[1] = static_cast<uint8>(e.augslot2type);
item.AugSlotVisible[2] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot3visible])); item.AugSlotVisible[1] = static_cast<uint8>(e.augslot2visible);
item.AugSlotType[3] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot4type])); item.AugSlotType[2] = static_cast<uint8>(e.augslot3type);
item.AugSlotVisible[3] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot4visible])); item.AugSlotVisible[2] = static_cast<uint8>(e.augslot3visible);
item.AugSlotType[4] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot5type])); item.AugSlotType[3] = static_cast<uint8>(e.augslot4type);
item.AugSlotVisible[4] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot5visible])); item.AugSlotVisible[3] = static_cast<uint8>(e.augslot4visible);
item.AugSlotType[5] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot6type])); item.AugSlotType[4] = static_cast<uint8>(e.augslot5type);
item.AugSlotVisible[5] = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::augslot6visible])); item.AugSlotVisible[4] = static_cast<uint8>(e.augslot5visible);
item.AugSlotType[5] = static_cast<uint8>(e.augslot6type);
item.AugSlotVisible[5] = static_cast<uint8>(e.augslot6visible);
// Augment Unknowns // Augment Unknowns
for (uint8 i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) { for (uint8 i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
@ -1239,79 +1179,79 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_
} }
// LDoN // LDoN
item.LDoNTheme = Strings::ToUnsignedInt(row[ItemField::ldontheme]); item.LDoNTheme = e.ldontheme;
item.LDoNPrice = Strings::ToUnsignedInt(row[ItemField::ldonprice]); item.LDoNPrice = e.ldonprice;
item.LDoNSellBackRate = Strings::ToUnsignedInt(row[ItemField::ldonsellbackrate]); item.LDoNSellBackRate = e.ldonsellbackrate;
item.LDoNSold = Strings::ToUnsignedInt(row[ItemField::ldonsold]); item.LDoNSold = e.ldonsold;
item.PointType = Strings::ToUnsignedInt(row[ItemField::pointtype]); item.PointType = e.pointtype;
// Bag // Bag
item.BagSize = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bagsize])); item.BagSize = static_cast<uint8>(e.bagsize);
item.BagSlots = static_cast<uint8>(EQ::Clamp(Strings::ToInt(row[ItemField::bagslots]), 0, static_cast<int>(EQ::invbag::SLOT_COUNT))); item.BagSlots = EQ::Clamp(e.bagslots, 0, static_cast<int>(EQ::invbag::SLOT_COUNT));
item.BagType = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bagtype])); item.BagType = static_cast<uint8>(e.bagtype);
item.BagWR = static_cast<uint8>(EQ::Clamp(Strings::ToInt(row[ItemField::bagwr]), 0, 100)); item.BagWR = EQ::Clamp(e.bagwr, 0, 100);
// Bard Effect // Bard Effect
item.Bard.Effect = disable_bard_focus_effects ? 0 : Strings::ToInt(row[ItemField::bardeffect]); item.Bard.Effect = disable_bard_focus_effects ? 0 : e.bardeffect;
item.Bard.Type = disable_bard_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bardtype])); item.Bard.Type = disable_bard_focus_effects ? 0 : static_cast<uint8>(e.bardtype);
item.Bard.Level = disable_bard_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bardlevel])); item.Bard.Level = disable_bard_focus_effects ? 0 : static_cast<uint8>(e.bardlevel);
item.Bard.Level2 = disable_bard_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::bardlevel2])); item.Bard.Level2 = disable_bard_focus_effects ? 0 : static_cast<uint8>(e.bardlevel2);
// Book // Book
item.Book = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::book])); item.Book = static_cast<uint8>(e.book);
item.BookType = Strings::ToUnsignedInt(row[ItemField::booktype]); item.BookType = e.booktype;
// Click Effect // Click Effect
item.CastTime = Strings::ToUnsignedInt(row[ItemField::casttime]); item.CastTime = e.casttime;
item.CastTime_ = Strings::ToInt(row[ItemField::casttime_]); item.CastTime_ = e.casttime_;
item.Click.Effect = Strings::ToInt(row[ItemField::clickeffect]); item.Click.Effect = e.clickeffect;
item.Click.Type = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::clicktype])); item.Click.Type = static_cast<uint8>(e.clicktype);
item.Click.Level = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::clicklevel])); item.Click.Level = static_cast<uint8>(e.clicklevel);
item.Click.Level2 = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::clicklevel2])); item.Click.Level2 = static_cast<uint8>(e.clicklevel2);
strn0cpy(item.ClickName, row[ItemField::clickname], sizeof(item.ClickName)); strn0cpy(item.ClickName, e.clickname.c_str(), sizeof(item.ClickName));
item.RecastDelay = Strings::ToUnsignedInt(row[ItemField::recastdelay]); item.RecastDelay = e.recastdelay;
item.RecastType = Strings::ToInt(row[ItemField::recasttype]); item.RecastType = e.recasttype;
// Focus Effect // Focus Effect
item.Focus.Effect = disable_spell_focus_effects ? 0 : Strings::ToInt(row[ItemField::focuseffect]); item.Focus.Effect = disable_spell_focus_effects ? 0 : e.focuseffect;
item.Focus.Type = disable_spell_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::focustype])); item.Focus.Type = disable_spell_focus_effects ? 0 : static_cast<uint8>(e.focustype);
item.Focus.Level = disable_spell_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::focuslevel])); item.Focus.Level = disable_spell_focus_effects ? 0 : static_cast<uint8>(e.focuslevel);
item.Focus.Level2 = disable_spell_focus_effects ? 0 : static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::focuslevel2])); item.Focus.Level2 = disable_spell_focus_effects ? 0 : static_cast<uint8>(e.focuslevel2);
strn0cpy(item.FocusName, disable_spell_focus_effects ? "" : row[ItemField::focusname], sizeof(item.FocusName)); strn0cpy(item.FocusName, disable_spell_focus_effects ? "" : e.focusname.c_str(), sizeof(item.FocusName));
// Proc Effect // Proc Effect
item.Proc.Effect = Strings::ToInt(row[ItemField::proceffect]); item.Proc.Effect = e.proceffect;
item.Proc.Type = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::proctype])); item.Proc.Type = static_cast<uint8>(e.proctype);
item.Proc.Level = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::proclevel])); item.Proc.Level = static_cast<uint8>(e.proclevel);
item.Proc.Level2 = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::proclevel2])); item.Proc.Level2 = static_cast<uint8>(e.proclevel2);
strn0cpy(item.ProcName, row[ItemField::procname], sizeof(item.ProcName)); strn0cpy(item.ProcName, e.procname.c_str(), sizeof(item.ProcName));
item.ProcRate = Strings::ToInt(row[ItemField::procrate]); item.ProcRate = e.procrate;
// Scroll Effect // Scroll Effect
item.Scroll.Effect = Strings::ToInt(row[ItemField::scrolleffect]); item.Scroll.Effect = e.scrolleffect;
item.Scroll.Type = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::scrolltype])); item.Scroll.Type = static_cast<uint8>(e.scrolltype);
item.Scroll.Level = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::scrolllevel])); item.Scroll.Level = static_cast<uint8>(e.scrolllevel);
item.Scroll.Level2 = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::scrolllevel2])); item.Scroll.Level2 = static_cast<uint8>(e.scrolllevel2);
strn0cpy(item.ScrollName, row[ItemField::scrollname], sizeof(item.ScrollName)); strn0cpy(item.ScrollName, e.scrollname.c_str(), sizeof(item.ScrollName));
// Worn Effect // Worn Effect
item.Worn.Effect = Strings::ToInt(row[ItemField::worneffect]); item.Worn.Effect = e.worneffect;
item.Worn.Type = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::worntype])); item.Worn.Type = static_cast<uint8>(e.worntype);
item.Worn.Level = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::wornlevel])); item.Worn.Level = static_cast<uint8>(e.wornlevel);
item.Worn.Level2 = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::wornlevel2])); item.Worn.Level2 = static_cast<uint8>(e.wornlevel2);
strn0cpy(item.WornName, row[ItemField::wornname], sizeof(item.WornName)); strn0cpy(item.WornName, e.wornname.c_str(), sizeof(item.WornName));
// Evolving Item // Evolving Item
item.EvolvingID = Strings::ToUnsignedInt(row[ItemField::evoid]); item.EvolvingID = e.evoid;
item.EvolvingItem = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::evoitem])); item.EvolvingItem = static_cast<uint8>(e.evoitem);
item.EvolvingLevel = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::evolvinglevel])); item.EvolvingLevel = static_cast<uint8>(e.evolvinglevel);
item.EvolvingMax = static_cast<uint8>(Strings::ToUnsignedInt(row[ItemField::evomax])); item.EvolvingMax = static_cast<uint8>(e.evomax);
// Scripting // Scripting
item.CharmFileID = Strings::IsNumber(row[ItemField::charmfileid]) ? Strings::ToUnsignedInt(row[ItemField::charmfileid]) : 0; item.CharmFileID = Strings::IsNumber(e.charmfileid) ? Strings::ToUnsignedInt(e.charmfileid) : 0;
strn0cpy(item.CharmFile, row[ItemField::charmfile], sizeof(item.CharmFile)); strn0cpy(item.CharmFile, e.charmfile.c_str(), sizeof(item.CharmFile));
strn0cpy(item.Filename, row[ItemField::filename], sizeof(item.Filename)); strn0cpy(item.Filename, e.filename.c_str(), sizeof(item.Filename));
item.ScriptFileID = Strings::ToUnsignedInt(row[ItemField::scriptfileid]); item.ScriptFileID = e.scriptfileid;
try { try {
hash.insert(item.ID, item); hash.insert(item.ID, item);
@ -1544,12 +1484,60 @@ bool SharedDatabase::GetCommandSettings(std::map<std::string, std::pair<uint8, s
return true; return true;
} }
template<typename T1, typename T2>
inline std::vector<std::string> join_pair(
const std::string &glue,
const std::pair<char, char> &encapsulation,
const std::vector<std::pair<T1, T2>> &src
)
{
if (src.empty()) {
return {};
}
std::vector<std::string> output;
for (const std::pair<T1, T2> &src_iter: src) {
output.emplace_back(
fmt::format(
"{}{}{}{}{}{}{}",
encapsulation.first,
src_iter.first,
encapsulation.second,
glue,
encapsulation.first,
src_iter.second,
encapsulation.second
)
);
}
return output;
}
template<typename T>
inline std::string
ImplodePair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
{
if (src.empty()) {
return {};
}
std::ostringstream oss;
for (const T &src_iter: src) {
oss << encapsulation.first << src_iter << encapsulation.second << glue;
}
std::string output(oss.str());
output.resize(output.size() - glue.size());
return output;
}
bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected) bool SharedDatabase::UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected)
{ {
if (injected.size()) { if (injected.size()) {
const std::string query = fmt::format( const std::string query = fmt::format(
"REPLACE INTO `command_settings`(`command`, `access`) VALUES {}", "REPLACE INTO `command_settings`(`command`, `access`) VALUES {}",
Strings::ImplodePair( ImplodePair(
",", ",",
std::pair<char, char>('(', ')'), std::pair<char, char>('(', ')'),
join_pair(",", std::pair<char, char>('\'', '\''), injected) join_pair(",", std::pair<char, char>('\'', '\''), injected)
@ -1576,7 +1564,7 @@ bool SharedDatabase::UpdateOrphanedCommandSettings(const std::vector<std::string
if (orphaned.size()) { if (orphaned.size()) {
std::string query = fmt::format( std::string query = fmt::format(
"DELETE FROM `command_settings` WHERE `command` IN ({})", "DELETE FROM `command_settings` WHERE `command` IN ({})",
Strings::ImplodePair(",", std::pair<char, char>('\'', '\''), orphaned) ImplodePair(",", std::pair<char, char>('\'', '\''), orphaned)
); );
auto results = QueryDatabase(query); auto results = QueryDatabase(query);
@ -1586,7 +1574,7 @@ bool SharedDatabase::UpdateOrphanedCommandSettings(const std::vector<std::string
query = fmt::format( query = fmt::format(
"DELETE FROM `command_subsettings` WHERE `parent_command` IN ({})", "DELETE FROM `command_subsettings` WHERE `parent_command` IN ({})",
Strings::ImplodePair(",", std::pair<char, char>('\'', '\''), orphaned) ImplodePair(",", std::pair<char, char>('\'', '\''), orphaned)
); );
auto results_two = QueryDatabase(query); auto results_two = QueryDatabase(query);
@ -1625,20 +1613,17 @@ bool SharedDatabase::GetCommandSubSettings(std::vector<CommandSubsettingsReposit
return true; return true;
} }
void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) { void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* s)
const std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 " {
"AND `spellid` <= %i", iMaxSpellID); const auto& l = DamageshieldtypesRepository::All(*this);
auto results = QueryDatabase(query);
if (!results.Success()) { if (l.empty()) {
return; return;
} }
for(auto& row = results.begin(); row != results.end(); ++row) { for (const auto& e : l) {
const int spellID = Strings::ToInt(row[0]); s[e.spellid].damage_shield_type = e.type;
if((spellID > 0) && (spellID <= iMaxSpellID))
sp[spellID].damage_shield_type = Strings::ToUnsignedInt(row[1]);
} }
} }
const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) { const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) {
@ -1665,7 +1650,7 @@ bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const
EQ::IPCMutex mutex("spells"); EQ::IPCMutex mutex("spells");
mutex.Lock(); mutex.Lock();
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("spells")); std::string file_name = fmt::format("{}/{}{}", PathManager::Instance()->GetSharedMemoryPath(), prefix, std::string("spells"));
spells_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name); spells_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
LogInfo("Loading [{}]", file_name); LogInfo("Loading [{}]", file_name);
*records = *static_cast<uint32*>(spells_mmf->Get()); *records = *static_cast<uint32*>(spells_mmf->Get());
@ -1855,21 +1840,32 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].damage_shield_type = 0; sp[tempid].damage_shield_type = 0;
} }
LoadDamageShieldTypes(sp, max_spells); LoadDamageShieldTypes(sp);
} }
void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) { void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* s)
const std::string query = StringFormat("SELECT `inspect_message` FROM `character_inspect_messages` WHERE `id` = %u LIMIT 1", character_id); {
auto results = QueryDatabase(query); const auto& e = CharacterInspectMessagesRepository::FindOne(*this, character_id);
memset(message, '\0', sizeof(InspectMessage_Struct));
for (auto& row = results.begin(); row != results.end(); ++row) { memset(s, '\0', sizeof(InspectMessage_Struct));
memcpy(message, row[0], sizeof(InspectMessage_Struct));
} if (!e.id) {
return;
} }
void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message) { memcpy(s, e.inspect_message.c_str(), sizeof(InspectMessage_Struct));
const std::string query = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message) VALUES (%u, '%s')", character_id, Strings::Escape(message->text).c_str()); }
auto results = QueryDatabase(query);
void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* s)
{
auto e = CharacterInspectMessagesRepository::NewEntity();
e.id = character_id;
e.inspect_message = s->text;
if (!CharacterInspectMessagesRepository::ReplaceOne(*this, e)) {
LogError("Failed to save character inspect message of [{}] for character_id [{}]", s->text, character_id);
}
} }
uint32 SharedDatabase::GetSpellsCount() uint32 SharedDatabase::GetSpellsCount()
@ -1890,18 +1886,7 @@ uint32 SharedDatabase::GetSpellsCount()
uint32 SharedDatabase::GetItemsCount() uint32 SharedDatabase::GetItemsCount()
{ {
auto results = QueryDatabase("SELECT count(*) FROM items"); return ItemsRepository::Count(*this);
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto& row = results.begin();
if (row[0]) {
return Strings::ToUnsignedInt(row[0]);
}
return 0;
} }
void SharedDatabase::SetSharedItemsCount(uint32 shared_items_count) void SharedDatabase::SetSharedItemsCount(uint32 shared_items_count)

View File

@ -76,21 +76,20 @@ public:
uint8 GetGMSpeed(uint32 account_id); uint8 GetGMSpeed(uint32 account_id);
bool SetHideMe(uint32 account_id, uint8 hideme); bool SetHideMe(uint32 account_id, uint8 hideme);
int DeleteStalePlayerCorpses(); int DeleteStalePlayerCorpses();
void LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct *message); void LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* s);
void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct *message); void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* s);
bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &command_settings); bool GetCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &command_settings);
bool UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected); bool UpdateInjectedCommandSettings(const std::vector<std::pair<std::string, uint8>> &injected);
bool UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned); bool UpdateOrphanedCommandSettings(const std::vector<std::string> &orphaned);
bool GetCommandSubSettings(std::vector<CommandSubsettingsRepository::CommandSubsettings> &command_subsettings); bool GetCommandSubSettings(std::vector<CommandSubsettingsRepository::CommandSubsettings> &command_subsettings);
uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID);
bool SetGMInvul(uint32 account_id, bool gminvul); bool SetGMInvul(uint32 account_id, bool gminvul);
bool SetGMFlymode(uint32 account_id, uint8 flymode); bool SetGMFlymode(uint32 account_id, uint8 flymode);
void SetMailKey(int CharID, int IPAddress, int MailKey); void SetMailKey(uint32 character_id, uint32 ip_address, uint32 mail_key);
struct MailKeys { struct MailKeys {
std::string mail_key; std::string mail_key;
std::string mail_key_full; std::string mail_key_full;
}; };
MailKeys GetMailKey(int character_id); MailKeys GetMailKey(uint32 character_id);
bool SaveCursor( bool SaveCursor(
uint32 char_id, uint32 char_id,
std::list<EQ::ItemInstance *>::const_iterator &start, std::list<EQ::ItemInstance *>::const_iterator &start,
@ -104,7 +103,7 @@ public:
bool VerifyInventory(uint32 account_id, int16 slot_id, const EQ::ItemInstance *inst); bool VerifyInventory(uint32 account_id, int16 slot_id, const EQ::ItemInstance *inst);
bool GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is_charid); bool GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is_charid);
int32 GetSharedPlatinum(uint32 account_id); int32 GetSharedPlatinum(uint32 account_id);
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add); bool AddSharedPlatinum(uint32 account_id, int amount);
bool GetInventory(Client* c); bool GetInventory(Client* c);
bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id); std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
@ -173,7 +172,7 @@ public:
int GetMaxSpellID(); int GetMaxSpellID();
bool LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp); bool LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp);
void LoadSpells(void *data, int max_spells); void LoadSpells(void *data, int max_spells);
void LoadDamageShieldTypes(SPDat_Spell_Struct *sp, int32 iMaxSpellID); void LoadDamageShieldTypes(SPDat_Spell_Struct* s);
uint32 GetSharedSpellsCount() { return m_shared_spells_count; } uint32 GetSharedSpellsCount() { return m_shared_spells_count; }
uint32 GetSpellsCount(); uint32 GetSpellsCount();

View File

@ -16,12 +16,16 @@ public:
static int32_t GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id); static int32_t GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id);
SkillCaps *SetContentDatabase(Database *db); SkillCaps *SetContentDatabase(Database *db);
static SkillCaps* Instance()
{
static SkillCaps instance;
return &instance;
}
private: private:
Database *m_content_database{}; Database *m_content_database{};
std::map<uint64, SkillCapsRepository::SkillCaps> m_skill_caps = {}; std::map<uint64, SkillCapsRepository::SkillCaps> m_skill_caps = {};
}; };
extern SkillCaps skill_caps;
#endif //CODE_SKILL_CAPS_H #endif //CODE_SKILL_CAPS_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -358,6 +358,7 @@ bool RequiresStackCheck(uint16 spell_type) {
case BotSpellTypes::CompleteHeal: case BotSpellTypes::CompleteHeal:
case BotSpellTypes::PetCompleteHeals: case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::GroupCompleteHeals: case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::Resurrect:
return false; return false;
default: default:
return true; return true;

View File

@ -34,6 +34,7 @@
*/ */
#include "strings.h" #include "strings.h"
#include <cereal/external/rapidjson/document.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@ -41,6 +42,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <sstream>
#include <random> #include <random>
#include <string> #include <string>
@ -49,6 +51,12 @@
#include "strings_legacy.cpp" // legacy c functions #include "strings_legacy.cpp" // legacy c functions
#include "strings_misc.cpp" // anything non "Strings" scoped #include "strings_misc.cpp" // anything non "Strings" scoped
#ifdef _WINDOWS
#include <ctype.h>
#include <functional>
#include <algorithm>
#endif
std::string Strings::Random(size_t length) std::string Strings::Random(size_t length)
{ {
static auto &chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static auto &chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@ -305,6 +313,12 @@ std::string Strings::Commify(const std::string &number)
auto string_length = static_cast<int>(number.length()); auto string_length = static_cast<int>(number.length());
if (string_length == 3) {
return number;
} else if (string_length == 4 && number.starts_with("-")) {
return number;
}
int i = 0; int i = 0;
for (i = string_length - 3; i >= 0; i -= 3) { for (i = string_length - 3; i >= 0; i -= 3) {
if (i > 0) { if (i > 0) {
@ -701,6 +715,18 @@ std::string &Strings::Trim(std::string &str, const std::string &chars)
return LTrim(RTrim(str, chars), chars); return LTrim(RTrim(str, chars), chars);
} }
const std::string NUM_TO_ENGLISH_X[] = {
"", "One ", "Two ", "Three ", "Four ",
"Five ", "Six ", "Seven ", "Eight ", "Nine ", "Ten ", "Eleven ",
"Twelve ", "Thirteen ", "Fourteen ", "Fifteen ",
"Sixteen ", "Seventeen ", "Eighteen ", "Nineteen "
};
const std::string NUM_TO_ENGLISH_Y[] = {
"", "", "Twenty ", "Thirty ", "Forty ",
"Fifty ", "Sixty ", "Seventy ", "Eighty ", "Ninety "
};
// Function to convert single digit or two digit number into words // Function to convert single digit or two digit number into words
std::string Strings::ConvertToDigit(int n, const std::string& suffix) std::string Strings::ConvertToDigit(int n, const std::string& suffix)
{ {

View File

@ -36,53 +36,19 @@
#define _STRINGUTIL_H_ #define _STRINGUTIL_H_
#include <charconv> #include <charconv>
#include <sstream> #include <cstring>
#include <string.h>
#include <string_view> #include <string_view>
#include <string>
#include <vector> #include <vector>
#include <cstdarg> #include <cstdarg>
#include <tuple>
#include <type_traits> #include <type_traits>
#include <fmt/format.h> #ifdef _WIN32
#include <cereal/external/rapidjson/document.h>
#ifndef _WIN32
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
#endif
#ifdef _WINDOWS
#include <ctype.h> #include <ctype.h>
#include <functional>
#include <algorithm>
#endif #endif
#include "types.h" #include "types.h"
namespace detail {
// template magic to check if std::from_chars floating point functions exist
template <typename T, typename = void>
struct has_from_chars_float : std::false_type { };
// basically it "uses" this template if they do exist because reasons
template <typename T>
struct has_from_chars_float < T,
std::void_t<decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(),
std::declval<T &>()))>> : std::true_type { };
}; // namespace detail
namespace EQ {
// lame -- older GCC's didn't define this, clang's libc++ however does, even though they lack FP support
#if defined(__GNUC__) && (__GNUC__ < 11) && !defined(__clang__)
enum class chars_format {
scientific = 1, fixed = 2, hex = 4, general = fixed | scientific
};
#else
using chars_format = std::chars_format;
#endif
}; // namespace EQ
class Strings { class Strings {
public: public:
static bool Contains(std::vector<std::string> container, const std::string& element); static bool Contains(std::vector<std::string> container, const std::string& element);
@ -133,61 +99,6 @@ public:
static bool BeginsWith(const std::string& subject, const std::string& search); static bool BeginsWith(const std::string& subject, const std::string& search);
static bool EndsWith(const std::string& subject, const std::string& search); static bool EndsWith(const std::string& subject, const std::string& search);
static std::string ZoneTime(const uint8 hours, const uint8 minutes); static std::string ZoneTime(const uint8 hours, const uint8 minutes);
template<typename T>
static std::string
ImplodePair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
{
if (src.empty()) {
return {};
}
std::ostringstream oss;
for (const T &src_iter: src) {
oss << encapsulation.first << src_iter << encapsulation.second << glue;
}
std::string output(oss.str());
output.resize(output.size() - glue.size());
return output;
}
// basic string_view overloads that just use std stuff since they work!
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && detail::has_from_chars_float<T>::value, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
return std::from_chars(str.data(), str.data() + str.size(), value, fmt);
}
template <typename T>
std::enable_if_t<std::is_integral_v<T>, std::from_chars_result>
static from_chars(std::string_view str, T& value, int base = 10)
{
return std::from_chars(str.data(), str.data() + str.size(), value, base);
}
// fallback versions of floating point in case they're not implemented
// TODO: add error handling ...
// This does have to allocate since from_chars doesn't need a null terminated string and neither does string_view
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && !detail::has_from_chars_float<T>::value && std::is_same_v<T, float>, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
std::from_chars_result res{};
std::string tmp_str(str.data(), str.size());
value = strtof(tmp_str.data(), nullptr);
return res;
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T> && !detail::has_from_chars_float<T>::value && std::is_same_v<T, double>, std::from_chars_result>
static from_chars(std::string_view str, T& value, EQ::chars_format fmt = EQ::chars_format::general)
{
std::from_chars_result res{};
std::string tmp_str(str.data(), str.size());
value = strtod(tmp_str.data(), nullptr);
return res;
}
static std::string Slugify(const std::string &input, const std::string &separator = "-"); static std::string Slugify(const std::string &input, const std::string &separator = "-");
static bool IsValidJson(const std::string& json); static bool IsValidJson(const std::string& json);
}; };
@ -199,93 +110,6 @@ const std::string vStringFormat(const char *format, va_list args);
// Used for grid nodes, as NPC names remove numerals. // Used for grid nodes, as NPC names remove numerals.
// But general purpose // But general purpose
const std::string NUM_TO_ENGLISH_X[] = {
"", "One ", "Two ", "Three ", "Four ",
"Five ", "Six ", "Seven ", "Eight ", "Nine ", "Ten ", "Eleven ",
"Twelve ", "Thirteen ", "Fourteen ", "Fifteen ",
"Sixteen ", "Seventeen ", "Eighteen ", "Nineteen "
};
const std::string NUM_TO_ENGLISH_Y[] = {
"", "", "Twenty ", "Thirty ", "Forty ",
"Fifty ", "Sixty ", "Seventy ", "Eighty ", "Ninety "
};
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
template<typename T1, typename T2>
std::vector<std::string> join_pair(
const std::string &glue,
const std::pair<char, char> &encapsulation,
const std::vector<std::pair<T1, T2>> &src
)
{
if (src.empty()) {
return {};
}
std::vector<std::string> output;
for (const std::pair<T1, T2> &src_iter: src) {
output.emplace_back(
fmt::format(
"{}{}{}{}{}{}{}",
encapsulation.first,
src_iter.first,
encapsulation.second,
glue,
encapsulation.first,
src_iter.second,
encapsulation.second
)
);
}
return output;
}
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
template<typename T1, typename T2, typename T3, typename T4>
std::vector<std::string> join_tuple(
const std::string &glue,
const std::pair<char, char> &encapsulation,
const std::vector<std::tuple<T1, T2, T3, T4>> &src
)
{
if (src.empty()) {
return {};
}
std::vector<std::string> output;
for (const std::tuple<T1, T2, T3, T4> &src_iter: src) {
output.emplace_back(
fmt::format(
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
encapsulation.first,
std::get<0>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<1>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<2>(src_iter),
encapsulation.second,
glue,
encapsulation.first,
std::get<3>(src_iter),
encapsulation.second
)
);
}
return output;
}
// misc functions // misc functions
std::string SanitizeWorldServerName(std::string server_long_name); std::string SanitizeWorldServerName(std::string server_long_name);
std::vector<std::string> GetBadWords(); std::vector<std::string> GetBadWords();
@ -310,18 +134,4 @@ std::string FormatName(const std::string &char_name);
bool IsAllowedWorldServerCharacterList(char c); bool IsAllowedWorldServerCharacterList(char c);
void SanitizeWorldServerName(char *name); void SanitizeWorldServerName(char *name);
template<typename InputIterator, typename OutputIterator>
auto CleanMobName(InputIterator first, InputIterator last, OutputIterator result)
{
for (; first != last; ++first) {
if (*first == '_') {
*result = ' ';
}
else if (isalpha(*first) || *first == '`') {
*result = *first;
}
}
return result;
}
#endif #endif

View File

@ -25,7 +25,7 @@
// Build variables // Build variables
// these get injected during the build pipeline // these get injected during the build pipeline
#define CURRENT_VERSION "23.6.0-dev" // always append -dev to the current version for custom-builds #define CURRENT_VERSION "23.10.3-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0" #define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__ #define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__ #define COMPILE_TIME __TIME__
@ -42,8 +42,9 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9323 #define CURRENT_BINARY_DATABASE_VERSION 9328
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
#define CUSTOM_BINARY_DATABASE_VERSION 0
#endif #endif

View File

@ -104,36 +104,39 @@ public:
uint8 GetZoneIdleWhenEmpty(uint32 zone_id, int version = 0); uint8 GetZoneIdleWhenEmpty(uint32 zone_id, int version = 0);
uint32 GetZoneSecondsBeforeIdle(uint32 zone_id, int version = 0); uint32 GetZoneSecondsBeforeIdle(uint32 zone_id, int version = 0);
static ZoneStore* Instance()
{
static ZoneStore instance;
return &instance;
}
private: private:
std::vector<ZoneRepository::Zone> m_zones; std::vector<ZoneRepository::Zone> m_zones;
}; };
extern ZoneStore zone_store;
/** /**
* Global helpers * Global helpers
*/ */
inline uint32 ZoneID(const char *in_zone_name) { return zone_store.GetZoneID(in_zone_name); } inline uint32 ZoneID(const char *in_zone_name) { return ZoneStore::Instance()->GetZoneID(in_zone_name); }
inline uint32 ZoneID(const std::string& zone_name) { return zone_store.GetZoneID(zone_name); } inline uint32 ZoneID(const std::string& zone_name) { return ZoneStore::Instance()->GetZoneID(zone_name); }
inline const char *ZoneName(uint32 zone_id, bool error_unknown = false) inline const char *ZoneName(uint32 zone_id, bool error_unknown = false)
{ {
return zone_store.GetZoneName( return ZoneStore::Instance()->GetZoneName(
zone_id, zone_id,
error_unknown error_unknown
); );
} }
inline const char *ZoneLongName(uint32 zone_id, bool error_unknown = false) inline const char *ZoneLongName(uint32 zone_id, bool error_unknown = false)
{ {
return zone_store.GetZoneLongName( return ZoneStore::Instance()->GetZoneLongName(
zone_id, zone_id,
error_unknown error_unknown
); );
} }
inline ZoneRepository::Zone *GetZone(uint32 zone_id, int version = 0) { return zone_store.GetZone(zone_id, version); }; inline ZoneRepository::Zone *GetZone(uint32 zone_id, int version = 0) { return ZoneStore::Instance()->GetZone(zone_id, version); };
inline ZoneRepository::Zone *GetZone(const char *in_zone_name) { return zone_store.GetZone(in_zone_name); }; inline ZoneRepository::Zone *GetZone(const char *in_zone_name) { return ZoneStore::Instance()->GetZone(in_zone_name); };
inline ZoneRepository::Zone *GetZone(const char *in_zone_name, int version = 0) inline ZoneRepository::Zone *GetZone(const char *in_zone_name, int version = 0)
{ {
return zone_store.GetZone( return ZoneStore::Instance()->GetZone(
ZoneID( ZoneID(
in_zone_name in_zone_name
), version ), version
@ -141,7 +144,7 @@ inline ZoneRepository::Zone *GetZone(const char *in_zone_name, int version = 0)
}; };
inline ZoneRepository::Zone *GetZoneVersionWithFallback(uint32 zone_id, int version = 0) inline ZoneRepository::Zone *GetZoneVersionWithFallback(uint32 zone_id, int version = 0)
{ {
return zone_store.GetZoneWithFallback( return ZoneStore::Instance()->GetZoneWithFallback(
zone_id, zone_id,
version version
); );

View File

@ -33,19 +33,16 @@
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
EQEmuLogSys LogSys;
PathManager path;
bool RunLoops = false; bool RunLoops = false;
void CatchSignal(int sig_num); void CatchSignal(int sig_num);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
RegisterExecutablePlatform(ExePlatformLaunch); RegisterExecutablePlatform(ExePlatformLaunch);
LogSys.LoadLogSettingsDefaults(); EQEmuLogSys::Instance()->LoadLogSettingsDefaults();
set_exception_handler(); set_exception_handler();
path.LoadPaths(); PathManager::Instance()->Init();
std::string launcher_name; std::string launcher_name;
if(argc == 2) { if(argc == 2) {
@ -169,7 +166,7 @@ int main(int argc, char *argv[]) {
delete zone->second; delete zone->second;
} }
LogSys.CloseFileLogs(); EQEmuLogSys::Instance()->CloseFileLogs();
return 0; return 0;
} }

View File

@ -33,7 +33,7 @@ EverQuest::EverQuest(const std::string &host, int port, const std::string &user,
} }
else { else {
m_host = addr; m_host = addr;
m_login_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); m_login_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager());
m_login_connection_manager->OnNewConnection(std::bind(&EverQuest::LoginOnNewConnection, this, std::placeholders::_1)); m_login_connection_manager->OnNewConnection(std::bind(&EverQuest::LoginOnNewConnection, this, std::placeholders::_1));
m_login_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::LoginOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_login_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::LoginOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
@ -48,13 +48,13 @@ EverQuest::~EverQuest()
{ {
} }
void EverQuest::LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection) void EverQuest::LoginOnNewConnection(std::shared_ptr<EQ::Net::ReliableStreamConnection> connection)
{ {
m_login_connection = connection; m_login_connection = connection;
Log.OutF(Logs::General, Logs::Headless_Client, "Connecting..."); Log.OutF(Logs::General, Logs::Headless_Client, "Connecting...");
} }
void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to)
{ {
if (to == EQ::Net::StatusConnected) { if (to == EQ::Net::StatusConnected) {
Log.OutF(Logs::General, Logs::Headless_Client, "Login connected."); Log.OutF(Logs::General, Logs::Headless_Client, "Login connected.");
@ -70,14 +70,14 @@ void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::Day
} }
} }
void EverQuest::LoginOnStatusChangeReconnectDisabled(std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) void EverQuest::LoginOnStatusChangeReconnectDisabled(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to)
{ {
if (to == EQ::Net::StatusDisconnected) { if (to == EQ::Net::StatusDisconnected) {
m_login_connection.reset(); m_login_connection.reset();
} }
} }
void EverQuest::LoginOnPacketRecv(std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet & p) void EverQuest::LoginOnPacketRecv(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, const EQ::Net::Packet & p)
{ {
auto opcode = p.GetUInt16(0); auto opcode = p.GetUInt16(0);
switch (opcode) { switch (opcode) {
@ -251,20 +251,20 @@ void EverQuest::LoginDisableReconnect()
void EverQuest::ConnectToWorld() void EverQuest::ConnectToWorld()
{ {
m_world_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); m_world_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager());
m_world_connection_manager->OnNewConnection(std::bind(&EverQuest::WorldOnNewConnection, this, std::placeholders::_1)); m_world_connection_manager->OnNewConnection(std::bind(&EverQuest::WorldOnNewConnection, this, std::placeholders::_1));
m_world_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::WorldOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_world_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::WorldOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_world_connection_manager->OnPacketRecv(std::bind(&EverQuest::WorldOnPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); m_world_connection_manager->OnPacketRecv(std::bind(&EverQuest::WorldOnPacketRecv, this, std::placeholders::_1, std::placeholders::_2));
m_world_connection_manager->Connect(m_host, 9000); m_world_connection_manager->Connect(m_host, 9000);
} }
void EverQuest::WorldOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection) void EverQuest::WorldOnNewConnection(std::shared_ptr<EQ::Net::ReliableStreamConnection> connection)
{ {
m_world_connection = connection; m_world_connection = connection;
Log.OutF(Logs::General, Logs::Headless_Client, "Connecting to world..."); Log.OutF(Logs::General, Logs::Headless_Client, "Connecting to world...");
} }
void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to)
{ {
if (to == EQ::Net::StatusConnected) { if (to == EQ::Net::StatusConnected) {
Log.OutF(Logs::General, Logs::Headless_Client, "World connected."); Log.OutF(Logs::General, Logs::Headless_Client, "World connected.");
@ -278,14 +278,14 @@ void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr<EQ::Net::Day
} }
} }
void EverQuest::WorldOnStatusChangeReconnectDisabled(std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) void EverQuest::WorldOnStatusChangeReconnectDisabled(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to)
{ {
if (to == EQ::Net::StatusDisconnected) { if (to == EQ::Net::StatusDisconnected) {
m_world_connection.reset(); m_world_connection.reset();
} }
} }
void EverQuest::WorldOnPacketRecv(std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet & p) void EverQuest::WorldOnPacketRecv(std::shared_ptr<EQ::Net::ReliableStreamConnection> conn, const EQ::Net::Packet & p)
{ {
auto opcode = p.GetUInt16(0); auto opcode = p.GetUInt16(0);
switch (opcode) { switch (opcode) {

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