Compare commits

..

110 Commits

Author SHA1 Message Date
Chris Miles 4fda3c045e [Release] 22.62.2 (#4633) 2025-02-01 16:25:53 -06:00
Mitch Freeman 0a20100d12 [Fix] Add price change check to the Bazaar Search Window purchase mechanics (#4632) 2025-02-01 14:30:07 -06:00
Mitch Freeman 29701d0ea7 [Fix] Update the shard bazaar search feature (#4630) 2025-02-01 13:36:26 -06:00
Mitch Freeman 4a38fd8829 [Fix] NewBazaar Search Consumables (#4631) 2025-02-01 13:35:08 -06:00
Chris Miles 08c8e0d81f [Performance] Significantly Improve Client Network Resends (#4629)
* [Performance] Significantly Improve Client Network Resends

* Update daybreak_connection.cpp

* Improve resend algorithm to be exact about when to resend
2025-01-31 22:23:08 -06:00
Chris Miles c966f26ac1 [Release] 22.62.1 (#4627) 2025-01-27 16:36:51 -06:00
Akkadius fe66c24352 Revert "[Memory Leak] Change raw pointer to unique_ptr to avoid potential leak in dbg stream (#4616)"
This reverts commit 1f3ac2dc4f.
2025-01-27 16:34:05 -06:00
Chris Miles bdcded7d45 [Performance] Re-use OP_PlayerStateAdd packet memory (#4626) 2025-01-27 15:33:03 -06:00
Chris Miles f939f25aa1 [Performance] Re-use OP_Damage packet memory (#4625) 2025-01-27 15:32:55 -06:00
Chris Miles 401f1038f3 [Performance] Re-use OP_SendFindableNPCs packet memory (#4623) 2025-01-27 15:32:48 -06:00
Chris Miles 95c6560e7c [Performance] Re-use OP_HPUpdate packet memory (#4622) 2025-01-27 15:32:40 -06:00
Chris Miles 59f645b5c3 [Performance] Re-use OP_Animation packet (#4621) 2025-01-27 15:32:30 -06:00
Chris Miles bbfed8300c [Repop] Make #repop instant (#4620) 2025-01-27 15:32:22 -06:00
Chris Miles 07c762068f [Performance] Re-use ClientUpdate packet memory (#4619) 2025-01-27 15:32:14 -06:00
dependabot[bot] 6525051d2d Bump golang.org/x/net in /utils/scripts/build/should-release (#4618)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.23.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.23.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-26 21:28:40 -06:00
Chris Miles b7f94e8315 [Release] 22.62.0 (#4617) 2025-01-26 21:26:34 -06:00
Chris Miles d1f368ab7f [Databuckets] Implement Nested Databuckets (#4604)
* WIP

* Fixes

* Fin

* Update data_bucket.cpp

* Update data_bucket.cpp

* Cleanup

* Update data_bucket.cpp

* Update data_bucket.cpp

* NESTED_KEY_DELIMITER
2025-01-26 21:13:31 -06:00
Alex 1f3ac2dc4f [Memory Leak] Change raw pointer to unique_ptr to avoid potential leak in dbg stream (#4616)
Co-authored-by: KimLS <KimLS@peqtgc.com>
2025-01-26 19:05:45 -06:00
Mitch Freeman 7a226ca4ef [Bazaar] Improve Bazaar Search Performance (#4615)
* Create Alternate BazaarSearch Routine

Establishes an alterative to the in memory bazaar search routine and instead uses a db query process.  For large Bazaars (with 1000s of items) this is much faster.  Testing with 30k items produced a search in ~1sec version 2.7sec for the in memory version.
Default is false - Do not use this version.

* Indexes for trader and items

* Set query-based bazaar search the default

* Update database_update_manifest.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-01-26 19:04:56 -06:00
Akkadius 119151c0e3 [Hotfix] Delete later in RemoveItem second case 2025-01-25 14:04:57 -06:00
Chris Miles faa8a492f7 [Memory Leak] Fix leak in Client::RemoveDuplicateLore (#4614) 2025-01-24 13:22:58 -05:00
Chris Miles 2926b4df78 [Memory Leak] Fix memory leak in Client::Handle_OP_MoveMultipleItems (#4613)
* [Memory Leak] Fix memory leak in Client::Handle_OP_MoveMultipleItems

* Update client_packet.cpp
2025-01-24 02:59:08 -06:00
Chris Miles 986eda44aa [Memory Leak] Fix leaks in Client::Handle_OP_AugmentItem (#4612)
* [Memory Leak] Fix leaks in Client::Handle_OP_AugmentItem

* Update client_packet.cpp
2025-01-24 02:58:58 -06:00
Chris Miles b2f71f16fc [Memory Leak] Fix leak in NPC::RemoveItem (#4611)
* [Memory Leak] Fix leak in NPC::RemoveItem

* Update loot.cpp
2025-01-24 03:10:06 -05:00
Chris Miles 861eac3660 [Memory Leak] Fix leak in QuestManager::varlink (#4610) 2025-01-24 02:56:22 -05:00
Chris Miles a376bc4471 [Memory Leak] Fix leak in BuyTraderItemOutsideBazaar (#4609) 2025-01-24 02:56:15 -05:00
Mitch Freeman e83d0942ad [Fix] Repair levers opening the Evolving XP Transfer Window (#4607) 2025-01-22 18:55:21 -06:00
catapultam-habeo 31abaf8016 [Feature] Implement Custom Pet Names (#4594)
* rebase\tidy up to address commends

* I blame git for this one

* last typo

* spaces

* formating fixes I think?

* Repository fixes

* Cleanup

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-01-22 03:31:05 -06:00
Chris Miles 0acad18067 [CLI] Add --skip-backup to world database:updates (#4605) 2025-01-21 19:11:58 -06:00
Akkadius 90c37390f1 [Hotfix] CLI help menu from parsing correctly in World 2025-01-21 18:48:02 -06:00
Akkadius dba494cd8e [Hotfix] Update database version to match manifest 2025-01-21 17:39:33 -06:00
Chris Miles 37ced4b003 [Databuckets] Add Account Scoped Databuckets (#4603)
* [Databuckets] Add Account Scoped Databuckets

* Add variation

* Fix Lua after testing
2025-01-21 16:06:18 -06:00
Chris Miles d13c725a74 [Linux] Implement KSM Kernel Samepage Merging with Maps (#4601)
* KSM work

* Windows fixes

* Add KSM logging, cleanup

* Cleanup raycast logging
2025-01-21 15:50:20 -06:00
Chris Miles 25826c6686 [Performance] Client / NPC Position Update Optimizations (#4602)
* Zone optimizations

* More changes

* More

* Update entity.cpp

* Beautiful

* Amazing

* Feature flag all logic

* Broadcast to group

* Update mob.cpp

* Updates

* Update client.cpp

* Update client.cpp

* Add rule Zone:EnableEntityClipping

* Little bit of cleanup

* Don't send update to self while in group

* Remove visibility work and feature flags

* Cleanup

* Logging

* Improve CheckSendBulkNpcPositions

* No need to cast

* Field cleanup

* Build initial list on zone-in
2025-01-21 15:35:19 -06:00
Akkadius 1a27127c39 [Hotfix] Fix query error in character_evolving_items 2025-01-20 23:21:37 -06:00
Alex King 75698a809f [Feature] Add Support for Item Previews (#4599)
* [Feature] Add Support for Item Previews

* Update client_packet.cpp
2025-01-19 19:18:17 -06:00
Mitch Freeman 37a7b7fc41 [Feature] Add Alternate Bazaar Search Approach (#4600)
* Add Alternate Bazaar Search

This adds an alternate bazaar search allowing multinstance bazaar searching and traders above 600.  Allows searches based on Bazaar Shard

* Update worldserver.cpp

---------

Co-authored-by: Mitch Freeman <neckkola@gmail.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-01-19 19:02:53 -06:00
Mitch Freeman f21cc170df [Feature] Evolving Item Support for RoF2 (#4496)
* basic evolving items framework created

* Implement evolving tab in the inventory window

* Implement experience and number of kills

* Move zone evolving map to a evolvingitemsmanager class

* rework gm commands

* rework GetInventory

* wip

* wip loot testing

* Fix Duplicate Message

* reworked evolving item looting, swapping, etc

* reworked const functions for evolving methods

* Functioning Player Trade of evolving items test item_id is 89550

* First pass of Final Result link working

* First pass of item upgrading when reaching 100%

* Add strings and logic for displaying the evolving item xp transfer window in Corathus

* Prototype of xp transfer window sending items

* WIP for evolve xp transfer

* WIP for evolve xp transfer.  First tests passed

* XP Transfer Cleanup

* XP Transfer Cleanup

* Add Rule for evolving items equip timer/  default is 30 secs

* Add logging and player events

Add logging and player events

* Formatting

* Database updates

* Updates for linux build

* Perl/Cleanup

* Command cleanup

* Lua

* Added a crash condition check if final item id is blank or not found.

* Review Changes

Updates to resolve review comments and a rebase.

* migrate to content_db for items_evolving_details

migrate to content_db for items_evolving_details

* Simplify, don't hit database unless evolving

* Update 2025_01_19_items_evolving_details.sql

* Update client.cpp

* Update manifest with items_evolving_details

* character_id vs char_id

* Remove _Struct from structs

* Remove license header in evolving.cpp

* Move evolving constants from eq_constants.h to evolving.h since it is more specific

* Update database_schema.h

* General cleanup

* Be more specific with `evolving_items` vs `evolving`

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-01-19 18:10:19 -06:00
Mitch Freeman d47bf687d0 [Fix] Update trader add/remove packets to limits for RoF2 (#4595)
* Update trader add/remove to limit for RoF2

Update trader add/remove to limit for RoF2

* Update for feedback

---------

Co-authored-by: Mitch Freeman <neckkola@gmail.com>
2025-01-19 16:37:09 -06:00
Alex King 035c51944f [Quest API] Add SetAAEXPPercentage to Perl/Lua (#4597) 2025-01-19 16:36:48 -06:00
Mitch Freeman c2ebc2540a [Fix] Update a few Bazaar RoF2 routines for memory leaks (#4592)
Memory leak repairs
2025-01-08 17:45:03 -06:00
Chris Miles c82f1b9afc [Zone] Implement zone player count sharding (#4536)
* [Zone] Implement zone player count sharding

* Update client.cpp

* Update database_instances.cpp

* You must request a shard change from the zone you are currently in.

* // zone sharding

* You cannot request a shard change while in combat.

* Query adjustment

* Use safe coords

* Changes

* Fixes to instance query

* Push

* Push

* Final push

* Update client.cpp

* Update eq_packet_structs.h

* Remove pick menu

* Comment

* Update character_data_repository.h

* Update zoning.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2025-01-08 17:41:16 -06:00
Mitch Freeman 15684567cf [Fix] Add Bazaar BulkSendTrader Limit for RoF2 (#4590)
Add Bazaar BulkSendTrader Limit
2025-01-08 13:28:44 -06:00
Mitch Freeman 533dc997fd [Fix] Repair a memory leak in #summonitem (#4591) 2025-01-07 23:50:34 -05:00
Chris Miles 03b30d5c7a [Database] Change npc_types walkspeed to be of type float (#4589)
* [Database] Change npc_types walkspeed to be of type float

* Update database_update_manifest.cpp
2025-01-07 14:46:32 -05:00
Mitch Freeman d89f9bdcc7 [Fix] Repair an incorrect safe_delete call memory leak. (#4588) 2025-01-07 00:01:49 -05:00
Chris Miles 490cffb5ea [Release] 22.61.0 (#4587) 2025-01-06 00:27:11 -06:00
Alex King d95b64e0b8 [Cleanup] Fix GM Flag Spell Restriction Bypasses (#4571)
* [Cleanup] Fix GM Flag Spell Restriction Bypasses

* Update spells.cpp
2025-01-06 00:18:25 -06:00
Alex King 1ed282f6ff [Inventory] Add GetInventorySlots() Method (#4566)
* [Inventory] Add GetInventorySlots() Method

* Update client.cpp

* Push
2025-01-05 23:48:39 -06:00
Chris Miles a3a498634f [Maps] Fix broken Map MMFS implementation (#4576) 2025-01-05 23:48:09 -06:00
Chris Miles c44596b38a [Network] Prune / disconnect TCP connections gracefully (#4574) 2025-01-05 23:48:00 -06:00
Mitch Freeman fe43d26dd6 [Fix] Guild creation to propagate across zones (#4575)
Fix guild creation to propagate across zones
2025-01-05 23:47:22 -06:00
Chris Miles 3155b82abb [Command] Fix #copycharacter (#4582)
* [Command] Fix #copycharacter

* Update copy_character.cpp
2025-01-05 23:46:59 -06:00
Chris Miles 4c6aaa6995 [Logs] Improve Crash log defaults (#4579) 2025-01-05 23:46:43 -06:00
Mitch Freeman c82dee575a [Fix] Guild Membership Update Fix (#4581)
When the guild membership was large (1k+) the client would studder for half a sec when a guild member would login or logout.  This was reproduceable with a guild size of 2k members though floor would be client dependent most likely.
2025-01-05 23:46:19 -06:00
Mitch Freeman 33db85f2ee [Fix] Repair a EQEMUConfig Memory Leak (#4584)
Co-authored-by: Mitch Freeman <neckkola@gmail.com>
2025-01-05 23:45:28 -06:00
Mitch Freeman b40e4ce7cd [Fix] Repair a memory leak in GuildsList (#4585)
There was a leak generated when sending the GuildsList

Co-authored-by: Mitch Freeman <neckkola@gmail.com>
2025-01-05 23:45:09 -06:00
Mitch Freeman 20ff325013 [Fix] Repair a LoadNPCEmote MemoryLeak (#4586) 2025-01-05 23:44:51 -06:00
Chris Miles 8a7d5e72cb [Filesystem] Path Manager Improvements (#4557)
* [Filesystem] Path Manager Improvements

* Update path_manager.cpp

* Use native fs path building syntax
2025-01-05 23:44:16 -06:00
Mitch Freeman 4493ebebab [Bug Fix] Resolve a client crash when logging in or zoning (#4572) 2024-12-14 14:27:43 -05:00
Alex King 77793f364e [Commands] Add #find bot Subcommand (#4563)
* [Commands] Add #find bot Subcommand

* Update find.cpp

* Update find.cpp
2024-12-12 16:55:33 -06:00
Alex King e258aaa068 [Bug Fix] Allow Items in ROF2 to Stack to 32,767 (#4556)
* [Bug Fix] Allow Items in ROF2 to Stack to 32,767

* Update rof2.cpp
2024-12-12 16:39:38 -06:00
Paul Johnson 3b779ef301 [Rules] Add rules for requiring custom files from client (#4561)
* rules for enabling requiring custom files

* shorten default

* variable name

* check account status for enforcing client key

* rule for custom files admin level

---------

Co-authored-by: Paul Johnson <Paul@pjohnsomac-6366.digi.box>
2024-12-12 01:47:50 -06:00
Alex King 3f3c0f2fda [Commands] Add #find ldon_theme Subcommand (#4564) 2024-12-12 01:27:25 -06:00
Alex King 0f164c456e [Cleanup] Remove Unused Group Methods (#4559) 2024-12-12 01:25:36 -06:00
Mitch Freeman 6172c49b08 [Feature] Enable bazaar window 'Find Trader' functionality (#4560)
* First pass to enable trader 'Find Trader' functionality

* Move SendBulkTraders out of zoning routines and send as part of the opening of the bazaar search window.
Add zone instance to SendBulkTraders to support multi-instanced bazaars.
2024-12-12 01:25:12 -06:00
Chris Miles 66a7dd0143 [Databuckets] Improved Reliability and Performance of Databuckets (#4562)
* [Databuckets] Don't broadcast client-scoped updates

* Remove temp feature flag

* Remove distributed caching, only cache for character scoped data, simplify

* Update bot.cpp

* Cleanup

* Update data_bucket.cpp

* Cleanup

* Cleanup

* Remove BulkLoadEntities from LoadNPCTypes

* Update data_bucket.cpp

* Cleanup

* More cleanup

* More cleanup

* BulkLoadEntities to BulkLoadEntitiesToCache

* Add CanCache in DeleteData to gate an unnecessary call
2024-12-12 01:17:08 -06:00
Alex King 5c6e7a8b09 [Cleanup] Convert Event Parses to Single Line (#4569)
* [Cleanup] Convert Event Parses to Single Line

* Push

* Update spells.cpp

* Update spells.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-12-12 00:43:22 -06:00
dependabot[bot] bd85fc96a0 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#4570)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.31.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 00:17:28 -06:00
nytmyr 8e40e5357c [Bots] Fix AA ranks to account for level (#4567)
Previously level requirement was only being checked on the initial rank of an AA. If passed, bots would gain all ranks for that AA regardless of level, this will now check for the level requirement for each rank before granting the AA
2024-12-06 23:58:11 -05:00
nytmyr 5f0b999ca9 [Groups] Fix AmIMainAssist incorrectly checking for MainTankName (#4565) 2024-12-04 16:04:34 -05:00
Alex King fe9df46a24 [Bug Fix] Fix EVENT_COMBAT on NPC Death (#4558) 2024-11-27 20:30:29 -05:00
Alex King 3d7cf4235c [Release] 22.60.0 (#4555) 2024-11-25 17:17:03 -06:00
hg 187ee10218 [Tasks] Update tasks in all zones if invalid zone set (#4550)
This allows task elements to update in any zone when it has an invalid
zone id <= 0. This has the same effect as leaving the zones field empty
except "Unknown Zone" instead of "ALL" will be shown in task windows.

Note that Titanium shows "ALL" for a zone id of 0 despite it being an
invalid zone id. This could be manipulated server side to match newer
clients but there isn't much benefit since any other invalid zone id
below 0 can be used to do the same.
2024-11-25 18:02:14 -05:00
Alex King 6bd758b3dd [Rules] Add Rule to Disable NPCs Facing Target (#4543) 2024-11-24 17:30:44 -06:00
Alex King 9938755517 [Bug Fix] Fix Possible Item Loss in Trades (#4554) 2024-11-24 17:29:27 -06:00
Chris Miles 630da0eee6 [Config] Fix World TCP Address Configuration Default (#4551) 2024-11-24 17:27:31 -06:00
Alex King 3158386aa3 [Bug Fix] Fix Issue with Perl EVENT_PAYLOAD (#4545) 2024-11-24 17:19:40 -06:00
hg 12ada57ee8 [Code] Fix build with older C++ libraries (#4549)
This adds a compile time concept to determine if from_chars has
floating-point support and uses fallbacks if not.

This is a C++17 feature but support for floats was only added to
libstdc++ with GCC 11.1 and LLVM libc++ in 20.0 (unreleased).
2024-11-24 17:18:36 -06:00
Mitch Freeman 7a841c11c5 [Bug Fix] Players could become flagged as a Trader when they were not trading (#4553) 2024-11-24 17:17:01 -06:00
Mitch Freeman a49d1446b7 [Bug Fix] Fix for sending money via Parcel, then changing your mind (#4552) 2024-11-24 17:15:18 -06:00
carolus21rex b2d0fa6a2f [Bug Fix] Fix Strings::Commify bug with #mystats (#4547)
* Fix a formatting bug with #mystats

When using values larger than 1,000, we were calling commify on a string that already had commas. This resulted in the value 1005 looking like 1,,005.

* Update mob.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-11-22 16:23:48 -05:00
Mitch Freeman 62ac015fff [Bug Fix] Fix an edge case with augmented items inside parceled containers (#4546) 2024-11-20 21:17:04 -05:00
Mitch Freeman 4977a7c2e0 [Bazaar] Further refinements for instanced bazaar (#4544)
Resolves
- Parcels being delivered with incorrect item
- Inspecting an item from the bazaar window showing the incorrect item
2024-11-16 15:14:17 -06:00
Mitch Freeman 9967384ab8 [Fix] Fix for mult-instanced bazaar zones (#4541)
* Enable bazaar for multiple instances.

* Enable buyer for multiple instances.

* Update to buyer/barter for multiple instances and attuned items.
2024-11-14 19:44:03 -06:00
Mitch Freeman d3da2e5501 [Fix] Fix for bazaar search of containers. (#4540) 2024-11-14 19:32:19 -06:00
Chris Miles 33f5c4c6a7 [Bug Fix] Fix issue where NPC's are being hidden as traders (#4539)
* [Fix] Fix issue where NPC's are being hidden as traders

* Fix

* Update mob.cpp
2024-11-14 19:15:03 -05:00
Akkadius e4aa6a6957 [Release] 22.59.1 2024-11-13 20:52:46 -06:00
Chris Miles e4d812f4b4 [Release] 22.59.0 (#4538) 2024-11-13 20:08:03 -06:00
hg bcedfe7032 [Quest API] Add Native Database Querying Interface (#4531)
* Add database quest API

API functions are named to be similar to LuaSQL and perl DBI

New connections are made for Database objects. These can either use
credentials from the server eqemu_config or manual connections.

* Add option to use zone db connections
2024-11-12 20:01:18 -06:00
Paul Johnson c1df3fbcb0 [Rules] Add Rule for restricting client versions to world server (#4527)
* add rule for supported clients, unsupported client packet

* whitespace

* PR feedback - Update client.cpp

* PR Feedback - Update client.cpp

* Update client.cpp

* Update client.cpp

---------

Co-authored-by: Paul Johnson <Paul@PJOHNSOMAC-6366.digi.box>
2024-11-12 11:00:22 -05:00
Akkadius 011e1d05e7 [Hotfix] Check if the mob is already in the close mobs list before inserting 2024-11-10 23:19:40 -06:00
Akkadius 3f0f95976c [Hotfix] ScanCloseMobs - Ensure scanning mob has an entity ID 2024-11-10 06:47:42 -06:00
Chris Miles 77de9619b5 [Databuckets] Add database index to data_buckets (#4535)
* [Databuckets] Add database index to data_buckets

* Update database_update_manifest.cpp
2024-11-08 22:26:00 -05:00
Mitch Freeman 20d3ab2ac5 [Bug Fix] Bazaar two edge case issues resolved (#4533)
This update resolves two bazaar issues that have been reported.
- If parcel delivery is used to purchase an item, and the seller has several of the same items, that have various charges, the item would not be removed from the db.  This allowed for incorrect purchases.
- If a player 'reclaims' an alt currency item that they also have for sale with an active trader,  the item would remain for sale, and be reclaimed.  This impacted custom alt currency items that were no trade.
2024-11-08 22:15:12 -05:00
Chris Miles 0ea47fadee [Performance] Improvements to ScanCloseMobs logic (#4534)
* [Performance] Minor improvements to ScanCloseMobs

* Remove timer checks one level up to reduce branching

* Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
2024-11-08 17:48:39 -06:00
Chris Miles 1ce51ca3b0 [Release] 22.58.0 (#4532) 2024-11-05 22:02:32 -06:00
hg 25ef3d2cdb [Code] Update perlbind to 1.1.0 (#4529)
- Adds a perl::ref alias for perl::reference

- Optimizes array return pushes by accessing SV* values directly instead
  of using operator[] scalar_proxy

- Allows functions with a perl::hash parameter to accept hashes with any
  scalar key type instead of requiring explicit string keys

  e.g., foo(123 => 1) will now work on functions accepting a perl::hash
2024-11-05 20:14:29 -06:00
hg 95249889a6 [Code] Add mysql prepared statement support (#4530)
This adds support for using prepared statements for MySQL queries. It is
intended for use in a database quest API but it can be used in source
with some caveats:

 - It uses exceptions for error handling instead of returning a fake
   result that needs checked. Usage must be wrapped in try/catch.

 - DBcore has a connection mutex which indicates the connection might be
   shared with other threads. This mutex is locked for certain stmt
   operations in an attempt to make it safe to use with multi threaded
   connections.

 - Prepared statements should only be used on the main thread since the
   internal logging is not synchronized.

 - Unlike the current query API which retrieves all results as strings,
   results are stored in buffers that represent the db field type.
   Getter functions are available to retrieve values as desired types.
2024-11-05 20:12:17 -06:00
mmcgarvey 428cccfa50 [Feature] Focus Skill Attack Spells (#4528)
* Add Rule Spells:AllowFocusOnSkillDamageSpells

* Currently, focus mods defaults to 0 when processing spell effect 193.
* The default value for this rule is false.
* When false, the rule will retain the current default behavior.
* When true, the aforementioned focus effects will allow focus effects (185, 459, and 482) to modify spell effect 193.

* Removed undesirable whitespace

* Update spell_effects.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-10-31 08:13:16 -04:00
Alex King 41dd8a5754 [Quest API] Add Spawn Circle/Grid Methods to Perl/Lua (#4524)
* [Quest API] Add Spawn Circle/Grid Methods to Perl/Lua

* Update lua_general.cpp

* Update questmgr.cpp

* Update questmgr.cpp
2024-10-23 23:40:25 -04:00
Alex King d02d766563 [Bug Fix] Fix cross_zone_set_entity_variable_by_char_id in Lua (#4526) 2024-10-23 22:47:02 -04:00
Alex King dfd2729b28 [Bug Fix] Add Missing Lua Registers (#4525) 2024-10-23 22:37:21 -04:00
Chris Miles b92eafd21b [Release] 22.57.1 (#4523) 2024-10-22 00:02:14 -05:00
nytmyr d6d5d992cb [Bots] Fix pet buffs from saving duplicates every save (#4520)
* [Bots] Fix pet buffs from saving duplicates every save

Previously we were not checking the pet index properly when clearing buffs in the database before saving which resulted in no prior data being deleted.

This corrects the logic for the save and also will clean up any buffs for pets that don't exist in the table.

* Changes

* Update world_boot.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-10-21 23:57:42 -05:00
Alex King d524cb6a5a [Bots] Enable Bot Commands Only if Rule Enabled (#4519) 2024-10-21 23:49:36 -05:00
Alex e6469878ce [Loginserver] Automatifc Opcode File Creation (#4521)
* Loginserver will auto create the opcodes file if it doesn't exist on load.

* Use path manager in login opcodes.

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
2024-10-21 23:48:43 -05:00
Chris Miles 9583099ace [Release] 22.57.0 (#4517) 2024-10-20 16:17:15 -05:00
nytmyr cf3483b402 [Bots] Fix timers loading on spawn and zone (#4516)
Timers were not properly checking their expiration time on spawn and load and could cause invalid timers to load if the server was restarted resulting in improper lockouts.
2024-10-20 10:44:30 -04:00
carolus21rex 311af7bbe9 [Cleanup] Fixed a typo in Zoning.cpp (#4515)
* Fixed a typo in Zoning.cpp changed reguest to request.

* Update zoning.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2024-10-19 21:59:10 -04:00
228 changed files with 11279 additions and 9599 deletions
+1
View File
@@ -68,3 +68,4 @@ compile_flags.txt
# CMake Files
cmake-build-relwithdebinfo/*
skill-caps.diff
+319
View File
@@ -1,3 +1,322 @@
## [22.62.2] 2/1/2025
### Fixes
* Add price change check to the Bazaar Search Window purchase mechanics ([#4632](https://github.com/EQEmu/Server/pull/4632)) @neckkola 2025-02-01
* NewBazaar Search Consumables ([#4631](https://github.com/EQEmu/Server/pull/4631)) @neckkola 2025-02-01
* Update the shard bazaar search feature ([#4630](https://github.com/EQEmu/Server/pull/4630)) @neckkola 2025-02-01
### Memory Leak
* Revert " Change raw pointer to unique_ptr to avoid potential leak in dbg stream " ([#4616](https://github.com/EQEmu/Server/pull/4616)) @Akkadius 2025-01-27
### Performance
* Significantly Improve Client Network Resends ([#4629](https://github.com/EQEmu/Server/pull/4629)) @Akkadius 2025-02-01
## [22.62.1] 1/27/2025
### Memory Leak
* Revert "Change raw pointer to unique_ptr to avoid potential leak in dbg stream" ([#4616](https://github.com/EQEmu/Server/pull/4616)) @Akkadius 2025-01-27
### Performance
* Re-use ClientUpdate packet memory ([#4619](https://github.com/EQEmu/Server/pull/4619)) @Akkadius 2025-01-27
* Re-use OP_Animation packet ([#4621](https://github.com/EQEmu/Server/pull/4621)) @Akkadius 2025-01-27
* Re-use OP_Damage packet memory ([#4625](https://github.com/EQEmu/Server/pull/4625)) @Akkadius 2025-01-27
* Re-use OP_HPUpdate packet memory ([#4622](https://github.com/EQEmu/Server/pull/4622)) @Akkadius 2025-01-27
* Re-use OP_PlayerStateAdd packet memory ([#4626](https://github.com/EQEmu/Server/pull/4626)) @Akkadius 2025-01-27
* Re-use OP_SendFindableNPCs packet memory ([#4623](https://github.com/EQEmu/Server/pull/4623)) @Akkadius 2025-01-27
### Repop
* Make #repop instant ([#4620](https://github.com/EQEmu/Server/pull/4620)) @Akkadius 2025-01-27
## [22.62.0] 1/26/2025
### Bazaar
* Improve Bazaar Search Performance ([#4615](https://github.com/EQEmu/Server/pull/4615)) @neckkola 2025-01-27
### CLI
* Add --skip-backup to world database:updates ([#4605](https://github.com/EQEmu/Server/pull/4605)) @Akkadius 2025-01-22
### Database
* Change npc_types walkspeed to be of type float ([#4589](https://github.com/EQEmu/Server/pull/4589)) @Akkadius 2025-01-07
### Databuckets
* Add Account Scoped Databuckets ([#4603](https://github.com/EQEmu/Server/pull/4603)) @Akkadius 2025-01-21
* Implement Nested Databuckets ([#4604](https://github.com/EQEmu/Server/pull/4604)) @Akkadius 2025-01-27
### Feature
* Add Alternate Bazaar Search Approach ([#4600](https://github.com/EQEmu/Server/pull/4600)) @neckkola 2025-01-20
* Add Support for Item Previews ([#4599](https://github.com/EQEmu/Server/pull/4599)) @Kinglykrab 2025-01-20
* Evolving Item Support for RoF2 ([#4496](https://github.com/EQEmu/Server/pull/4496)) @neckkola 2025-01-20
* Implement Custom Pet Names ([#4594](https://github.com/EQEmu/Server/pull/4594)) @catapultam-habeo 2025-01-22
### Fixes
* Add Bazaar BulkSendTrader Limit for RoF2 ([#4590](https://github.com/EQEmu/Server/pull/4590)) @neckkola 2025-01-08
* CLI help menu from parsing correctly in World @Akkadius 2025-01-22
* Delete later in RemoveItem second case @Akkadius 2025-01-25
* Fix query error in character_evolving_items @Akkadius 2025-01-21
* Repair a memory leak in #summonitem ([#4591](https://github.com/EQEmu/Server/pull/4591)) @neckkola 2025-01-08
* Repair an incorrect safe_delete call memory leak. ([#4588](https://github.com/EQEmu/Server/pull/4588)) @neckkola 2025-01-07
* Repair levers opening the Evolving XP Transfer Window ([#4607](https://github.com/EQEmu/Server/pull/4607)) @neckkola 2025-01-23
* Update a few Bazaar RoF2 routines for memory leaks ([#4592](https://github.com/EQEmu/Server/pull/4592)) @neckkola 2025-01-08
* Update database version to match manifest @Akkadius 2025-01-21
* Update trader add/remove packets to limits for RoF2 ([#4595](https://github.com/EQEmu/Server/pull/4595)) @neckkola 2025-01-19
### Linux
* Implement KSM Kernel Samepage Merging with Maps ([#4601](https://github.com/EQEmu/Server/pull/4601)) @Akkadius 2025-01-21
### Memory Leak
* Change raw pointer to unique_ptr to avoid potential leak in dbg stream ([#4616](https://github.com/EQEmu/Server/pull/4616)) @KimLS 2025-01-27
* Fix leak in BuyTraderItemOutsideBazaar ([#4609](https://github.com/EQEmu/Server/pull/4609)) @Akkadius 2025-01-24
* Fix leak in Client::RemoveDuplicateLore ([#4614](https://github.com/EQEmu/Server/pull/4614)) @Akkadius 2025-01-24
* Fix leak in NPC::RemoveItem ([#4611](https://github.com/EQEmu/Server/pull/4611)) @Akkadius 2025-01-24
* Fix leak in QuestManager::varlink ([#4610](https://github.com/EQEmu/Server/pull/4610)) @Akkadius 2025-01-24
* Fix leaks in Client::Handle_OP_AugmentItem ([#4612](https://github.com/EQEmu/Server/pull/4612)) @Akkadius 2025-01-24
* Fix memory leak in Client::Handle_OP_MoveMultipleItems ([#4613](https://github.com/EQEmu/Server/pull/4613)) @Akkadius 2025-01-24
### Performance
* Client / NPC Position Update Optimizations ([#4602](https://github.com/EQEmu/Server/pull/4602)) @Akkadius 2025-01-21
### Quest API
* Add SetAAEXPPercentage to Perl/Lua ([#4597](https://github.com/EQEmu/Server/pull/4597)) @Kinglykrab 2025-01-19
### Zone
* Implement zone player count sharding ([#4536](https://github.com/EQEmu/Server/pull/4536)) @Akkadius 2025-01-08
## [22.61.0] 1/6/2025
### Bots
* Fix AA ranks to account for level ([#4567](https://github.com/EQEmu/Server/pull/4567)) @nytmyr 2024-12-07
### Code
* Convert Event Parses to Single Line ([#4569](https://github.com/EQEmu/Server/pull/4569)) @Kinglykrab 2024-12-12
* Fix GM Flag Spell Restriction Bypasses ([#4571](https://github.com/EQEmu/Server/pull/4571)) @Kinglykrab 2025-01-06
* Remove Unused Group Methods ([#4559](https://github.com/EQEmu/Server/pull/4559)) @Kinglykrab 2024-12-12
### Commands
* Add #find bot Subcommand ([#4563](https://github.com/EQEmu/Server/pull/4563)) @Kinglykrab 2024-12-12
* Add #find ldon_theme Subcommand ([#4564](https://github.com/EQEmu/Server/pull/4564)) @Kinglykrab 2024-12-12
* Fix #copycharacter ([#4582](https://github.com/EQEmu/Server/pull/4582)) @Akkadius 2025-01-06
### Databuckets
* Improved Reliability and Performance of Databuckets ([#4562](https://github.com/EQEmu/Server/pull/4562)) @Akkadius 2024-12-12
### Feature
* Enable bazaar window 'Find Trader' functionality ([#4560](https://github.com/EQEmu/Server/pull/4560)) @neckkola 2024-12-12
### Filesystem
* Path Manager Improvements ([#4557](https://github.com/EQEmu/Server/pull/4557)) @Akkadius 2025-01-06
### Fixes
* Allow Items in ROF2 to Stack to 32,767 ([#4556](https://github.com/EQEmu/Server/pull/4556)) @Kinglykrab 2024-12-12
* Fix EVENT_COMBAT on NPC Death ([#4558](https://github.com/EQEmu/Server/pull/4558)) @Kinglykrab 2024-11-28
* Guild Membership Update Fix ([#4581](https://github.com/EQEmu/Server/pull/4581)) @neckkola 2025-01-06
* Guild creation to propagate across zones ([#4575](https://github.com/EQEmu/Server/pull/4575)) @neckkola 2025-01-06
* Repair a EQEMUConfig Memory Leak ([#4584](https://github.com/EQEmu/Server/pull/4584)) @neckkola 2025-01-06
* Repair a LoadNPCEmote MemoryLeak ([#4586](https://github.com/EQEmu/Server/pull/4586)) @neckkola 2025-01-06
* Repair a memory leak in GuildsList ([#4585](https://github.com/EQEmu/Server/pull/4585)) @neckkola 2025-01-06
* Resolve a client crash when logging in or zoning ([#4572](https://github.com/EQEmu/Server/pull/4572)) @neckkola 2024-12-14
### Groups
* Fix AmIMainAssist incorrectly checking for MainTankName ([#4565](https://github.com/EQEmu/Server/pull/4565)) @nytmyr 2024-12-04
### Inventory
* Add GetInventorySlots() Method ([#4566](https://github.com/EQEmu/Server/pull/4566)) @Kinglykrab 2025-01-06
### Logs
* Improve Crash log defaults ([#4579](https://github.com/EQEmu/Server/pull/4579)) @Akkadius 2025-01-06
### Maps
* Fix broken Map MMFS implementation ([#4576](https://github.com/EQEmu/Server/pull/4576)) @Akkadius 2025-01-06
### Network
* Prune / disconnect TCP connections gracefully ([#4574](https://github.com/EQEmu/Server/pull/4574)) @Akkadius 2025-01-06
### Rules
* Add rules for requiring custom files from client ([#4561](https://github.com/EQEmu/Server/pull/4561)) @knervous 2024-12-12
## [22.60.0] 11/25/2024
### Bazaar
* Further refinements for instanced bazaar ([#4544](https://github.com/EQEmu/Server/pull/4544)) @neckkola 2024-11-16
### Code
* Fix build with older C++ libraries ([#4549](https://github.com/EQEmu/Server/pull/4549)) @hgtw 2024-11-24
### Config
* Fix World TCP Address Configuration Default ([#4551](https://github.com/EQEmu/Server/pull/4551)) @Akkadius 2024-11-24
### Fixes
* Fix Issue with Perl EVENT_PAYLOAD ([#4545](https://github.com/EQEmu/Server/pull/4545)) @Kinglykrab 2024-11-24
* Fix Possible Item Loss in Trades ([#4554](https://github.com/EQEmu/Server/pull/4554)) @Kinglykrab 2024-11-24
* Fix Strings::Commify bug with #mystats ([#4547](https://github.com/EQEmu/Server/pull/4547)) @carolus21rex 2024-11-22
* Fix an edge case with augmented items inside parceled containers ([#4546](https://github.com/EQEmu/Server/pull/4546)) @neckkola 2024-11-21
* Fix for bazaar search of containers. ([#4540](https://github.com/EQEmu/Server/pull/4540)) @neckkola 2024-11-15
* Fix for mult-instanced bazaar zones ([#4541](https://github.com/EQEmu/Server/pull/4541)) @neckkola 2024-11-15
* Fix for sending money via Parcel, then changing your mind ([#4552](https://github.com/EQEmu/Server/pull/4552)) @neckkola 2024-11-24
* Fix issue where NPC's are being hidden as traders ([#4539](https://github.com/EQEmu/Server/pull/4539)) @Akkadius 2024-11-15
* Players could become flagged as a Trader when they were not trading ([#4553](https://github.com/EQEmu/Server/pull/4553)) @neckkola 2024-11-24
### Rules
* Add Rule to Disable NPCs Facing Target ([#4543](https://github.com/EQEmu/Server/pull/4543)) @Kinglykrab 2024-11-24
### Tasks
* Update tasks in all zones if invalid zone set ([#4550](https://github.com/EQEmu/Server/pull/4550)) @hgtw 2024-11-25
## [22.59.1] 11/13/2024
### Hotfix
* Fix faulty database migration condition with databuckets (9285)
## [22.59.0] 11/13/2024
### Databuckets
* Add database index to data_buckets ([#4535](https://github.com/EQEmu/Server/pull/4535)) @Akkadius 2024-11-09
### Fixes
* Bazaar two edge case issues resolved ([#4533](https://github.com/EQEmu/Server/pull/4533)) @neckkola 2024-11-09
* Check if the mob is already in the close mobs list before inserting @Akkadius 2024-11-11
* ScanCloseMobs - Ensure scanning mob has an entity ID @Akkadius 2024-11-10
### Performance
* Improvements to ScanCloseMobs logic ([#4534](https://github.com/EQEmu/Server/pull/4534)) @Akkadius 2024-11-08
### Quest API
* Add Native Database Querying Interface ([#4531](https://github.com/EQEmu/Server/pull/4531)) @hgtw 2024-11-13
### Rules
* Add Rule for restricting client versions to world server ([#4527](https://github.com/EQEmu/Server/pull/4527)) @knervous 2024-11-12
## [22.58.0] 11/5/2024
### Code
* Add mysql prepared statement support ([#4530](https://github.com/EQEmu/Server/pull/4530)) @hgtw 2024-11-06
* Update perlbind to 1.1.0 ([#4529](https://github.com/EQEmu/Server/pull/4529)) @hgtw 2024-11-06
### Feature
* Focus Skill Attack Spells ([#4528](https://github.com/EQEmu/Server/pull/4528)) @mmcgarvey 2024-10-31
### Fixes
* Add Missing Lua Registers ([#4525](https://github.com/EQEmu/Server/pull/4525)) @Kinglykrab 2024-10-24
* Fix cross_zone_set_entity_variable_by_char_id in Lua ([#4526](https://github.com/EQEmu/Server/pull/4526)) @Kinglykrab 2024-10-24
### Loginserver
* Automatifc Opcode File Creation ([#4521](https://github.com/EQEmu/Server/pull/4521)) @KimLS 2024-10-22
### Quest API
* Add Spawn Circle/Grid Methods to Perl/Lua ([#4524](https://github.com/EQEmu/Server/pull/4524)) @Kinglykrab 2024-10-24
## [22.57.1] 10/22/2024
### Bots
* Enable Bot Commands Only if Rule Enabled ([#4519](https://github.com/EQEmu/Server/pull/4519)) @Kinglykrab 2024-10-22
* Fix pet buffs from saving duplicates every save ([#4520](https://github.com/EQEmu/Server/pull/4520)) @nytmyr 2024-10-22
### Loginserver
* Automatic Opcode File Creation ([#4521](https://github.com/EQEmu/Server/pull/4521)) @KimLS 2024-10-22
## [22.57.0] 10/20/2024
### Bots
* Add "silent" option to ^spawn and mute raid spawn ([#4494](https://github.com/EQEmu/Server/pull/4494)) @nytmyr 2024-10-05
* Add attack flag when told to attack ([#4490](https://github.com/EQEmu/Server/pull/4490)) @nytmyr 2024-09-29
* Fix timers loading on spawn and zone ([#4516](https://github.com/EQEmu/Server/pull/4516)) @nytmyr 2024-10-20
### Code
* Fixed a typo in Zoning.cpp ([#4515](https://github.com/EQEmu/Server/pull/4515)) @carolus21rex 2024-10-20
* Optimization Code Cleanup ([#4489](https://github.com/EQEmu/Server/pull/4489)) @Akkadius 2024-09-30
* Remove Extra Skill in EQ::skills::GetExtraDamageSkills() ([#4486](https://github.com/EQEmu/Server/pull/4486)) @Kinglykrab 2024-10-03
### Crash
* Fixes a crash when the faction_list db table is empty. ([#4511](https://github.com/EQEmu/Server/pull/4511)) @KimLS 2024-10-14
### Fixes
* Add character_instance_safereturns to tables_to_zero_id ([#4485](https://github.com/EQEmu/Server/pull/4485)) @Morzain 2024-09-26
* Correctly limit max targets of PBAOE ([#4507](https://github.com/EQEmu/Server/pull/4507)) @catapultam-habeo 2024-10-11
* FindBestZ selecting false zone floor as bestz - Results in roambox failures ([#4504](https://github.com/EQEmu/Server/pull/4504)) @fryguy503 2024-10-13
* Fix #set motd Crash ([#4495](https://github.com/EQEmu/Server/pull/4495)) @Kinglykrab 2024-10-05
* Fix `character_exp_modifiers` Default Values ([#4502](https://github.com/EQEmu/Server/pull/4502)) @Kinglykrab 2024-10-09
* Fix a display error regarding a few trader/buyer query errors ([#4514](https://github.com/EQEmu/Server/pull/4514)) @neckkola 2024-10-17
* Fix Group ID 0 in Group::SaveGroupLeaderAA() ([#4487](https://github.com/EQEmu/Server/pull/4487)) @Kinglykrab 2024-10-03
* Fix Mercenary Encounter Crash ([#4509](https://github.com/EQEmu/Server/pull/4509)) @Kinglykrab 2024-10-12
* Fix NPC::CanTalk() Crash ([#4499](https://github.com/EQEmu/Server/pull/4499)) @Kinglykrab 2024-10-07
* Fix Spells:DefaultAOEMaxTargets Default Value ([#4508](https://github.com/EQEmu/Server/pull/4508)) @Kinglykrab 2024-10-12
* Fix Targeted AOE Max Targets Rule ([#4488](https://github.com/EQEmu/Server/pull/4488)) @Kinglykrab 2024-10-03
* fixed a bug where it would use npc value instead of faction value in the database. ([#4491](https://github.com/EQEmu/Server/pull/4491)) @regneq 2024-09-29
* Master of Disguise should apply to illusions casted by others. ([#4506](https://github.com/EQEmu/Server/pull/4506)) @fryguy503 2024-10-11
* Spells - Self Only (Yellow) cast when non group member is targeted ([#4503](https://github.com/EQEmu/Server/pull/4503)) @fryguy503 2024-10-11
### Loginserver
* Larion loginserver support ([#4492](https://github.com/EQEmu/Server/pull/4492)) @KimLS 2024-10-03
* Login Fatal Error Spamming ([#4476](https://github.com/EQEmu/Server/pull/4476)) @KimLS 2024-10-09
### Logs
* Add NPC Trades to Player Events ([#4505](https://github.com/EQEmu/Server/pull/4505)) @Kinglykrab 2024-10-13
### Quest API
* Add Buff Fade Methods to Perl/Lua ([#4501](https://github.com/EQEmu/Server/pull/4501)) @Kinglykrab 2024-10-09
* Add EVENT_READ_ITEM to Perl/Lua ([#4497](https://github.com/EQEmu/Server/pull/4497)) @Kinglykrab 2024-10-08
* Add NPC List Filter Methods to Perl/Lua ([#4493](https://github.com/EQEmu/Server/pull/4493)) @Kinglykrab 2024-10-04
* Add Scripting Support to Mercenaries ([#4500](https://github.com/EQEmu/Server/pull/4500)) @Kinglykrab 2024-10-11
### Rules
* Add Rule to disable PVP Regions ([#4513](https://github.com/EQEmu/Server/pull/4513)) @Kinglykrab 2024-10-17
## [22.56.3] 9/23/2024
### Fixes
+3
View File
@@ -37,6 +37,9 @@ IF(EQEMU_ADD_PROFILER)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed,-lprofiler,--as-needed")
ENDIF(EQEMU_ADD_PROFILER)
IF(USE_MAP_MMFS)
ADD_DEFINITIONS(-DUSE_MAP_MMFS)
ENDIF (USE_MAP_MMFS)
IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+7 -5
View File
@@ -36,12 +36,14 @@
#include "../../common/file.h"
#include "../../common/events/player_event_logs.h"
#include "../../common/skill_caps.h"
#include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EvolvingItemsManager evolving_items_manager;
void ExportSpells(SharedDatabase *db);
void ExportSkillCaps(SharedDatabase *db);
+7 -5
View File
@@ -30,12 +30,14 @@
#include "../../common/repositories/base_data_repository.h"
#include "../../common/file.h"
#include "../../common/events/player_event_logs.h"
#include "../../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EvolvingItemsManager evolving_items_manager;
void ImportSpells(SharedDatabase *db);
void ImportSkillCaps(SharedDatabase *db);
+10 -13
View File
@@ -39,6 +39,7 @@ SET(common_sources
event_sub.cpp
events/player_event_logs.cpp
events/player_event_discord_formatter.cpp
evolving_items.cpp
expedition_lockout_timer.cpp
extprofile.cpp
discord/discord_manager.cpp
@@ -62,6 +63,7 @@ SET(common_sources
mutex.cpp
mysql_request_result.cpp
mysql_request_row.cpp
mysql_stmt.cpp
opcode_map.cpp
opcodemgr.cpp
packet_dump.cpp
@@ -96,6 +98,7 @@ SET(common_sources
json/json.hpp
json/jsoncpp.cpp
zone_store.cpp
memory/ksm.hpp
net/console_server.cpp
net/console_server_connection.cpp
net/crc32.cpp
@@ -111,8 +114,6 @@ SET(common_sources
net/websocket_server.cpp
net/websocket_server_connection.cpp
patches/patches.cpp
patches/larion.cpp
patches/larion_limits.cpp
patches/sod.cpp
patches/sod_limits.cpp
patches/sof.cpp
@@ -173,6 +174,7 @@ SET(repositories
repositories/base/base_character_currency_repository.h
repositories/base/base_character_data_repository.h
repositories/base/base_character_disciplines_repository.h
repositories/base/base_character_evolving_items_repository.h
repositories/base/base_character_expedition_lockouts_repository.h
repositories/base/base_character_exp_modifiers_repository.h
repositories/base/base_character_inspect_messages_repository.h
@@ -241,6 +243,7 @@ SET(repositories
repositories/base/base_inventory_snapshots_repository.h
repositories/base/base_ip_exemptions_repository.h
repositories/base/base_items_repository.h
repositories/base/base_items_evolving_details_repository.h
repositories/base/base_ldon_trap_entries_repository.h
repositories/base/base_ldon_trap_templates_repository.h
repositories/base/base_level_exp_mods_repository.h
@@ -356,6 +359,7 @@ SET(repositories
repositories/character_currency_repository.h
repositories/character_data_repository.h
repositories/character_disciplines_repository.h
repositories/character_evolving_items_repository.h
repositories/character_expedition_lockouts_repository.h
repositories/character_exp_modifiers_repository.h
repositories/character_inspect_messages_repository.h
@@ -424,6 +428,7 @@ SET(repositories
repositories/inventory_snapshots_repository.h
repositories/ip_exemptions_repository.h
repositories/items_repository.h
repositories/items_evolving_details_repository.h
repositories/ldon_trap_entries_repository.h
repositories/ldon_trap_templates_repository.h
repositories/level_exp_mods_repository.h
@@ -556,6 +561,7 @@ SET(common_headers
events/player_event_discord_formatter.h
events/player_events.h
event_sub.h
evolving_items.h
expedition_lockout_timer.h
extprofile.h
faction.h
@@ -588,6 +594,7 @@ SET(common_headers
mutex.h
mysql_request_result.h
mysql_request_row.h
mysql_stmt.h
op_codes.h
opcode_dispatch.h
opcodemgr.h
@@ -655,11 +662,7 @@ SET(common_headers
net/websocket_server.h
net/websocket_server_connection.h
patches/patches.h
patches/larion.h
patches/larion_limits.h
patches/larion_ops.h
patches/larion_structs.h
patches/sod.h
patches/sod.h
patches/sod_limits.h
patches/sod_ops.h
patches/sod_structs.h
@@ -745,10 +748,6 @@ SOURCE_GROUP(Net FILES
SOURCE_GROUP(Patches FILES
patches/patches.h
patches/larion.h
patches/larion_limits.h
patches/larion_ops.h
patches/larion_structs.h
patches/sod.h
patches/sod_limits.h
patches/sod_ops.h
@@ -777,8 +776,6 @@ SOURCE_GROUP(Patches FILES
patches/uf_ops.h
patches/uf_structs.h
patches/patches.cpp
patches/larion.cpp
patches/larion_limits.cpp
patches/sod.cpp
patches/sod_limits.cpp
patches/sof.cpp
-1
View File
@@ -59,7 +59,6 @@ public:
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
void WriteUInt64(uint64 value) { *(uint64 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint64); }
void WriteSInt16(int32 value) { *(int16*)(pBuffer + _wpos) = value; _wpos += sizeof(int16); }
void WriteUInt16(uint32 value) { *(uint16 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint16); }
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
+262 -288
View File
@@ -6,15 +6,17 @@
std::vector<BazaarSearchResultsFromDB_Struct>
Bazaar::GetSearchResults(
SharedDatabase &db,
Database &db,
Database &content_db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
uint32 char_zone_id,
int32 char_zone_instance_id
)
{
LogTrading(
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
"search_scope [{}] char_zone_id [{}]",
"search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]",
search.item_name,
search.min_cost,
search.max_cost,
@@ -26,26 +28,173 @@ Bazaar::GetSearchResults(
search.trader_entity_id,
search.trader_id,
search.search_scope,
char_zone_id
char_zone_id,
char_zone_instance_id
);
std::string search_criteria_trader("TRUE ");
static std::map<uint8, uint32> item_slot_searches_new = {
{EQ::invslot::slotCharm, 1},
{EQ::invslot::slotEar1, 2},
{EQ::invslot::slotHead, 4},
{EQ::invslot::slotFace, 8},
{EQ::invslot::slotEar2, 16},
{EQ::invslot::slotNeck, 32},
{EQ::invslot::slotShoulders, 64},
{EQ::invslot::slotArms, 128},
{EQ::invslot::slotBack, 256},
{EQ::invslot::slotWrist1, 512},
{EQ::invslot::slotWrist2, 1024},
{EQ::invslot::slotRange, 2048},
{EQ::invslot::slotHands, 4096},
{EQ::invslot::slotPrimary, 8192},
{EQ::invslot::slotSecondary, 16384},
{EQ::invslot::slotFinger1, 32768},
{EQ::invslot::slotFinger2, 65536},
{EQ::invslot::slotChest, 131072},
{EQ::invslot::slotLegs, 262144},
{EQ::invslot::slotFeet, 524288},
{EQ::invslot::slotWaist, 1048576},
{EQ::invslot::slotPowerSource, 2097152},
{EQ::invslot::slotAmmo, 4194304},
};
struct ItemSearchType {
EQ::item::ItemType type;
std::string condition;
};
std::vector<ItemSearchType> item_search_types_new = {
{EQ::item::ItemType::ItemTypeBook, " AND (items.itemclass = 2 or items.itemclass = 31)"},
{EQ::item::ItemType::ItemTypeContainer, " AND (items.itemclass = 1 or items.itemclass = 67)"},
{EQ::item::ItemType::ItemTypeAllEffects, " AND (items.scrolleffect > 0 && items.scrolleffect < 65000)"},
{EQ::item::ItemType::ItemTypeUnknown9, " AND items.worneffect = 998"},
{EQ::item::ItemType::ItemTypeUnknown10, " AND (items.worneffect >= 1298 && items.worneffect <= 1307)"},
{EQ::item::ItemType::ItemTypeFocusEffect, " AND items.focuseffect > 0"},
{EQ::item::ItemType::ItemTypeArmor, " AND items.itemtype = 10"},
{EQ::item::ItemType::ItemType1HBlunt, " AND items.itemtype = 3"},
{EQ::item::ItemType::ItemType1HPiercing, " AND items.itemtype = 2"},
{EQ::item::ItemType::ItemType1HSlash, " AND items.itemtype = 0"},
{EQ::item::ItemType::ItemType2HBlunt, " AND items.itemtype = 4"},
{EQ::item::ItemType::ItemType2HSlash, " AND items.itemtype = 1"},
{EQ::item::ItemType::ItemTypeBow, " AND items.itemtype = 5"},
{EQ::item::ItemType::ItemTypeShield, " AND items.itemtype = 8"},
{EQ::item::ItemType::ItemTypeMisc, " AND items.itemtype = 11"},
{EQ::item::ItemType::ItemTypeFood, " AND items.itemtype = 14"},
{EQ::item::ItemType::ItemTypeDrink, " AND items.itemtype = 15"},
{EQ::item::ItemType::ItemTypeLight, " AND items.itemtype = 16"},
{EQ::item::ItemType::ItemTypeCombinable, " AND items.itemtype = 17"},
{EQ::item::ItemType::ItemTypeBandage, " AND items.itemtype = 18"},
{EQ::item::ItemType::ItemTypeSmallThrowing, " AND (items.itemtype = 19 OR items.itemtype = 7)"},
{EQ::item::ItemType::ItemTypeSpell, " AND items.itemtype = 20"},
{EQ::item::ItemType::ItemTypePotion, " AND items.itemtype = 21"},
{EQ::item::ItemType::ItemTypeBrassInstrument, " AND items.itemtype = 25"},
{EQ::item::ItemType::ItemTypeWindInstrument, " AND items.itemtype = 23"},
{EQ::item::ItemType::ItemTypeStringedInstrument, " AND items.itemtype = 24"},
{EQ::item::ItemType::ItemTypePercussionInstrument, " AND items.itemtype = 26"},
{EQ::item::ItemType::ItemTypeArrow, " AND items.itemtype = 27"},
{EQ::item::ItemType::ItemTypeJewelry, " AND items.itemtype = 29"},
{EQ::item::ItemType::ItemTypeNote, " AND items.itemtype = 32"},
{EQ::item::ItemType::ItemTypeKey, " AND items.itemtype = 33"},
{EQ::item::ItemType::ItemType2HPiercing, " AND items.itemtype = 35"},
{EQ::item::ItemType::ItemTypeAlcohol, " AND items.itemtype = 38"},
{EQ::item::ItemType::ItemTypeMartial, " AND items.itemtype = 45"},
{EQ::item::ItemType::ItemTypeAugmentation, " AND items.itemtype = 54"},
{EQ::item::ItemType::ItemTypeAlternateAbility, " AND items.itemtype = 57"},
{EQ::item::ItemType::ItemTypeCount, " AND items.itemtype = 65"},
{EQ::item::ItemType::ItemTypeCollectible, " AND items.itemtype = 66"}
};
// item stat searches
struct ItemStatSearch {
std::string query_string;
EQ::skills::SkillType skill_type;
};
std::map<uint32, ItemStatSearch> item_stat_searches_new = {
{STAT_AC, {" items.ac" , static_cast<EQ::skills::SkillType>(0)} },
{STAT_AGI, {" items.aagi", static_cast<EQ::skills::SkillType>(0)} },
{STAT_CHA, {" items.acha", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DEX, {" items.adex", static_cast<EQ::skills::SkillType>(0)} },
{STAT_INT, {" items.aint", static_cast<EQ::skills::SkillType>(0)} },
{STAT_STA, {" items.asta", static_cast<EQ::skills::SkillType>(0)} },
{STAT_STR, {" items.astr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_WIS, {" items.awis", static_cast<EQ::skills::SkillType>(0)} },
{STAT_COLD, {" items.cr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DISEASE, {" items.dr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_FIRE, {" items.fr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MAGIC, {" items.mr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_POISON, {" items.pr", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HP, {" items.hp", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MANA, {" items.mana", static_cast<EQ::skills::SkillType>(0)} },
{STAT_ENDURANCE, {" items.endur", static_cast<EQ::skills::SkillType>(0)} },
{STAT_ATTACK, {" items.attack", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HP_REGEN, {" items.regen", static_cast<EQ::skills::SkillType>(0)} },
{STAT_MANA_REGEN, {" items.manaregen", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HASTE, {" items.haste", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DAMAGE_SHIELD, {" items.damageshield", static_cast<EQ::skills::SkillType>(0)} },
{STAT_DS_MITIGATION, {" items.dsmitigation", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEAL_AMOUNT, {" items.healamt", static_cast<EQ::skills::SkillType>(0)} },
{STAT_SPELL_DAMAGE, {" items.spelldmg", static_cast<EQ::skills::SkillType>(0)} },
{STAT_CLAIRVOYANCE, {" items.clairvoyance", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_AGILITY, {" items.heroic_agi", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_CHARISMA, {" items.heroic_cha", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_DEXTERITY, {" items.heroic_dex", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_INTELLIGENCE, {" items.heroic_int", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_STAMINA, {" items.heroic_sta", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_STRENGTH, {" items.heroic_str", static_cast<EQ::skills::SkillType>(0)} },
{STAT_HEROIC_WISDOM, {" items.heroic_wis", static_cast<EQ::skills::SkillType>(0)} },
{STAT_BASH, {" items.skillmodvalue", EQ::skills::SkillBash} },
{STAT_BACKSTAB, {" items.backstabdmg", EQ::skills::SkillBackstab} },
{STAT_DRAGON_PUNCH, {" items.skillmodvalue", EQ::skills::SkillDragonPunch} },
{STAT_EAGLE_STRIKE, {" items.skillmodvalue", EQ::skills::SkillEagleStrike} },
{STAT_FLYING_KICK, {" items.skillmodvalue", EQ::skills::SkillFlyingKick} },
{STAT_KICK, {" items.skillmodvalue", EQ::skills::SkillKick} },
{STAT_ROUND_KICK, {" items.skillmodvalue", EQ::skills::SkillRoundKick} },
{STAT_TIGER_CLAW, {" items.skillmodvalue", EQ::skills::SkillTigerClaw} },
{STAT_FRENZY, {" items.skillmodvalue", EQ::skills::SkillFrenzy} },
};
bool convert = false;
std::string search_criteria_trader("TRUE");
std::string field_criteria_items("FALSE");
std::string where_criteria_items(" TRUE ");
if (search.search_scope == NonRoFBazaarSearchScope) {
search_criteria_trader.append(
fmt::format(
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
" AND trader.char_entity_id = {} AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
search.trader_entity_id,
Zones::BAZAAR
Zones::BAZAAR,
char_zone_instance_id
)
);
}
else if (search.search_scope == Local_Scope) {
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
search_criteria_trader.append(fmt::format(
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
char_zone_id,
char_zone_instance_id)
);
}
else if (search.trader_id > 0) {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (search.trader_id >= TraderRepository::TRADER_CONVERT_ID) {
convert = true;
search_criteria_trader.append(fmt::format(
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
Zones::BAZAAR,
search.trader_id - TraderRepository::TRADER_CONVERT_ID)
);
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
}
else {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
}
}
if (search.min_cost != 0) {
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
}
@@ -53,299 +202,124 @@ Bazaar::GetSearchResults(
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
}
// not yet implemented
// if (search.prestige != 0) {
// 0xffffffff prestige only, 0xfffffffe non-prestige, 0 all
// search_criteria.append(fmt::format(" AND items.type = {} ", search.prestige));
// }
if (search.slot != std::numeric_limits<uint32>::max()) {
if (item_slot_searches_new.contains(search.slot)) {
where_criteria_items.append(
fmt::format(" AND items.slots & {0} = {0}", item_slot_searches_new[search.slot]));
}
}
std::string query = fmt::format(
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 "
"FROM trader, character_data "
"WHERE {} AND trader.char_id = character_data.id "
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
search_criteria_trader.c_str()
);
if (search.type != std::numeric_limits<uint32>::max()) {
for (auto const &[type, condition]: item_search_types_new) {
if (type == search.type) {
where_criteria_items.append(condition);
break;
}
}
}
if (search.race != std::numeric_limits<uint32>::max()) {
where_criteria_items.append(
fmt::format(" AND items.races & {0} = {0}", GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race))));
}
if (search._class != std::numeric_limits<uint32>::max()) {
where_criteria_items.append(fmt::format(" AND items.classes & {0} = {0}", GetPlayerClassBit(search._class)));
}
if (search.item_stat != std::numeric_limits<uint32>::max()) {
if (item_stat_searches_new.contains(search.item_stat)) {
field_criteria_items = fmt::format("{}", item_stat_searches_new[search.item_stat].query_string);
if (item_stat_searches_new[search.item_stat].skill_type) {
where_criteria_items.append(
fmt::format(" AND items.skillmodtype = {} ", item_stat_searches_new[search.item_stat].skill_type));
}
else {
where_criteria_items.append(
fmt::format(" AND {} > 0 ", item_stat_searches_new[search.item_stat].query_string));
}
}
}
if (search.augment) {
where_criteria_items.append(fmt::format(
" AND (items.augslot1type = {0} OR "
"items.augslot2type = {0} OR "
"items.augslot3type = {0} OR "
"items.augslot4type = {0} OR "
"items.augslot5type = {0} OR "
"items.augslot6type = {0})",
search.augment)
);
}
if (search.min_level != 1) {
where_criteria_items.append(fmt::format(" AND items.reclevel >= {}", search.min_level));
}
if (search.max_level != 100) {
where_criteria_items.append(fmt::format(" AND items.reclevel <= {}", search.max_level));
}
std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
std::vector<std::string> trader_items_ids{};
auto results = db.QueryDatabase(query);
if (!results.Success()) {
auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader);
if (trader_results.empty()) {
LogTradingDetail("Bazaar - No traders found in bazaar search.");
return all_entries;
}
struct ItemSearchType {
EQ::item::ItemType type;
bool condition;
};
for (auto const &i: trader_results) {
trader_items_ids.push_back(std::to_string(i.trader.item_id));
}
struct AddititiveSearchCriteria {
bool should_check;
bool condition;
};
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
content_db,
trader_items_ids,
std::string(search.item_name),
field_criteria_items,
where_criteria_items
);
if (item_results.empty()) {
LogError("Bazaar - No items found in bazaar search.");
return all_entries;
}
all_entries.reserve(trader_results.size());
for (auto const& t:trader_results) {
if (!item_results.contains(t.trader.item_id)) {
continue;
}
for (auto row: results) {
BazaarSearchResultsFromDB_Struct r{};
r.count = 1;
r.trader_id = t.trader.char_id;
r.serial_number = t.trader.item_sn;
r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id;
r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable;
r.icon_id = item_results.at(t.trader.item_id).icon;
r.trader_zone_id = t.trader.char_zone_id;
r.trader_zone_instance_id = t.trader.char_zone_instance_id;
r.trader_entity_id = t.trader.char_entity_id;
r.serial_number_RoF = fmt::format("{:016}\0", t.trader.item_sn);
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
r.trader_name = fmt::format("{:.63}\0", t.trader_name);
r.item_stat = item_results.at(t.trader.item_id).stats;
r.item_id = Strings::ToInt(row[2]);
r.charges = Strings::ToInt(row[4]);
auto item = db.GetItem(r.item_id);
if (!item) {
continue;
}
uint32 aug_slot_1 = Strings::ToUnsignedInt(row[11]);
uint32 aug_slot_2 = Strings::ToUnsignedInt(row[12]);
uint32 aug_slot_3 = Strings::ToUnsignedInt(row[13]);
uint32 aug_slot_4 = Strings::ToUnsignedInt(row[14]);
uint32 aug_slot_5 = Strings::ToUnsignedInt(row[15]);
uint32 aug_slot_6 = Strings::ToUnsignedInt(row[16]);
std::unique_ptr<EQ::ItemInstance> inst(
db.CreateItem(
item,
r.charges,
aug_slot_1,
aug_slot_2,
aug_slot_3,
aug_slot_4,
aug_slot_5,
aug_slot_6
)
);
if (!inst->GetItem()) {
continue;
}
r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable;
r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_entity_id = Strings::ToInt(row[9]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
LogTradingDetail(
"Searching against item [{}] ({}) for trader [{}]",
item->Name,
item->ID,
r.trader_name
);
// item stat searches
std::map<uint32, uint32> item_stat_searches = {
{STAT_AC, inst->GetItemArmorClass(true)},
{STAT_AGI, static_cast<uint32>(inst->GetItemAgi(true))},
{STAT_CHA, static_cast<uint32>(inst->GetItemCha(true))},
{STAT_DEX, static_cast<uint32>(inst->GetItemDex(true))},
{STAT_INT, static_cast<uint32>(inst->GetItemInt(true))},
{STAT_STA, static_cast<uint32>(inst->GetItemSta(true))},
{STAT_STR, static_cast<uint32>(inst->GetItemStr(true))},
{STAT_WIS, static_cast<uint32>(inst->GetItemWis(true))},
{STAT_COLD, static_cast<uint32>(inst->GetItemCR(true))},
{STAT_DISEASE, static_cast<uint32>(inst->GetItemDR(true))},
{STAT_FIRE, static_cast<uint32>(inst->GetItemFR(true))},
{STAT_MAGIC, static_cast<uint32>(inst->GetItemMR(true))},
{STAT_POISON, static_cast<uint32>(inst->GetItemPR(true))},
{STAT_HP, static_cast<uint32>(inst->GetItemHP(true))},
{STAT_MANA, static_cast<uint32>(inst->GetItemMana(true))},
{STAT_ENDURANCE, static_cast<uint32>(inst->GetItemEndur(true))},
{STAT_ATTACK, static_cast<uint32>(inst->GetItemAttack(true))},
{STAT_HP_REGEN, static_cast<uint32>(inst->GetItemRegen(true))},
{STAT_MANA_REGEN, static_cast<uint32>(inst->GetItemManaRegen(true))},
{STAT_HASTE, static_cast<uint32>(inst->GetItemHaste(true))},
{STAT_DAMAGE_SHIELD, static_cast<uint32>(inst->GetItemDamageShield(true))},
{STAT_DS_MITIGATION, static_cast<uint32>(inst->GetItemDSMitigation(true))},
{STAT_HEAL_AMOUNT, static_cast<uint32>(inst->GetItemHealAmt(true))},
{STAT_SPELL_DAMAGE, static_cast<uint32>(inst->GetItemSpellDamage(true))},
{STAT_CLAIRVOYANCE, static_cast<uint32>(inst->GetItemClairvoyance(true))},
{STAT_HEROIC_AGILITY, static_cast<uint32>(inst->GetItemHeroicAgi(true))},
{STAT_HEROIC_CHARISMA, static_cast<uint32>(inst->GetItemHeroicCha(true))},
{STAT_HEROIC_DEXTERITY, static_cast<uint32>(inst->GetItemHeroicDex(true))},
{STAT_HEROIC_INTELLIGENCE, static_cast<uint32>(inst->GetItemHeroicInt(true))},
{STAT_HEROIC_STAMINA, static_cast<uint32>(inst->GetItemHeroicSta(true))},
{STAT_HEROIC_STRENGTH, static_cast<uint32>(inst->GetItemHeroicStr(true))},
{STAT_HEROIC_WISDOM, static_cast<uint32>(inst->GetItemHeroicWis(true))},
{STAT_BASH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillBash, true))},
{STAT_BACKSTAB, static_cast<uint32>(inst->GetItemBackstabDamage(true))},
{STAT_DRAGON_PUNCH, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillDragonPunch, true))},
{STAT_EAGLE_STRIKE, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillEagleStrike, true))},
{STAT_FLYING_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFlyingKick, true))},
{STAT_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillKick, true))},
{STAT_ROUND_KICK, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillRoundKick, true))},
{STAT_TIGER_CLAW, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillTigerClaw, true))},
{STAT_FRENZY, static_cast<uint32>(inst->GetItemSkillsStat(EQ::skills::SkillFrenzy, true))},
};
r.item_stat = item_stat_searches.contains(search.item_stat) ? item_stat_searches[search.item_stat] : 0;
if (item_stat_searches.contains(search.item_stat) && item_stat_searches[search.item_stat] <= 0) {
continue;
}
static std::map<uint8, uint32> item_slot_searches = {
{EQ::invslot::slotCharm, 1},
{EQ::invslot::slotEar1, 2},
{EQ::invslot::slotHead, 4},
{EQ::invslot::slotFace, 8},
{EQ::invslot::slotEar2, 16},
{EQ::invslot::slotNeck, 32},
{EQ::invslot::slotShoulders, 64},
{EQ::invslot::slotArms, 128},
{EQ::invslot::slotBack, 256},
{EQ::invslot::slotWrist1, 512},
{EQ::invslot::slotWrist2, 1024},
{EQ::invslot::slotRange, 2048},
{EQ::invslot::slotHands, 4096},
{EQ::invslot::slotPrimary, 8192},
{EQ::invslot::slotSecondary, 16384},
{EQ::invslot::slotFinger1, 32768},
{EQ::invslot::slotFinger2, 65536},
{EQ::invslot::slotChest, 131072},
{EQ::invslot::slotLegs, 262144},
{EQ::invslot::slotFeet, 524288},
{EQ::invslot::slotWaist, 1048576},
{EQ::invslot::slotPowerSource, 2097152},
{EQ::invslot::slotAmmo, 4194304},
};
auto GetEquipmentSlotBit = [&](uint32 slot) -> uint32 {
return item_slot_searches.contains(slot) ? item_slot_searches[slot] : 0;
};
auto FindItemAugSlot = [&]() -> bool {
for (auto const &s: inst->GetItem()->AugSlotType) {
return s == search.augment;
}
return false;
};
// item type searches
std::vector<ItemSearchType> item_search_types = {
{EQ::item::ItemType::ItemTypeAll, true},
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer},
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
{EQ::item::ItemType::ItemTypeFocusEffect, item->Focus.Effect > 0},
{EQ::item::ItemType::ItemTypeArmor, item->ItemType == EQ::item::ItemType::ItemTypeArmor},
{EQ::item::ItemType::ItemType1HBlunt, item->ItemType == EQ::item::ItemType::ItemType1HBlunt},
{EQ::item::ItemType::ItemType1HPiercing, item->ItemType == EQ::item::ItemType::ItemType1HPiercing},
{EQ::item::ItemType::ItemType1HSlash, item->ItemType == EQ::item::ItemType::ItemType1HSlash},
{EQ::item::ItemType::ItemType2HBlunt, item->ItemType == EQ::item::ItemType::ItemType2HBlunt},
{EQ::item::ItemType::ItemType2HSlash, item->ItemType == EQ::item::ItemType::ItemType2HSlash},
{EQ::item::ItemType::ItemTypeBow, item->ItemType == EQ::item::ItemType::ItemTypeBow},
{EQ::item::ItemType::ItemTypeShield, item->ItemType == EQ::item::ItemType::ItemTypeShield},
{EQ::item::ItemType::ItemTypeMisc, item->ItemType == EQ::item::ItemType::ItemTypeMisc},
{EQ::item::ItemType::ItemTypeFood, item->ItemType == EQ::item::ItemType::ItemTypeFood},
{EQ::item::ItemType::ItemTypeDrink, item->ItemType == EQ::item::ItemType::ItemTypeDrink},
{EQ::item::ItemType::ItemTypeLight, item->ItemType == EQ::item::ItemType::ItemTypeLight},
{EQ::item::ItemType::ItemTypeCombinable, item->ItemType == EQ::item::ItemType::ItemTypeCombinable},
{EQ::item::ItemType::ItemTypeBandage, item->ItemType == EQ::item::ItemType::ItemTypeBandage},
{EQ::item::ItemType::ItemTypeSmallThrowing, item->ItemType == EQ::item::ItemType::ItemTypeSmallThrowing ||
item->ItemType == EQ::item::ItemType::ItemTypeLargeThrowing},
{EQ::item::ItemType::ItemTypeSpell, item->ItemType == EQ::item::ItemType::ItemTypeSpell},
{EQ::item::ItemType::ItemTypePotion, item->ItemType == EQ::item::ItemType::ItemTypePotion},
{EQ::item::ItemType::ItemTypeBrassInstrument, item->ItemType == EQ::item::ItemType::ItemTypeBrassInstrument},
{EQ::item::ItemType::ItemTypeWindInstrument, item->ItemType == EQ::item::ItemType::ItemTypeWindInstrument},
{EQ::item::ItemType::ItemTypeStringedInstrument, item->ItemType == EQ::item::ItemType::ItemTypeStringedInstrument},
{EQ::item::ItemType::ItemTypePercussionInstrument, item->ItemType == EQ::item::ItemType::ItemTypePercussionInstrument},
{EQ::item::ItemType::ItemTypeArrow, item->ItemType == EQ::item::ItemType::ItemTypeArrow},
{EQ::item::ItemType::ItemTypeJewelry, item->ItemType == EQ::item::ItemType::ItemTypeJewelry},
{EQ::item::ItemType::ItemTypeNote, item->ItemType == EQ::item::ItemType::ItemTypeNote},
{EQ::item::ItemType::ItemTypeKey, item->ItemType == EQ::item::ItemType::ItemTypeKey},
{EQ::item::ItemType::ItemType2HPiercing, item->ItemType == EQ::item::ItemType::ItemType2HPiercing},
{EQ::item::ItemType::ItemTypeAlcohol, item->ItemType == EQ::item::ItemType::ItemTypeAlcohol},
{EQ::item::ItemType::ItemTypeMartial, item->ItemType == EQ::item::ItemType::ItemTypeMartial},
{EQ::item::ItemType::ItemTypeAugmentation, item->ItemType == EQ::item::ItemType::ItemTypeAugmentation},
{EQ::item::ItemType::ItemTypeAlternateAbility, item->ItemType == EQ::item::ItemType::ItemTypeAlternateAbility},
{EQ::item::ItemType::ItemTypeCount, item->ItemType == EQ::item::ItemType::ItemTypeCount},
{EQ::item::ItemType::ItemTypeCollectible, item->ItemType == EQ::item::ItemType::ItemTypeCollectible}
};
bool met_filter = false;
bool has_filter = false;
for (auto &i: item_search_types) {
if (i.type == search.type) {
has_filter = true;
if (i.condition) {
LogTradingDetail("Item [{}] met search criteria for type [{}]", item->Name, uint8(i.type));
met_filter = true;
break;
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (convert ||
char_zone_id != Zones::BAZAAR ||
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
) {
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
}
}
}
if (has_filter && !met_filter) {
continue;
}
// TODO: Add catch-all item type filter for specific item types
// item additive searches
std::vector<AddititiveSearchCriteria> item_additive_searches = {
{
.should_check = search.min_level != 1 && inst->GetItemRequiredLevel(true) > 0,
.condition = inst->GetItemRequiredLevel(true) >= search.min_level
},
{
.should_check = search.max_level != 1 && inst->GetItemRequiredLevel(true) > 0,
.condition = inst->GetItemRequiredLevel(true) <= search.max_level
},
{
.should_check = !std::string(search.item_name).empty(),
.condition = Strings::ContainsLower(item->Name, search.item_name)
},
{
.should_check = search._class != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Classes & GetPlayerClassBit(search._class))
},
{
.should_check = search.race != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Races & GetPlayerRaceBit(GetRaceIDFromPlayerRaceValue(search.race)))
},
{
.should_check = search.augment != 0,
.condition = FindItemAugSlot()
},
{
.should_check = search.slot != 0xFFFFFFFF,
.condition = static_cast<bool>(item->Slots & GetEquipmentSlotBit(search.slot))
},
};
bool should_add = true;
for (auto &i: item_additive_searches) {
LogTradingDetail(
"Checking item [{}] for search criteria - should_check [{}] condition [{}]",
item->Name,
i.should_check,
i.condition
);
if (i.should_check && !i.condition) {
should_add = false;
continue;
}
}
if (!should_add) {
continue;
}
LogTradingDetail("Found item [{}] meeting search criteria.", r.item_name);
all_entries.push_back(r);
}
+3 -1
View File
@@ -3,11 +3,13 @@
#include <vector>
#include "shareddb.h"
#include "../../common/item_instance.h"
class Bazaar {
public:
static std::vector<BazaarSearchResultsFromDB_Struct>
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
GetSearchResults(Database &content_db, Database &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id);
};
+2
View File
@@ -294,6 +294,8 @@ void print_trace()
SendCrashReport(crash_report);
}
LogSys.CloseFileLogs();
exit(1);
}
-18
View File
@@ -101,24 +101,6 @@ void CRC32::SetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at)
memcpy(in_data, (char*)&check, 4);
}
unsigned long CRC32::GetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at)
{
unsigned long data;
unsigned long check = 0xffffffff;
for (uint32 i = start_at; i < in_length; i++)
{
data = in_data[i];
data = data ^ (check);
data = data & 0x000000ff;
check = check >> 8;
data = CRC32Table[data];
check = check ^ data;
}
return check;
}
uint32 CRC32::Update(const uint8* buf, uint32 bufsize, uint32 crc32var) {
for(uint32 i=0; i < bufsize; i++)
Calc(buf[i], crc32var);
-1
View File
@@ -8,7 +8,6 @@ public:
static uint32 Generate(const uint8* buf, uint32 bufsize);
static uint32 GenerateNoFlip(const uint8* buf, uint32 bufsize); // Same as Generate(), but without the ~
static void SetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at=4);
static unsigned long GetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at = 4);
// Multiple buffer CRC32
static uint32 Update(const uint8* buf, uint32 bufsize, uint32 crc32 = 0xFFFFFFFF);
+56 -1
View File
@@ -50,6 +50,7 @@
#include "../common/repositories/raid_members_repository.h"
#include "../common/repositories/reports_repository.h"
#include "../common/repositories/variables_repository.h"
#include "../common/repositories/character_pet_name_repository.h"
#include "../common/events/player_event_logs.h"
// Disgrace: for windows compile
@@ -313,6 +314,12 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
return false;
}
const auto& p = CharacterPetNameRepository::GetWhere(*this, where_filter);
if (!p.empty()) {
LogInfo("Account [{}] requested name [{}] but name is already taken by an Pet", account_id, name);
return false;
}
auto e = CharacterDataRepository::NewEntity();
e.account_id = account_id;
@@ -1860,7 +1867,35 @@ bool Database::CopyCharacter(
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
// validate destination name doesn't exist already
const auto& destination_characters = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}' AND `deleted_at` IS NULL LIMIT 1",
Strings::Escape(destination_character_name)
)
);
if (!destination_characters.empty()) {
LogError("Character [{}] already exists", destination_character_name);
return false;
}
std::vector<std::string> tables_to_zero_id = {
"keyring",
"data_buckets",
"character_instance_safereturns",
"character_expedition_lockouts",
"character_instance_lockouts",
"character_parcels",
"character_tribute",
"player_titlesets",
};
std::vector<std::string> ignore_tables = {
"guilds",
};
size_t total_rows_copied = 0;
TransactionBegin();
@@ -1868,6 +1903,10 @@ bool Database::CopyCharacter(
const std::string& table_name = t.first;
const std::string& character_id_column_name = t.second;
if (Strings::Contains(ignore_tables, table_name)) {
continue;
}
auto results = QueryDatabase(
fmt::format(
"SHOW COLUMNS FROM {}",
@@ -1918,6 +1957,10 @@ bool Database::CopyCharacter(
value = std::to_string(destination_account_id);
}
if (!Strings::IsNumber(value)) {
value = Strings::Escape(value);
}
new_values.emplace_back(value);
}
@@ -1950,6 +1993,11 @@ bool Database::CopyCharacter(
)
);
size_t rows_copied = insert_rows.size(); // Rows copied for this table
total_rows_copied += rows_copied; // Increment grand total
LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied));
if (!insert.ErrorMessage().empty()) {
TransactionRollback();
return false;
@@ -1959,6 +2007,13 @@ bool Database::CopyCharacter(
TransactionCommit();
LogInfo(
"Character [{}] copied to [{}] total rows [{}]",
source_character_name,
destination_character_name,
Strings::Commify(total_rows_copied)
);
return true;
}
+11 -1
View File
@@ -169,7 +169,10 @@ bool DatabaseUpdate::UpdateManifest(
LogSys.EnableMySQLErrorLogs();
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
if (!missing_migrations.empty()) {
if (!missing_migrations.empty() && m_skip_backup) {
LogInfo("Skipping database backup");
}
else if (!missing_migrations.empty()) {
LogInfo("Automatically backing up database before applying updates");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
auto s = DatabaseDumpService();
@@ -271,6 +274,13 @@ DatabaseUpdate *DatabaseUpdate::SetContentDatabase(Database *db)
return this;
}
DatabaseUpdate *DatabaseUpdate::SetSkipBackup(bool skip)
{
m_skip_backup = skip;
return this;
}
bool DatabaseUpdate::CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b)
{
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
+3
View File
@@ -29,12 +29,15 @@ public:
DatabaseUpdate *SetDatabase(Database *db);
DatabaseUpdate *SetContentDatabase(Database *db);
DatabaseUpdate *SetSkipBackup(bool skip);
bool HasPendingUpdates();
private:
bool m_skip_backup = false;
Database *m_database;
Database *m_content_database;
static bool CheckVersionsUpToDate(DatabaseVersion v, DatabaseVersion b);
void InjectBotsVersionColumn();
};
#endif //EQEMU_DATABASE_UPDATE_H
@@ -5759,7 +5759,639 @@ ALTER TABLE `character_exp_modifiers`
MODIFY COLUMN `aa_modifier` float NOT NULL DEFAULT 1.0 AFTER `instance_version`,
MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
)"
},
ManifestEntry{
.version = 9285,
.description = "2024_11_08_data_buckets_indexes.sql",
.check = "SHOW CREATE TABLE `data_buckets`",
.condition = "missing",
.match = "idx_character_expires",
.sql = R"(
CREATE INDEX idx_character_expires ON data_buckets (character_id, expires);
CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires);
CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
)"
},
ManifestEntry{
.version = 9286,
.description = "2024_11_26_bazaar_find_trader.sql",
.check = "SHOW COLUMNS FROM `trader` LIKE 'char_zone_instance_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `trader`
ADD COLUMN `char_zone_instance_id` INT NULL DEFAULT '0' AFTER `char_zone_id`;
)"
},
ManifestEntry{
.version = 9287,
.description = "2024_11_26_bazaar_find_trader.sql",
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'walkspeed'",
.condition = "missing",
.match = "float",
.sql = R"(
ALTER TABLE `npc_types` MODIFY COLUMN `walkspeed` float NOT NULL DEFAULT 0;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9288,
.description = "2024_11_10_zone_player_partitioning.sql",
.check = "SHOW CREATE TABLE `zone`",
.condition = "missing",
.match = "shard_at_player_count",
.sql = R"(
ALTER TABLE `zone`
ADD COLUMN `shard_at_player_count` int(11) NULL DEFAULT 0 AFTER `seconds_before_idle`;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9289,
.description = "2025_01_19_evolving_items__character_evolving_items",
.check = "SHOW TABLES LIKE 'character_evolving_items'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `character_evolving_items` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`character_id` INT(10) UNSIGNED NULL DEFAULT '0',
`item_id` INT(10) UNSIGNED NULL DEFAULT '0',
`activated` TINYINT(1) UNSIGNED NULL DEFAULT '0',
`equipped` TINYINT(3) UNSIGNED NULL DEFAULT '0',
`current_amount` BIGINT(20) NULL DEFAULT '0',
`progression` DOUBLE(22,0) NULL DEFAULT '0',
`final_item_id` INT(10) UNSIGNED NULL DEFAULT '0',
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
)"
},
ManifestEntry{
.version = 9290,
.description = "2025_01_19_evolving_items__items_evolving_details",
.check = "SHOW TABLES LIKE 'items_evolving_details'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `items_evolving_details` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`item_evo_id` int(10) unsigned DEFAULT 0 COMMENT 'items.evoid',
`item_evolve_level` int(10) unsigned DEFAULT 0 COMMENT 'items.evolvinglevel',
`item_id` int(10) unsigned DEFAULT 0 COMMENT 'items.id',
`type` int(10) unsigned DEFAULT 0,
`sub_type` int(10) unsigned DEFAULT 0,
`required_amount` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
INSERT INTO `items_evolving_details` VALUES
(1,1000,1,86900,99,1,0),
(2,1000,2,86901,99,1,0),
(3,1000,3,86902,99,1,0),
(4,1000,4,86903,99,1,0),
(5,1000,5,86904,99,1,0),
(6,1001,1,86910,99,1,0),
(7,1001,2,86911,99,1,0),
(8,1001,3,86912,99,1,0),
(9,1001,4,86913,99,1,0),
(10,1001,5,86914,99,1,0),
(11,1001,6,86915,99,1,0),
(12,1001,7,86916,99,1,0),
(13,1002,1,86920,99,1,0),
(14,1002,2,86921,99,1,0),
(15,1002,3,86922,99,1,0),
(16,1002,4,86923,99,1,0),
(17,1002,5,86924,99,1,0),
(18,1002,6,86925,99,1,0),
(19,1002,7,86926,99,1,0),
(20,1003,1,86930,99,1,0),
(21,1003,2,86931,99,1,0),
(22,1003,3,86932,99,1,0),
(23,1003,4,86933,99,1,0),
(24,1003,5,86934,99,1,0),
(25,1003,6,86935,99,1,0),
(26,1004,1,86940,99,1,0),
(27,1004,2,86941,99,1,0),
(28,1004,3,86942,99,1,0),
(29,1004,4,86943,99,1,0),
(30,1004,5,86944,99,1,0),
(31,1004,6,86945,99,1,0),
(32,1005,1,86950,99,1,0),
(33,1005,2,86951,99,1,0),
(34,1005,3,86952,99,1,0),
(35,1005,4,86953,99,1,0),
(36,1005,5,86954,99,1,0),
(37,1005,6,86955,99,1,0),
(38,1005,7,86956,99,1,0),
(39,1006,1,86960,99,1,0),
(40,1006,2,86961,99,1,0),
(41,1006,3,86962,99,1,0),
(42,1006,4,86963,99,1,0),
(43,1006,5,86964,99,1,0),
(44,1006,6,86965,99,1,0),
(45,1006,7,86966,99,1,0),
(46,1007,1,86970,99,1,0),
(47,1007,2,86971,99,1,0),
(48,1007,3,86972,99,1,0),
(49,1007,4,86973,99,1,0),
(50,1007,5,86974,99,1,0),
(51,1007,6,86975,99,1,0),
(52,1007,7,86976,99,1,0),
(53,1008,1,86980,99,1,0),
(54,1008,2,86981,99,1,0),
(55,1008,3,86982,99,1,0),
(56,1008,4,86983,99,1,0),
(57,1008,5,86984,99,1,0),
(58,1009,1,86990,99,1,0),
(59,1009,2,86991,99,1,0),
(60,1009,3,86992,99,1,0),
(61,1009,4,86993,99,1,0),
(62,1009,5,86994,99,1,0),
(63,1009,6,86995,99,1,0),
(64,1009,7,86996,99,1,0),
(65,1009,8,86997,99,1,0),
(66,1009,9,86998,99,1,0),
(67,1009,10,86999,99,1,0),
(68,1010,1,90001,99,1,0),
(69,1010,2,90002,99,1,0),
(70,1010,3,90003,99,1,0),
(71,1010,6,90006,99,1,0),
(72,1010,7,90007,99,1,0),
(73,1010,8,90008,99,1,0),
(74,1010,10,90010,99,1,0),
(75,1050,1,89270,99,1,0),
(76,1050,2,89271,99,1,0),
(77,1050,3,89272,99,1,0),
(78,1050,4,89273,99,1,0),
(79,1050,5,89274,99,1,0),
(80,1050,6,89275,99,1,0),
(81,1051,1,89280,99,1,0),
(82,1051,2,89281,99,1,0),
(83,1051,3,89282,99,1,0),
(84,1051,4,89283,99,1,0),
(85,1051,5,89284,99,1,0),
(86,1052,1,89290,99,1,0),
(87,1052,2,89291,99,1,0),
(88,1052,3,89292,99,1,0),
(89,1052,4,89293,99,1,0),
(90,1052,5,89294,99,1,0),
(91,1052,6,89295,99,1,0),
(92,1052,7,89296,99,1,0),
(93,1053,1,89300,99,1,0),
(94,1053,2,89301,99,1,0),
(95,1053,3,89302,99,1,0),
(96,1053,4,89303,99,1,0),
(97,1053,5,89304,99,1,0),
(98,1053,6,89305,99,1,0),
(99,1053,7,89306,99,1,0),
(100,1053,8,89307,99,1,0),
(101,1053,9,89308,99,1,0),
(102,1054,1,89310,99,1,0),
(103,1054,2,89311,99,1,0),
(104,1054,3,89312,99,1,0),
(105,1054,4,89313,99,1,0),
(106,1054,5,89314,99,1,0),
(107,1054,6,89315,99,1,0),
(108,1055,1,89320,99,1,0),
(109,1055,2,89321,99,1,0),
(110,1055,3,89322,99,1,0),
(111,1055,4,89323,99,1,0),
(112,1055,5,89324,99,1,0),
(113,1055,6,89325,99,1,0),
(114,1055,7,89326,99,1,0),
(115,1056,1,89330,99,1,0),
(116,1056,2,89331,99,1,0),
(117,1056,3,89332,99,1,0),
(118,1056,4,89333,99,1,0),
(119,1056,5,89334,99,1,0),
(120,1057,1,89340,99,1,0),
(121,1057,2,89341,99,1,0),
(122,1057,3,89342,99,1,0),
(123,1057,4,89343,99,1,0),
(124,1057,5,89344,99,1,0),
(125,1057,6,89345,99,1,0),
(126,1057,7,89346,99,1,0),
(127,1057,8,89347,99,1,0),
(128,1058,1,89350,99,1,0),
(129,1058,2,89351,99,1,0),
(130,1058,3,89352,99,1,0),
(131,1058,4,89353,99,1,0),
(132,1058,5,89354,99,1,0),
(133,1058,6,89355,99,1,0),
(134,1058,7,89356,99,1,0),
(135,1059,1,89360,99,1,0),
(136,1059,2,89361,99,1,0),
(137,1059,3,89362,99,1,0),
(138,1060,1,89490,99,1,0),
(139,1060,2,89491,99,1,0),
(140,1060,3,89492,99,1,0),
(141,1061,1,89500,99,1,0),
(142,1061,2,89501,99,1,0),
(143,1061,3,89502,99,1,0),
(144,1062,1,89510,99,1,0),
(145,1062,2,89511,99,1,0),
(146,1062,3,89512,99,1,0),
(147,1063,1,89520,99,1,0),
(148,1063,2,89521,99,1,0),
(149,1063,3,89522,99,1,0),
(150,1064,1,89530,99,1,0),
(151,1064,2,89531,99,1,0),
(152,1064,3,89532,99,1,0),
(153,1065,1,89540,99,1,0),
(154,1065,2,89541,99,1,0),
(155,1065,3,89542,99,1,0),
(156,1066,1,89550,3,274,500),
(157,1066,2,89551,3,274,1000),
(158,1066,3,89552,3,274,2000),
(159,1067,1,89560,99,1,0),
(160,1067,2,89561,99,1,0),
(161,1067,3,89562,99,1,0),
(162,1069,1,85571,99,1,0),
(163,1069,2,85572,99,1,0),
(164,1069,3,85573,99,1,0),
(165,1200,1,95001,99,1,0),
(166,1200,2,95002,99,1,0),
(167,1200,3,95003,99,1,0),
(168,1200,4,95004,99,1,0),
(169,1200,5,95005,99,1,0),
(170,1200,6,95006,99,1,0),
(171,1200,7,95007,99,1,0),
(172,1201,1,95008,99,1,0),
(173,1201,2,95009,99,1,0),
(174,1201,3,95010,99,1,0),
(175,1201,4,95011,99,1,0),
(176,1201,5,95012,99,1,0),
(177,1201,6,95013,99,1,0),
(178,1201,7,95014,99,1,0),
(179,1202,1,95015,99,1,0),
(180,1202,2,95016,99,1,0),
(181,1202,3,95017,99,1,0),
(182,1202,4,95018,99,1,0),
(183,1202,5,95019,99,1,0),
(184,1202,6,95020,99,1,0),
(185,1202,7,95021,99,1,0),
(186,1203,1,95022,99,1,0),
(187,1203,2,95023,99,1,0),
(188,1203,3,95024,99,1,0),
(189,1203,4,95025,99,1,0),
(190,1203,5,95026,99,1,0),
(191,1203,6,95027,99,1,0),
(192,1203,7,95028,99,1,0),
(193,1204,1,95029,99,1,0),
(194,1204,2,95030,99,1,0),
(195,1204,3,95031,99,1,0),
(196,1204,4,95032,99,1,0),
(197,1204,5,95033,99,1,0),
(198,1204,6,95034,99,1,0),
(199,1204,7,95035,99,1,0),
(200,1205,1,95036,99,1,0),
(201,1205,2,95037,99,1,0),
(202,1205,3,95038,99,1,0),
(203,1205,4,95039,99,1,0),
(204,1205,5,95040,99,1,0),
(205,1205,6,95041,99,1,0),
(206,1205,7,95042,99,1,0),
(207,1206,1,95043,99,1,0),
(208,1206,2,95044,99,1,0),
(209,1206,3,95045,99,1,0),
(210,1206,4,95046,99,1,0),
(211,1206,5,95047,99,1,0),
(212,1206,6,95048,99,1,0),
(213,1206,7,95049,99,1,0),
(214,1207,1,95050,99,1,0),
(215,1207,2,95051,99,1,0),
(216,1207,3,95052,99,1,0),
(217,1207,4,95053,99,1,0),
(218,1207,5,95054,99,1,0),
(219,1207,6,95055,99,1,0),
(220,1207,7,95056,99,1,0),
(221,1208,1,95057,99,1,0),
(222,1208,2,95058,99,1,0),
(223,1208,3,95059,99,1,0),
(224,1208,4,95060,99,1,0),
(225,1208,5,95061,99,1,0),
(226,1208,6,95062,99,1,0),
(227,1208,7,95063,99,1,0),
(228,1209,1,95064,99,1,0),
(229,1209,2,95065,99,1,0),
(230,1209,3,95066,99,1,0),
(231,1209,4,95067,99,1,0),
(232,1209,5,95068,99,1,0),
(233,1209,6,95069,99,1,0),
(234,1209,7,95070,99,1,0),
(235,1210,1,95071,99,1,0),
(236,1210,2,95072,99,1,0),
(237,1210,3,95073,99,1,0),
(238,1210,4,95074,99,1,0),
(239,1210,5,95075,99,1,0),
(240,1210,6,95076,99,1,0),
(241,1210,7,95077,99,1,0),
(242,1211,1,85612,1,1,100000),
(243,1211,2,85613,1,1,200000),
(244,1211,3,85614,1,1,300000),
(245,1214,1,80035,99,1,0),
(246,1301,1,102700,99,1,0),
(247,1301,4,102703,99,1,0),
(248,1302,1,102704,99,1,0),
(249,1302,2,102705,99,1,0),
(250,1303,1,102706,99,1,0),
(251,1303,2,102707,99,1,0),
(252,1303,3,102708,99,1,0),
(253,1304,1,102709,99,1,0),
(254,1304,5,102713,99,1,0),
(255,1305,1,102714,99,1,0),
(256,1306,1,102716,99,1,0),
(257,1306,5,102720,99,1,0),
(258,1307,1,102721,99,1,0),
(259,1307,3,102723,99,1,0),
(260,1308,1,102724,99,1,0),
(261,1309,1,102727,99,1,0),
(262,1309,2,102728,99,1,0),
(263,1310,1,102729,99,1,0),
(264,1310,3,102731,99,1,0),
(265,1311,1,102732,99,1,0),
(266,1311,4,102735,99,1,0),
(267,1312,1,102736,99,1,0),
(268,1312,3,102738,99,1,0),
(269,1313,1,102739,99,1,0),
(270,1314,1,102743,99,1,0),
(271,1314,2,102744,99,1,0),
(272,1314,3,102745,99,1,0),
(273,1315,1,102746,99,1,0),
(274,1315,2,102747,99,1,0),
(275,1316,1,102748,99,1,0),
(276,1316,5,102752,99,1,0),
(277,1317,1,102753,99,1,0),
(278,1318,1,102756,99,1,0),
(279,1319,1,102759,99,1,0),
(280,1319,3,102761,99,1,0),
(281,1320,1,102762,99,1,0),
(282,1321,1,102765,99,1,0),
(283,1321,2,102766,99,1,0),
(284,1321,3,102767,99,1,0),
(285,1322,1,102768,99,1,0),
(286,1322,2,102769,99,1,0),
(287,1322,3,102770,99,1,0),
(288,1323,1,102771,99,1,0),
(289,1324,1,102774,99,1,0),
(290,1400,1,102800,99,1,0),
(291,1401,1,102807,99,1,0),
(292,1401,7,102813,99,1,0),
(293,1402,1,102814,99,1,0),
(294,1402,7,102820,99,1,0),
(295,1403,1,102821,99,1,0),
(296,1404,1,102828,99,1,0),
(297,1405,1,102835,99,1,0),
(298,1406,1,102842,99,1,0),
(299,1408,1,109310,99,1,0),
(300,1408,5,109314,99,1,0),
(301,1409,1,109315,99,1,0),
(302,1409,5,109319,99,1,0),
(303,1410,1,109320,99,1,0),
(304,1410,5,109324,99,1,0),
(305,1411,1,109325,99,1,0),
(306,1411,5,109329,99,1,0),
(307,1412,1,109330,99,1,0),
(308,1412,5,109334,99,1,0),
(309,1413,1,109335,99,1,0),
(310,1413,5,109339,99,1,0),
(311,1414,1,109340,99,1,0),
(312,1414,5,109344,99,1,0),
(313,1415,1,109345,99,1,0),
(314,1415,5,109349,99,1,0),
(315,1416,1,109350,99,1,0),
(316,1416,2,109351,99,1,0),
(317,1416,5,109354,99,1,0),
(318,1417,1,109355,99,1,0),
(319,1417,5,109359,99,1,0),
(320,1418,1,109360,99,1,0),
(321,1418,5,109364,99,1,0),
(322,1419,1,109365,99,1,0),
(323,1419,3,109367,99,1,0),
(324,1419,5,109369,99,1,0),
(325,1420,1,109370,99,1,0),
(326,1420,5,109374,99,1,0),
(327,1421,1,109375,99,1,0),
(328,1421,5,109379,99,1,0),
(329,1422,1,109380,99,1,0),
(330,1422,5,109384,99,1,0),
(331,1423,1,109385,99,1,0),
(332,1423,2,109386,99,1,0),
(333,1423,5,109389,99,1,0),
(334,1436,1,120378,99,1,0),
(335,1436,2,120379,99,1,0),
(336,1436,3,120380,99,1,0),
(337,1436,4,120381,99,1,0),
(338,1436,5,120382,99,1,0),
(339,1436,6,120383,99,1,0),
(340,1436,7,120384,99,1,0),
(341,1436,8,120385,99,1,0),
(342,1436,9,120386,99,1,0),
(343,1436,10,120387,99,1,0),
(344,1436,11,120388,99,1,0),
(345,1436,12,120389,99,1,0),
(346,1436,13,120390,99,1,0),
(347,1436,14,120391,99,1,0),
(348,1436,15,120392,99,1,0),
(349,1436,16,120393,99,1,0),
(350,1436,17,120394,99,1,0),
(351,1436,18,120395,99,1,0),
(352,1436,19,120396,99,1,0),
(353,1436,20,120397,99,1,0),
(354,1440,1,56992,99,1,0),
(355,1440,2,56993,99,1,0),
(356,1440,3,56994,99,1,0),
(357,1440,4,56995,99,1,0),
(358,1440,5,56996,99,1,0),
(359,1441,1,132787,99,1,0),
(360,1441,2,132788,99,1,0),
(361,1441,3,132789,99,1,0),
(362,1441,4,132790,99,1,0),
(363,1441,5,132791,99,1,0),
(364,1441,6,132792,99,1,0),
(365,1441,7,132793,99,1,0),
(366,1441,8,132794,99,1,0),
(367,1441,9,132795,99,1,0),
(368,1441,10,132796,99,1,0),
(369,1441,11,132797,99,1,0),
(370,1441,13,132799,99,1,0),
(371,1441,14,132800,99,1,0),
(372,1441,15,132801,99,1,0),
(373,1441,16,132802,99,1,0),
(374,1441,17,132803,99,1,0),
(375,1441,18,132804,99,1,0),
(376,1441,19,132805,99,1,0),
(377,1441,20,132806,99,1,0),
(378,1442,1,133137,99,1,0),
(379,1442,2,133138,99,1,0),
(380,1442,3,133139,99,1,0),
(381,1442,4,133140,99,1,0),
(382,1442,10,133146,99,1,0),
(383,1442,11,133147,99,1,0),
(384,1442,12,133148,99,1,0),
(385,1442,13,133149,99,1,0),
(386,1442,14,133150,99,1,0),
(387,1442,15,133151,99,1,0),
(388,1442,16,133152,99,1,0),
(389,1442,17,133153,99,1,0),
(390,1442,18,133154,99,1,0),
(391,1442,19,133155,99,1,0),
(392,1442,20,133156,99,1,0),
(393,1443,1,133406,99,1,0),
(394,1443,2,133407,99,1,0),
(395,1443,3,133408,99,1,0),
(396,1443,4,133409,99,1,0),
(397,1443,5,133410,99,1,0),
(398,1443,6,133411,99,1,0),
(399,1443,7,133412,99,1,0),
(400,1443,8,133413,99,1,0),
(401,1443,9,133414,99,1,0),
(402,1443,10,133415,99,1,0),
(403,1443,11,133416,99,1,0),
(404,1443,12,133417,99,1,0),
(405,1443,13,133418,99,1,0),
(406,1443,14,133419,99,1,0),
(407,1443,15,133420,99,1,0),
(408,1443,16,133421,99,1,0),
(409,1443,17,133422,99,1,0),
(410,1443,18,133423,99,1,0),
(411,1443,19,133424,99,1,0),
(412,1443,20,133425,99,1,0),
(413,1444,1,94938,99,1,0),
(414,1444,2,94939,99,1,0),
(415,1444,3,94940,99,1,0),
(416,1444,4,94941,99,1,0),
(417,1444,5,94942,99,1,0),
(418,1444,6,94943,99,1,0),
(419,1444,7,94944,99,1,0),
(420,1444,8,94945,99,1,0),
(421,1444,9,94946,99,1,0),
(422,1444,10,94947,99,1,0),
(423,1444,11,94948,99,1,0),
(424,1444,12,94949,99,1,0),
(425,1444,13,94950,99,1,0),
(426,1444,14,94951,99,1,0),
(427,1444,15,94952,99,1,0),
(428,1444,16,94953,99,1,0),
(429,1444,17,94954,99,1,0),
(430,1444,18,94955,99,1,0),
(431,1444,19,94956,99,1,0),
(432,1444,20,94957,99,1,0),
(433,1445,1,98858,99,1,0),
(434,1445,2,98859,99,1,0),
(435,1445,3,98860,99,1,0),
(436,1445,4,98861,99,1,0),
(437,1445,5,98862,99,1,0);
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9291,
.description = "2025_01_21_add_remove_zone_fields",
.check = "SHOW COLUMNS FROM `zone` LIKE 'client_update_range'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE zone DROP COLUMN IF EXISTS npc_update_range;
ALTER TABLE zone DROP COLUMN IF EXISTS max_movement_update_range;
ALTER TABLE `zone` ADD COLUMN `client_update_range` int(11) NOT NULL DEFAULT 600 AFTER `npc_max_aggro_dist`;
)",
.content_schema_update = true,
},
ManifestEntry{
.version = 9292,
.description = "2025_01_21_data_buckets_account_id",
.check = "SHOW COLUMNS FROM `data_buckets` LIKE 'account_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `data_buckets`
ADD COLUMN `account_id` bigint(11) NULL DEFAULT 0 AFTER `expires`,
DROP INDEX `keys`,
ADD UNIQUE INDEX `keys` (`key`, `character_id`, `npc_id`, `bot_id`, `account_id`) USING BTREE;
-- Add the INDEX for character_id and key
ALTER TABLE `data_buckets` ADD KEY `idx_account_id_key` (`account_id`, `key`);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9293,
.description = "2025_01_10_create_pet_names_table.sql",
.check = "SHOW TABLES LIKE 'character_pet_name'",
.condition = "empty",
.match = "",
.sql = R"(
CREATE TABLE `character_pet_name` (
`character_id` INT(11) NOT NULL PRIMARY KEY,
`name` VARCHAR(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
)",
},
ManifestEntry{
.version = 9294,
.description = "2025_01_26_items_table_bazaar_search_indexes.sql",
.check = "SHOW CREATE TABLE `items`",
.condition = "missing",
.match = "idx_slots_reclevel",
.sql = R"(
-- indexes for the `items` table
CREATE INDEX idx_slots_reclevel ON items (slots, reclevel);
CREATE INDEX idx_itemclass_itemtype ON items (itemclass, itemtype);
CREATE INDEX idx_augment_slots ON items (
augslot1type,
augslot2type,
augslot3type,
augslot4type,
augslot5type,
augslot6type
);
CREATE INDEX idx_races_classes ON items (races, classes);
-- common stat fields
CREATE INDEX idx_item_ac ON items (ac);
CREATE INDEX idx_item_hp ON items (hp);
CREATE INDEX idx_item_mana ON items (mana);
CREATE INDEX idx_item_reclevel ON items (reclevel);
CREATE INDEX idx_item_type_skill ON items (itemtype, skillmodtype);
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9295,
.description = "2025_01_26_trader_table_bazaar_search_indexes.sql",
.check = "SHOW CREATE TABLE `trader`",
.condition = "missing",
.match = "idx_trader_item",
.sql = R"(
-- indexes for the `trader` table
CREATE INDEX idx_trader_item ON trader (item_id, item_cost);
CREATE INDEX idx_trader_char ON trader (char_id, char_zone_id, char_zone_instance_id);
CREATE INDEX idx_trader_item_sn ON trader (item_sn);
CREATE INDEX idx_trader_item_cost ON trader (item_cost);
CREATE INDEX idx_trader_active_transaction ON trader (active_transaction);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9296,
.description = "2025_02_01_trader_table_listing_date.sql",
.check = "SHOW CREATE TABLE `trader`",
.condition = "missing",
.match = "listing_date",
.sql = R"(
ALTER TABLE `trader`
ADD COLUMN `listing_date` DATETIME NULL DEFAULT NULL AFTER `active_transaction`,
ADD INDEX `idx_trader_listing_date` (`listing_date`);
)",
.content_schema_update = false
}
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
// .version = 9228,
+5 -5
View File
@@ -114,7 +114,9 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
timeval tv{};
gettimeofday(&tv, nullptr);
return (i.start_time + i.duration) <= tv.tv_sec;
// Use uint64_t for the addition to prevent overflow
uint64_t expiration_time = static_cast<uint64_t>(i.start_time) + static_cast<uint64_t>(i.duration);
return expiration_time <= tv.tv_sec;
}
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
@@ -469,15 +471,13 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
void Database::DeleteInstance(uint16 instance_id)
{
// I'm not sure why this isn't in here but we should add it in a later change and make sure it's tested
// InstanceListRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
InstanceListPlayerRepository::DeleteWhere(*this, fmt::format("id = {}", instance_id));
RespawnTimesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
SpawnConditionValuesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
DynamicZoneMembersRepository::DeleteByInstance(*this, instance_id);
DynamicZonesRepository::DeleteWhere(*this, fmt::format("instance_id = {}", instance_id));
CharacterCorpsesRepository::BuryInstance(*this, instance_id);
}
+4
View File
@@ -51,6 +51,7 @@ namespace DatabaseSchema {
{"character_enabledtasks", "charid"},
{"character_expedition_lockouts", "character_id"},
{"character_exp_modifiers", "character_id"},
{"character_evolving_items", "character_id"},
{"character_inspect_messages", "id"},
{"character_instance_safereturns", "character_id"},
{"character_item_recast", "id"},
@@ -63,6 +64,7 @@ namespace DatabaseSchema {
{"character_pet_buffs", "char_id"},
{"character_pet_info", "char_id"},
{"character_pet_inventory", "char_id"},
{"character_pet_name", "character_id"},
{"character_peqzone_flags", "id"},
{"character_potionbelt", "id"},
{"character_skills", "id"},
@@ -124,6 +126,7 @@ namespace DatabaseSchema {
"character_enabledtasks",
"character_expedition_lockouts",
"character_exp_modifiers",
"character_evolving_items",
"character_inspect_messages",
"character_instance_safereturns",
"character_item_recast",
@@ -212,6 +215,7 @@ namespace DatabaseSchema {
"ground_spawns",
"horses",
"items",
"items_evolving_details",
"ldon_trap_entries",
"ldon_trap_templates",
"lootdrop",
+6
View File
@@ -7,6 +7,7 @@
#include "timer.h"
#include "dbcore.h"
#include "mysql_stmt.h"
#include <fstream>
#include <iostream>
@@ -436,3 +437,8 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
return r;
}
mysql::PreparedStmt DBcore::Prepare(std::string query)
{
return mysql::PreparedStmt(*mysql, std::move(query), m_mutex);
}
+7
View File
@@ -17,6 +17,8 @@
#define CR_SERVER_GONE_ERROR 2006
#define CR_SERVER_LOST 2013
namespace mysql { class PreparedStmt; }
class DBcore {
public:
enum eStatus {
@@ -48,6 +50,11 @@ public:
}
void SetMutex(Mutex *mutex);
// only safe on connections shared with other threads if results buffered
// unsafe to use off main thread due to internal server logging
// throws std::runtime_error on failure
mysql::PreparedStmt Prepare(std::string query);
protected:
bool Open(
const char *iHost,
+15 -23
View File
@@ -140,29 +140,6 @@ std::string EQ::constants::GetLanguageName(uint8 language_id)
return EQ::constants::GetLanguageMap().find(language_id)->second;
}
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
{
static const std::map<uint32, std::string> ldon_theme_map = {
{ LDoNThemes::Unused, "Unused" },
{ LDoNThemes::GUK, "Deepest Guk" },
{ LDoNThemes::MIR, "Miragul's Menagerie" },
{ LDoNThemes::MMC, "Mistmoore Catacombs" },
{ LDoNThemes::RUJ, "Rujarkian Hills" },
{ LDoNThemes::TAK, "Takish-Hiz" },
};
return ldon_theme_map;
}
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
{
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
return std::string();
}
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
}
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
{
static const std::map<int8, std::string> flymode_map = {
@@ -459,3 +436,18 @@ bool ComparisonType::IsValid(uint8 type)
{
return comparison_types.find(type) != comparison_types.end();
}
uint32 LDoNTheme::GetBitmask(uint32 theme_id)
{
return IsValid(theme_id) ? ldon_theme_names[theme_id].second : LDoNTheme::UnusedBit;
}
std::string LDoNTheme::GetName(uint32 theme_id)
{
return IsValid(theme_id) ? ldon_theme_names[theme_id].first : "UNKNOWN LDON THEME";
}
bool LDoNTheme::IsValid(uint32 theme_id)
{
return ldon_theme_names.find(theme_id) != ldon_theme_names.end();
}
+29 -3
View File
@@ -352,9 +352,6 @@ namespace EQ
extern const std::map<uint8, std::string>& GetLanguageMap();
std::string GetLanguageName(uint8 language_id);
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
std::string GetLDoNThemeName(uint32 theme_id);
extern const std::map<int8, std::string>& GetFlyModeMap();
std::string GetFlyModeName(int8 flymode_id);
@@ -751,6 +748,35 @@ static std::map<uint32, std::string> stance_names = {
{ Stance::AEBurn, "AE Burn" }
};
namespace LDoNTheme {
constexpr uint32 Unused = 0;
constexpr uint32 GUK = 1;
constexpr uint32 MIR = 2;
constexpr uint32 MMC = 3;
constexpr uint32 RUJ = 4;
constexpr uint32 TAK = 5;
constexpr uint32 UnusedBit = 0;
constexpr uint32 GUKBit = 1;
constexpr uint32 MIRBit = 2;
constexpr uint32 MMCBit = 4;
constexpr uint32 RUJBit = 8;
constexpr uint32 TAKBit = 16;
uint32 GetBitmask(uint32 theme_id);
std::string GetName(uint32 theme_id);
bool IsValid(uint32 theme_id);
}
static std::map<uint32, std::pair<std::string, uint32>> ldon_theme_names = {
{ LDoNTheme::Unused, { "Unused", LDoNTheme::UnusedBit }, },
{ LDoNTheme::GUK, { "Deepest Guk", LDoNTheme::GUKBit }, },
{ LDoNTheme::MIR, { "Miragul's Menagerie", LDoNTheme::MIRBit }, },
{ LDoNTheme::MMC, { "Mistmoore Catacombs", LDoNTheme::MMCBit }, },
{ LDoNTheme::RUJ, { "Rujarkian Hills", LDoNTheme::RUJBit }, },
{ LDoNTheme::TAK, { "Takish-Hiz", LDoNTheme::TAKBit }, },
};
namespace PCNPCOnlyFlagType {
constexpr int PC = 1;
constexpr int NPC = 2;
+9 -2
View File
@@ -35,7 +35,7 @@ N(OP_AltCurrencyMerchantRequest),
N(OP_AltCurrencyPurchase),
N(OP_AltCurrencyReclaim),
N(OP_AltCurrencySell),
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
N(OP_AltCurrencySellSelection), // Used by eqstr_us.txt 8066, 8068, 8069
N(OP_Animation),
N(OP_AnnoyingZoneUnknown),
N(OP_ApplyPoison),
@@ -77,6 +77,7 @@ N(OP_CashReward),
N(OP_CastSpell),
N(OP_ChangeSize),
N(OP_ChannelMessage),
N(OP_ChangePetName),
N(OP_CharacterCreate),
N(OP_CharacterCreateRequest),
N(OP_CharInventory),
@@ -162,6 +163,7 @@ N(OP_EnduranceUpdate),
N(OP_EnterChat),
N(OP_EnterWorld),
N(OP_EnvDamage),
N(OP_EvolveItem),
N(OP_ExpansionInfo),
N(OP_ExpUpdate),
N(OP_FaceChange),
@@ -283,12 +285,15 @@ N(OP_InspectMessageUpdate),
N(OP_InspectRequest),
N(OP_InstillDoubt),
N(OP_InterruptCast),
N(OP_InvokeChangePetName),
N(OP_InvokeChangePetNameImmediate),
N(OP_ItemLinkClick),
N(OP_ItemLinkResponse),
N(OP_ItemLinkText),
N(OP_ItemName),
N(OP_ItemPacket),
N(OP_ItemPreview),
N(OP_ItemPreviewRequest),
N(OP_ItemRecastDelay),
N(OP_ItemVerifyReply),
N(OP_ItemVerifyRequest),
@@ -400,6 +405,8 @@ N(OP_PetitionSearchText),
N(OP_PetitionUnCheckout),
N(OP_PetitionUpdate),
N(OP_PickPocket),
N(OP_PickZone),
N(OP_PickZoneWindow),
N(OP_PlayerProfile),
N(OP_PlayerStateAdd),
N(OP_PlayerStateRemove),
@@ -514,7 +521,7 @@ N(OP_ShopPlayerSell),
N(OP_ShopSendParcel),
N(OP_ShopDeleteParcel),
N(OP_ShopRespondParcel),
N(OP_ShopRetrieveParcel),
N(OP_ShopRetrieveParcel),
N(OP_ShopParcelIcon),
N(OP_ShopRequest),
N(OP_SimpleMessage),
-103
View File
@@ -56,8 +56,6 @@ const char* EQ::versions::ClientVersionName(ClientVersion client_version)
return "RoF";
case ClientVersion::RoF2:
return "RoF2";
case ClientVersion::Larion:
return "Larion";
default:
return "Invalid Version";
};
@@ -78,8 +76,6 @@ uint32 EQ::versions::ConvertClientVersionToClientVersionBit(ClientVersion client
return bitRoF;
case ClientVersion::RoF2:
return bitRoF2;
case ClientVersion::Larion:
return bitLarion;
default:
return bitUnknown;
}
@@ -100,8 +96,6 @@ EQ::versions::ClientVersion EQ::versions::ConvertClientVersionBitToClientVersion
return ClientVersion::RoF;
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF2) - 1)) :
return ClientVersion::RoF2;
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::Larion) - 1)):
return ClientVersion::Larion;
default:
return ClientVersion::Unknown;
}
@@ -190,8 +184,6 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
return "RoF";
case MobVersion::RoF2:
return "RoF2";
case MobVersion::Larion:
return "Larion";
case MobVersion::NPC:
return "NPC";
case MobVersion::NPCMerchant:
@@ -220,8 +212,6 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
return "Offline RoF";
case MobVersion::OfflineRoF2:
return "Offline RoF2";
case MobVersion::OfflineLarion:
return "Offline Larion";
default:
return "Invalid Version";
};
@@ -245,8 +235,6 @@ EQ::versions::ClientVersion EQ::versions::ConvertMobVersionToClientVersion(MobVe
return ClientVersion::RoF;
case MobVersion::RoF2:
return ClientVersion::RoF2;
case MobVersion::Larion:
return ClientVersion::Larion;
default:
return ClientVersion::Unknown;
}
@@ -270,8 +258,6 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToMobVersion(ClientVe
return MobVersion::RoF;
case ClientVersion::RoF2:
return MobVersion::RoF2;
case ClientVersion::Larion:
return MobVersion::Larion;
default:
return MobVersion::Unknown;
}
@@ -292,8 +278,6 @@ EQ::versions::MobVersion EQ::versions::ConvertPCMobVersionToOfflinePCMobVersion(
return MobVersion::OfflineRoF;
case MobVersion::RoF2:
return MobVersion::OfflineRoF2;
case MobVersion::Larion:
return MobVersion::OfflineLarion;
default:
return MobVersion::Unknown;
}
@@ -314,8 +298,6 @@ EQ::versions::MobVersion EQ::versions::ConvertOfflinePCMobVersionToPCMobVersion(
return MobVersion::RoF;
case MobVersion::OfflineRoF2:
return MobVersion::RoF2;
case MobVersion::OfflineLarion:
return MobVersion::Larion;
default:
return MobVersion::Unknown;
}
@@ -336,8 +318,6 @@ EQ::versions::ClientVersion EQ::versions::ConvertOfflinePCMobVersionToClientVers
return ClientVersion::RoF;
case MobVersion::OfflineRoF2:
return ClientVersion::RoF2;
case MobVersion::OfflineLarion:
return ClientVersion::Larion;
default:
return ClientVersion::Unknown;
}
@@ -358,8 +338,6 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToOfflinePCMobVersion
return MobVersion::OfflineRoF;
case ClientVersion::RoF2:
return MobVersion::OfflineRoF2;
case ClientVersion::Larion:
return MobVersion::OfflineLarion;
default:
return MobVersion::Unknown;
}
@@ -410,27 +388,6 @@ const char* EQ::expansions::ExpansionName(Expansion expansion)
return "Rain of Fear";
case Expansion::CotF:
return "Call of the Forsaken";
case Expansion::TDS:
return "The Darkened Sea";
case Expansion::TBM:
return "The Broken Mirror";
case Expansion::EoK:
return "Empires of Kunark";
case Expansion::RoS:
return "Ring of Scale";
case Expansion::TBL:
return "The Burning Lands";
case Expansion::ToV:
return "Torment of Velious";
case Expansion::CoV:
return "Claws of Veeshan";
case Expansion::ToL:
return "Terror of Luclin";
case Expansion::NoS:
return "Night of Shadows";
case Expansion::LS:
return "Laurion's Song";
default:
return "Invalid Expansion";
}
@@ -484,26 +441,6 @@ uint32 EQ::expansions::ConvertExpansionToExpansionBit(Expansion expansion)
return bitRoF;
case Expansion::CotF:
return bitCotF;
case Expansion::TDS:
return bitTDS;
case Expansion::TBM:
return bitTBM;
case Expansion::EoK:
return bitEoK;
case Expansion::RoS:
return bitRoS;
case Expansion::TBL:
return bitTBL;
case Expansion::ToV:
return bitToV;
case Expansion::CoV:
return bitCoV;
case Expansion::ToL:
return bitToL;
case Expansion::NoS:
return bitNoS;
case Expansion::LS:
return bitLS;
default:
return bitEverQuest;
}
@@ -552,26 +489,6 @@ EQ::expansions::Expansion EQ::expansions::ConvertExpansionBitToExpansion(uint32
return Expansion::RoF;
case bitCotF:
return Expansion::CotF;
case bitTDS:
return Expansion::TDS;
case bitTBM:
return Expansion::TBM;
case bitEoK:
return Expansion::EoK;
case bitRoS:
return Expansion::RoS;
case bitTBL:
return Expansion::TBL;
case bitToV:
return Expansion::ToV;
case bitCoV:
return Expansion::CoV;
case bitToL:
return Expansion::ToL;
case bitNoS:
return Expansion::NoS;
case bitLS:
return Expansion::LS;
default:
return Expansion::EverQuest;
}
@@ -620,26 +537,6 @@ uint32 EQ::expansions::ConvertExpansionToExpansionsMask(Expansion expansion)
return maskRoF;
case Expansion::CotF:
return maskCotF;
case Expansion::TDS:
return maskTDS;
case Expansion::TBM:
return maskTBM;
case Expansion::EoK:
return maskEoK;
case Expansion::RoS:
return maskRoS;
case Expansion::TBL:
return maskTBL;
case Expansion::ToV:
return maskToV;
case Expansion::CoV:
return maskCoV;
case Expansion::ToL:
return maskToL;
case Expansion::NoS:
return maskNoS;
case Expansion::LS:
return maskLS;
default:
return maskEverQuest;
}
+9 -45
View File
@@ -36,8 +36,7 @@ namespace EQ
SoD, // Build: 'Dec 19 2008 15:22:49'
UF, // Build: 'Jun 8 2010 16:44:32'
RoF, // Build: 'Dec 10 2012 17:35:44'
RoF2, // Build: 'May 10 2013 23:30:08'
Larion
RoF2 // Build: 'May 10 2013 23:30:08'
};
enum ClientVersionBitmask : uint32 {
@@ -49,7 +48,6 @@ namespace EQ
bitUF = 0x00000010,
bitRoF = 0x00000020,
bitRoF2 = 0x00000040,
bitLarion = 0x00000080,
maskUnknown = 0x00000000,
maskTitaniumAndEarlier = 0x00000003,
maskSoFAndEarlier = 0x00000007,
@@ -61,11 +59,10 @@ namespace EQ
maskUFAndLater = 0xFFFFFFF0,
maskRoFAndLater = 0xFFFFFFE0,
maskRoF2AndLater = 0xFFFFFFC0,
maskLarionAndLater = 0xFFFFFF80,
maskAllClients = 0xFFFFFFFF
};
const ClientVersion LastClientVersion = ClientVersion::Larion;
const ClientVersion LastClientVersion = ClientVersion::RoF2;
const size_t ClientVersionCount = (static_cast<size_t>(LastClientVersion) + 1);
bool IsValidClientVersion(ClientVersion client_version);
@@ -83,7 +80,6 @@ namespace EQ
UF,
RoF,
RoF2,
Larion,
NPC,
NPCMerchant,
Merc,
@@ -97,14 +93,13 @@ namespace EQ
OfflineSoD,
OfflineUF,
OfflineRoF,
OfflineRoF2,
OfflineLarion
OfflineRoF2
};
const MobVersion LastMobVersion = MobVersion::OfflineLarion;
const MobVersion LastPCMobVersion = MobVersion::Larion;
const MobVersion LastMobVersion = MobVersion::OfflineRoF2;
const MobVersion LastPCMobVersion = MobVersion::RoF2;
const MobVersion LastNonPCMobVersion = MobVersion::BotPet;
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineLarion;
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineRoF2;
const size_t MobVersionCount = (static_cast<size_t>(LastMobVersion) + 1);
bool IsValidMobVersion(MobVersion mob_version);
@@ -136,8 +131,7 @@ namespace EQ
ucsSoDCombined = 'D',
ucsUFCombined = 'E',
ucsRoFCombined = 'F',
ucsRoF2Combined = 'G',
ucsLaurionCombined = 'G'
ucsRoF2Combined = 'G'
};
} /*versions*/
@@ -164,17 +158,7 @@ namespace EQ
HoT,
VoA,
RoF,
CotF,
TDS,
TBM,
EoK,
RoS,
TBL,
ToV,
CoV,
ToL,
NoS,
LS
CotF
};
enum ExpansionBitmask : uint32 {
@@ -199,16 +183,6 @@ namespace EQ
bitVoA = 0x00020000,
bitRoF = 0x00040000,
bitCotF = 0x00080000,
bitTDS = 0x00100000,
bitTBM = 0x00200000,
bitEoK = 0x00400000,
bitRoS = 0x00800000,
bitTBL = 0x01000000,
bitToV = 0x02000000,
bitCoV = 0x04000000,
bitToL = 0x08000000,
bitNoS = 0x10000000,
bitLS = 0x20000000,
maskEverQuest = 0x00000000,
maskRoK = 0x00000001,
maskSoV = 0x00000003,
@@ -229,17 +203,7 @@ namespace EQ
maskHoT = 0x0001FFFF,
maskVoA = 0x0003FFFF,
maskRoF = 0x0007FFFF,
maskCotF = 0x000FFFFF,
maskTDS = 0x001FFFFF,
maskTBM = 0x003FFFFF,
maskEoK = 0x007FFFFF,
maskRoS = 0x00FFFFFF,
maskTBL = 0x01FFFFFF,
maskToV = 0x03FFFFFF,
maskCoV = 0x07FFFFFF,
maskToL = 0x0FFFFFFF,
maskNoS = 0x1FFFFFFF,
maskLS = 0x3FFFFFFF,
maskCotF = 0x000FFFFF
};
const char* ExpansionName(Expansion expansion);
+1 -18
View File
@@ -993,24 +993,6 @@ enum class DynamicZoneMemberStatus : uint8_t
LinkDead
};
enum LDoNThemes {
Unused = 0,
GUK,
MIR,
MMC,
RUJ,
TAK
};
enum LDoNThemeBits {
UnusedBit = 0,
GUKBit = 1,
MIRBit = 2,
MMCBit = 4,
RUJBit = 8,
TAKBit = 16
};
enum StartZoneIndex {
Odus = 0,
Qeynos,
@@ -1132,4 +1114,5 @@ enum ExpSource
namespace DoorType {
constexpr uint32 BuyerStall = 155;
}
#endif /*COMMON_EQ_CONSTANTS_H*/
+14 -89
View File
@@ -47,6 +47,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
ClientUnknown::constants::EXPANSION_BIT,
ClientUnknown::constants::EXPANSIONS_MASK,
ClientUnknown::INULL,
ClientUnknown::INULL,
ClientUnknown::INULL
),
/*[ClientVersion::Client62] =*/
@@ -55,6 +56,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Client62::constants::EXPANSION_BIT,
Client62::constants::EXPANSIONS_MASK,
Client62::INULL,
Client62::INULL,
Client62::INULL
),
/*[ClientVersion::Titanium] =*/
@@ -63,7 +65,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
Titanium::constants::EXPANSION_BIT,
Titanium::constants::EXPANSIONS_MASK,
Titanium::constants::CHARACTER_CREATION_LIMIT,
Titanium::constants::SAY_LINK_BODY_SIZE
Titanium::constants::SAY_LINK_BODY_SIZE,
Titanium::INULL
),
/*[ClientVersion::SoF] =*/
EQ::constants::LookupEntry(
@@ -71,7 +74,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoF::constants::EXPANSION_BIT,
SoF::constants::EXPANSIONS_MASK,
SoF::constants::CHARACTER_CREATION_LIMIT,
SoF::constants::SAY_LINK_BODY_SIZE
SoF::constants::SAY_LINK_BODY_SIZE,
SoF::INULL
),
/*[ClientVersion::SoD] =*/
EQ::constants::LookupEntry(
@@ -79,7 +83,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
SoD::constants::EXPANSION_BIT,
SoD::constants::EXPANSIONS_MASK,
SoD::constants::CHARACTER_CREATION_LIMIT,
SoD::constants::SAY_LINK_BODY_SIZE
SoD::constants::SAY_LINK_BODY_SIZE,
SoD::INULL
),
/*[ClientVersion::UF] =*/
EQ::constants::LookupEntry(
@@ -87,7 +92,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
UF::constants::EXPANSION_BIT,
UF::constants::EXPANSIONS_MASK,
UF::constants::CHARACTER_CREATION_LIMIT,
UF::constants::SAY_LINK_BODY_SIZE
UF::constants::SAY_LINK_BODY_SIZE,
UF::INULL
),
/*[ClientVersion::RoF] =*/
EQ::constants::LookupEntry(
@@ -95,7 +101,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF::constants::EXPANSION_BIT,
RoF::constants::EXPANSIONS_MASK,
RoF::constants::CHARACTER_CREATION_LIMIT,
RoF::constants::SAY_LINK_BODY_SIZE
RoF::constants::SAY_LINK_BODY_SIZE,
RoF::INULL
),
/*[ClientVersion::RoF2] =*/
EQ::constants::LookupEntry(
@@ -103,15 +110,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
RoF2::constants::EXPANSION_BIT,
RoF2::constants::EXPANSIONS_MASK,
RoF2::constants::CHARACTER_CREATION_LIMIT,
RoF2::constants::SAY_LINK_BODY_SIZE
),
/*[ClientVersion::Larion] =*/
EQ::constants::LookupEntry(
Larion::constants::EXPANSION,
Larion::constants::EXPANSION_BIT,
Larion::constants::EXPANSIONS_MASK,
Larion::constants::CHARACTER_CREATION_LIMIT,
Larion::constants::SAY_LINK_BODY_SIZE
RoF2::constants::SAY_LINK_BODY_SIZE,
RoF2::constants::MAX_BAZAAR_TRADERS
)
};
@@ -378,33 +378,6 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF2::inventory::ConcatenateInvTypeLimbo,
RoF2::inventory::AllowOverLevelEquipment
),
/*[MobVersion::LS] =*/
EQ::inventory::LookupEntry(
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
EQ::invtype::POSSESSIONS_SIZE, RoF2::invtype::BANK_SIZE, RoF2::invtype::SHARED_BANK_SIZE,
RoF2::invtype::TRADE_SIZE, RoF2::invtype::WORLD_SIZE, RoF2::invtype::LIMBO_SIZE,
RoF2::invtype::TRIBUTE_SIZE, RoF2::invtype::TROPHY_TRIBUTE_SIZE, RoF2::invtype::GUILD_TRIBUTE_SIZE,
RoF2::invtype::MERCHANT_SIZE, RoF2::invtype::DELETED_SIZE, RoF2::invtype::CORPSE_SIZE,
RoF2::invtype::BAZAAR_SIZE, RoF2::invtype::INSPECT_SIZE, RoF2::invtype::REAL_ESTATE_SIZE,
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::invtype::ALT_STORAGE_SIZE, RoF2::invtype::ARCHIVED_SIZE,
RoF2::invtype::MAIL_SIZE, RoF2::invtype::GUILD_TROPHY_TRIBUTE_SIZE, RoF2::invtype::KRONO_SIZE,
RoF2::invtype::OTHER_SIZE
),
RoF2::invslot::EQUIPMENT_BITMASK,
RoF2::invslot::GENERAL_BITMASK,
RoF2::invslot::CURSOR_BITMASK,
RoF2::invslot::POSSESSIONS_BITMASK,
RoF2::invslot::CORPSE_BITMASK,
RoF2::invbag::SLOT_COUNT,
RoF2::invaug::SOCKET_COUNT,
RoF2::inventory::AllowEmptyBagInBag,
RoF2::inventory::AllowClickCastFromBag,
RoF2::inventory::ConcatenateInvTypeLimbo,
RoF2::inventory::AllowOverLevelEquipment
),
/*[MobVersion::NPC] =*/
EQ::inventory::LookupEntry(
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
@@ -778,33 +751,6 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
RoF2::invbag::SLOT_COUNT,
RoF2::invaug::SOCKET_COUNT,
false,
false,
false,
false
),
/*[MobVersion::OfflineLS] =*/
EQ::inventory::LookupEntry(
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
RoF2::INULL, RoF2::INULL, RoF2::INULL,
RoF2::invtype::TRADE_SIZE, RoF2::INULL, RoF2::INULL,
RoF2::INULL, RoF2::INULL, RoF2::INULL,
RoF2::invtype::MERCHANT_SIZE, RoF2::INULL, RoF2::INULL,
RoF2::invtype::BAZAAR_SIZE, RoF2::invtype::INSPECT_SIZE, RoF2::INULL,
RoF2::invtype::VIEW_MOD_PC_SIZE, RoF2::invtype::VIEW_MOD_BANK_SIZE, RoF2::invtype::VIEW_MOD_SHARED_BANK_SIZE,
RoF2::invtype::VIEW_MOD_LIMBO_SIZE, RoF2::INULL, RoF2::INULL,
RoF2::INULL, RoF2::INULL, RoF2::INULL,
RoF2::INULL
),
RoF2::INULL,
RoF2::INULL,
RoF2::INULL,
RoF2::INULL,
RoF2::INULL,
RoF2::invbag::SLOT_COUNT,
RoF2::invaug::SOCKET_COUNT,
false,
false,
false,
@@ -1056,10 +1002,6 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
EQ::behavior::LookupEntry(
RoF2::behavior::CoinHasWeight
),
/*[MobVersion::LS] =*/
EQ::behavior::LookupEntry(
RoF2::behavior::CoinHasWeight
),
/*[MobVersion::NPC] =*/
EQ::behavior::LookupEntry(
EQ::behavior::CoinHasWeight
@@ -1113,10 +1055,6 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
RoF::behavior::CoinHasWeight
),
/*[MobVersion::OfflineRoF2] =*/
EQ::behavior::LookupEntry(
RoF2::behavior::CoinHasWeight
),
/*[MobVersion::OfflineLS] =*/
EQ::behavior::LookupEntry(
RoF2::behavior::CoinHasWeight
)
@@ -1272,19 +1210,6 @@ static const EQ::spells::LookupEntry spells_static_lookup_entries[EQ::versions::
RoF2::spells::NPC_BUFFS,
RoF2::spells::PET_BUFFS,
RoF2::spells::MERC_BUFFS
),
/*[ClientVersion::Larion] =*/
EQ::spells::LookupEntry(
Larion::spells::SPELL_ID_MAX,
Larion::spells::SPELLBOOK_SIZE,
UF::spells::SPELL_GEM_COUNT, // client translators are setup to allow the max value a client supports..however, the top 4 indices are not valid in this case
Larion::spells::LONG_BUFFS,
Larion::spells::SHORT_BUFFS,
Larion::spells::DISC_BUFFS,
Larion::spells::TOTAL_BUFFS,
Larion::spells::NPC_BUFFS,
Larion::spells::PET_BUFFS,
Larion::spells::MERC_BUFFS
)
};
+6 -3
View File
@@ -29,7 +29,7 @@
#include "../common/patches/uf_limits.h"
#include "../common/patches/rof_limits.h"
#include "../common/patches/rof2_limits.h"
#include "../common/patches/larion_limits.h"
namespace EQ
{
@@ -42,6 +42,7 @@ namespace EQ
uint32 ExpansionsMask;
int16 CharacterCreationLimit;
size_t SayLinkBodySize;
uint32 BazaarTraderLimit;
LookupEntry(const LookupEntry *lookup_entry) { }
LookupEntry(
@@ -49,13 +50,15 @@ namespace EQ
uint32 ExpansionBit,
uint32 ExpansionsMask,
int16 CharacterCreationLimit,
size_t SayLinkBodySize
size_t SayLinkBodySize,
uint32 BazaarTraderLimit
) :
Expansion(Expansion),
ExpansionBit(ExpansionBit),
ExpansionsMask(ExpansionsMask),
CharacterCreationLimit(CharacterCreationLimit),
SayLinkBodySize(SayLinkBodySize)
SayLinkBodySize(SayLinkBodySize),
BazaarTraderLimit(BazaarTraderLimit)
{ }
};
+103 -6
View File
@@ -3221,6 +3221,7 @@ struct BuyerMessaging_Struct {
char item_name[64];
uint32 slot;
uint32 seller_quantity;
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
};
struct BuyerAddBuyertoBarterWindow_Struct {
@@ -3741,7 +3742,8 @@ struct GetItems_Struct{
struct BecomeTrader_Struct {
uint32 action;
uint32 zone_id;
uint16 zone_id;
uint16 zone_instance_id;
uint32 trader_id;
uint32 entity_id;
char trader_name[64];
@@ -5817,6 +5819,21 @@ struct ChangeSize_Struct
/*16*/
};
struct ChangePetName_Struct {
/*00*/ char new_pet_name[64];
/*40*/ char pet_owner_name[64];
/*80*/ int response_code;
};
enum ChangePetNameResponse : int {
Denied = 0, // 5167 You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name.
Accepted = 1, // 5976 Your request for a name change was successful.
Timeout = -3, // 5979 You must wait longer before submitting another name request. Please try again in a few minutes.
NotEligible = -4, // 5980 Your character is not eligible for a name change.
Pending = -5, // 5193 You already have a name change pending. Please wait until it is fully processed before attempting another name change.
Unhandled = -1
};
// New OpCode/Struct for SoD+
struct GroupMakeLeader_Struct
{
@@ -6346,6 +6363,7 @@ enum BazaarTraderBarterActions {
TraderAck2 = 22,
AddTraderToBazaarWindow = 24,
RemoveTraderFromBazaarWindow = 25,
FirstOpenSearch = 26,
ClickTrader = 28,
DeliveryCostUpdate = 29
};
@@ -6385,6 +6403,7 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 icon_id;
uint32 sum_charges;
uint32 trader_zone_id;
int32 trader_zone_instance_id;
uint32 trader_entity_id;
uint32 item_stat;
bool stackable;
@@ -6406,6 +6425,7 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(icon_id),
CEREAL_NVP(sum_charges),
CEREAL_NVP(trader_zone_id),
CEREAL_NVP(trader_zone_instance_id),
CEREAL_NVP(trader_entity_id),
CEREAL_NVP(item_stat),
CEREAL_NVP(stackable),
@@ -6435,11 +6455,88 @@ struct BuylineItemDetails_Struct {
uint32 item_quantity;
};
struct EqGuid
{
uint32_t Id;
uint16_t WorldId;
uint16_t Reserved;
struct PickZoneEntry_Struct {
int16 zone_id;
int16 unknown;
int32 player_count;
int32 instance_id;
};
struct PickZoneWindow_Struct {
char padding000[64];
int64 session_id;
int8 option_count;
char padding073[23];
PickZoneEntry_Struct entries[10];
};
struct PickZone_Struct {
int64 session_id;
int32 selection_id;
};
struct EvolveItemToggle {
uint32 action;
uint32 unknown_004;
uint64 unique_id;
uint32 percentage;
uint32 activated;
};
struct EvolveXPWindowReceive {
uint32 action;
uint32 unknown_004;
uint64 item1_unique_id;
uint64 item2_unique_id;
};
struct EvolveItemMessaging {
uint32 action;
char serialized_data[];
};
struct EvolveXPWindowSend {
/*000*/ uint32 action;
/*004*/ uint64 item1_unique_id;
/*012*/ uint64 item2_unique_id;
/*020*/ uint32 compatibility;
/*024*/ uint32 max_transfer_level;
/*028*/ uint8 item1_present;
/*029*/ uint8 item2_present;
/*030*/ std::string serialize_item_1;
/*034*/ std::string serialize_item_2;
template<class Archive>
void serialize(Archive &archive)
{
archive(
CEREAL_NVP(action),
CEREAL_NVP(item1_unique_id),
CEREAL_NVP(item2_unique_id),
CEREAL_NVP(compatibility),
CEREAL_NVP(max_transfer_level),
CEREAL_NVP(item1_present),
CEREAL_NVP(item2_present),
CEREAL_NVP(serialize_item_1),
CEREAL_NVP(serialize_item_2)
);
}
};
struct EvolveTransfer {
uint32 item_from_id;
uint32 item_from_current_amount;
uint32 item_to_id;
uint32 item_to_current_amount;
uint32 compatibility;
uint32 max_transfer_level;
};
struct EvolveGetNextItem {
uint32 new_item_id;
uint64 new_current_amount;
uint64 from_current_amount;
uint32 max_transfer_level;
};
// Restore structure packing to default
+2 -1
View File
@@ -94,7 +94,7 @@ void EQEmuConfig::parse_config()
auto_database_updates = true;
}
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldIP = _root["server"]["world"]["tcp"].get("ip", "127.0.0.1").asString();
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
@@ -171,6 +171,7 @@ void EQEmuConfig::parse_config()
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
OpcodeDir = _root["server"]["directories"].get("opcodes", "./").asString();
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
+2 -1
View File
@@ -95,6 +95,7 @@ class EQEmuConfig
std::string PluginDir;
std::string LuaModuleDir;
std::string PatchDir;
std::string OpcodeDir;
std::string SharedMemDir;
std::string LogDir;
@@ -136,9 +137,9 @@ class EQEmuConfig
{
}
virtual ~EQEmuConfig() {}
public:
virtual ~EQEmuConfig() {}
// Produce a const singleton
static const EQEmuConfig *get()
+8
View File
@@ -25,6 +25,8 @@
#include "repositories/discord_webhooks_repository.h"
#include "repositories/logsys_categories_repository.h"
#include "termcolor/rang.hpp"
#include "path_manager.h"
#include "file.h"
#include <iostream>
#include <string>
@@ -85,6 +87,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
* Set Defaults
*/
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
@@ -532,6 +535,11 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
{
EQEmuLogSys::CloseFileLogs();
if (!File::Exists(path.GetLogPath())) {
LogInfo("Logs directory not found, creating [{}]", path.GetLogPath());
File::Makedir(path.GetLogPath());
}
/**
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
*/
+7 -1
View File
@@ -142,6 +142,9 @@ namespace Logs {
EqTime,
Corpses,
XTargets,
EvolveItem,
PositionUpdate,
KSM,
MaxCategoryID /* Don't Remove this */
};
@@ -242,7 +245,10 @@ namespace Logs {
"Zoning",
"EqTime",
"Corpses",
"XTargets"
"XTargets",
"EvolveItem",
"PositionUpdate",
"KSM" // Kernel Samepage Merging
};
}
+30
View File
@@ -131,6 +131,16 @@
OutF(LogSys, Logs::Detail, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogEvolveItem(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::EvolveItem))\
OutF(LogSys, Logs::General, Logs::EvolveItem, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogEvolveItemDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::EvolveItem))\
OutF(LogSys, Logs::Detail, Logs::EvolveItem, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogGuilds(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::Guilds))\
OutF(LogSys, Logs::General, Logs::Guilds, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@@ -844,6 +854,26 @@
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPositionUpdate(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::PositionUpdate))\
OutF(LogSys, Logs::General, Logs::PositionUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPositionUpdateDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PositionUpdate))\
OutF(LogSys, Logs::Detail, Logs::PositionUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__); \
} while (0)
#define LogKSM(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::KSM))\
OutF(LogSys, Logs::General, Logs::KSM, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogKSMDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::KSM))\
OutF(LogSys, Logs::Detail, Logs::KSM, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+1
View File
@@ -707,6 +707,7 @@ void PlayerEventLogs::SetSettingsDefaults()
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
m_settings[PlayerEvent::EVOLVE_ITEM].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
+26 -1
View File
@@ -62,6 +62,7 @@ namespace PlayerEvent {
PARCEL_RETRIEVE,
PARCEL_DELETE,
BARTER_TRANSACTION,
EVOLVE_ITEM,
MAX // dont remove
};
@@ -124,7 +125,8 @@ namespace PlayerEvent {
"Parcel Item Sent",
"Parcel Item Retrieved",
"Parcel Prune Routine",
"Barter Transaction"
"Barter Transaction",
"Evolve Item Update"
};
// Generic struct used by all events
@@ -1115,6 +1117,29 @@ namespace PlayerEvent {
);
}
};
struct EvolveItem {
std::string status;
uint32 item_id;
uint64 unique_id;
std::string item_name;
uint32 level;
double progression;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(status),
CEREAL_NVP(item_id),
CEREAL_NVP(unique_id),
CEREAL_NVP(item_name),
CEREAL_NVP(level),
CEREAL_NVP(progression)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
+303
View File
@@ -0,0 +1,303 @@
#include "evolving_items.h"
#include "item_instance.h"
#include "events/player_event_logs.h"
#include "repositories/character_evolving_items_repository.h"
EvolvingItemsManager::EvolvingItemsManager()
{
m_db = nullptr;
m_content_db = nullptr;
}
void EvolvingItemsManager::LoadEvolvingItems() const
{
auto const &results = ItemsEvolvingDetailsRepository::All(*m_content_db);
if (results.empty()) {
return;
}
std::ranges::transform(
results.begin(),
results.end(),
std::inserter(
evolving_items_manager.GetEvolvingItemsCache(),
evolving_items_manager.GetEvolvingItemsCache().end()
),
[](const ItemsEvolvingDetailsRepository::ItemsEvolvingDetails &x) {
return std::make_pair(x.item_id, x);
}
);
}
void EvolvingItemsManager::SetDatabase(Database *db)
{
m_db = db;
}
void EvolvingItemsManager::SetContentDatabase(Database *db)
{
m_content_db = db;
}
double EvolvingItemsManager::CalculateProgression(const uint64 current_amount, const uint32 item_id)
{
if (!evolving_items_manager.GetEvolvingItemsCache().contains(item_id)) {
return 0;
}
return evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount > 0
? static_cast<double>(current_amount)
/ static_cast<double>(evolving_items_manager.GetEvolvingItemsCache().at(item_id).required_amount) * 100
: 0;
}
void EvolvingItemsManager::DoLootChecks(const uint32 char_id, const uint16 slot_id, const EQ::ItemInstance &inst) const
{
inst.SetEvolveEquipped(false);
if (inst.IsEvolving() && slot_id <= EQ::invslot::EQUIPMENT_END && slot_id >= EQ::invslot::EQUIPMENT_BEGIN) {
inst.SetEvolveEquipped(true);
}
if (!inst.IsEvolving()) {
return;
}
if (!inst.GetEvolveUniqueID()) {
auto e = CharacterEvolvingItemsRepository::NewEntity();
e.character_id = char_id;
e.item_id = inst.GetID();
e.equipped = inst.GetEvolveEquipped();
e.final_item_id = evolving_items_manager.GetFinalItemID(inst);
auto r = CharacterEvolvingItemsRepository::InsertOne(*m_db, e);
e.id = r.id;
inst.SetEvolveUniqueID(e.id);
inst.SetEvolveCharID(e.character_id);
inst.SetEvolveItemID(e.item_id);
inst.SetEvolveFinalItemID(e.final_item_id);
return;
}
CharacterEvolvingItemsRepository::SetEquipped(*m_db, inst.GetEvolveUniqueID(), inst.GetEvolveEquipped());
}
uint32 EvolvingItemsManager::GetFinalItemID(const EQ::ItemInstance &inst) const
{
const auto start_iterator = std::ranges::find_if(
evolving_items_manager.GetEvolvingItemsCache().cbegin(),
evolving_items_manager.GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID();
}
);
if (start_iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) {
return 0;
}
const auto final_id = std::ranges::max_element(
start_iterator,
evolving_items_manager.GetEvolvingItemsCache().cend(),
[&](
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a,
const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &b
) {
return a.second.item_evo_id == b.second.item_evo_id &&
a.second.item_evolve_level < b.second.item_evolve_level;
}
);
return final_id->first;
}
uint32 EvolvingItemsManager::GetNextEvolveItemID(const EQ::ItemInstance &inst) const
{
int8 const current_level = inst.GetEvolveLvl();
const auto iterator = std::ranges::find_if(
evolving_items_manager.GetEvolvingItemsCache().cbegin(),
evolving_items_manager.GetEvolvingItemsCache().cend(),
[&](const std::pair<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> &a) {
return a.second.item_evo_id == inst.GetEvolveLoreID() &&
a.second.item_evolve_level == current_level + 1;
}
);
if (iterator == std::end(evolving_items_manager.GetEvolvingItemsCache())) {
return 0;
}
return iterator->first;
}
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails EvolvingItemsManager::GetEvolveItemDetails(const uint64 unique_id)
{
if (GetEvolvingItemsCache().contains(unique_id)) {
return GetEvolvingItemsCache().at(unique_id);
}
return ItemsEvolvingDetailsRepository::NewEntity();
}
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> EvolvingItemsManager::GetEvolveIDItems(
const uint32 evolve_id
)
{
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> e{};
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_evo_id == evolve_id) {
e.push_back(value);
}
}
std::ranges::sort(
e.begin(),
e.end(),
[&](
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &a,
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails const &b
) {
return a.item_evolve_level < b.item_evolve_level;
}
);
return e;
}
uint64 EvolvingItemsManager::GetTotalEarnedXP(const EQ::ItemInstance &inst)
{
if (!inst) {
return 0;
}
uint64 xp = inst.GetEvolveCurrentAmount();
auto evolve_id_item_cache = GetEvolveIDItems(inst.GetEvolveLoreID());
auto current_level = inst.GetEvolveLvl();
for (auto const &i: evolve_id_item_cache) {
if (i.item_evolve_level < current_level) {
xp += i.required_amount;
}
}
return xp;
}
EvolveGetNextItem EvolvingItemsManager::GetNextItemByXP(const EQ::ItemInstance &inst_in, const int64 in_xp)
{
EvolveGetNextItem ets{};
const auto evolve_items = GetEvolveIDItems(inst_in.GetEvolveLoreID());
uint32 max_transfer_level = 0;
int64 xp = in_xp;
for (auto const &e: evolve_items) {
if (e.item_evolve_level < inst_in.GetEvolveLvl()) {
continue;
}
int64 have = 0;
if (e.item_evolve_level == inst_in.GetEvolveLvl()) {
have = inst_in.GetEvolveCurrentAmount();
}
const auto required = e.required_amount;
const int64 need = required - have;
const int64 balance = xp - need;
if (balance <= 0) {
ets.new_current_amount = have + xp;
ets.new_item_id = e.item_id;
ets.from_current_amount = 0;
ets.max_transfer_level = max_transfer_level;
return ets;
}
xp = balance;
max_transfer_level += 1;
ets.new_current_amount = required;
ets.new_item_id = e.item_id;
ets.from_current_amount = balance - required;
ets.max_transfer_level = max_transfer_level;
}
return ets;
}
EvolveTransfer EvolvingItemsManager::DetermineTransferResults(
const EQ::ItemInstance &inst_from,
const EQ::ItemInstance &inst_to
)
{
EvolveTransfer ets{};
auto evolving_details_inst_from = evolving_items_manager.GetEvolveItemDetails(inst_from.GetID());
auto evolving_details_inst_to = evolving_items_manager.GetEvolveItemDetails(inst_to.GetID());
if (!evolving_details_inst_from.id || !evolving_details_inst_to.id) {
return ets;
}
if (evolving_details_inst_from.type == evolving_details_inst_to.type) {
uint32 compatibility = 0;
uint64 xp = 0;
if (evolving_details_inst_from.sub_type == evolving_details_inst_to.sub_type) {
compatibility = 100;
}
else {
compatibility = 30;
}
xp = evolving_items_manager.GetTotalEarnedXP(inst_from) * compatibility / 100;
auto results = evolving_items_manager.GetNextItemByXP(inst_to, xp);
ets.item_from_id = evolving_items_manager.GetFirstItemInLoreGroup(inst_from.GetEvolveLoreID());
ets.item_from_current_amount = results.from_current_amount;
ets.item_to_id = results.new_item_id;
ets.item_to_current_amount = results.new_current_amount;
ets.compatibility = compatibility;
ets.max_transfer_level = results.max_transfer_level;
}
return ets;
}
uint32 EvolvingItemsManager::GetFirstItemInLoreGroup(const uint32 lore_id)
{
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_evo_id == lore_id && value.item_evolve_level == 1) {
return key;
}
}
return 0;
}
uint32 EvolvingItemsManager::GetFirstItemInLoreGroupByItemID(const uint32 item_id)
{
for (auto const &[key, value]: GetEvolvingItemsCache()) {
if (value.item_id == item_id) {
for (auto const &[key2, value2]: GetEvolvingItemsCache()) {
if (value2.item_evo_id == value.item_evo_id && value2.item_evolve_level == 1) {
return key;
}
}
}
}
return 0;
}
void EvolvingItemsManager::LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e)
{
e.item_id = inst.GetID();
e.item_name = inst.GetItem() ? inst.GetItem()->Name : std::string();
e.level = inst.GetEvolveLvl();
e.progression = inst.GetEvolveProgression();
e.unique_id = inst.GetEvolveUniqueID();
}
+67
View File
@@ -0,0 +1,67 @@
#ifndef EVOLVING_H
#define EVOLVING_H
#include "shareddb.h"
#include "events/player_events.h"
#include "repositories/items_evolving_details_repository.h"
namespace EQ {
class ItemInstance;
}
namespace EvolvingItems {
namespace Actions {
constexpr int8 UPDATE_ITEMS = 0;
constexpr int8 TRANSFER_WINDOW_OPEN = 1;
constexpr int8 TRANSFER_WINDOW_DETAILS = 2;
constexpr int8 TRANSFER_XP = 3;
constexpr int8 FINAL_RESULT = 4;
}
namespace Types {
constexpr int8 AMOUNT_OF_EXP = 1;
constexpr int8 NUMBER_OF_KILLS = 2;
constexpr int8 SPECIFIC_MOB_RACE = 3;
constexpr int8 SPECIFIC_ZONE_ID = 4;
}
namespace SubTypes {
constexpr int8 ALL_EXP = 0;
constexpr int8 SOLO_EXP = 1;
constexpr int8 GROUP_EXP = 2;
constexpr int8 RAID_EXP = 3;
}
}
class EvolvingItemsManager
{
public:
EvolvingItemsManager();
void SetDatabase(Database *db);
void SetContentDatabase(Database *db);
void LoadEvolvingItems() const;
void DoLootChecks(uint32 char_id, uint16 slot_id, const EQ::ItemInstance &inst) const;
uint32 GetFinalItemID(const EQ::ItemInstance &inst) const;
uint32 GetNextEvolveItemID(const EQ::ItemInstance &inst) const;
uint32 GetFirstItemInLoreGroup(uint32 lore_id);
uint32 GetFirstItemInLoreGroupByItemID(uint32 item_id);
uint64 GetTotalEarnedXP(const EQ::ItemInstance &inst);
static double CalculateProgression(uint64 current_amount, uint32 item_id);
static void LoadPlayerEvent(const EQ::ItemInstance &inst, PlayerEvent::EvolveItem &e);
ItemsEvolvingDetailsRepository::ItemsEvolvingDetails GetEvolveItemDetails(uint64 id);
EvolveTransfer DetermineTransferResults(const EQ::ItemInstance& inst_from, const EQ::ItemInstance& inst_to);
EvolveGetNextItem GetNextItemByXP(const EQ::ItemInstance &inst_in, int64 in_xp);
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails>& GetEvolvingItemsCache() { return evolving_items_cache; }
std::vector<ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> GetEvolveIDItems(uint32 evolve_id);
private:
std::map<uint32, ItemsEvolvingDetailsRepository::ItemsEvolvingDetails> evolving_items_cache;
Database * m_db;
Database * m_content_db;
};
extern EvolvingItemsManager evolving_items_manager;
#endif //EVOLVING_H
+199 -5
View File
@@ -344,6 +344,8 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapNotAllowed;
return false;
}
source_item_instance->SetEvolveEquipped(false);
if ((destination_slot >= invslot::EQUIPMENT_BEGIN && destination_slot <= invslot::EQUIPMENT_END)) {
auto source_item = source_item_instance->GetItem();
if (!source_item) {
@@ -362,6 +364,9 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapLevel;
return false;
}
if (source_item_instance->IsEvolving() > 0) {
source_item_instance->SetEvolveEquipped(true);
}
}
}
@@ -370,6 +375,8 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapNotAllowed;
return false;
}
destination_item_instance->SetEvolveEquipped(false);
if ((source_slot >= invslot::EQUIPMENT_BEGIN && source_slot <= invslot::EQUIPMENT_END)) {
auto destination_item = destination_item_instance->GetItem();
if (!destination_item) {
@@ -388,6 +395,9 @@ bool EQ::InventoryProfile::SwapItem(
fail_state = swapLevel;
return false;
}
if (destination_item_instance->IsEvolving()) {
destination_item_instance->SetEvolveEquipped(true);
}
}
}
@@ -612,9 +622,9 @@ bool EQ::InventoryProfile::HasAugmentEquippedByID(uint32 item_id)
return has_equipped;
}
int EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
uint32 EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
{
int quantity = 0;
uint32 quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
@@ -643,9 +653,9 @@ bool EQ::InventoryProfile::HasItemEquippedByID(uint32 item_id)
return has_equipped;
}
int EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
uint32 EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
{
int quantity = 0;
uint32 quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
@@ -1402,6 +1412,8 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
int16 result = INVALID_INDEX;
int16 parentSlot = INVALID_INDEX;
inst->SetEvolveEquipped(false);
if (slot_id == invslot::slotCursor) {
// Replace current item on cursor, if exists
m_cursor.pop(); // no memory delete, clients of this function know what they are doing
@@ -1410,6 +1422,9 @@ int16 EQ::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
}
else if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) != 0) {
if (inst->IsEvolving()) {
inst->SetEvolveEquipped(true);
}
m_worn[slot_id] = inst;
result = slot_id;
}
@@ -1807,4 +1822,183 @@ int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItem(const EQ::ItemData *it
}
}
return 0;
}
}
//This function has the same flaw as noted above
// Helper functions for evolving items
int16 EQ::InventoryProfile::HasEvolvingItem(uint64 evolve_unique_id, uint8 quantity, uint8 where)
{
int16 slot_id = INVALID_INDEX;
// Altered by Father Nitwit to support a specification of
// where to search, with a default value to maintain compatibility
// Check each inventory bucket
if (where & invWhereWorn) {
slot_id = _HasEvolvingItem(m_worn, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
if (where & invWherePersonal) {
slot_id = _HasEvolvingItem(m_inv, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
if (where & invWhereBank) {
slot_id = _HasEvolvingItem(m_bank, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
if (where & invWhereSharedBank) {
slot_id = _HasEvolvingItem(m_shbank, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
if (where & invWhereTrading) {
slot_id = _HasEvolvingItem(m_trade, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
// Behavioral change - Limbo is no longer checked due to improper handling of return value
if (where & invWhereCursor) {
// Check cursor queue
slot_id = _HasEvolvingItem(m_cursor, evolve_unique_id, quantity);
if (slot_id != INVALID_INDEX) {
return slot_id;
}
}
return slot_id;
}
// Internal Method: Checks an inventory bucket for a particular evolving item unique id
int16 EQ::InventoryProfile::_HasEvolvingItem(
std::map<int16, ItemInstance *> &bucket, uint64 evolve_unique_id, uint8 quantity)
{
uint32 quantity_found = 0;
for (auto const &[key, value]: bucket) {
if (!value) {
continue;
}
if (key <= EQ::invslot::POSSESSIONS_END && key >= EQ::invslot::POSSESSIONS_BEGIN) {
if (((uint64) 1 << key & m_lookup->PossessionsBitmask) == 0) {
continue;
}
}
else if (key <= EQ::invslot::BANK_END && key >= EQ::invslot::BANK_BEGIN) {
if (key - EQ::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize.Bank) {
continue;
}
}
if (value->GetEvolveUniqueID() == evolve_unique_id) {
quantity_found += value->GetCharges() <= 0 ? 1 : value->GetCharges();
if (quantity_found >= quantity) {
return key;
}
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
}
}
if (!value->IsClassBag()) {
continue;
}
for (auto const &[bag_key, bag_value]: *value->GetContents()) {
if (!bag_value) {
continue;
}
if (bag_value->GetEvolveUniqueID() == evolve_unique_id) {
quantity_found += bag_value->GetCharges() <= 0 ? 1 : bag_value->GetCharges();
if (quantity_found >= quantity) {
return CalcSlotId(key, bag_key);
}
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (bag_value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
}
}
}
}
return INVALID_INDEX;
}
// Internal Method: Checks an inventory queue type bucket for a particular item
int16 EQ::InventoryProfile::_HasEvolvingItem(ItemInstQueue &iqueue, uint64 evolve_unique_id, uint8 quantity)
{
// The downfall of this (these) queue procedure is that callers presume that when an item is
// found, it is presented as being available on the cursor. In cases of a parity check, this
// is sufficient. However, in cases where referential criteria is considered, this can lead
// to unintended results. Funtionality should be observed when referencing the return value
// of this query
uint32 quantity_found = 0;
for (auto const &inst: iqueue) {
if (!inst) {
continue;
}
if (inst->GetEvolveUniqueID() == evolve_unique_id) {
quantity_found += inst->GetCharges() <= 0 ? 1 : inst->GetCharges();
if (quantity_found >= quantity) {
return invslot::slotCursor;
}
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (inst->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
}
}
if (!inst->IsClassBag()) {
continue;
}
for (auto const &[bag_key, bag_value]: *inst->GetContents()) {
if (!bag_value) {
continue;
}
if (bag_value->GetEvolveUniqueID() == evolve_unique_id) {
quantity_found += bag_value->GetCharges() <= 0 ? 1 : bag_value->GetCharges();
if (quantity_found >= quantity) {
return CalcSlotId(invslot::slotCursor, bag_key);
}
}
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
if (bag_value->GetAugmentEvolveUniqueID(index) == evolve_unique_id && quantity <= 1) {
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
}
}
}
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
break;
}
return INVALID_INDEX;
}
+13 -2
View File
@@ -57,6 +57,8 @@ public:
inline std::list<EQ::ItemInstance*>::const_iterator cbegin() { return m_list.cbegin(); }
inline std::list<EQ::ItemInstance*>::const_iterator cend() { return m_list.cend(); }
inline std::list<EQ::ItemInstance*>::iterator begin() { return m_list.begin(); }
inline std::list<EQ::ItemInstance*>::iterator end() { return m_list.end(); }
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
inline bool empty() { return m_list.empty(); }
@@ -147,13 +149,13 @@ namespace EQ
bool HasItemEquippedByID(uint32 item_id);
// Check how many of a specific item the player has equipped by Item ID
int CountItemEquippedByID(uint32 item_id);
uint32 CountItemEquippedByID(uint32 item_id);
// Check if player has a specific augment equipped by Item ID
bool HasAugmentEquippedByID(uint32 item_id);
// Check how many of a specific augment the player has equipped by Item ID
int CountAugmentEquippedByID(uint32 item_id);
uint32 CountAugmentEquippedByID(uint32 item_id);
// Get a list of augments from a specific slot ID
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
@@ -211,6 +213,13 @@ namespace EQ
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
std::map<int16, ItemInstance*>& GetWorn() { return m_worn; }
std::map<int16, ItemInstance*>& GetPersonal() { return m_inv; }
int16 HasEvolvingItem(uint64 evolve_unique_id, uint8 quantity, uint8 where);
inline int16 PushItem(int16 slot_id, ItemInstance* inst) { return _PutItem(slot_id, inst); }
protected:
///////////////////////////////
// Protected Methods
@@ -233,6 +242,8 @@ namespace EQ
int16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);
int16 _HasItemByLoreGroup(std::map<int16, ItemInstance*>& bucket, uint32 loregroup);
int16 _HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup);
int16 _HasEvolvingItem(std::map<int16, ItemInstance*>& bucket, uint64 evolve_unique_id, uint8 quantity);
int16 _HasEvolvingItem(ItemInstQueue& iqueue, uint64 evolve_unique_id, uint8 quantity);
// Player inventory
+56 -51
View File
@@ -25,6 +25,7 @@
#include "rulesys.h"
#include "shareddb.h"
#include "strings.h"
#include "evolving_items.h"
//#include "../common/light_source.h"
@@ -76,6 +77,10 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_color = m_item->Color;
}
if (IsEvolving()) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
}
m_SerialNumber = GetNextItemInstSerialNumber();
}
@@ -95,6 +100,10 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
m_color = 0;
}
if (IsEvolving()) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
}
m_SerialNumber = GetNextItemInstSerialNumber();
}
@@ -146,7 +155,6 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
m_exp = copy.m_exp;
m_evolveLvl = copy.m_evolveLvl;
m_activated = copy.m_activated;
if (copy.m_scaledItem) {
m_scaledItem = new ItemData(*copy.m_scaledItem);
@@ -154,12 +162,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
m_scaledItem = nullptr;
}
if (copy.m_evolveInfo) {
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
} else {
m_evolveInfo = nullptr;
}
m_evolving_details = copy.m_evolving_details;
m_scaling = copy.m_scaling;
m_ornamenticon = copy.m_ornamenticon;
m_ornamentidfile = copy.m_ornamentidfile;
@@ -174,7 +177,6 @@ EQ::ItemInstance::~ItemInstance()
Clear();
safe_delete(m_item);
safe_delete(m_scaledItem);
safe_delete(m_evolveInfo);
}
// Query item type
@@ -1030,29 +1032,6 @@ void EQ::ItemInstance::ScaleItem() {
m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself.
}
bool EQ::ItemInstance::EvolveOnAllKills() const {
return (m_evolveInfo && m_evolveInfo->AllKills);
}
int8 EQ::ItemInstance::GetMaxEvolveLvl() const {
if (m_evolveInfo)
return m_evolveInfo->MaxLvl;
else
return 0;
}
uint32 EQ::ItemInstance::GetKillsNeeded(uint8 currentlevel) {
uint32 kills = -1; // default to -1 (max uint32 value) because this value is usually divided by, so we don't want to ever return zero.
if (m_evolveInfo)
if (currentlevel != m_evolveInfo->MaxLvl)
kills = m_evolveInfo->LvlKills[currentlevel - 1];
if (kills == 0)
kills = -1;
return kills;
}
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) {
Timer t(time);
t.Start(time, false);
@@ -1951,28 +1930,54 @@ void EQ::ItemInstance::ClearGUIDMap()
{
guids.clear();
}
//
// class EvolveInfo
//
EvolveInfo::EvolveInfo() {
// nothing here yet
bool EQ::ItemInstance::TransferOwnership(Database &db, const uint32 to_char_id) const
{
if (!to_char_id || !IsEvolving()) {
return false;
}
SetEvolveCharID(to_char_id);
CharacterEvolvingItemsRepository::UpdateCharID(db, GetEvolveUniqueID(), to_char_id);
return true;
}
EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10) {
FirstItem = first;
MaxLvl = max;
AllKills = allkills;
LvlKills[0] = L2;
LvlKills[1] = L3;
LvlKills[2] = L4;
LvlKills[3] = L5;
LvlKills[4] = L6;
LvlKills[5] = L7;
LvlKills[6] = L8;
LvlKills[7] = L9;
LvlKills[8] = L10;
uint32 EQ::ItemInstance::GetAugmentEvolveUniqueID(uint8 augment_index) const
{
if (!m_item || !m_item->IsClassCommon()) {
return 0;
}
const auto item = GetItem(augment_index);
if (item) {
return item->GetEvolveUniqueID();
}
return 0;
}
EvolveInfo::~EvolveInfo() {
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) const{
Timer t(time);
t.Start(time, false);
m_timers[name] = t;
}
void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
{
if (!IsEvolving()) {
return;
}
m_evolving_details.equipped = in;
if (in && !GetTimers().contains("evolve")) {
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
return;
}
if (in) {
GetTimers().at("evolve").SetTimer(RuleI(EvolvingItems, DelayUponEquipping));
return;
}
GetTimers().at("evolve").Disable();
}
+56 -48
View File
@@ -23,6 +23,7 @@
#ifndef COMMON_ITEM_INSTANCE_H
#define COMMON_ITEM_INSTANCE_H
#include "evolving_items.h"
class ItemParse; // Parses item packets
@@ -34,6 +35,7 @@ class EvolveInfo; // Stores information about an evolving item family
#include "../common/bodytypes.h"
#include "../common/deity.h"
#include "../common/memory_buffer.h"
#include "../common/repositories/character_evolving_items_repository.h"
#include <map>
@@ -205,13 +207,9 @@ namespace EQ
bool IsDroppable(bool recurse = true) const;
bool IsScaling() const { return m_scaling; }
bool IsEvolving() const { return (m_evolveLvl >= 1); }
uint32 GetExp() const { return m_exp; }
void SetExp(uint32 exp) { m_exp = exp; }
void AddExp(uint32 exp) { m_exp += exp; }
bool IsActivated() { return m_activated; }
void SetActivated(bool activated) { m_activated = activated; }
int8 GetEvolveLvl() const { return m_evolveLvl; }
void SetScaling(bool v) { m_scaling = v; }
uint32 GetOrnamentationIcon() const { return m_ornamenticon; }
void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; }
@@ -226,9 +224,6 @@ namespace EQ
void Initialize(SharedDatabase *db = nullptr);
void ScaleItem();
bool EvolveOnAllKills() const;
int8 GetMaxEvolveLvl() const;
uint32 GetKillsNeeded(uint8 currentlevel);
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; }
void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); }
@@ -236,8 +231,9 @@ namespace EQ
inline int32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
std::map<std::string, ::Timer>& GetTimers() { return m_timers; }
std::map<std::string, ::Timer>& GetTimers() const { return m_timers; }
void SetTimer(std::string name, uint32 time);
void SetTimer(std::string name, uint32 time) const;
void StopTimer(std::string name);
void ClearTimers();
@@ -312,6 +308,34 @@ namespace EQ
static void AddGUIDToMap(uint64 existing_serial_number);
static void ClearGUIDMap();
// evolving items stuff
CharacterEvolvingItemsRepository::CharacterEvolvingItems &GetEvolvingDetails() const { return m_evolving_details; }
int8 GetEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingLevel; } return false; }
bool IsEvolving() const { if (GetItem()) { return GetItem()->EvolvingItem; } return false; }
int8 GetMaxEvolveLvl() const { if (GetItem()) { return GetItem()->EvolvingMax; } return false; }
bool GetEvolveActivated() const { return m_evolving_details.activated ? true : false; }
bool GetEvolveEquipped() const { return m_evolving_details.equipped ? true : false; }
double GetEvolveProgression() const { return m_evolving_details.progression; }
uint64 GetEvolveUniqueID() const { return m_evolving_details.id; }
uint32 GetEvolveCharID() const { return m_evolving_details.character_id; }
uint32 GetEvolveItemID() const { return m_evolving_details.item_id; }
uint32 GetEvolveLoreID() const { if (GetItem()) { return GetItem()->EvolvingID; } return false; }
uint64 GetEvolveCurrentAmount() const { return m_evolving_details.current_amount; }
uint32 GetEvolveFinalItemID() const { return m_evolving_details.final_item_id; }
uint32 GetAugmentEvolveUniqueID(uint8 augment_index) const;
void SetEvolveEquipped(const bool in) const;
void SetEvolveActivated(const bool in) const { m_evolving_details.activated = in; }
void SetEvolveProgression(const double in) const { m_evolving_details.progression = in; }
void SetEvolveUniqueID(const uint64 in) const { m_evolving_details.id = in; }
void SetEvolveCharID(const uint32 in) const { m_evolving_details.character_id = in; }
void SetEvolveItemID(const uint32 in) const { m_evolving_details.item_id = in; }
void SetEvolveCurrentAmount(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; }
bool TransferOwnership(Database& db, const uint32 to_char_id) const;
void CalculateEvolveProgression() const { m_evolving_details.progression = evolving_items_manager.CalculateProgression(GetEvolveCurrentAmount(), GetID()); }
protected:
//////////////////////////
// Protected Members
@@ -323,48 +347,32 @@ namespace EQ
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
ItemInstTypes m_use_type {ItemInstNormal}; // Usage type for item
const ItemData* m_item {nullptr}; // Ptr to item data
int16 m_charges {0}; // # of charges for chargeable items
uint32 m_price {0}; // Bazaar /trader price
uint32 m_color {0};
uint32 m_merchantslot {0};
int16 m_currentslot {0};
bool m_attuned {false};
int32 m_merchantcount {1}; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber {0}; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp {0};
int8 m_evolveLvl {0};
bool m_activated {false};
ItemData* m_scaledItem {nullptr};
::EvolveInfo* m_evolveInfo {nullptr};
bool m_scaling {false};
uint32 m_ornamenticon {0};
uint32 m_ornamentidfile {0};
uint32 m_new_id_file {0};
uint32 m_ornament_hero_model {0};
uint32 m_recast_timestamp {0};
int m_task_delivered_count {0};
ItemInstTypes m_use_type{ItemInstNormal};// Usage type for item
const ItemData * m_item{nullptr}; // Ptr to item data
int16 m_charges{0}; // # of charges for chargeable items
uint32 m_price{0}; // Bazaar /trader price
uint32 m_color{0};
uint32 m_merchantslot{0};
int16 m_currentslot{0};
bool m_attuned{false};
int32 m_merchantcount{1};//number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber{0}; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp{0};
int8 m_evolveLvl{0};
ItemData * m_scaledItem{nullptr};
bool m_scaling{false};
uint32 m_ornamenticon{0};
uint32 m_ornamentidfile{0};
uint32 m_new_id_file{0};
uint32 m_ornament_hero_model{0};
uint32 m_recast_timestamp{0};
int m_task_delivered_count{0};
mutable CharacterEvolvingItemsRepository::CharacterEvolvingItems m_evolving_details{};
// Items inside of this item (augs or contents) {};
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
std::map<std::string, std::string> m_custom_data {};
std::map<std::string, ::Timer> m_timers {};
std::map<uint8, ItemInstance*> m_contents {}; // Zero-based index: min=0, max=9
std::map<std::string, std::string> m_custom_data {};
mutable std::map<std::string, ::Timer> m_timers {};
};
}
class EvolveInfo {
public:
friend class EQ::ItemInstance;
//temporary
uint16 LvlKills[9];
uint32 FirstItem;
uint8 MaxLvl;
bool AllKills;
EvolveInfo();
EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10);
~EvolveInfo();
};
#endif /*COMMON_ITEM_INSTANCE_H*/
+220
View File
@@ -0,0 +1,220 @@
#ifndef EQEMU_KSM_HPP
#define EQEMU_KSM_HPP
#include "../eqemu_logsys.h"
#include <iostream>
#include <vector>
#include <cstring>
#ifdef _WIN32
#include <malloc.h> // For _aligned_malloc, _aligned_free
#include <windows.h>
#else
#include <sys/mman.h> // For madvise
#include <unistd.h> // For sysconf, sbrk
#endif
// Page-aligned allocator for std::vector
template <typename T>
class PageAlignedAllocator {
public:
using value_type = T;
PageAlignedAllocator() noexcept = default;
template <typename U>
PageAlignedAllocator(const PageAlignedAllocator<U>&) noexcept {}
T* allocate(std::size_t n) {
void* ptr = nullptr;
size_t size = n * sizeof(T);
#ifdef _WIN32
// Simply allocate memory without alignment
ptr = malloc(size);
if (!ptr) throw std::bad_alloc();
#else
size_t alignment = getPageSize(); // Get the system's page size
if (posix_memalign(&ptr, alignment, size) != 0) {
throw std::bad_alloc();
}
#endif
return static_cast<T*>(ptr);
}
void deallocate(T* p, std::size_t) noexcept {
free(p);
}
private:
size_t getPageSize() const
{
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwPageSize; // Page size in bytes
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
#endif
};
};
template <typename T, typename U>
bool operator==(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
return true;
}
template <typename T, typename U>
bool operator!=(const PageAlignedAllocator<T>&, const PageAlignedAllocator<U>&) noexcept {
return false;
}
// Kernel Samepage Merging (KSM) functionality
namespace KSM {
#ifdef _WIN32
// Windows-specific placeholder functions (no-op)
inline void CheckPageAlignment(void* ptr) {
}
inline void* AllocatePageAligned(size_t size) {
return memset(malloc(size), 0, size);
}
inline void MarkMemoryForKSM(void* start, size_t size) {
}
inline void AlignHeapToPageBoundary() {
}
inline void* MarkHeapStart() {
return nullptr;
}
inline size_t MeasureHeapUsage(void* start) {
return 0;
}
#else
// Linux-specific functionality
inline void CheckPageAlignment(void* ptr) {
size_t page_size = sysconf(_SC_PAGESIZE);
if (reinterpret_cast<uintptr_t>(ptr) % page_size == 0) {
LogKSMDetail("Memory is page-aligned [{}]", ptr);
} else {
LogKSMDetail("Memory is NOT page-aligned [{}]", ptr);
}
}
inline void* AllocatePageAligned(size_t size) {
size_t page_size = sysconf(_SC_PAGESIZE);
void* aligned_ptr = nullptr;
if (posix_memalign(&aligned_ptr, page_size, size) != 0) {
LogKSM("Failed to allocate page-aligned memory on Linux. page_size [{}] size [{}] bytes", page_size, size);
}
std::memset(aligned_ptr, 0, size);
return aligned_ptr;
}
inline void MarkMemoryForKSM(void* start, size_t size) {
if (madvise(start, size, MADV_MERGEABLE) == 0) {
LogKSM("Marked memory for KSM | start [{}] size [{}] bytes", start, size);
} else {
perror("madvise failed");
}
}
inline void AlignHeapToPageBoundary() {
size_t page_size = sysconf(_SC_PAGESIZE);
if (page_size == 0) {
LogKSM("Failed to retrieve page size SC_PAGESIZE [{}]", page_size);
return;
}
void* current_break = sbrk(0);
if (current_break == (void*)-1) {
LogKSM("Failed to retrieve the current program break");
return;
}
uintptr_t current_address = reinterpret_cast<uintptr_t>(current_break);
size_t misalignment = current_address % page_size;
if (misalignment != 0) {
size_t adjustment = page_size - misalignment;
if (sbrk(adjustment) == (void*)-1) {
LogKSM("Failed to align heap to page boundary. adjustment [{}] bytes", adjustment);
return;
}
}
LogKSMDetail("Heap aligned to next page boundary. Current break [{}]", sbrk(0));
}
inline void* MarkHeapStart() {
void* current_pos = sbrk(0);
AlignHeapToPageBoundary();
return current_pos;
}
inline size_t MeasureHeapUsage(void* start) {
void* current_break = sbrk(0);
return static_cast<char*>(current_break) - static_cast<char*>(start);
}
#endif
inline size_t getPageSize()
{
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwPageSize; // Page size in bytes
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE)); // POSIX page size
#endif
};
template <typename T>
inline void PageAlignVectorAligned(std::vector<T, PageAlignedAllocator<T>>& vec) {
if (vec.empty()) {
return;
}
size_t page_size = getPageSize();
void* start = vec.data();
size_t size = vec.size() * sizeof(T);
// Check if the memory is page-aligned
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
// Allocate a new aligned vector
std::vector<T, PageAlignedAllocator<T>> aligned_vec(vec.get_allocator());
aligned_vec.reserve(vec.capacity()); // Match capacity to avoid reallocation during copy
// Copy elements from the original vector
aligned_vec.insert(aligned_vec.end(), vec.begin(), vec.end());
// Swap the aligned vector with the original vector
vec.swap(aligned_vec);
// Clear the temporary aligned vector to free its memory
aligned_vec.clear();
// Verify the new alignment
start = vec.data();
if (reinterpret_cast<std::uintptr_t>(start) % page_size != 0) {
throw std::runtime_error("Failed to align vector memory to page boundaries.");
}
LogKSMDetail("Vector reallocated to ensure page alignment. start [{}] size [{}] bytes", start, size);
} else {
LogKSMDetail("Vector is already page-aligned. start [{}] size [{}] bytes", start, size);
}
#ifndef _WIN32
// Mark memory for KSM (only on non-Windows systems)
MarkMemoryForKSM(start, size);
#endif
}
}
#endif // EQEMU_KSM_HPP
+600
View File
@@ -0,0 +1,600 @@
#include "mysql_stmt.h"
#include "eqemu_logsys.h"
#include "mutex.h"
#include "timer.h"
#include <charconv>
namespace mysql
{
void PreparedStmt::StmtDeleter::operator()(MYSQL_STMT* stmt) noexcept
{
// The connection must be locked when closing the stmt to avoid mysql errors
// in case another thread tries to use it during the close. If the mutex is
// changed to one that throws then exceptions need to be caught here.
LockMutex lock(mutex);
mysql_stmt_close(stmt);
}
PreparedStmt::PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts)
: m_stmt(mysql_stmt_init(&mysql), { mutex }), m_query(std::move(query)), m_mutex(mutex), m_options(opts)
{
LockMutex lock(m_mutex);
if (mysql_stmt_prepare(m_stmt.get(), m_query.c_str(), static_cast<unsigned long>(m_query.size())) != 0)
{
ThrowError(fmt::format("Prepare error: {}", GetStmtError()));
}
m_params.resize(mysql_stmt_param_count(m_stmt.get()));
m_inputs.resize(m_params.size());
}
void PreparedStmt::ThrowError(const std::string& error)
{
LogMySQLError("{}", error);
throw std::runtime_error(error);
}
std::string PreparedStmt::GetStmtError()
{
auto err = mysql_stmt_errno(m_stmt.get());
auto str = mysql_stmt_error(m_stmt.get());
return fmt::format("({}) [{}] for query [{}]", err, str, m_query);
}
template <typename T>
void PreparedStmt::BindInput(size_t index, T value)
{
if (index >= m_inputs.size())
{
ThrowError(fmt::format("Cannot bind input, index {} out of range", index));
}
impl::Bind& arg = m_inputs[index];
arg.is_null = std::is_same_v<T, std::nullptr_t>;
MYSQL_BIND& bind = m_params[index];
bind.is_unsigned = std::is_unsigned_v<T>;
bind.is_null = &arg.is_null;
bind.length = &arg.length;
auto old_type = bind.buffer_type;
if constexpr (std::is_arithmetic_v<T>)
{
if (arg.buffer.size() < sizeof(T))
{
arg.buffer.resize(std::max(sizeof(T), sizeof(int64_t)));
bind.buffer = arg.buffer.data();
m_need_bind = true;
}
memcpy(arg.buffer.data(), &value, sizeof(T));
}
if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, uint8_t> || std::is_same_v<T, bool>)
{
bind.buffer_type = MYSQL_TYPE_TINY;
}
else if constexpr (std::is_same_v<T, int16_t> || std::is_same_v<T, uint16_t>)
{
bind.buffer_type = MYSQL_TYPE_SHORT;
}
else if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>)
{
bind.buffer_type = MYSQL_TYPE_LONG;
}
else if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>)
{
bind.buffer_type = MYSQL_TYPE_LONGLONG;
}
else if constexpr (std::is_same_v<T, float>)
{
bind.buffer_type = MYSQL_TYPE_FLOAT;
}
else if constexpr (std::is_same_v<T, double>)
{
bind.buffer_type = MYSQL_TYPE_DOUBLE;
}
else if constexpr (std::is_same_v<T, std::string_view>)
{
bind.buffer_type = MYSQL_TYPE_STRING;
if (arg.buffer.empty() || arg.buffer.size() < value.size())
{
arg.buffer.resize(static_cast<size_t>((value.size() + 1) * 1.5));
bind.buffer = arg.buffer.data();
bind.buffer_length = static_cast<unsigned long>(arg.buffer.size());
m_need_bind = true;
}
std::copy(value.begin(), value.end(), arg.buffer.begin());
arg.length = static_cast<unsigned long>(value.size());
}
else if constexpr (!std::is_same_v<T, std::nullptr_t>)
{
static_assert(false_v<T>, "Cannot bind unsupported type");
}
if (old_type != bind.buffer_type)
{
m_need_bind = true;
}
}
void PreparedStmt::BindInput(size_t index, const char* str)
{
BindInput(index, std::string_view(str));
}
void PreparedStmt::BindInput(size_t index, const std::string& str)
{
BindInput(index, std::string_view(str));
}
StmtResult PreparedStmt::Execute()
{
CheckArgs(0);
return DoExecute();
}
StmtResult PreparedStmt::Execute(const std::vector<param_t>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
std::visit([&](const auto& arg) { BindInput(i, arg); }, args[i]);
}
return DoExecute();
}
template <typename T>
StmtResult PreparedStmt::Execute(const std::vector<T>& args)
{
CheckArgs(args.size());
for (size_t i = 0; i < args.size(); ++i)
{
BindInput(i, args[i]);
}
return DoExecute();
}
void PreparedStmt::CheckArgs(size_t argc)
{
if (argc != m_params.size())
{
ThrowError(fmt::format("Bad arg count (got {}, expected {}) for [{}]", argc, m_params.size(), m_query));
}
}
StmtResult PreparedStmt::DoExecute()
{
BenchTimer timer;
LockMutex lock(m_mutex);
if (m_need_bind && mysql_stmt_bind_param(m_stmt.get(), m_params.data()) != 0)
{
ThrowError(fmt::format("Bind param error: {}", GetStmtError()));
}
m_need_bind = false;
if (mysql_stmt_execute(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Execute error: {}", GetStmtError()));
}
my_bool attr = m_options.use_max_length;
mysql_stmt_attr_set(m_stmt.get(), STMT_ATTR_UPDATE_MAX_LENGTH, &attr);
if (m_options.buffer_results && mysql_stmt_store_result(m_stmt.get()) != 0)
{
ThrowError(fmt::format("Store result error: {}", GetStmtError()));
}
// Result buffers are bound on first execute and re-used if needed
if (m_results.empty())
{
BindResults();
}
StmtResult res(m_stmt.get(), m_results.size());
if (m_results.empty())
{
LogMySQLQuery("{} -- ({} row(s) affected) ({:.6f}s)", m_query, res.RowsAffected(), timer.elapsed());
}
else
{
LogMySQLQuery("{} -- ({} row(s) returned) ({:.6f}s)", m_query, res.RowCount(), timer.elapsed());
}
return res;
}
void PreparedStmt::BindResults()
{
MYSQL_RES* res = mysql_stmt_result_metadata(m_stmt.get());
if (!res)
{
return; // did not produce a result set
}
MYSQL_FIELD* fields = mysql_fetch_fields(res);
m_columns.resize(mysql_num_fields(res));
m_results.resize(m_columns.size());
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
MYSQL_BIND& bind = m_results[i];
col.index = i;
col.name = fields[i].name;
col.buffer_type = fields[i].type;
col.is_unsigned = (fields[i].flags & UNSIGNED_FLAG) != 0;
col.buffer.resize(GetResultBufferSize(fields[i]));
bind.buffer_type = col.buffer_type;
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
bind.is_unsigned = col.is_unsigned;
bind.is_null = &col.is_null;
bind.length = &col.length;
bind.error = &col.error;
}
mysql_free_result(res);
if (!m_results.empty() && mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Bind result error: {}", GetStmtError()));
}
}
int PreparedStmt::GetResultBufferSize(const MYSQL_FIELD& field) const
{
switch (field.type)
{
case MYSQL_TYPE_TINY:
return sizeof(int8_t);
case MYSQL_TYPE_SHORT:
return sizeof(int16_t);
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return sizeof(int32_t);
case MYSQL_TYPE_LONGLONG:
return sizeof(int64_t);
case MYSQL_TYPE_FLOAT:
return sizeof(float);
case MYSQL_TYPE_DOUBLE:
return sizeof(double);
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return sizeof(MYSQL_TIME);
default: // if max_length is unavailable for strings buffers are resized on fetch
return field.max_length + 1; // ensure valid buffer created
}
}
StmtRow PreparedStmt::Fetch()
{
StmtRow row;
if (!m_columns.empty())
{
int rc = mysql_stmt_fetch(m_stmt.get());
if (rc == 1)
{
ThrowError(fmt::format("Fetch error: {}", GetStmtError()));
}
if (rc != MYSQL_NO_DATA)
{
if (rc == MYSQL_DATA_TRUNCATED)
{
FetchTruncated();
}
row = StmtRow(m_columns);
}
}
return row;
}
void PreparedStmt::FetchTruncated()
{
for (int i = 0; i < static_cast<int>(m_columns.size()); ++i)
{
impl::BindColumn& col = m_columns[i].m_col;
if (col.error)
{
MYSQL_BIND& bind = m_results[i];
col.buffer.resize(static_cast<size_t>(col.length * 1.5));
bind.buffer = col.buffer.data();
bind.buffer_length = static_cast<unsigned long>(col.buffer.size());
mysql_stmt_fetch_column(m_stmt.get(), &bind, i, 0);
}
}
if (mysql_stmt_bind_result(m_stmt.get(), m_results.data()) != 0)
{
ThrowError(fmt::format("Fetch rebind result error: {}", GetStmtError()));
}
}
// ---------------------------------------------------------------------------
StmtResult::StmtResult(MYSQL_STMT* stmt, size_t columns)
{
m_num_cols = static_cast<int>(columns);
m_num_rows = mysql_stmt_num_rows(stmt); // requires buffered results
m_affected = mysql_stmt_affected_rows(stmt);
m_insert_id = mysql_stmt_insert_id(stmt);
}
// ---------------------------------------------------------------------------
const StmtColumn* StmtRow::GetColumn(size_t index) const
{
return index < m_columns.size() ? &m_columns[index] : nullptr;
}
const StmtColumn* StmtRow::GetColumn(std::string_view name) const
{
auto it = std::ranges::find_if(m_columns,
[name](const StmtColumn& col) { return col.Name() == name; });
return it != m_columns.end() ? &(*it) : nullptr;
}
std::optional<std::string> StmtRow::operator[](size_t index) const
{
return GetStr(index);
}
std::optional<std::string> StmtRow::operator[](std::string_view name) const
{
return GetStr(name);
}
std::optional<std::string> StmtRow::GetStr(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->GetStr() : std::nullopt;
}
std::optional<std::string> StmtRow::GetStr(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->GetStr() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(size_t index) const
{
const StmtColumn* col = GetColumn(index);
return col ? col->Get<T>() : std::nullopt;
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtRow::Get(std::string_view name) const
{
const StmtColumn* col = GetColumn(name);
return col ? col->Get<T>() : std::nullopt;
}
// ---------------------------------------------------------------------------
static time_t MakeTime(const MYSQL_TIME& mt)
{
// buffer mt given in mysql session time zone (assumes local)
std::tm tm{};
tm.tm_year = mt.year - 1900;
tm.tm_mon = mt.month - 1;
tm.tm_mday = mt.day;
tm.tm_hour = mt.hour;
tm.tm_min = mt.minute;
tm.tm_sec = mt.second;
tm.tm_isdst = -1;
return std::mktime(&tm);
}
static int MakeSeconds(const MYSQL_TIME& mt)
{
return (mt.neg ? -1 : 1) * static_cast<int>(mt.hour * 3600 + mt.minute * 60 + mt.second);
}
static uint64_t MakeBits(std::span<const uint8_t> data)
{
// byte stream for bits is in big endian
uint64_t bits = 0;
for (size_t i = 0; i < data.size() && i < sizeof(uint64_t); ++i)
{
bits |= static_cast<uint64_t>(data[data.size() - i - 1] & 0xff) << (i * 8);
}
return bits;
}
template <typename T>
concept has_from_chars = requires (const char* first, const char* last, T value)
{
std::from_chars(first, last, value);
};
template <typename T>
static T FromString(std::string_view sv)
{
if constexpr (std::is_same_v<T, bool>)
{
// return false for empty (zero-length) strings
return !sv.empty();
}
else if constexpr (std::is_same_v<T, float> && !has_from_chars<T>)
{
return std::strtof(std::string(sv).c_str(), nullptr);
}
else if constexpr (std::is_same_v<T, double> && !has_from_chars<T>)
{
return std::strtod(std::string(sv).c_str(), nullptr);
}
else
{
// non numbers return a zero initialized T (could return nullopt instead)
T value = {};
std::from_chars(sv.data(), sv.data() + sv.size(), value);
return value;
}
}
static std::string FormatTime(enum_field_types type, const MYSQL_TIME& mt)
{
switch (type)
{
case MYSQL_TYPE_TIME: // hhh:mm:ss '-838:59:59' to '838:59:59'
return fmt::format("{}{:02d}:{:02d}:{:02d}", mt.neg ? "-" : "", mt.hour, mt.minute, mt.second);
case MYSQL_TYPE_DATE: // YYYY-MM-DD '1000-01-01' to '9999-12-31'
return fmt::format("{}-{:02d}-{:02d}", mt.year, mt.month, mt.day);
case MYSQL_TYPE_DATETIME: // YYYY-MM-DD hh:mm:ss '1000-01-01 00:00:00' to '9999-12-31 23:59:59'
case MYSQL_TYPE_TIMESTAMP: // YYYY-MM-DD hh:mm:ss '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC
return fmt::format("{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}", mt.year, mt.month, mt.day, mt.hour, mt.minute, mt.second);
default:
return std::string();
}
}
std::optional<std::string_view> StmtColumn::GetStrView() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string_view>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
std::optional<std::string> StmtColumn::GetStr() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint8_t>()).c_str() : fmt::format_int(BitCast<int8_t>()).c_str();
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint16_t>()).c_str() : fmt::format_int(BitCast<int16_t>()).c_str();
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint32_t>()).c_str() : fmt::format_int(BitCast<int32_t>()).c_str();
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? fmt::format_int(BitCast<uint64_t>()).c_str() : fmt::format_int(BitCast<int64_t>()).c_str();
case MYSQL_TYPE_FLOAT:
return fmt::format("{}", BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return fmt::format("{}", BitCast<double>());
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
return FormatTime(m_col.buffer_type, BitCast<MYSQL_TIME>());
case MYSQL_TYPE_BIT:
return fmt::format_int(*Get<uint64_t>()).c_str();
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return std::make_optional<std::string>(reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length);
default:
return std::nullopt;
}
}
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> StmtColumn::Get() const
{
if (m_col.is_null)
{
return std::nullopt;
}
switch (m_col.buffer_type)
{
case MYSQL_TYPE_TINY:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint8_t>()) : static_cast<T>(BitCast<int8_t>());
case MYSQL_TYPE_SHORT:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint16_t>()) : static_cast<T>(BitCast<int16_t>());
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint32_t>()) : static_cast<T>(BitCast<int32_t>());
case MYSQL_TYPE_LONGLONG:
return m_col.is_unsigned ? static_cast<T>(BitCast<uint64_t>()) : static_cast<T>(BitCast<int64_t>());
case MYSQL_TYPE_FLOAT:
return static_cast<T>(BitCast<float>());
case MYSQL_TYPE_DOUBLE:
return static_cast<T>(BitCast<double>());
case MYSQL_TYPE_TIME: // return as total seconds
return static_cast<T>(MakeSeconds(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP: // return as epoch timestamp
return static_cast<T>(MakeTime(BitCast<MYSQL_TIME>()));
case MYSQL_TYPE_BIT:
return static_cast<T>(MakeBits({ m_col.buffer.data(), m_col.length }));
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
return FromString<T>({ reinterpret_cast<const char*>(m_col.buffer.data()), m_col.length });
default:
return std::nullopt;
}
}
// ---------------------------------------------------------------------------
// explicit template instantiations for supported types
template void PreparedStmt::BindInput(size_t, std::string_view);
template void PreparedStmt::BindInput(size_t, std::nullptr_t);
template StmtResult PreparedStmt::Execute(const std::vector<std::string_view>&);
template StmtResult PreparedStmt::Execute(const std::vector<std::string>&);
template StmtResult PreparedStmt::Execute(const std::vector<const char*>&);
#define INSTANTIATE(T) \
template void PreparedStmt::BindInput(size_t, T); \
template StmtResult PreparedStmt::Execute(const std::vector<T>&); \
template std::optional<T> StmtRow::Get(size_t) const; \
template std::optional<T> StmtRow::Get(std::string_view) const; \
template std::optional<T> StmtColumn::Get() const;
INSTANTIATE(bool);
INSTANTIATE(int8_t);
INSTANTIATE(uint8_t);
INSTANTIATE(int16_t);
INSTANTIATE(uint16_t);
INSTANTIATE(int32_t);
INSTANTIATE(uint32_t);
INSTANTIATE(int64_t);
INSTANTIATE(uint64_t);
INSTANTIATE(float);
INSTANTIATE(double);
} // namespace mysql
+221
View File
@@ -0,0 +1,221 @@
#pragma once
#include "mysql.h"
#include <cassert>
#include <cstring>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
class Mutex;
namespace mysql
{
// support MySQL 8.0.1+ API which removed the my_bool type
#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80001
using my_bool = bool;
#endif
template <typename>
inline constexpr bool false_v = false;
namespace impl
{
struct Bind
{
std::vector<uint8_t> buffer;
unsigned long length = 0;
my_bool is_null = false;
my_bool error = false;
};
struct BindColumn : Bind
{
int index = 0;
std::string name;
bool is_unsigned = false;
enum_field_types buffer_type = {};
};
} // namespace impl
// ---------------------------------------------------------------------------
struct StmtOptions
{
// Enable buffering (storing) entire result set after executing a statement
bool buffer_results = true;
// Enable MySQL to update max_length of fields in execute result set (requires buffering)
bool use_max_length = true;
};
// ---------------------------------------------------------------------------
// Holds ownership of bound column value buffer
class StmtColumn
{
public:
int Index() const { return m_col.index; }
bool IsNull() const { return m_col.is_null; }
bool IsUnsigned() const { return m_col.is_unsigned; }
enum_field_types Type() const { return m_col.buffer_type; }
const std::string& Name() const { return m_col.name; }
// Get view of column value buffer
std::span<const uint8_t> GetBuf() const { return { m_col.buffer.data(), m_col.length }; }
// Get view of column string value. Returns nullopt if value is NULL or not a string
std::optional<std::string_view> GetStrView() const;
// Get column value as string. Returns nullopt if value is NULL or field type unsupported
std::optional<std::string> GetStr() const;
// Get column value as numeric T. Returns nullopt if value NULL or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get() const;
private:
// uses memcpy for type punning buffer data to avoid UB with strict aliasing
template <typename T>
T BitCast() const
{
T val;
assert(sizeof(T) == m_col.length);
memcpy(&val, m_col.buffer.data(), sizeof(T));
return val;
}
friend class PreparedStmt; // access to allocate and bind buffers
friend class StmtResult; // access to resize truncated buffers
impl::BindColumn m_col;
};
// ---------------------------------------------------------------------------
// Provides a non-owning view of PreparedStmt column value buffers
// Evaluates false if it does not contain a valid row
class StmtRow
{
public:
StmtRow() = default;
StmtRow(std::span<const StmtColumn> columns) : m_columns(columns) {};
explicit operator bool() const noexcept { return !m_columns.empty(); }
int ColumnCount() const { return static_cast<int>(m_columns.size()); }
const StmtColumn* GetColumn(size_t index) const;
const StmtColumn* GetColumn(std::string_view name) const;
// Get specified column value as string
// Returns nullopt if column invalid, value is NULL, or field type unsupported
std::optional<std::string> operator[](size_t index) const;
std::optional<std::string> operator[](std::string_view name) const;
std::optional<std::string> GetStr(size_t index) const;
std::optional<std::string> GetStr(std::string_view name) const;
// Get specified column value as numeric T
// Returns nullopt if column invalid, value is NULL, or field type unsupported
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(size_t index) const;
template <typename T> requires std::is_arithmetic_v<T>
std::optional<T> Get(std::string_view name) const;
auto begin() const { return m_columns.begin(); }
auto end() const { return m_columns.end(); }
private:
std::span<const StmtColumn> m_columns;
};
// ---------------------------------------------------------------------------
// Result meta data for an executed prepared statement
class StmtResult
{
public:
StmtResult() = default;
StmtResult(MYSQL_STMT* stmt, size_t columns);
int ColumnCount() const { return m_num_cols; }
uint64_t RowCount() const { return m_num_rows; }
uint64_t RowsAffected() const { return m_affected; }
uint64_t LastInsertID() const { return m_insert_id; }
private:
int m_num_cols = 0;
uint64_t m_num_rows = 0;
uint64_t m_affected = 0;
uint64_t m_insert_id = 0;
};
// ---------------------------------------------------------------------------
class PreparedStmt
{
public:
// Supported argument types for execute
using param_t = std::variant<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
int64_t, uint64_t, float, double, bool, std::string_view, std::nullptr_t>;
PreparedStmt() = delete;
PreparedStmt(MYSQL& mysql, std::string query, Mutex* mutex, StmtOptions opts = {});
const std::string& GetQuery() const { return m_query; }
StmtOptions GetOptions() const { return m_options; }
void SetOptions(StmtOptions options) { m_options = options; }
void FreeResult() { mysql_stmt_free_result(m_stmt.get()); }
// Execute the prepared statement with specified arguments
// Throws exception on error
template <typename T>
StmtResult Execute(const std::vector<T>& args);
StmtResult Execute(const std::vector<param_t>& args);
StmtResult Execute();
// Fetch the next row into column buffers (overwrites previous row values)
// Return value evaluates false if no more rows to fetch
// Throws exception on error
StmtRow Fetch();
private:
void CheckArgs(size_t argc);
StmtResult DoExecute();
void BindResults();
void FetchTruncated();
int GetResultBufferSize(const MYSQL_FIELD& field) const;
void ThrowError(const std::string& error);
std::string GetStmtError();
// bind an input value to a query parameter by index
template <typename T>
void BindInput(size_t index, T value);
void BindInput(size_t index, const char* str);
void BindInput(size_t index, const std::string& str);
struct StmtDeleter
{
Mutex* mutex = nullptr;
void operator()(MYSQL_STMT* stmt) noexcept;
};
private:
std::unique_ptr<MYSQL_STMT, StmtDeleter> m_stmt;
std::vector<MYSQL_BIND> m_params; // input binds
std::vector<MYSQL_BIND> m_results; // result binds
std::vector<impl::Bind> m_inputs; // execute buffers (addresses bound)
std::vector<StmtColumn> m_columns; // fetch buffers (addresses bound)
std::string m_query;
StmtOptions m_options = {};
bool m_need_bind = true;
Mutex* m_mutex = nullptr; // connection mutex
};
} // namespace mysql
+92 -52
View File
@@ -1091,70 +1091,109 @@ void EQ::Net::DaybreakConnection::ProcessResend()
}
}
// observed client receive window is 300 packets, 140KB
constexpr size_t MAX_CLIENT_RECV_PACKETS_PER_WINDOW = 300;
constexpr size_t MAX_CLIENT_RECV_BYTES_PER_WINDOW = 140 * 1024;
void EQ::Net::DaybreakConnection::ProcessResend(int stream)
{
if (m_status == DbProtocolStatus::StatusDisconnected) {
return;
}
auto resends = 0;
auto now = Clock::now();
auto s = &m_streams[stream];
for (auto &entry : s->sent_packets) {
auto time_since_last_send = std::chrono::duration_cast<std::chrono::milliseconds>(now - entry.second.last_sent);
if (entry.second.times_resent == 0) {
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
auto &p = entry.second.packet;
if (p.Length() >= DaybreakHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++;
}
else {
m_stats.resent_full++;
}
}
else {
m_stats.resent_full++;
}
m_stats.resent_packets++;
if (m_streams[stream].sent_packets.empty()) {
return;
}
InternalBufferedSend(p);
entry.second.last_sent = now;
entry.second.times_resent++;
entry.second.resend_delay = EQ::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
resends++;
m_resend_packets_sent = 0;
m_resend_bytes_sent = 0;
auto now = Clock::now(); // Current time
auto s = &m_streams[stream];
// Get a reference resend delay (assume first packet represents the typical case)
if (!s->sent_packets.empty()) {
// Check if the first packet has timed out
auto &first_packet = s->sent_packets.begin()->second;
auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - first_packet.first_sent).count();
// 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 (time_since_first_sent <= first_packet.resend_delay && !m_acked_since_last_resend) {
LogNetcodeDetail(
"Not resending packets for stream [{}] time since first sent [{}] resend delay [{}] m_acked_since_last_resend [{}]",
stream,
time_since_first_sent,
first_packet.resend_delay,
m_acked_since_last_resend
);
return;
}
if (time_since_first_sent >= m_owner->m_options.resend_timeout) {
Close();
return;
}
}
if (LogSys.IsLogEnabled(Logs::Detail, Logs::Netcode)) {
size_t total_size = 0;
for (auto &e: s->sent_packets) {
total_size += e.second.packet.Length();
}
LogNetcodeDetail(
"Resending packets for stream [{}] packet count [{}] total packet size [{}] m_acked_since_last_resend [{}]",
stream,
s->sent_packets.size(),
total_size,
m_acked_since_last_resend
);
}
for (auto &e: s->sent_packets) {
if (m_resend_packets_sent >= MAX_CLIENT_RECV_PACKETS_PER_WINDOW ||
m_resend_bytes_sent >= MAX_CLIENT_RECV_BYTES_PER_WINDOW) {
LogNetcodeDetail(
"Stopping resend because we hit thresholds m_resend_packets_sent [{}] max [{}] m_resend_bytes_sent [{}] max [{}]",
m_resend_packets_sent,
MAX_CLIENT_RECV_PACKETS_PER_WINDOW,
m_resend_bytes_sent,
MAX_CLIENT_RECV_BYTES_PER_WINDOW
);
break;
}
auto &sp = e.second;
auto &p = sp.packet;
if (p.Length() >= DaybreakHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++;
}
else {
m_stats.resent_full++;
}
}
else {
auto time_since_first_sent = std::chrono::duration_cast<std::chrono::milliseconds>(now - entry.second.first_sent);
if (time_since_first_sent.count() >= m_owner->m_options.resend_timeout) {
Close();
return;
}
if ((size_t)time_since_last_send.count() > entry.second.resend_delay) {
auto &p = entry.second.packet;
if (p.Length() >= DaybreakHeader::size()) {
if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) {
m_stats.resent_fragments++;
}
else {
m_stats.resent_full++;
}
}
else {
m_stats.resent_full++;
}
m_stats.resent_packets++;
InternalBufferedSend(p);
entry.second.last_sent = now;
entry.second.times_resent++;
entry.second.resend_delay = EQ::Clamp(entry.second.resend_delay * 2, m_owner->m_options.resend_delay_min, m_owner->m_options.resend_delay_max);
resends++;
}
m_stats.resent_full++;
}
m_stats.resent_packets++;
// Resend the packet
InternalBufferedSend(p);
m_resend_packets_sent++;
m_resend_bytes_sent += p.Length();
sp.last_sent = now;
sp.times_resent++;
sp.resend_delay = EQ::Clamp(
sp.resend_delay * 2,
m_owner->m_options.resend_delay_min,
m_owner->m_options.resend_delay_max
);
}
m_acked_since_last_resend = false;
}
void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
@@ -1175,6 +1214,7 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq)
m_rolling_ping = (m_rolling_ping * 2 + round_time) / 3;
iter = s->sent_packets.erase(iter);
m_acked_since_last_resend = true;
}
else {
++iter;
+5
View File
@@ -181,6 +181,11 @@ namespace EQ
Timestamp m_close_time;
double m_outgoing_budget;
// resend tracking
size_t m_resend_packets_sent = 0;
size_t m_resend_bytes_sent = 0;
bool m_acked_since_last_resend = false;
struct DaybreakSentPacket
{
DynamicPacket packet;
+2
View File
@@ -80,6 +80,8 @@ void EQ::Net::TCPConnection::Start() {
}
}
else if (nread == UV_EOF) {
connection->Disconnect();
if (buf->base) {
delete[] buf->base;
}
+1
View File
@@ -250,6 +250,7 @@ IN(OP_TraderBuy, TraderBuy_Struct);
IN(OP_Trader, Trader_ShowItems_Struct);
IN(OP_GMFind, GMSummon_Struct);
IN(OP_PickPocket, PickPocket_Struct);
IN(OP_PickZone, PickZone_Struct);
IN(OP_Bind_Wound, BindWound_Struct);
INr(OP_TrackTarget);
INr(OP_Track);
File diff suppressed because it is too large Load Diff
-55
View File
@@ -1,55 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMON_LARION_H
#define COMMON_LARION_H
#include "../struct_strategy.h"
class EQStreamIdentifier;
namespace Larion
{
//these are the only public member of this namespace.
extern void Register(EQStreamIdentifier& into);
extern void Reload();
//you should not directly access anything below..
//I just dont feel like making a seperate header for it.
class Strategy : public StructStrategy {
public:
Strategy();
protected:
virtual std::string Describe() const;
virtual const EQ::versions::ClientVersion ClientVersion() const;
//magic macro to declare our opcode processors
#include "ss_declare.h"
#include "larion_ops.h"
};
}; /*Larion*/
#endif /*COMMON_LARION_H*/
-284
View File
@@ -1,284 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "larion_limits.h"
#include "../strings.h"
int16 Larion::invtype::GetInvTypeSize(int16 inv_type)
{
switch (inv_type) {
case invtype::typePossessions:
return invtype::POSSESSIONS_SIZE;
case invtype::typeBank:
return invtype::BANK_SIZE;
case invtype::typeSharedBank:
return invtype::SHARED_BANK_SIZE;
case invtype::typeTrade:
return invtype::TRADE_SIZE;
case invtype::typeWorld:
return invtype::WORLD_SIZE;
case invtype::typeLimbo:
return invtype::LIMBO_SIZE;
case invtype::typeTribute:
return invtype::TRIBUTE_SIZE;
case invtype::typeTrophyTribute:
return invtype::TROPHY_TRIBUTE_SIZE;
case invtype::typeGuildTribute:
return invtype::GUILD_TRIBUTE_SIZE;
case invtype::typeMerchant:
return invtype::MERCHANT_SIZE;
case invtype::typeDeleted:
return invtype::DELETED_SIZE;
case invtype::typeCorpse:
return invtype::CORPSE_SIZE;
case invtype::typeBazaar:
return invtype::BAZAAR_SIZE;
case invtype::typeInspect:
return invtype::INSPECT_SIZE;
case invtype::typeRealEstate:
return invtype::REAL_ESTATE_SIZE;
case invtype::typeViewMODPC:
return invtype::VIEW_MOD_PC_SIZE;
case invtype::typeViewMODBank:
return invtype::VIEW_MOD_BANK_SIZE;
case invtype::typeViewMODSharedBank:
return invtype::VIEW_MOD_SHARED_BANK_SIZE;
case invtype::typeViewMODLimbo:
return invtype::VIEW_MOD_LIMBO_SIZE;
case invtype::typeAltStorage:
return invtype::ALT_STORAGE_SIZE;
case invtype::typeArchived:
return invtype::ARCHIVED_SIZE;
case invtype::typeMail:
return invtype::MAIL_SIZE;
case invtype::typeGuildTrophyTribute:
return invtype::GUILD_TROPHY_TRIBUTE_SIZE;
case invtype::typeKrono:
return invtype::KRONO_SIZE;
case invtype::typeOther:
return invtype::OTHER_SIZE;
default:
return INULL;
}
}
const char* Larion::invtype::GetInvTypeName(int16 inv_type)
{
switch (inv_type) {
case invtype::TYPE_INVALID:
return "Invalid Type";
case invtype::typePossessions:
return "Possessions";
case invtype::typeBank:
return "Bank";
case invtype::typeSharedBank:
return "Shared Bank";
case invtype::typeTrade:
return "Trade";
case invtype::typeWorld:
return "World";
case invtype::typeLimbo:
return "Limbo";
case invtype::typeTribute:
return "Tribute";
case invtype::typeTrophyTribute:
return "Trophy Tribute";
case invtype::typeGuildTribute:
return "Guild Tribute";
case invtype::typeMerchant:
return "Merchant";
case invtype::typeDeleted:
return "Deleted";
case invtype::typeCorpse:
return "Corpse";
case invtype::typeBazaar:
return "Bazaar";
case invtype::typeInspect:
return "Inspect";
case invtype::typeRealEstate:
return "Real Estate";
case invtype::typeViewMODPC:
return "View MOD PC";
case invtype::typeViewMODBank:
return "View MOD Bank";
case invtype::typeViewMODSharedBank:
return "View MOD Shared Bank";
case invtype::typeViewMODLimbo:
return "View MOD Limbo";
case invtype::typeAltStorage:
return "Alt Storage";
case invtype::typeArchived:
return "Archived";
case invtype::typeMail:
return "Mail";
case invtype::typeGuildTrophyTribute:
return "Guild Trophy Tribute";
case invtype::typeKrono:
return "Krono";
case invtype::typeOther:
return "Other";
default:
return "Unknown Type";
}
}
bool Larion::invtype::IsInvTypePersistent(int16 inv_type)
{
switch (inv_type) {
case invtype::typePossessions:
case invtype::typeBank:
case invtype::typeSharedBank:
case invtype::typeTrade:
case invtype::typeWorld:
case invtype::typeLimbo:
case invtype::typeTribute:
case invtype::typeTrophyTribute:
case invtype::typeGuildTribute:
return true;
default:
return false;
}
}
const char* Larion::invslot::GetInvPossessionsSlotName(int16 inv_slot)
{
switch (inv_slot) {
case invslot::SLOT_INVALID:
return "Invalid Slot";
case invslot::slotCharm:
return "Charm";
case invslot::slotEar1:
return "Ear 1";
case invslot::slotHead:
return "Head";
case invslot::slotFace:
return "Face";
case invslot::slotEar2:
return "Ear 2";
case invslot::slotNeck:
return "Neck";
case invslot::slotShoulders:
return "Shoulders";
case invslot::slotArms:
return "Arms";
case invslot::slotBack:
return "Back";
case invslot::slotWrist1:
return "Wrist 1";
case invslot::slotWrist2:
return "Wrist 2";
case invslot::slotRange:
return "Range";
case invslot::slotHands:
return "Hands";
case invslot::slotPrimary:
return "Primary";
case invslot::slotSecondary:
return "Secondary";
case invslot::slotFinger1:
return "Finger 1";
case invslot::slotFinger2:
return "Finger 2";
case invslot::slotChest:
return "Chest";
case invslot::slotLegs:
return "Legs";
case invslot::slotFeet:
return "Feet";
case invslot::slotWaist:
return "Waist";
case invslot::slotPowerSource:
return "Power Source";
case invslot::slotAmmo:
return "Ammo";
case invslot::slotGeneral1:
return "General 1";
case invslot::slotGeneral2:
return "General 2";
case invslot::slotGeneral3:
return "General 3";
case invslot::slotGeneral4:
return "General 4";
case invslot::slotGeneral5:
return "General 5";
case invslot::slotGeneral6:
return "General 6";
case invslot::slotGeneral7:
return "General 7";
case invslot::slotGeneral8:
return "General 8";
case invslot::slotGeneral9:
return "General 9";
case invslot::slotGeneral10:
return "General 10";
case invslot::slotCursor:
return "Cursor";
default:
return "Unknown Slot";
}
}
const char* Larion::invslot::GetInvSlotName(int16 inv_type, int16 inv_slot)
{
if (inv_type == invtype::typePossessions)
return invslot::GetInvPossessionsSlotName(inv_slot);
int16 type_size = invtype::GetInvTypeSize(inv_type);
if (!type_size || inv_slot == invslot::SLOT_INVALID)
return "Invalid Slot";
if ((inv_slot + 1) >= type_size)
return "Unknown Slot";
static std::string ret_str;
ret_str = StringFormat("Slot %i", (inv_slot + 1));
return ret_str.c_str();
}
const char* Larion::invbag::GetInvBagIndexName(int16 bag_index)
{
if (bag_index == invbag::SLOT_INVALID)
return "Invalid Bag";
if (bag_index >= invbag::SLOT_COUNT)
return "Unknown Bag";
static std::string ret_str;
ret_str = StringFormat("Bag %i", (bag_index + 1));
return ret_str.c_str();
}
const char* Larion::invaug::GetInvAugIndexName(int16 aug_index)
{
if (aug_index == invaug::SOCKET_INVALID)
return "Invalid Augment";
if (aug_index >= invaug::SOCKET_COUNT)
return "Unknown Augment";
static std::string ret_str;
ret_str = StringFormat("Augment %i", (aug_index + 1));
return ret_str.c_str();
}
-330
View File
@@ -1,330 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMON_LARION_LIMITS_H
#define COMMON_LARION_LIMITS_H
#include "../types.h"
#include "../emu_versions.h"
#include "../skills.h"
namespace Larion
{
const int16 IINVALID = -1;
const int16 INULL = 0;
namespace inventory {
inline EQ::versions::ClientVersion GetInventoryRef() { return EQ::versions::ClientVersion::Larion; }
const bool ConcatenateInvTypeLimbo = false;
const bool AllowOverLevelEquipment = true;
const bool AllowEmptyBagInBag = true;
const bool AllowClickCastFromBag = true;
} /*inventory*/
namespace invtype {
inline EQ::versions::ClientVersion GetInvTypeRef() { return EQ::versions::ClientVersion::Larion; }
namespace enum_ {
enum InventoryTypes : int16 {
typePossessions = INULL,
typeBank,
typeSharedBank,
typeTrade,
typeWorld,
typeLimbo,
typeTribute,
typeTrophyTribute,
typeGuildTribute,
typeMerchant,
typeDeleted,
typeCorpse,
typeBazaar,
typeInspect,
typeRealEstate,
typeViewMODPC,
typeViewMODBank,
typeViewMODSharedBank,
typeViewMODLimbo,
typeAltStorage,
typeArchived,
typeMail,
typeGuildTrophyTribute,
typeKrono,
typeOther
};
} // namespace enum_
using namespace enum_;
const int16 POSSESSIONS_SIZE = 34;
const int16 BANK_SIZE = 24;
const int16 SHARED_BANK_SIZE = 2;
const int16 TRADE_SIZE = 8;
const int16 WORLD_SIZE = 10;
const int16 LIMBO_SIZE = 36;
const int16 TRIBUTE_SIZE = 5;
const int16 TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 GUILD_TRIBUTE_SIZE = 2;//unverified
const int16 MERCHANT_SIZE = 200;
const int16 DELETED_SIZE = 0;//unknown - "Recovery Tab"
const int16 CORPSE_SIZE = POSSESSIONS_SIZE;
const int16 BAZAAR_SIZE = 200;
const int16 INSPECT_SIZE = 23;
const int16 REAL_ESTATE_SIZE = 0;//unknown
const int16 VIEW_MOD_PC_SIZE = POSSESSIONS_SIZE;
const int16 VIEW_MOD_BANK_SIZE = BANK_SIZE;
const int16 VIEW_MOD_SHARED_BANK_SIZE = SHARED_BANK_SIZE;
const int16 VIEW_MOD_LIMBO_SIZE = LIMBO_SIZE;
const int16 ALT_STORAGE_SIZE = 0;//unknown - "Shroud Bank"
const int16 ARCHIVED_SIZE = 0;//unknown
const int16 MAIL_SIZE = 0;//unknown
const int16 GUILD_TROPHY_TRIBUTE_SIZE = 0;//unknown
const int16 KRONO_SIZE = 0;//unknown
const int16 OTHER_SIZE = 0;//unknown
const int16 TRADE_NPC_SIZE = 4; // defined by implication
const int16 TYPE_INVALID = IINVALID;
const int16 TYPE_BEGIN = typePossessions;
const int16 TYPE_END = typeOther;
const int16 TYPE_COUNT = (TYPE_END - TYPE_BEGIN) + 1;
int16 GetInvTypeSize(int16 inv_type);
const char* GetInvTypeName(int16 inv_type);
bool IsInvTypePersistent(int16 inv_type);
} /*invtype*/
namespace invslot {
inline EQ::versions::ClientVersion GetInvSlotRef() { return EQ::versions::ClientVersion::Larion; }
namespace enum_ {
enum InventorySlots : int16 {
slotCharm = INULL,
slotEar1,
slotHead,
slotFace,
slotEar2,
slotNeck,
slotShoulders,
slotArms,
slotBack,
slotWrist1,
slotWrist2,
slotRange,
slotHands,
slotPrimary,
slotSecondary,
slotFinger1,
slotFinger2,
slotChest,
slotLegs,
slotFeet,
slotWaist,
slotPowerSource,
slotAmmo,
slotGeneral1,
slotGeneral2,
slotGeneral3,
slotGeneral4,
slotGeneral5,
slotGeneral6,
slotGeneral7,
slotGeneral8,
slotGeneral9,
slotGeneral10,
slotCursor
};
constexpr int16 format_as(InventorySlots slot) { return static_cast<int16>(slot); }
} // namespace enum_
using namespace enum_;
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
const int16 EQUIPMENT_BEGIN = slotCharm;
const int16 EQUIPMENT_END = slotAmmo;
const int16 EQUIPMENT_COUNT = (EQUIPMENT_END - EQUIPMENT_BEGIN) + 1;
const int16 GENERAL_BEGIN = slotGeneral1;
const int16 GENERAL_END = slotGeneral10;
const int16 GENERAL_COUNT = (GENERAL_END - GENERAL_BEGIN) + 1;
const int16 BONUS_BEGIN = invslot::slotCharm;
const int16 BONUS_STAT_END = invslot::slotPowerSource;
const int16 BONUS_SKILL_END = invslot::slotAmmo;
const int16 CORPSE_BEGIN = invslot::slotGeneral1;
const int16 CORPSE_END = invslot::slotGeneral1 + invslot::slotCursor;
const uint64 EQUIPMENT_BITMASK = 0x00000000007FFFFF;
const uint64 GENERAL_BITMASK = 0x00000001FF800000;
const uint64 CURSOR_BITMASK = 0x0000000200000000;
const uint64 POSSESSIONS_BITMASK = (EQUIPMENT_BITMASK | GENERAL_BITMASK | CURSOR_BITMASK); // based on 34-slot count (RoF+)
const uint64 CORPSE_BITMASK = (GENERAL_BITMASK | CURSOR_BITMASK | (EQUIPMENT_BITMASK << 34)); // based on 34-slot count (RoF+)
const char* GetInvPossessionsSlotName(int16 inv_slot);
const char* GetInvSlotName(int16 inv_type, int16 inv_slot);
} /*invslot*/
namespace invbag {
inline EQ::versions::ClientVersion GetInvBagRef() { return EQ::versions::ClientVersion::Larion; }
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_END = 9; //254;
const int16 SLOT_COUNT = 10; //255; // server Size will be 255..unsure what actual client is (test)
const char* GetInvBagIndexName(int16 bag_index);
} /*invbag*/
namespace invaug {
inline EQ::versions::ClientVersion GetInvAugRef() { return EQ::versions::ClientVersion::Larion; }
const int16 SOCKET_INVALID = IINVALID;
const int16 SOCKET_BEGIN = INULL;
const int16 SOCKET_END = 5;
const int16 SOCKET_COUNT = 6;
const char* GetInvAugIndexName(int16 aug_index);
} /*invaug*/
namespace item {
inline EQ::versions::ClientVersion GetItemRef() { return EQ::versions::ClientVersion::Larion; }
//enum Unknown : int { // looks like item class..but, RoF has it too - nothing in UF-
// Unknown1 = 0,
// Unknown2 = 1,
// Unknown3 = 2,
// Unknown4 = 5 // krono?
//};
enum ItemPacketType : int {
ItemPacketMerchant = 100,
ItemPacketTradeView = 101,
ItemPacketLoot = 102,
ItemPacketTrade = 103,
ItemPacketCharInventory = 105,
ItemPacketLimbo = 106,
ItemPacketWorldContainer = 107,
ItemPacketTributeItem = 108,
ItemPacketGuildTribute = 109,
ItemPacket10 = 110,
ItemPacket11 = 111,
ItemPacket12 = 112,
ItemPacketRecovery = 113,
ItemPacket14 = 115 // Parcel? adds to merchant window too
};
} /*item*/
namespace profile {
inline EQ::versions::ClientVersion GetProfileRef() { return EQ::versions::ClientVersion::Larion; }
const int16 BANDOLIERS_SIZE = 20; // number of bandolier instances
const int16 BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
const int16 POTION_BELT_SIZE = 5;
const int16 SKILL_ARRAY_SIZE = 100;
} /*profile*/
namespace constants {
inline EQ::versions::ClientVersion GetConstantsRef() { return EQ::versions::ClientVersion::Larion; }
const EQ::expansions::Expansion EXPANSION = EQ::expansions::Expansion::LS;
const uint32 EXPANSION_BIT = EQ::expansions::bitLS;
const uint32 EXPANSIONS_MASK = EQ::expansions::maskLS;
const size_t CHARACTER_CREATION_LIMIT = 12;
const size_t SAY_LINK_BODY_SIZE = 56;
const uint32 MAX_GUILD_ID = 50000;
} /*constants*/
namespace behavior {
inline EQ::versions::ClientVersion GetBehaviorRef() { return EQ::versions::ClientVersion::Larion; }
const bool CoinHasWeight = false;
} /*behavior*/
namespace skills {
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::Larion; }
const size_t LastUsableSkill = EQ::skills::Skill2HPiercing;
} /*skills*/
namespace spells {
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::Larion; }
enum class CastingSlot : uint32 {
Gem1 = 0,
Gem2 = 1,
Gem3 = 2,
Gem4 = 3,
Gem5 = 4,
Gem6 = 5,
Gem7 = 6,
Gem8 = 7,
Gem9 = 8,
Gem10 = 9,
Gem11 = 10,
Gem12 = 11,
MaxGems = 18, // fallacy..only 12 slot are useable...
Item = 12,
Discipline = 13,
AltAbility = 0xFF
};
const int SPELL_ID_MAX = 71999;
const int SPELLBOOK_SIZE = 1120;
const int SPELL_GEM_COUNT = static_cast<uint32>(CastingSlot::MaxGems);
const int SPELL_GEM_RECAST_TIMER = 15;
const int LONG_BUFFS = 42;
const int SHORT_BUFFS = 20;
const int DISC_BUFFS = 1;
const int TOTAL_BUFFS = LONG_BUFFS + SHORT_BUFFS + DISC_BUFFS;
const int NPC_BUFFS = 97;
const int PET_BUFFS = NPC_BUFFS;
const int MERC_BUFFS = LONG_BUFFS;
} /*spells*/
}; /* Larion */
#endif /*COMMON_LARION_LIMITS_H*/
-19
View File
@@ -1,19 +0,0 @@
//list of packets we need to encode on the way out:
E(OP_LogServer)
E(OP_SendMembership)
E(OP_SendMembershipDetails)
E(OP_SendMaxCharacters)
E(OP_SendCharInfo)
E(OP_ExpansionInfo)
E(OP_SpawnAppearance)
//E(OP_SendAATable)
E(OP_PlayerProfile)
E(OP_ZoneEntry)
E(OP_ZoneSpawns)
//list of packets we need to decode on the way in:
D(OP_ZoneEntry)
#undef E
#undef D
-233
View File
@@ -1,233 +0,0 @@
#ifndef LARION_STRUCTS_H_
#define LARION_STRUCTS_H_
namespace Larion {
namespace structs {
// constants
static const uint32 MAX_PP_AA_ARRAY = 300;
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE;
static const uint32 MAX_PP_INNATE_SKILL = 25;
static const uint32 MAX_PP_DISCIPLINES = 300;
static const uint32 MAX_PP_COMBAT_ABILITY_TIMERS = 25;
static const uint32 MAX_PP_UNKNOWN_ABILITIES = 25;
static const uint32 MAX_RECAST_TYPES = 25;
static const uint32 MAX_ITEM_RECAST_TYPES = 100;
static const uint32 BUFF_COUNT = 62;
static const uint32 MAX_PP_LANGUAGE = 32;
#pragma pack(1)
struct LoginInfo_Struct {
/*000*/ char login_info[64];
/*064*/ uint8 unknown064[124];
/*188*/ uint8 zoning; // 01 if zoning, 00 if not
/*189*/ uint8 unknown189[275];
/*488*/
};
struct ClientZoneEntry_Struct {
/*00*/ uint32 unknown00; // ***Placeholder
/*04*/ char char_name[64]; // Player firstname [32]
/*68*/ uint32 unknown68;
/*72*/ uint32 unknown72;
/*76*/ uint32 unknown76;
/*80*/ uint32 unknown80;
/*84*/ uint32 unknown84;
/*88*/ uint32 unknown88;
/*92*/
};
struct Membership_Struct
{
/*000*/ uint8 membership; //0 not gold, 2 gold
/*001*/ uint32 races; // Seen ff ff 01 00
/*005*/ uint32 classes; // Seen ff ff 01 00
/*009*/ uint32 entrysize; // Seen 33
/*013*/ int32 entries[33]; // Most -1, 1, and 0 for Gold Status
/*145*/
};
struct Membership_Entry_Struct
{
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
/*004*/ uint32 bitwise_entry; // Seen 16 to 65536 - Skips 4096
/*008*/
};
struct Membership_Setting_Struct
{
/*000*/ int8 setting_index; // 0, 1, 2 or 3: f2p, silver, gold, platinum?
/*001*/ int32 setting_id; // 0 to 23 actually seen but the OP_Membership packet has up to 32
/*005*/ int32 setting_value;
/*009*/
};
struct Membership_Details_Struct
{
/*000*/ uint32 membership_setting_count; // Seen 96
/*004*/ Membership_Setting_Struct settings[96]; // 864 Bytes
/*364*/ uint32 race_entry_count; // Seen 17
/*368*/ Membership_Entry_Struct membership_races[17]; // 136 Bytes
/*3f0*/ uint32 class_entry_count; // Seen 15
/*3f4*/ Membership_Entry_Struct membership_classes[17]; // 136 Bytes
/*47c*/ uint32 exit_url_length; // Length of the exit_url string (0 for none)
/*480*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL
};
struct MaxCharacters_Struct {
/*000*/ uint32 max_chars;
/*004*/ uint32 marketplace_chars;
/*008*/ int32 unknown008; //some of these probably deal with heroic characters or something
/*00c*/ int32 unknown00c;
/*010*/ int32 unknown010;
/*014*/ int32 unknown014;
/*018*/ int32 unknown018;
/*01c*/ int32 unknown01c;
/*020*/ int32 unknown020;
/*024*/ int32 unknown024;
/*028*/ int32 unknown028;
/*02c*/ int32 unknown02c;
/*030*/ int32 unknown030;
/*034*/ int32 unknown034;
/*038*/
};
struct ExpansionInfo_Struct {
/*000*/ char Unknown000[64];
/*064*/ uint32 Expansions;
};
/*
* Visible equiptment.
* Size: 20 Octets
*/
struct Texture_Struct
{
uint32 Material;
uint32 Unknown1;
uint32 EliteMaterial;
uint32 HeroForgeModel;
uint32 Material2; // Same as material?
};
/*
** Color_Struct
** Size: 4 bytes
** Used for convenience
** Merth: Gave struct a name so gcc 2.96 would compile
**
*/
struct Tint_Struct
{
union {
struct {
uint8 Blue;
uint8 Green;
uint8 Red;
uint8 UseTint; // if there's a tint this is FF
};
uint32 Color;
};
};
struct CharSelectEquip : Texture_Struct, Tint_Struct {};
struct CharacterSelectEntry_Struct
{
char Name[1];
uint32 Class;
uint32 Race;
uint8 Level;
uint32 ShroudClass;
uint32 ShroudRace;
uint16 Zone;
uint16 Instance;
uint8 Gender;
uint8 Face;
CharSelectEquip Equip[9];
uint8 Unknown1; //Seen 256
uint8 Unknown2; //Seen 0
uint32 DrakkinTattoo;
uint32 DrakkinDetails;
uint32 Deity;
uint32 PrimaryIDFile;
uint32 SecondaryIDFile;
uint8 HairColor;
uint8 BeardColor;
uint8 EyeColor1;
uint8 EyeColor2;
uint8 HairStyle;
uint8 Beard;
uint8 Enabled;
uint8 Tutorial;
uint32 DrakkinHeritage;
uint8 Unknown3;
uint8 GoHome;
uint32 LastLogin;
uint8 Unknown4; // Seen 0
uint8 Unknown5; // Seen 0
uint8 Unknown6; // Seen 0
uint8 Unknown7; // Seen 0
uint32 CharacterId; //A Guess, Character I made a little bit after has a number a few hundred after the first
uint32 Unknown8; // Seen 1
};
/*
** Character Selection Struct
**
*/
struct CharacterSelect_Struct
{
/*000*/ uint32 CharCount; //number of chars in this packet
};
struct SpawnAppearance_Struct
{
/*0000*/ uint32 spawn_id; // ID of the spawn
/*0004*/ uint32 type; // Values associated with the type
/*0008*/ uint32 parameter; // Type of data sent
/*0012*/ uint32 unknown012;
/*0016*/ uint32 unknown016;
/*0020*/ uint32 unknown020;
/*0024*/
};
struct Spawn_Struct_Bitfields
{
// byte 1
/*00*/ unsigned gender : 2; // Gender (0=male, 1=female, 2=monster)
/*02*/ unsigned ispet : 1; // Guessed based on observing live spawns
/*03*/ unsigned afk : 1; // 0=no, 1=afk
/*04*/ unsigned anon : 2; // 0=normal, 1=anon, 2=roleplay
/*06*/ unsigned gm : 1;
/*07*/ unsigned sneak : 1;
// byte 2
/*08*/ unsigned lfg : 1;
/*09*/ unsigned unk9 : 1;
/*10*/ unsigned invis : 12; // there are 3000 different (non-GM) invis levels
/*22*/ unsigned linkdead : 1; // 1 Toggles LD on or off after name. Correct for RoF2
/*23*/ unsigned showhelm : 1;
// byte 4
/*24*/ unsigned betabuffed : 1; // Prefixes name with !
/*25*/ unsigned trader : 1;
/*26*/ unsigned animationonpop : 1;
/*27*/ unsigned targetable : 1;
/*28*/ unsigned targetable_with_hotkey : 1;
/*29*/ unsigned showname : 1;
/*30*/ unsigned idleanimationsoff : 1; // what we called statue?
/*31*/ unsigned untargetable : 1; // bClickThrough
// byte 5
/*32*/ unsigned buyer : 1;
/*33*/ unsigned offline : 1;
/*34*/ unsigned interactiveobject : 1;
/*35*/ unsigned missile : 1;
/*36*/ unsigned title : 1;
/*37*/ unsigned suffix : 1;
/*38*/ unsigned unk38 : 1;
/*39*/ unsigned unk39 : 1;
};
#pragma pack()
}; //end namespace structs
}; //end namespace larion
#endif /*LARION_STRUCTS_H_*/
+1 -3
View File
@@ -26,7 +26,7 @@
#include "sod.h"
#include "rof.h"
#include "rof2.h"
#include "larion.h"
void RegisterAllPatches(EQStreamIdentifier &into)
{
@@ -36,7 +36,6 @@ void RegisterAllPatches(EQStreamIdentifier &into)
UF::Register(into);
RoF::Register(into);
RoF2::Register(into);
Larion::Register(into);
}
void ReloadAllPatches()
@@ -47,5 +46,4 @@ void ReloadAllPatches()
UF::Reload();
RoF::Reload();
RoF2::Reload();
Larion::Reload();
}
+8 -1
View File
@@ -5188,7 +5188,14 @@ namespace RoF
//sprintf(hdr.unknown000, "06e0002Y1W00");
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
strn0cpy(
hdr.unknown000,
fmt::format(
"{:016}\0",
packet_type == ItemPacketInvalid ? 0 : inst->GetSerialNumber()
).c_str(),
sizeof(hdr.unknown000)
);
hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1);
hdr.unknown004 = 0;
+139 -34
View File
@@ -433,7 +433,9 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
VARSTRUCT_SKIP_TYPE(uint32, eq);
}
dest->QueuePacket(outapp.get());
safe_delete(in);
break;
}
default: {
@@ -468,8 +470,8 @@ namespace RoF2
}
auto p_size = 41 * results.size() + name_size + 14;
auto buffer = std::make_unique<char[]>(p_size);
auto bufptr = buffer.get();
auto buffer = new char[p_size];
auto bufptr = buffer;
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, results[0].trader_zone_id);
@@ -487,10 +489,11 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, i.item_stat); //itemstat
}
safe_delete(in->pBuffer);
safe_delete_array(in->pBuffer);
in->size = p_size;
in->pBuffer = (uchar *) buffer.get();
in->pBuffer = (uchar*)buffer;
dest->QueuePacket(in);
safe_delete(in);
break;
}
@@ -500,21 +503,22 @@ namespace RoF2
break;
}
case WelcomeMessage: {
auto buffer = std::make_unique<char[]>(sizeof(structs::BazaarWelcome_Struct));
auto buffer = new char[sizeof(structs::BazaarWelcome_Struct)];
auto emu = (BazaarWelcome_Struct *) in->pBuffer;
auto eq = (structs::BazaarWelcome_Struct *) buffer.get();
auto eq = (structs::BazaarWelcome_Struct *) buffer;
eq->action = structs::RoF2BazaarTraderBuyerActions::WelcomeMessage;
eq->num_of_traders = emu->traders;
eq->num_of_items = emu->items;
safe_delete(in->pBuffer);
safe_delete_array(in->pBuffer);
in->SetOpcode(OP_TraderShop);
in->size = sizeof(structs::BazaarWelcome_Struct);
in->pBuffer = (uchar *) buffer.get();
in->pBuffer = (uchar *)buffer;
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
dest->QueuePacket(in);
safe_delete(in);
break;
}
@@ -583,19 +587,21 @@ namespace RoF2
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
eq->action = emu->action;
eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_id;
eq->zone_id = emu->zone_id;
eq->action = emu->action;
eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_id;
eq->zone_id = emu->zone_id;
eq->zone_instance_id = emu->zone_instance_id;
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
LogTrading(
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] "
"zone_id <green>[{}] zone_instance_id <green>[{}]",
eq->action,
eq->trader_id,
eq->entity_id,
eq->zone_id
);
eq->zone_id,
eq->zone_instance_id);
dest->FastQueuePacket(&outapp);
break;
}
@@ -890,7 +896,9 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id);
VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str());
}
dest->QueuePacket(outapp.get());
safe_delete(inapp);
break;
}
case Barter_RemoveFromMerchantWindow: {
@@ -961,6 +969,7 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity);
dest->QueuePacket(outapp.get());
safe_delete(inapp);
break;
}
default: {
@@ -1341,6 +1350,58 @@ namespace RoF2
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_EvolveItem)
{
EQApplicationPacket *in = *p;
*p = nullptr;
auto action = *reinterpret_cast<uint32 *>(in->pBuffer);
switch (action) {
case EvolvingItems::Actions::TRANSFER_WINDOW_DETAILS: {
auto emu = reinterpret_cast<EvolveItemMessaging *>(in->pBuffer);
EvolveXPWindowSend e{};
EQ::Util::MemoryStreamReader ss(emu->serialized_data, in->size - sizeof(emu->action));
cereal::BinaryInputArchive ar(ss);
ar(e);
auto item_1 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
*>(e.serialize_item_1.data())->inst);
auto item_2 = static_cast<const EQ::ItemInstance *>(reinterpret_cast<EQ::InternalSerializedItem_Struct
*>(e.serialize_item_2.data())->inst);
EQ::OutBuffer ob;
SerializeItem(ob, item_1, 0, 0, ItemPacketMerchant);
SerializeItem(ob, item_2, 0, 0, ItemPacketMerchant);
auto out = std::make_unique<EQApplicationPacket>(
OP_EvolveItem,
sizeof(EvolveXPWindowSendDetails_Struct) + ob.size()
);
auto data = reinterpret_cast<EvolveXPWindowSendDetails_Struct *>(out->pBuffer);
data->action = e.action;
data->compatibility = e.compatibility;
data->max_transfer_level = e.max_transfer_level;
data->item1_unique_id = e.item1_unique_id;
data->item2_unique_id = e.item2_unique_id;
data->item1_present = e.item1_present;
data->item2_present = e.item2_present;
memcpy(data->serialize_data, ob.str().data(), ob.size());
dest->QueuePacket(out.get());
safe_delete(in);
break;
}
default: {
dest->FastQueuePacket(&in);
break;
}
}
}
ENCODE(OP_ExpansionInfo)
{
ENCODE_LENGTH_EXACT(ExpansionInfo_Struct);
@@ -1843,11 +1904,11 @@ namespace RoF2
}
}
auto outapp = new EQApplicationPacket(OP_GuildsList);
outapp->size = packet_size;
outapp->pBuffer = buffer;
safe_delete_array(in->pBuffer);
dest->FastQueuePacket(&outapp);
in->pBuffer = buffer;
in->size = packet_size;
dest->FastQueuePacket(&in);
}
ENCODE(OP_GuildTributeDonateItem)
@@ -2044,6 +2105,33 @@ namespace RoF2
}
}
ENCODE(OP_ItemPreviewRequest)
{
EQApplicationPacket* in = *p;
*p = nullptr;
uchar* in_buf = in->pBuffer;
auto int_item = (EQ::InternalSerializedItem_Struct*) in_buf;
EQ::OutBuffer buf;
EQ::OutBuffer::pos_type last_pos = buf.tellp();
SerializeItem(buf, (const EQ::ItemInstance*) int_item->inst, int_item->slot_id, 0, ItemPacketInvalid);
if (buf.tellp() == last_pos) {
LogNetcode("RoF2::ENCODE(OP_ItemPreviewRequest) Serialization failed");
safe_delete_array(in_buf);
safe_delete(in);
return;
}
in->size = buf.size();
in->pBuffer = buf.detach();
safe_delete_array(in_buf);
dest->FastQueuePacket(&in, ack_req);
}
ENCODE(OP_ItemVerifyReply)
{
ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct);
@@ -2680,7 +2768,7 @@ namespace RoF2
{
float instrument_mod = 0.0f;
uint8 effect_type = emu->buffs[r].effect_type;
uint32 player_id = emu->buffs[r].player_id;
uint32 player_id = emu->buffs[r].player_id;;
if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0)
{
@@ -6218,6 +6306,11 @@ namespace RoF2
FINISH_DIRECT_DECODE();
break;
}
case structs::RoF2BazaarTraderBuyerActions::FirstOpenSearch: {
__packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) First time opening Bazaar Search since zoning. Action <green>[{}]", action);
break;
}
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
__packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
@@ -6358,9 +6451,18 @@ namespace RoF2
//sprintf(hdr.unknown000, "06e0002Y1W00");
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
hdr.stacksize =
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
? 0xFFFFFFFF : inst->GetCharges()) : 1);
hdr.stacksize = 1;
if (item->ID == PARCEL_MONEY_ITEM_ID) {
hdr.stacksize = inst->GetPrice();
} else if (inst->IsStackable()) {
if (inst->GetCharges() > std::numeric_limits<int16>::max()) {
hdr.stacksize = std::numeric_limits<uint32>::max();
} else {
hdr.stacksize = inst->GetCharges();
}
}
hdr.unknown004 = 0;
structs::InventorySlot_Struct slot_id{};
@@ -6382,6 +6484,11 @@ namespace RoF2
hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0);
hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber());
hdr.parcel_item_id = packet_type == ItemPacketParcel ? inst->GetID() : 0;
if (item->EvolvingItem) {
hdr.instance_id = inst->GetEvolveUniqueID() & 0xFFFFFFFF; //lower dword
hdr.parcel_item_id = inst->GetEvolveUniqueID() >> 32; //upper dword
}
hdr.last_cast_time = inst->GetRecastTimestamp();
hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254)
? 0xFFFFFFFF
@@ -6395,18 +6502,15 @@ namespace RoF2
ob.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader));
if (item->EvolvingItem > 0) {
RoF2::structs::EvolvingItem evotop;
RoF2::structs::EvolvingItem_Struct evotop;
evotop.unknown001 = 0;
evotop.unknown002 = 0;
evotop.unknown003 = 0;
evotop.unknown004 = 0;
evotop.evoLevel = item->EvolvingLevel;
evotop.progress = 0;
evotop.Activated = 1;
evotop.evomaxlevel = item->EvolvingMax;
evotop.final_item_id = inst->GetEvolveFinalItemID();
evotop.evolve_level = item->EvolvingLevel;
evotop.progress = inst->GetEvolveProgression();
evotop.activated = inst->GetEvolveActivated();
evotop.evolve_max_level = item->EvolvingMax;
ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem));
ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem_Struct));
}
/**
@@ -6780,12 +6884,13 @@ namespace RoF2
iqbs.Heirloom = 0;
iqbs.Placeable = 0;
iqbs.unknown28 = -1;
iqbs.unknown29 = packet_type == ItemPacketInvalid ? 0xFF : 0;
iqbs.unknown30 = -1;
iqbs.NoZone = 0;
iqbs.NoGround = 0;
iqbs.unknown37a = 0; // (guessed position) New to RoF2
iqbs.unknown38 = 0;
iqbs.unknown39 = 1;
iqbs.unknown39 = packet_type == ItemPacketInvalid ? 0 : 1;;
ob.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct));
+1
View File
@@ -272,6 +272,7 @@ namespace RoF2
const size_t SAY_LINK_BODY_SIZE = 56;
const uint32 MAX_GUILD_ID = 50000;
const uint32 MAX_BAZAAR_TRADERS = 600;
} /*constants*/
+3 -1
View File
@@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
@@ -70,6 +70,7 @@ E(OP_DzMemberListName)
E(OP_DzMemberListStatus)
E(OP_DzSetLeaderName)
E(OP_Emote)
E(OP_EvolveItem)
E(OP_ExpansionInfo)
E(OP_FormattedMessage)
E(OP_GMLastName)
@@ -91,6 +92,7 @@ E(OP_InspectBuffs)
E(OP_InspectRequest)
E(OP_ItemLinkResponse)
E(OP_ItemPacket)
E(OP_ItemPreviewRequest)
E(OP_ItemVerifyReply)
E(OP_LeadershipExpUpdate)
E(OP_LogServer)
+34 -10
View File
@@ -3119,7 +3119,8 @@ enum RoF2BazaarTraderBuyerActions {
BazaarInspect = 18,
ClickTrader = 28,
ItemMove = 19,
ReconcileItems = 20
ReconcileItems = 20,
FirstOpenSearch = 26
};
enum RoF2BuyerActions {
@@ -4745,16 +4746,13 @@ struct ItemSerializationHeader
uint8 isEvolving;
};
struct EvolvingItem {
uint8 unknown001;
uint8 unknown002;
uint8 unknown003;
uint8 unknown004;
int32 evoLevel;
struct EvolvingItem_Struct {
uint32 final_item_id;
int32 evolve_level;
double progress;
uint8 Activated;
int32 evomaxlevel;
uint8 unknown005[4];
uint8 activated;
int32 evolve_max_level;
uint8 unknown005[4];
};
struct ItemSerializationHeaderFinish
@@ -5427,6 +5425,32 @@ struct Parcel_Struct
};
}; /*structs*/
struct EvolveItemToggle_Struct {
uint32 action;
uint32 unknown_004;
uint64 unique_id;
uint32 percentage;
uint32 activated;
};
struct EvolveXPWindowReceive_Struct {
uint32 action;
uint32 unknown_004;
uint64 item1_unique_id;
uint64 item2_unique_id;
};
struct EvolveXPWindowSendDetails_Struct {
/*000*/ uint32 action;
/*004*/ uint64 item1_unique_id;
/*012*/ uint64 item2_unique_id;
/*020*/ uint32 compatibility;
/*024*/ uint32 max_transfer_level;
/*028*/ uint8 item1_present;
/*029*/ uint8 item2_present;
/*030*/ char serialize_data[];
};
}; /*RoF2*/
#endif /*COMMON_ROF2_STRUCTS_H*/
+2 -2
View File
@@ -286,8 +286,8 @@ namespace Titanium
const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER
const size_t SAY_LINK_BODY_SIZE = 45;
const uint32 MAX_GUILD_ID = 1500;
const size_t SAY_LINK_BODY_SIZE = 45;
const uint32 MAX_GUILD_ID = 1500;
} /*constants*/
+57 -60
View File
@@ -5,31 +5,19 @@
#include "strings.h"
#include <filesystem>
namespace fs = std::filesystem;
inline std::string striptrailingslash(const std::string &file_path)
{
if (file_path.back() == '/' || file_path.back() == '\\') {
return file_path.substr(0, file_path.length() - 1);
}
return file_path;
}
void PathManager::LoadPaths()
{
m_server_path = File::FindEqemuConfigPath();
if (!m_server_path.empty()) {
std::filesystem::current_path(m_server_path);
}
if (m_server_path.empty()) {
LogInfo("Failed to load server path");
return;
}
LogInfo("server [{}]", m_server_path);
std::filesystem::current_path(m_server_path);
if (!EQEmuConfig::LoadConfig()) {
LogError("Failed to load eqemu config");
@@ -38,60 +26,64 @@ void PathManager::LoadPaths()
const auto c = EQEmuConfig::get();
// maps
if (File::Exists(fs::path{m_server_path + "/" + c->MapDir}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/" + c->MapDir}).string();
}
else if (File::Exists(fs::path{m_server_path + "/maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/maps"}).string();
}
else if (File::Exists(fs::path{m_server_path + "/Maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/Maps"}).string();
}
auto resolve_path = [&](const std::string& dir, const std::vector<std::string>& fallback_dirs = {}) -> std::string {
// relative
if (File::Exists((fs::path{m_server_path} / dir).string())) {
return fs::relative(fs::path{m_server_path} / dir).lexically_normal().string();
}
// quests
if (File::Exists(fs::path{m_server_path + "/" + c->QuestDir}.string())) {
m_quests_path = fs::relative(fs::path{m_server_path + "/" + c->QuestDir}).string();
}
// absolute
if (File::Exists(fs::path{dir}.string())) {
return fs::absolute(fs::path{dir}).string();
}
// plugins
if (File::Exists(fs::path{m_server_path + "/" + c->PluginDir}.string())) {
m_plugins_path = fs::relative(fs::path{m_server_path + "/" + c->PluginDir}).string();
}
// fallback search options if specified
for (const auto& fallback : fallback_dirs) {
if (File::Exists((fs::path{m_server_path} / fallback).string())) {
return fs::relative(fs::path{m_server_path} / fallback).lexically_normal().string();
}
}
// lua_modules
if (File::Exists(fs::path{m_server_path + "/" + c->LuaModuleDir}.string())) {
m_lua_modules_path = fs::relative(fs::path{m_server_path + "/" + c->LuaModuleDir}).string();
}
// if all else fails, just set it to the config value
return dir;
};
// lua mods
if (File::Exists(fs::path{ m_server_path + "/mods" }.string())) {
m_lua_mods_path = fs::relative(fs::path{ m_server_path + "/mods" }).string();
}
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_patch_path = resolve_path(c->PatchDir);
m_opcode_path = resolve_path(c->OpcodeDir);
m_shared_memory_path = resolve_path(c->SharedMemDir);
m_log_path = resolve_path(c->LogDir, {"logs"});
// patches
if (File::Exists(fs::path{m_server_path + "/" + c->PatchDir}.string())) {
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
}
// Log all paths in a loop
std::vector<std::pair<std::string, std::string>> paths = {
{"server", m_server_path},
{"logs", m_log_path},
{"lua mods", m_lua_mods_path},
{"lua_modules", m_lua_modules_path},
{"maps", m_maps_path},
{"patches", m_patch_path},
{"opcode", m_opcode_path},
{"plugins", m_plugins_path},
{"quests", m_quests_path},
{"shared_memory", m_shared_memory_path}
};
// shared_memory_path
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
}
constexpr int name_width = 15;
constexpr int path_width = 0;
constexpr int break_length = 70;
// logging path
if (File::Exists(fs::path{m_server_path + "/" + c->LogDir}.string())) {
m_log_path = fs::relative(fs::path{m_server_path + "/" + c->LogDir}).string();
std::cout << std::endl;
LogInfo("{}", Strings::Repeat("-", break_length));
for (const auto& [name, in_path] : paths) {
if (!in_path.empty()) {
LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width);
}
}
LogInfo("logs path [{}]", m_log_path);
LogInfo("lua mods path [{}]", m_lua_mods_path);
LogInfo("lua_modules path [{}]", m_lua_modules_path);
LogInfo("maps path [{}]", m_maps_path);
LogInfo("patches path [{}]", m_patch_path);
LogInfo("plugins path [{}]", m_plugins_path);
LogInfo("quests path [{}]", m_quests_path);
LogInfo("shared_memory path [{}]", m_shared_memory_path);
LogInfo("{}", Strings::Repeat("-", break_length));
}
const std::string &PathManager::GetServerPath() const
@@ -129,6 +121,11 @@ const std::string &PathManager::GetPatchPath() const
return m_patch_path;
}
const std::string &PathManager::GetOpcodePath() const
{
return m_opcode_path;
}
const std::string &PathManager::GetLuaModulesPath() const
{
return m_lua_modules_path;
+2
View File
@@ -13,6 +13,7 @@ public:
[[nodiscard]] const std::string &GetLuaModulesPath() const;
[[nodiscard]] const std::string &GetMapsPath() const;
[[nodiscard]] const std::string &GetPatchPath() 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;
@@ -24,6 +25,7 @@ private:
std::string m_lua_modules_path;
std::string m_maps_path;
std::string m_patch_path;
std::string m_opcode_path;
std::string m_plugins_path;
std::string m_quests_path;
std::string m_server_path;
@@ -49,23 +49,23 @@ public:
std::string field;
switch (theme_id) {
case LDoNThemes::GUK: {
case LDoNTheme::GUK: {
field = "guk_";
break;
}
case LDoNThemes::MIR: {
case LDoNTheme::MIR: {
field = "mir_";
break;
}
case LDoNThemes::MMC: {
case LDoNTheme::MMC: {
field = "mmc_";
break;
}
case LDoNThemes::RUJ: {
case LDoNTheme::RUJ: {
field = "ruj_";
break;
}
case LDoNThemes::TAK: {
case LDoNTheme::TAK: {
field = "tak_";
break;
}
@@ -0,0 +1,475 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
#define EQEMU_BASE_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseCharacterEvolvingItemsRepository {
public:
struct CharacterEvolvingItems {
uint64_t id;
uint32_t character_id;
uint32_t item_id;
uint8_t activated;
uint8_t equipped;
int64_t current_amount;
double progression;
uint32_t final_item_id;
time_t deleted_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"character_id",
"item_id",
"activated",
"equipped",
"current_amount",
"progression",
"final_item_id",
"deleted_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"character_id",
"item_id",
"activated",
"equipped",
"current_amount",
"progression",
"final_item_id",
"UNIX_TIMESTAMP(deleted_at)",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("character_evolving_items");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static CharacterEvolvingItems NewEntity()
{
CharacterEvolvingItems e{};
e.id = 0;
e.character_id = 0;
e.item_id = 0;
e.activated = 0;
e.equipped = 0;
e.current_amount = 0;
e.progression = 0;
e.final_item_id = 0;
e.deleted_at = 0;
return e;
}
static CharacterEvolvingItems GetCharacterEvolvingItems(
const std::vector<CharacterEvolvingItems> &character_evolving_itemss,
int character_evolving_items_id
)
{
for (auto &character_evolving_items : character_evolving_itemss) {
if (character_evolving_items.id == character_evolving_items_id) {
return character_evolving_items;
}
}
return NewEntity();
}
static CharacterEvolvingItems FindOne(
Database& db,
int character_evolving_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
character_evolving_items_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
CharacterEvolvingItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int character_evolving_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
character_evolving_items_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const CharacterEvolvingItems &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.character_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
v.push_back(columns[3] + " = " + std::to_string(e.activated));
v.push_back(columns[4] + " = " + std::to_string(e.equipped));
v.push_back(columns[5] + " = " + std::to_string(e.current_amount));
v.push_back(columns[6] + " = " + std::to_string(e.progression));
v.push_back(columns[7] + " = " + std::to_string(e.final_item_id));
v.push_back(columns[8] + " = FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static CharacterEvolvingItems InsertOne(
Database& db,
CharacterEvolvingItems e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.activated));
v.push_back(std::to_string(e.equipped));
v.push_back(std::to_string(e.current_amount));
v.push_back(std::to_string(e.progression));
v.push_back(std::to_string(e.final_item_id));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<CharacterEvolvingItems> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.activated));
v.push_back(std::to_string(e.equipped));
v.push_back(std::to_string(e.current_amount));
v.push_back(std::to_string(e.progression));
v.push_back(std::to_string(e.final_item_id));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<CharacterEvolvingItems> All(Database& db)
{
std::vector<CharacterEvolvingItems> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterEvolvingItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<CharacterEvolvingItems> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<CharacterEvolvingItems> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterEvolvingItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.character_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.activated = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.equipped = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.current_amount = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.progression = row[6] ? strtod(row[6], nullptr) : 0;
e.final_item_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[8] ? row[8] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const CharacterEvolvingItems &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.activated));
v.push_back(std::to_string(e.equipped));
v.push_back(std::to_string(e.current_amount));
v.push_back(std::to_string(e.progression));
v.push_back(std::to_string(e.final_item_id));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<CharacterEvolvingItems> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.activated));
v.push_back(std::to_string(e.equipped));
v.push_back(std::to_string(e.current_amount));
v.push_back(std::to_string(e.progression));
v.push_back(std::to_string(e.final_item_id));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
@@ -0,0 +1,392 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_CHARACTER_PET_NAME_REPOSITORY_H
#define EQEMU_BASE_CHARACTER_PET_NAME_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseCharacterPetNameRepository {
public:
struct CharacterPetName {
int32_t character_id;
std::string name;
};
static std::string PrimaryKey()
{
return std::string("character_id");
}
static std::vector<std::string> Columns()
{
return {
"character_id",
"name",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"character_id",
"name",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("character_pet_name");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static CharacterPetName NewEntity()
{
CharacterPetName e{};
e.character_id = 0;
e.name = "";
return e;
}
static CharacterPetName GetCharacterPetName(
const std::vector<CharacterPetName> &character_pet_names,
int character_pet_name_id
)
{
for (auto &character_pet_name : character_pet_names) {
if (character_pet_name.character_id == character_pet_name_id) {
return character_pet_name;
}
}
return NewEntity();
}
static CharacterPetName FindOne(
Database& db,
int character_pet_name_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
character_pet_name_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
CharacterPetName e{};
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.name = row[1] ? row[1] : "";
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int character_pet_name_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
character_pet_name_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const CharacterPetName &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.character_id));
v.push_back(columns[1] + " = '" + Strings::Escape(e.name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.character_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static CharacterPetName InsertOne(
Database& db,
CharacterPetName e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.character_id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<CharacterPetName> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<CharacterPetName> All(Database& db)
{
std::vector<CharacterPetName> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterPetName e{};
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.name = row[1] ? row[1] : "";
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<CharacterPetName> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<CharacterPetName> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
CharacterPetName e{};
e.character_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.name = row[1] ? row[1] : "";
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const CharacterPetName &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<CharacterPetName> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_CHARACTER_PET_NAME_REPOSITORY_H
@@ -23,6 +23,7 @@ public:
std::string key_;
std::string value;
uint32_t expires;
int64_t account_id;
int64_t character_id;
int64_t npc_id;
int64_t bot_id;
@@ -36,6 +37,7 @@ public:
CEREAL_NVP(key_),
CEREAL_NVP(value),
CEREAL_NVP(expires),
CEREAL_NVP(account_id),
CEREAL_NVP(character_id),
CEREAL_NVP(npc_id),
CEREAL_NVP(bot_id)
@@ -55,6 +57,7 @@ public:
"`key`",
"value",
"expires",
"account_id",
"character_id",
"npc_id",
"bot_id",
@@ -68,6 +71,7 @@ public:
"`key`",
"value",
"expires",
"account_id",
"character_id",
"npc_id",
"bot_id",
@@ -115,6 +119,7 @@ public:
e.key_ = "";
e.value = "";
e.expires = 0;
e.account_id = 0;
e.character_id = 0;
e.npc_id = 0;
e.bot_id = 0;
@@ -158,9 +163,10 @@ public:
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
return e;
}
@@ -197,9 +203,10 @@ public:
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.expires));
v.push_back(columns[4] + " = " + std::to_string(e.character_id));
v.push_back(columns[5] + " = " + std::to_string(e.npc_id));
v.push_back(columns[6] + " = " + std::to_string(e.bot_id));
v.push_back(columns[4] + " = " + std::to_string(e.account_id));
v.push_back(columns[5] + " = " + std::to_string(e.character_id));
v.push_back(columns[6] + " = " + std::to_string(e.npc_id));
v.push_back(columns[7] + " = " + std::to_string(e.bot_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -225,6 +232,7 @@ public:
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.npc_id));
v.push_back(std::to_string(e.bot_id));
@@ -261,6 +269,7 @@ public:
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.npc_id));
v.push_back(std::to_string(e.bot_id));
@@ -301,9 +310,10 @@ public:
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -332,9 +342,10 @@ public:
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.character_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.npc_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.bot_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.account_id = row[4] ? strtoll(row[4], nullptr, 10) : 0;
e.character_id = row[5] ? strtoll(row[5], nullptr, 10) : 0;
e.npc_id = row[6] ? strtoll(row[6], nullptr, 10) : 0;
e.bot_id = row[7] ? strtoll(row[7], nullptr, 10) : 0;
all_entries.push_back(e);
}
@@ -413,6 +424,7 @@ public:
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.npc_id));
v.push_back(std::to_string(e.bot_id));
@@ -442,6 +454,7 @@ public:
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.npc_id));
v.push_back(std::to_string(e.bot_id));
@@ -0,0 +1,451 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
#define EQEMU_BASE_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseItemsEvolvingDetailsRepository {
public:
struct ItemsEvolvingDetails {
uint32_t id;
uint32_t item_evo_id;
uint32_t item_evolve_level;
uint32_t item_id;
uint32_t type;
uint32_t sub_type;
int64_t required_amount;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"item_evo_id",
"item_evolve_level",
"item_id",
"type",
"sub_type",
"required_amount",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"item_evo_id",
"item_evolve_level",
"item_id",
"type",
"sub_type",
"required_amount",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("items_evolving_details");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static ItemsEvolvingDetails NewEntity()
{
ItemsEvolvingDetails e{};
e.id = 0;
e.item_evo_id = 0;
e.item_evolve_level = 0;
e.item_id = 0;
e.type = 0;
e.sub_type = 0;
e.required_amount = 0;
return e;
}
static ItemsEvolvingDetails GetItemsEvolvingDetails(
const std::vector<ItemsEvolvingDetails> &items_evolving_detailss,
int items_evolving_details_id
)
{
for (auto &items_evolving_details : items_evolving_detailss) {
if (items_evolving_details.id == items_evolving_details_id) {
return items_evolving_details;
}
}
return NewEntity();
}
static ItemsEvolvingDetails FindOne(
Database& db,
int items_evolving_details_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
items_evolving_details_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
ItemsEvolvingDetails e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int items_evolving_details_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
items_evolving_details_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const ItemsEvolvingDetails &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.item_evo_id));
v.push_back(columns[2] + " = " + std::to_string(e.item_evolve_level));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.type));
v.push_back(columns[5] + " = " + std::to_string(e.sub_type));
v.push_back(columns[6] + " = " + std::to_string(e.required_amount));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static ItemsEvolvingDetails InsertOne(
Database& db,
ItemsEvolvingDetails e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_evo_id));
v.push_back(std::to_string(e.item_evolve_level));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.sub_type));
v.push_back(std::to_string(e.required_amount));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<ItemsEvolvingDetails> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_evo_id));
v.push_back(std::to_string(e.item_evolve_level));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.sub_type));
v.push_back(std::to_string(e.required_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<ItemsEvolvingDetails> All(Database& db)
{
std::vector<ItemsEvolvingDetails> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ItemsEvolvingDetails e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<ItemsEvolvingDetails> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<ItemsEvolvingDetails> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
ItemsEvolvingDetails e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.item_evo_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_evolve_level = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.sub_type = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.required_amount = row[6] ? strtoll(row[6], nullptr, 10) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const ItemsEvolvingDetails &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_evo_id));
v.push_back(std::to_string(e.item_evolve_level));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.sub_type));
v.push_back(std::to_string(e.required_amount));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<ItemsEvolvingDetails> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_evo_id));
v.push_back(std::to_string(e.item_evolve_level));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.sub_type));
v.push_back(std::to_string(e.required_amount));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
@@ -28,13 +28,15 @@ public:
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
int32_t item_sn;
uint32_t item_sn;
int32_t item_charges;
uint64_t item_cost;
uint32_t item_cost;
uint8_t slot_id;
uint32_t char_entity_id;
uint32_t char_zone_id;
int8_t active_transaction;
int32_t char_zone_instance_id;
uint8_t active_transaction;
time_t listing_date;
};
static std::string PrimaryKey()
@@ -60,7 +62,9 @@ public:
"slot_id",
"char_entity_id",
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
"listing_date",
};
}
@@ -82,7 +86,9 @@ public:
"slot_id",
"char_entity_id",
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
"UNIX_TIMESTAMP(listing_date)",
};
}
@@ -123,22 +129,24 @@ public:
{
Trader e{};
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.char_entity_id = 0;
e.char_zone_id = 0;
e.active_transaction = 0;
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.char_entity_id = 0;
e.char_zone_id = 0;
e.char_zone_instance_id = 0;
e.active_transaction = 0;
e.listing_date = 0;
return e;
}
@@ -175,22 +183,24 @@ public:
if (results.RowCount() == 1) {
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
return e;
}
@@ -238,7 +248,9 @@ public:
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction));
v.push_back(columns[15] + " = " + std::to_string(e.char_zone_instance_id));
v.push_back(columns[16] + " = " + std::to_string(e.active_transaction));
v.push_back(columns[17] + " = FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -275,7 +287,9 @@ public:
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -320,7 +334,9 @@ public:
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -354,22 +370,24 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -394,22 +412,24 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -499,7 +519,9 @@ public:
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -537,7 +559,9 @@ public:
v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
+24 -12
View File
@@ -111,12 +111,13 @@ public:
int32_t fast_regen_mana;
int32_t fast_regen_endurance;
int32_t npc_max_aggro_dist;
uint32_t max_movement_update_range;
uint32_t client_update_range;
int32_t underworld_teleport_index;
int32_t lava_damage;
int32_t min_lava_damage;
uint8_t idle_when_empty;
uint32_t seconds_before_idle;
int32_t shard_at_player_count;
};
static std::string PrimaryKey()
@@ -219,12 +220,13 @@ public:
"fast_regen_mana",
"fast_regen_endurance",
"npc_max_aggro_dist",
"max_movement_update_range",
"client_update_range",
"underworld_teleport_index",
"lava_damage",
"min_lava_damage",
"idle_when_empty",
"seconds_before_idle",
"shard_at_player_count",
};
}
@@ -323,12 +325,13 @@ public:
"fast_regen_mana",
"fast_regen_endurance",
"npc_max_aggro_dist",
"max_movement_update_range",
"client_update_range",
"underworld_teleport_index",
"lava_damage",
"min_lava_damage",
"idle_when_empty",
"seconds_before_idle",
"shard_at_player_count",
};
}
@@ -461,12 +464,13 @@ public:
e.fast_regen_mana = 180;
e.fast_regen_endurance = 180;
e.npc_max_aggro_dist = 600;
e.max_movement_update_range = 600;
e.client_update_range = 600;
e.underworld_teleport_index = 0;
e.lava_damage = 50;
e.min_lava_damage = 10;
e.idle_when_empty = 1;
e.seconds_before_idle = 60;
e.shard_at_player_count = 0;
return e;
}
@@ -595,12 +599,13 @@ public:
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
return e;
}
@@ -725,12 +730,13 @@ public:
v.push_back(columns[89] + " = " + std::to_string(e.fast_regen_mana));
v.push_back(columns[90] + " = " + std::to_string(e.fast_regen_endurance));
v.push_back(columns[91] + " = " + std::to_string(e.npc_max_aggro_dist));
v.push_back(columns[92] + " = " + std::to_string(e.max_movement_update_range));
v.push_back(columns[92] + " = " + std::to_string(e.client_update_range));
v.push_back(columns[93] + " = " + std::to_string(e.underworld_teleport_index));
v.push_back(columns[94] + " = " + std::to_string(e.lava_damage));
v.push_back(columns[95] + " = " + std::to_string(e.min_lava_damage));
v.push_back(columns[96] + " = " + std::to_string(e.idle_when_empty));
v.push_back(columns[97] + " = " + std::to_string(e.seconds_before_idle));
v.push_back(columns[98] + " = " + std::to_string(e.shard_at_player_count));
auto results = db.QueryDatabase(
fmt::format(
@@ -844,12 +850,13 @@ public:
v.push_back(std::to_string(e.fast_regen_mana));
v.push_back(std::to_string(e.fast_regen_endurance));
v.push_back(std::to_string(e.npc_max_aggro_dist));
v.push_back(std::to_string(e.max_movement_update_range));
v.push_back(std::to_string(e.client_update_range));
v.push_back(std::to_string(e.underworld_teleport_index));
v.push_back(std::to_string(e.lava_damage));
v.push_back(std::to_string(e.min_lava_damage));
v.push_back(std::to_string(e.idle_when_empty));
v.push_back(std::to_string(e.seconds_before_idle));
v.push_back(std::to_string(e.shard_at_player_count));
auto results = db.QueryDatabase(
fmt::format(
@@ -971,12 +978,13 @@ public:
v.push_back(std::to_string(e.fast_regen_mana));
v.push_back(std::to_string(e.fast_regen_endurance));
v.push_back(std::to_string(e.npc_max_aggro_dist));
v.push_back(std::to_string(e.max_movement_update_range));
v.push_back(std::to_string(e.client_update_range));
v.push_back(std::to_string(e.underworld_teleport_index));
v.push_back(std::to_string(e.lava_damage));
v.push_back(std::to_string(e.min_lava_damage));
v.push_back(std::to_string(e.idle_when_empty));
v.push_back(std::to_string(e.seconds_before_idle));
v.push_back(std::to_string(e.shard_at_player_count));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -1102,12 +1110,13 @@ public:
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
all_entries.push_back(e);
}
@@ -1224,12 +1233,13 @@ public:
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
e.idle_when_empty = row[96] ? static_cast<uint8_t>(strtoul(row[96], nullptr, 10)) : 1;
e.seconds_before_idle = row[97] ? static_cast<uint32_t>(strtoul(row[97], nullptr, 10)) : 60;
e.shard_at_player_count = row[98] ? static_cast<int32_t>(atoi(row[98])) : 0;
all_entries.push_back(e);
}
@@ -1396,12 +1406,13 @@ public:
v.push_back(std::to_string(e.fast_regen_mana));
v.push_back(std::to_string(e.fast_regen_endurance));
v.push_back(std::to_string(e.npc_max_aggro_dist));
v.push_back(std::to_string(e.max_movement_update_range));
v.push_back(std::to_string(e.client_update_range));
v.push_back(std::to_string(e.underworld_teleport_index));
v.push_back(std::to_string(e.lava_damage));
v.push_back(std::to_string(e.min_lava_damage));
v.push_back(std::to_string(e.idle_when_empty));
v.push_back(std::to_string(e.seconds_before_idle));
v.push_back(std::to_string(e.shard_at_player_count));
auto results = db.QueryDatabase(
fmt::format(
@@ -1516,12 +1527,13 @@ public:
v.push_back(std::to_string(e.fast_regen_mana));
v.push_back(std::to_string(e.fast_regen_endurance));
v.push_back(std::to_string(e.npc_max_aggro_dist));
v.push_back(std::to_string(e.max_movement_update_range));
v.push_back(std::to_string(e.client_update_range));
v.push_back(std::to_string(e.underworld_teleport_index));
v.push_back(std::to_string(e.lava_damage));
v.push_back(std::to_string(e.min_lava_damage));
v.push_back(std::to_string(e.idle_when_empty));
v.push_back(std::to_string(e.seconds_before_idle));
v.push_back(std::to_string(e.shard_at_player_count));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -80,6 +80,93 @@ public:
return l.empty() ? CharacterDataRepository::NewEntity() : l.front();
}
struct InstancePlayerCount {
int32_t instance_id;
uint32_t zone_id;
uint32_t player_count;
};
static std::vector<InstancePlayerCount> GetInstanceZonePlayerCounts(Database& db, int zone_id) {
std::vector<InstancePlayerCount> zone_player_counts;
uint64_t shard_instance_duration = 3155760000;
auto query = fmt::format(SQL(
SELECT
zone_id,
0 AS instance_id,
COUNT(id) AS player_count
FROM
character_data
WHERE
zone_instance = 0
AND zone_id = {}
AND last_login >= UNIX_TIMESTAMP(NOW()) - 600
GROUP BY
zone_id
ORDER BY
zone_id, player_count DESC
), zone_id);
auto results = db.QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
InstancePlayerCount e{};
e.zone_id = std::stoi(row[0]);
e.instance_id = 0;
e.player_count = std::stoi(row[2]);
zone_player_counts.push_back(e);
}
if (zone_player_counts.empty()) {
InstancePlayerCount e{};
e.zone_id = zone_id;
e.instance_id = 0;
e.player_count = 0;
zone_player_counts.push_back(e);
}
// duration 3155760000 is for shards explicitly
query = fmt::format(
SQL(
SELECT
i.id AS instance_id,
i.zone AS zone_id,
COUNT(c.id) AS player_count
FROM
instance_list i
LEFT JOIN
character_data c
ON
i.zone = c.zone_id
AND i.id = c.zone_instance
AND c.last_login >= UNIX_TIMESTAMP(NOW()) - 600
AND (i.start_time + i.duration >= UNIX_TIMESTAMP(NOW()) OR i.never_expires = 0)
AND i.duration = {}
WHERE
i.zone IS NOT NULL AND i.zone = {}
GROUP BY
i.id, i.zone, i.version
ORDER BY
i.id ASC;
), shard_instance_duration, zone_id
);
results = db.QueryDatabase(query);
if (!results.Success() || results.RowCount() == 0) {
return zone_player_counts;
}
for (auto row = results.begin(); row != results.end(); ++row) {
InstancePlayerCount e{};
e.instance_id = std::stoi(row[0]);
e.zone_id = std::stoi(row[1]);
e.player_count = std::stoi(row[2]);
zone_player_counts.push_back(e);
}
return zone_player_counts;
}
};
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
@@ -0,0 +1,66 @@
#ifndef EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
#define EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_character_evolving_items_repository.h"
#include <boost/tuple/tuple_comparison.hpp>
class CharacterEvolvingItemsRepository: public BaseCharacterEvolvingItemsRepository {
public:
// Custom extended repository methods here
static CharacterEvolvingItems SetCurrentAmountAndProgression(Database& db, const uint64 id, const uint64 amount, const double progression)
{
auto e = FindOne(db, id);
if (e.id == 0) {
return NewEntity();
}
e.current_amount = amount;
e.progression = progression;
e.deleted_at = 0;
UpdateOne(db, e);
return e;
}
static CharacterEvolvingItems SetEquipped(Database& db, const uint64 id, const bool equipped)
{
auto e = FindOne(db, id);
if (e.id == 0) {
return NewEntity();
}
e.equipped = equipped;
e.deleted_at = 0;
UpdateOne(db, e);
return e;
}
static CharacterEvolvingItems SoftDelete(Database& db, const uint64 id)
{
auto e = FindOne(db, id);
if (e.id == 0) {
return NewEntity();
}
e.deleted_at = time(nullptr);
UpdateOne(db, e);
return e;
}
static bool UpdateCharID(Database &db, const uint64 id, const uint32 to_char_id)
{
auto e = FindOne(db, id);
if (e.id == 0) {
return false;
}
e.character_id = to_char_id;
e.deleted_at = 0;
return UpdateOne(db, e);
}
};
#endif //EQEMU_CHARACTER_EVOLVING_ITEMS_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
#define EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_character_pet_name_repository.h"
class CharacterPetNameRepository: public BaseCharacterPetNameRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_CHARACTER_PET_NAME_REPOSITORY_H
@@ -0,0 +1,14 @@
#ifndef EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
#define EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_items_evolving_details_repository.h"
class ItemsEvolvingDetailsRepository: public BaseItemsEvolvingDetailsRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_ITEMS_EVOLVING_DETAILS_REPOSITORY_H
+53
View File
@@ -7,6 +7,14 @@
class ItemsRepository: public BaseItemsRepository {
public:
struct Bazaar_Results {
uint32 item_id;
std::string name;
bool stackable;
uint32 icon;
uint32 stats;
};
static std::vector<int32> GetItemIDsBySearchCriteria(
Database& db,
std::string search_string,
@@ -37,6 +45,51 @@ public:
return item_id_list;
}
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
Database& db,
const std::vector<std::string> &search_ids,
const std::string &name,
const std::string &field_criteria_items,
const std::string &where_criteria_items,
const uint32 query_limit = 0
)
{
auto query = fmt::format(
"SELECT id, name, stackable, icon, {} "
"FROM items "
"WHERE `name` LIKE '%%{}%%' AND {} AND id IN({}) "
"ORDER BY id ASC",
field_criteria_items,
Strings::Escape(name),
where_criteria_items,
Strings::Implode(",", search_ids)
);
if (query_limit >= 1) {
query += fmt::format(" LIMIT {}", query_limit);
}
std::unordered_map<uint32, Bazaar_Results> item_list;
auto results = db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return item_list;
}
item_list.reserve(results.RowCount());
for (auto row : results) {
Bazaar_Results br{};
br.item_id = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
br.name = row[1] ? row[1] : "";
br.stackable = atoi(row[2]) ? true : false;
br.icon = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
br.stats = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
item_list.emplace(br.item_id, br);
}
return item_list;
}
};
+118 -20
View File
@@ -12,10 +12,12 @@
class TraderRepository : public BaseTraderRepository {
public:
static constexpr uint32 TRADER_CONVERT_ID = 4000000000;
struct DistinctTraders_Struct {
uint32 trader_id;
uint32 zone_id;
uint32 zone_instance_id;
uint32 entity_id;
std::string trader_name;
};
@@ -26,6 +28,11 @@ public:
std::vector<DistinctTraders_Struct> traders{};
};
struct BazaarTraderSearch_Struct {
Trader trader;
std::string trader_name;
};
struct WelcomeData_Struct {
uint32 count_of_traders;
uint32 count_of_items;
@@ -35,18 +42,28 @@ public:
GetBazaarSearchResults(
SharedDatabase &db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
uint32 char_zone_id,
int32 char_zone_instance_id
);
static BulkTraders_Struct GetDistinctTraders(Database &db)
static BulkTraders_Struct GetDistinctTraders(
Database &db,
uint32 char_zone_instance_id,
uint32 max_results = std::numeric_limits<uint32>::max()
)
{
BulkTraders_Struct all_entries{};
std::vector<DistinctTraders_Struct> distinct_traders;
auto results = db.QueryDatabase(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name "
auto results = db.QueryDatabase(fmt::format(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON t.char_id = c.id;"
"JOIN character_data AS c ON t.char_id = c.id "
"WHERE t.char_zone_instance_id = {} "
"ORDER BY t.char_zone_instance_id ASC "
"LIMIT {}",
char_zone_instance_id,
max_results)
);
distinct_traders.reserve(results.RowCount());
@@ -54,10 +71,11 @@ public:
for (auto row: results) {
DistinctTraders_Struct e{};
e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]);
e.entity_id = Strings::ToInt(row[2]);
e.trader_name = row[3] ? row[3] : "";
e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]);
e.zone_instance_id = Strings::ToInt(row[2]);
e.entity_id = Strings::ToInt(row[3]);
e.trader_name = row[4] ? row[4] : "";
all_entries.name_length += e.trader_name.length() + 1;
all_entries.traders.push_back(e);
@@ -112,7 +130,8 @@ public:
}
for (auto &i: items) {
i.item_cost = new_price;
i.item_cost = new_price;
i.listing_date = time(nullptr);
}
return ReplaceMany(db, items);
@@ -160,41 +179,40 @@ public:
auto m = trader_item[0];
m.item_charges = quantity;
m.listing_date = time(nullptr);
return UpdateOne(db, m);
}
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number)
static Trader GetItemBySerialNumber(Database &db, uint32 serial_number, uint32 trader_id)
{
Trader e{};
const auto trader_item = GetWhere(
db,
fmt::format("`item_sn` = '{}' LIMIT 1", serial_number)
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, serial_number)
);
if (trader_item.empty()) {
return e;
}
else {
return trader_item.at(0);
}
return trader_item.at(0);
}
static Trader GetItemBySerialNumber(Database &db, std::string serial_number)
static Trader GetItemBySerialNumber(Database &db, std::string serial_number, uint32 trader_id)
{
Trader e{};
auto sn = Strings::ToUnsignedBigInt(serial_number);
const auto trader_item = GetWhere(
db,
fmt::format("`item_sn` = '{}' LIMIT 1", sn)
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, sn)
);
if (trader_item.empty()) {
return e;
}
else {
return trader_item.at(0);
}
return trader_item.at(0);
}
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
@@ -205,6 +223,7 @@ public:
}
e.active_transaction = status == true ? 1 : 0;
e.listing_date = time(nullptr);
return UpdateOne(db, e);
}
@@ -223,6 +242,85 @@ public:
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
}
static DistinctTraders_Struct GetTraderByInstanceAndSerialnumber(
Database &db,
uint32 instance_id,
const char *serial_number
)
{
DistinctTraders_Struct trader{};
auto query = fmt::format(
"SELECT t.id, t.char_id, c.name "
"FROM trader AS t "
"JOIN character_data AS c ON c.id = t.char_id "
"WHERE t.char_zone_id = 151 AND t.char_zone_instance_id = {} AND t.item_sn = {} LIMIT 1",
instance_id,
serial_number
);
auto results = db.QueryDatabase(query);
if (results.RowCount() == 0) {
return trader;
}
auto row = results.begin();
std::string name = row[2];
trader.trader_id = Strings::ToUnsignedInt(row[1]);
trader.trader_name = row[2] ? row[2] : "";
return trader;
}
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
Database &db,
std::string &search_criteria_trader
)
{
std::vector<BazaarTraderSearch_Struct> all_entries{};
auto query = fmt::format(
"SELECT trader.*, c.`name` FROM `trader` INNER JOIN character_data AS c ON trader.char_id = c.id "
"WHERE {} ORDER BY trader.char_id ASC",
search_criteria_trader
);
auto results = db.QueryDatabase(query);
if (results.RowCount() == 0) {
return all_entries;
}
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BazaarTraderSearch_Struct e{};
e.trader.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.trader.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.trader.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.trader.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.trader.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.trader.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.trader.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.trader.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.trader.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.trader.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.trader.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.trader.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.trader.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.trader.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.trader.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.trader.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.trader.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.trader_name = row[17] ? row[17] : std::string("");
all_entries.push_back(e);
}
return all_entries;
}
};
#endif //EQEMU_TRADER_REPOSITORY_H
+15 -1
View File
@@ -339,7 +339,10 @@ RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to ha
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
RULE_INT(World, Id, 100, "Used by later clients to create GUIDs, expected to be Unique to the world but ultimately not that important")
RULE_STRING(World, SupportedClients, "", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
RULE_STRING(World, CustomFilesKey, "", "Enable if the server requires custom files and sends a key to validate. Empty string to disable. Example: eqcustom_v1")
RULE_STRING(World, CustomFilesUrl, "github.com/knervous/eqnexus/releases", "URL to display at character select if client is missing custom files")
RULE_INT(World, CustomFilesAdminLevel, 20, "Admin level at which custom file key is not required when CustomFilesKey is specified")
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@@ -369,6 +372,7 @@ RULE_INT(Zone, FishingChance, 399, "Chance of fishing from zone table vs global
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
RULE_CATEGORY_END()
RULE_CATEGORY(Map)
@@ -519,6 +523,7 @@ RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares
RULE_INT(Spells, TargetedAOEMaxTargets, 4, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blank AOE spell can cast on. Set to 0 for no limit.")
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -680,6 +685,7 @@ RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_STRING(NPC, ExcludedFaceTargetRaces, "52,72,73,141,233,328,329,372,376,377,378,379,380,381,382,383,404,422,423,424,425,426,428,429,445,449,460,462,463,500,501,502,503,504,505,506,507,508,509,510,511,513,514,515,516,533,534,535,536,537,538,539,540,541,542,543,544,545,546,550,551,552,553,554,555,556,557,567,573,577,586,589,590,591,592,593,595,596,599,601,616,619,621,628,629,630,633,634,635,636,665,683,684,685,691,692,693,694,702,703,705,706,707,710,711,714,720,2250,2254", "Race IDs excluded from facing target when hailed")
RULE_CATEGORY_END()
RULE_CATEGORY(Aggro)
@@ -824,6 +830,7 @@ RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a ba
RULE_INT(Bazaar, VoucherDeliveryCost, 200, "Number of vouchers for direct delivery for a bazaar purchase. Default is 200 vouchers. RoF+ Only.")
RULE_BOOL(Bazaar, EnableParcelDelivery, true, "Enable bazaar purchases via parcel delivery. Default is True.")
RULE_INT(Bazaar, MaxBuyerInventorySearchResults, 200, "Maximum number of search results when a Buyer searches the global item list. Default is 200. RoF+ Only.")
RULE_BOOL(Bazaar, UseAlternateBazaarSearch, false, "Allows the bazaar search window to search across bazaar shards. Default is false.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mail)
@@ -1032,6 +1039,13 @@ RULE_INT(Parcel, ParcelMaxItems, 50, "The maximum number of parcels a player is
RULE_INT(Parcel, ParcelPruneDelay, 30, "The number of days after which a parcel is deleted. Items are lost!")
RULE_CATEGORY_END()
RULE_CATEGORY(EvolvingItems)
RULE_REAL(EvolvingItems, PercentOfSoloExperience, 0.1, "Percentage of solo experience allocated to evolving items that require experience.")
RULE_REAL(EvolvingItems, PercentOfGroupExperience, 0.1, "Percentage of group experience allocated to evolving items that require experience.")
RULE_REAL(EvolvingItems, PercentOfRaidExperience, 0.1, "Percentage of solo experience allocated to evolving items that require experience.")
RULE_INT(EvolvingItems, DelayUponEquipping, 30000, "Delay in ms before an evolving item will earn rewards after equipping. Default is 30000ms or 30s.")
RULE_CATEGORY_END()
#undef RULE_CATEGORY
#undef RULE_INT
#undef RULE_REAL
+1 -2
View File
@@ -319,8 +319,6 @@
// player events
#define ServerOP_PlayerEvent 0x5100
#define ServerOP_DataBucketCacheUpdate 0x5200
enum {
CZUpdateType_Character,
CZUpdateType_Group,
@@ -1945,6 +1943,7 @@ struct ServerOP_GuildMessage_Struct {
struct TraderMessaging_Struct {
uint32 action;
uint32 zone_id;
uint32 instance_id;
uint32 trader_id;
uint32 entity_id;
char trader_name[64];
+68 -12
View File
@@ -37,11 +37,13 @@
#include "strings.h"
#include "eqemu_config.h"
#include "data_verification.h"
#include "evolving_items.h"
#include "repositories/criteria/content_filter_criteria.h"
#include "repositories/account_repository.h"
#include "repositories/faction_association_repository.h"
#include "repositories/starting_items_repository.h"
#include "path_manager.h"
#include "../zone/client.h"
#include "repositories/loottable_repository.h"
#include "repositories/character_item_recast_repository.h"
#include "repositories/character_corpses_repository.h"
@@ -645,15 +647,23 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is
return true;
}
// Overloaded: Retrieve character inventory based on character id (zone entry)
bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
//bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
bool SharedDatabase::GetInventory(Client *c)
{
if (!char_id || !inv)
if (!c) {
return false;
}
uint32 char_id = c->CharacterID();
EQ::InventoryProfile &inv = c->GetInv();
// Retrieve character inventory
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`;", char_id));
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`", char_id));
auto e_results = CharacterEvolvingItemsRepository::GetWhere(
*this, fmt::format("`character_id` = '{}' AND `deleted_at` IS NULL", char_id)
);
if (results.empty()) {
LogError("Error loading inventory for char_id {} from the database.", char_id);
return false;
@@ -667,8 +677,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
const auto timestamps = GetItemRecastTimestamps(char_id);
auto cv_conflict = false;
const auto pmask = inv->GetLookup()->PossessionsBitmask;
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
const auto pmask = inv.GetLookup()->PossessionsBitmask;
const auto bank_size = inv.GetLookup()->InventoryTypeSize.Bank;
std::vector<InventoryRepository::Inventory> queue{};
for (auto &row: results) {
@@ -785,9 +795,55 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
}
}
if (item->EvolvingItem) {
if (slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END) {
inst->SetEvolveEquipped(true);
}
auto t = std::ranges::find_if(
e_results.cbegin(),
e_results.cend(),
[&](const CharacterEvolvingItemsRepository::CharacterEvolvingItems &x) {
return x.item_id == item_id;
}
);
if (t == std::end(e_results)) {
auto e = CharacterEvolvingItemsRepository::NewEntity();
e.character_id = char_id;
e.item_id = item_id;
e.equipped = inst->GetEvolveEquipped();
e.final_item_id = evolving_items_manager.GetFinalItemID(*inst);
auto r = CharacterEvolvingItemsRepository::InsertOne(*this, e);
e.id = r.id;
e_results.push_back(e);
inst->SetEvolveUniqueID(e.id);
inst->SetEvolveCharID(e.character_id);
inst->SetEvolveItemID(e.item_id);
inst->SetEvolveActivated(e.activated);
inst->SetEvolveEquipped(e.equipped);
inst->SetEvolveCurrentAmount(e.current_amount);
inst->CalculateEvolveProgression();
inst->SetEvolveFinalItemID(e.final_item_id);
}
else {
inst->SetEvolveUniqueID(t->id);
inst->SetEvolveCharID(t->character_id);
inst->SetEvolveItemID(t->item_id);
inst->SetEvolveActivated(t->activated);
inst->SetEvolveEquipped(t->equipped);
inst->SetEvolveCurrentAmount(t->current_amount);
inst->CalculateEvolveProgression();
inst->SetEvolveFinalItemID(t->final_item_id);
}
}
int16 put_slot_id;
if (slot_id >= 8000 && slot_id <= 8999) {
put_slot_id = inv->PushCursor(*inst);
put_slot_id = inv.PushCursor(*inst);
}
else if (slot_id >= 3111 && slot_id <= 3179) {
// Admins: please report any occurrences of this error
@@ -797,10 +853,10 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
item_id,
slot_id
);
put_slot_id = inv->PushCursor(*inst);
put_slot_id = inv.PushCursor(*inst);
}
else {
put_slot_id = inv->PutItem(slot_id, *inst);
put_slot_id = inv.PutItem(slot_id, *inst);
}
row.guid = inst->GetSerialNumber();
@@ -825,8 +881,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
char_name,
char_id,
EQ::versions::MobVersionName(inv->InventoryVersion()),
(inv->GMInventory() ? "true" : "false")
EQ::versions::MobVersionName(inv.InventoryVersion()),
(inv.GMInventory() ? "true" : "false")
);
}
@@ -837,7 +893,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
EQ::ItemInstance::ClearGUIDMap();
// Retrieve shared inventory
return GetSharedBank(char_id, inv, true);
return GetSharedBank(char_id, &inv, true);
}
// Overloaded: Retrieve character inventory based on account_id and character name (char select)
+3 -1
View File
@@ -28,6 +28,8 @@
#include "fixed_memory_variable_hash_set.h"
#include "say_link.h"
#include "repositories/command_subsettings_repository.h"
#include "repositories/items_evolving_details_repository.h"
#include "../common/repositories/character_evolving_items_repository.h"
#include <list>
#include <map>
@@ -103,7 +105,7 @@ public:
bool GetSharedBank(uint32 id, EQ::InventoryProfile *inv, bool is_charid);
int32 GetSharedPlatinum(uint32 account_id);
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add);
bool GetInventory(uint32 char_id, EQ::InventoryProfile *inv);
bool GetInventory(Client* c);
bool GetInventory(uint32 account_id, char *name, EQ::InventoryProfile *inv); // deprecated
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
uint32 GetItemRecastTimestamp(uint32 char_id, uint32 recast_type);
+4 -3
View File
@@ -83,7 +83,8 @@ struct ActivityInformation {
if (zone_ids.empty()) {
return true;
}
bool found_zone = std::find(zone_ids.begin(), zone_ids.end(), zone_id) != zone_ids.end();
bool found_zone = std::any_of(zone_ids.begin(), zone_ids.end(),
[zone_id](int id) { return id <= 0 || id == zone_id; });
return found_zone && (zone_version == version || zone_version == -1);
}
@@ -100,7 +101,7 @@ struct ActivityInformation {
out.WriteInt32(activity_type == TaskActivityType::GiveCash ? 1 : goal_count);
out.WriteLengthString(skill_list); // used in SkillOn objective type string, "-1" for none
out.WriteLengthString(spell_list); // used in CastOn objective type string, "0" for none
out.WriteString(zones); // used in objective zone column and task select "begins in" (may have multiple, "0" for "unknown zone", empty for "ALL")
out.WriteString(zones); // used in ui zone columns and task select "begins in" (may have multiple, invalid id for "Unknown Zone", empty for "ALL")
}
else
{
@@ -114,7 +115,7 @@ struct ActivityInformation {
out.WriteString(description_override);
if (client_version >= EQ::versions::ClientVersion::RoF) {
out.WriteString(zones); // serialized again after description (seems unused)
out.WriteString(zones); // target zone version internal id (unused client side)
}
}
+3
View File
@@ -86,6 +86,9 @@ struct BenchTimer
void reset() { start_time = clock::now(); }
// this is seconds
double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); }
std::chrono::milliseconds::rep elapsedMilliseconds() { return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_time).count(); }
std::chrono::microseconds::rep elapsedMicroseconds() { return std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start_time).count(); }
std::chrono::nanoseconds::rep elapsedNanoseconds() { return std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now() - start_time).count(); }
private:
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
};
+2 -2
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.56.3-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.62.2-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9284
#define CURRENT_BINARY_DATABASE_VERSION 9296
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
#endif
-6
View File
@@ -676,12 +676,6 @@ int ZoneStore::GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
return z ? z->npc_max_aggro_dist : DEFAULT_ZONE_MAX_AGGRO_DISTANCE;
}
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
{
const auto& z = GetZoneVersionWithFallback(zone_id, version);
return z ? z->max_movement_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
}
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
{
const auto& z = GetZoneVersionWithFallback(zone_id, version);
-1
View File
@@ -94,7 +94,6 @@ public:
int GetZoneFastRegenMana(uint32 zone_id, int version = 0);
int GetZoneFastRegenEndurance(uint32 zone_id, int version = 0);
int GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version = 0);
uint32 GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version = 0);
int8 GetZoneMinimumExpansion(uint32 zone_id, int version = 0);
int8 GetZoneMaximumExpansion(uint32 zone_id, int version = 0);
const std::string GetZoneContentFlags(uint32 zone_id, int version = 0);
+2
View File
@@ -251,4 +251,6 @@ private:
scalar m_value;
};
using ref = reference;
} // namespace perlbind
+4 -3
View File
@@ -28,8 +28,8 @@ struct pusher
++m_pushed;
}
void push(const std::string& value) { mPUSHp(value.c_str(), value.size()); ++m_pushed; }
void push(scalar value) { mPUSHs(value.release()); ++m_pushed; };
void push(reference value) { mPUSHs(value.release()); ++m_pushed; };
void push(scalar value) { mPUSHs(value.release()); ++m_pushed; }
void push(reference value) { mPUSHs(value.release()); ++m_pushed; }
void push(array value)
{
@@ -38,7 +38,8 @@ struct pusher
for (int i = 0; i < count; ++i)
{
// mortalizes one reference to array element to avoid copying
PUSHs(sv_2mortal(SvREFCNT_inc(value[i].sv())));
SV** sv = av_fetch(static_cast<AV*>(value), i, true);
mPUSHs(SvREFCNT_inc(*sv));
}
m_pushed += count;
}
+1 -1
View File
@@ -242,7 +242,7 @@ struct read_as<hash>
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
{
int remaining = items - i;
return remaining > 0 && remaining % 2 == 0 && SvTYPE(ST(i)) == SVt_PV;
return remaining > 0 && remaining % 2 == 0 && SvTYPE(ST(i)) < SVt_PVAV;
}
static hash get(PerlInterpreter* my_perl, int i, int ax, int items)
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
constexpr int perlbind_version_major = 1;
constexpr int perlbind_version_minor = 0;
constexpr int perlbind_version_minor = 1;
constexpr int perlbind_version_patch = 0;
constexpr int perlbind_version()
+3 -25
View File
@@ -573,13 +573,10 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
{
SerializeBuffer buf;
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
int ExpansionLookup[30] = { 3007, 3008, 3009, 3010, 3012,
int ExpansionLookup[20] = { 3007, 3008, 3009, 3010, 3012,
3014, 3031, 3033, 3036, 3040,
3045, 3046, 3047, 3514, 3516,
3518, 3520, 3522, 3524, 3526,
3528, 3530, 3532, 3534, 3535,
3536, 3537, 3538, 3539, 3540
};
3518, 3520, 3522, 3524 };
if (server.options.IsDisplayExpansions()) {
@@ -587,26 +584,7 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
int32_t expansion = server.options.GetMaxExpansions();
int32_t owned_expansion = (expansion << 1) | 1;
if (m_client_version == cv_larion) {
buf.WriteInt32(0x00);
buf.WriteInt32(0x00);
buf.WriteInt16(0x00);
buf.WriteInt32(30);
for (int i = 0; i < 30; i++)
{
buf.WriteUInt32(i + 1);
buf.WriteUInt8(1);
buf.WriteInt32(ExpansionLookup[i]);
buf.WriteInt32(6046);
buf.WriteUInt32(0xFFFFFFFF);
buf.WriteUInt32(0);
}
auto out = std::make_unique<EQApplicationPacket>(OP_LoginExpansionPacketData, buf);
m_connection->QueuePacket(out.get());
}
else if (m_client_version == cv_sod) {
if (m_client_version == cv_sod) {
// header info of packet. Requires OP_LoginExpansionPacketData=0x0031 to be in login_opcodes_sod.conf
buf.WriteInt32(0x00);
+85 -18
View File
@@ -7,6 +7,79 @@ extern bool run_server;
#include "../common/eqemu_logsys.h"
#include "../common/misc.h"
#include "../common/path_manager.h"
#include "../common/file.h"
void CheckTitaniumOpcodeFile(const std::string &path) {
if (File::Exists(path)) {
return;
}
auto f = fopen(path.c_str(), "w");
if (f) {
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
fprintf(f, "OP_SessionReady=0x0001\n");
fprintf(f, "OP_Login=0x0002\n");
fprintf(f, "OP_ServerListRequest=0x0004\n");
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
fprintf(f, "OP_PlayEverquestResponse=0x0021\n");
fprintf(f, "OP_ChatMessage=0x0016\n");
fprintf(f, "OP_LoginAccepted=0x0017\n");
fprintf(f, "OP_ServerListResponse=0x0018\n");
fprintf(f, "OP_Poll=0x0029\n");
fprintf(f, "OP_EnterChat=0x000f\n");
fprintf(f, "OP_PollResponse=0x0011\n");
fclose(f);
}
}
void CheckSoDOpcodeFile(const std::string& path) {
if (File::Exists(path)) {
return;
}
auto f = fopen(path.c_str(), "w");
if (f) {
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
fprintf(f, "OP_SessionReady=0x0001\n");
fprintf(f, "OP_Login=0x0002\n");
fprintf(f, "OP_ServerListRequest=0x0004\n");
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
fprintf(f, "OP_ChatMessage=0x0017\n");
fprintf(f, "OP_LoginAccepted=0x0018\n");
fprintf(f, "OP_ServerListResponse=0x0019\n");
fprintf(f, "OP_Poll=0x0029\n");
fprintf(f, "OP_LoginExpansionPacketData=0x0031\n");
fprintf(f, "OP_EnterChat=0x000f\n");
fprintf(f, "OP_PollResponse=0x0011\n");
fclose(f);
}
}
void CheckLarionOpcodeFile(const std::string& path) {
if (File::Exists(path)) {
return;
}
auto f = fopen(path.c_str(), "w");
if (f) {
fprintf(f, "#EQEmu Public Login Server OPCodes\n");
fprintf(f, "OP_SessionReady=0x0001\n");
fprintf(f, "OP_Login=0x0002\n");
fprintf(f, "OP_ServerListRequest=0x0004\n");
fprintf(f, "OP_PlayEverquestRequest=0x000d\n");
fprintf(f, "OP_PlayEverquestResponse=0x0022\n");
fprintf(f, "OP_ChatMessage=0x0017\n");
fprintf(f, "OP_LoginAccepted=0x0018\n");
fprintf(f, "OP_ServerListResponse=0x0019\n");
fprintf(f, "OP_Poll=0x0029\n");
fprintf(f, "OP_EnterChat=0x000f\n");
fprintf(f, "OP_PollResponse=0x0011\n");
fprintf(f, "OP_SystemFingerprint=0x0016\n");
fprintf(f, "OP_ExpansionList=0x0030\n");
fclose(f);
}
}
ClientManager::ClientManager()
{
@@ -19,14 +92,12 @@ ClientManager::ClientManager()
std::string opcodes_path = fmt::format(
"{}/{}",
path.GetServerPath(),
server.config.GetVariableString(
"client_configuration",
"titanium_opcodes",
"login_opcodes.conf"
)
path.GetOpcodePath(),
"login_opcodes.conf"
);
CheckTitaniumOpcodeFile(opcodes_path);
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
@@ -58,14 +129,12 @@ ClientManager::ClientManager()
opcodes_path = fmt::format(
"{}/{}",
path.GetServerPath(),
server.config.GetVariableString(
"client_configuration",
"sod_opcodes",
"login_opcodes.conf"
)
path.GetOpcodePath(),
"login_opcodes_sod.conf"
);
CheckSoDOpcodeFile(opcodes_path);
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
@@ -98,14 +167,12 @@ ClientManager::ClientManager()
opcodes_path = fmt::format(
"{}/{}",
path.GetServerPath(),
server.config.GetVariableString(
"client_configuration",
"larion_opcodes",
"login_opcodes.conf"
)
path.GetOpcodePath(),
"login_opcodes_larion.conf"
);
CheckLarionOpcodeFile(opcodes_path);
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
+15 -70
View File
@@ -51,12 +51,6 @@ WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> wo
ServerOP_LSAccountUpdate,
std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)
);
m_keepalive = std::make_unique<EQ::Timer>(
1000,
true,
std::bind(&WorldServer::OnKeepAlive, this, std::placeholders::_1)
);
}
WorldServer::~WorldServer() = default;
@@ -977,7 +971,8 @@ bool WorldServer::ValidateWorldServerAdminLogin(
return false;
}
void WorldServer::SerializeForClientServerListLegacy(class SerializeBuffer& out, bool use_local_ip) const {
void WorldServer::SerializeForClientServerList(SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const
{
// see LoginClientServerData_Struct
if (use_local_ip) {
out.WriteString(GetLocalIP());
@@ -986,6 +981,10 @@ void WorldServer::SerializeForClientServerListLegacy(class SerializeBuffer& out,
out.WriteString(GetRemoteIP());
}
if (version == cv_larion) {
out.WriteUInt32(9000);
}
switch (GetServerListID()) {
case LS::ServerType::Legends:
out.WriteInt32(LS::ServerTypeFlags::Legends);
@@ -997,8 +996,15 @@ void WorldServer::SerializeForClientServerListLegacy(class SerializeBuffer& out,
out.WriteInt32(LS::ServerTypeFlags::Standard);
break;
}
out.WriteUInt32(GetServerId());
if (version == cv_larion) {
auto server_id = GetServerId();
//if this is 0, the client will not show the server in the list
out.WriteUInt32(1);
out.WriteUInt32(server_id);
}
else {
out.WriteUInt32(GetServerId());
}
out.WriteString(GetServerLongName());
out.WriteString("us"); // country code
@@ -1020,61 +1026,6 @@ void WorldServer::SerializeForClientServerListLegacy(class SerializeBuffer& out,
out.WriteUInt32(GetPlayersOnline());
}
void WorldServer::SerializeForClientServerListLarion(class SerializeBuffer& out, bool use_local_ip) const {
if (use_local_ip) {
out.WriteString(GetLocalIP());
}
else {
out.WriteString(GetRemoteIP());
}
out.WriteUInt32(9000);
out.WriteUInt32(0);
uint32_t flags = 32; //all servers i saw had this set
switch (GetServerListID()) {
case LS::ServerType::Legends:
flags += LS::ServerTypeFlags::Legends;
break;
case LS::ServerType::Preferred:
flags += LS::ServerTypeFlags::Preferred;
break;
default:
flags += LS::ServerTypeFlags::Standard;
break;
}
out.WriteUInt32(flags);
out.WriteUInt32(GetServerId());
out.WriteString(GetServerLongName());
out.WriteString("EN");
out.WriteString("US");
if (GetStatus() < 0) {
if (GetZonesBooted() == 0) {
out.WriteInt32(LS::ServerStatusFlags::Down);
}
else {
out.WriteInt32(LS::ServerStatusFlags::Locked);
}
}
else {
out.WriteInt32(LS::ServerStatusFlags::Up);
}
out.WriteUInt32(GetPlayersOnline());
}
void WorldServer::SerializeForClientServerList(SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const
{
if (version == cv_larion) {
SerializeForClientServerListLarion(out, use_local_ip);
}
else {
SerializeForClientServerListLegacy(out, use_local_ip);
}
}
/**
* @param in_server_list_id
* @return
@@ -1350,12 +1301,6 @@ const std::string &WorldServer::GetVersion() const
return m_version;
}
void WorldServer::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
m_connection->SendPacket(&pack);
}
void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
{
std::string server_long_name = name;
+1 -11
View File
@@ -149,10 +149,7 @@ public:
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
private:
void SerializeForClientServerListLegacy(class SerializeBuffer& out, bool use_local_ip) const;
void SerializeForClientServerListLarion(class SerializeBuffer& out, bool use_local_ip) const;
public:
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const;
private:
@@ -190,13 +187,6 @@ private:
bool m_is_server_logged_in;
bool m_is_server_trusted;
/**
* Keepalive
* @param t
*/
void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Timer> m_keepalive;
static void FormatWorldServerName(char *name, int8 server_list_type);
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.56.3",
"version": "22.62.2",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+7 -5
View File
@@ -33,12 +33,14 @@
#include "../common/zone_store.h"
#include "../common/path_manager.h"
#include "../common/events/player_event_logs.h"
#include "../common/evolving_items.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EQEmuLogSys LogSys;
WorldContentService content_service;
ZoneStore zone_store;
PathManager path;
PlayerEventLogs player_event_logs;
EvolvingItemsManager evolving_items_manager;
#ifdef _WINDOWS
#include <direct.h>
-730
View File
@@ -1,730 +0,0 @@
# ShowEQ Import Notes:
# ZERO THE FILE first
# perl -pi -e 's/0x[0-9a-fA-F]{4}/0x0000/g' opcodes.conf
# Unknown Mapping:
# OP_Action2 -> OP_Damage
# OP_EnvDamage -> OP_Damage ---> might have been a one time mistake
# Name Differences:
# OP_CancelInvite -> OP_GroupCancelInvite
# OP_GMFind -> OP_FindPersonRequest
# OP_CommonMessage -> OP_ChannelMessage
OP_Unknown=0x0000
OP_ExploreUnknown=0x0000 # used for unknown explorer
# world packets
# Required to reach Char Select:
OP_SendLoginInfo=0x2fca
OP_ApproveWorld=0x0000
OP_LogServer=0x6d4d
OP_SendCharInfo=0x832
OP_ExpansionInfo=0x066d
OP_GuildsList=0x0000
OP_EnterWorld=0x6691
OP_PostEnterWorld=0x2062
OP_World_Client_CRC1=0x74c8
OP_World_Client_CRC2=0x3984
OP_World_Client_CRC3=0x6516
OP_SendSpellChecksum=0x0000
OP_SendSkillCapsChecksum=0x0000
# Character Select Related:
OP_SendMaxCharacters=0x13af
OP_SendMembership=0x2aca
OP_SendMembershipDetails=0x2608
OP_CharacterCreateRequest=0x0000
OP_CharacterCreate=0x0000
OP_DeleteCharacter=0x0000
OP_RandomNameGenerator=0x0000
OP_ApproveName=0x0000
OP_MOTD=0x0000
OP_SetChatServer=0x2726
OP_SetChatServer2=0x0000
OP_ZoneServerInfo=0x2273
OP_WorldComplete=0x195c
OP_WorldUnknown001=0x2049
OP_FloatListThing=0x0000
# Reasons for Disconnect:
OP_ZoneUnavail=0x0000
OP_WorldClientReady=0x0000
OP_CharacterStillInZone=0x0000
OP_WorldChecksumFailure=0x0000
OP_WorldLoginFailed=0x0000
OP_WorldLogout=0x0000
OP_WorldLevelTooHigh=0x0000
OP_CharInacessable=0x0000
OP_UserCompInfo=0x0000
OP_SendExeChecksum=0x0000
OP_SendBaseDataChecksum=0x0000
# Zone in opcodes
OP_AckPacket=0x77c9
OP_ZoneEntry=0x0000
OP_ReqNewZone=0x0000
OP_NewZone=0x0000
OP_ZoneSpawns=0x0000
OP_PlayerProfile=0x0000
OP_TimeOfDay=0x0000
OP_LevelUpdate=0x0000
OP_Stamina=0x0000
OP_RequestClientZoneChange=0x0000
OP_ZoneChange=0x0000
OP_LockoutTimerInfo=0x0000
OP_ZoneServerReady=0x0000
OP_ZoneInUnknown=0x0000
OP_LogoutReply=0x0000
OP_PreLogoutReply=0x0000
# Required to fully log in
OP_SpawnAppearance=0x0000
OP_ChangeSize=0x0000
OP_TributeUpdate=0x0000
OP_TributeTimer=0x0000
OP_SendTributes=0x0000
OP_RequestGuildTributes=0x0000
OP_TributeInfo=0x0000
OP_Weather=0x0000
OP_ReqClientSpawn=0x0000
OP_SpawnDoor=0x0000
OP_GroundSpawn=0x0000
OP_SendZonepoints=0x0000
OP_BlockedBuffs=0x0000
OP_RemoveBlockedBuffs=0x0000
OP_ClearBlockedBuffs=0x0000
OP_WorldObjectsSent=0x0000
OP_SendExpZonein=0x0000
OP_SendAATable=0x0000
OP_ClearAA=0x0000
OP_ClearLeadershipAbilities=0x0000
OP_RespondAA=0x0000
OP_UpdateAA=0x0000
OP_SendAAStats=0x0000
OP_AAExpUpdate=0x0000
OP_ExpUpdate=0x0000
OP_HPUpdate=0x0000
OP_ManaChange=0x0000
OP_TGB=0x0000
OP_SpecialMesg=0x0000
OP_GuildMemberList=0x0000
OP_GuildMOTD=0x0000
OP_CharInventory=0x0000
OP_WearChange=0x0000
OP_ClientUpdate=0x0000
OP_ClientReady=0x0000
OP_SetServerFilter=0x0000
# Guild Opcodes
OP_GetGuildMOTD=0x0000
OP_GetGuildMOTDReply=0x0000
OP_GuildMemberUpdate=0x0000
OP_GuildInvite=0x0000
OP_GuildRemove=0x0000
OP_GuildPeace=0x0000
OP_SetGuildMOTD=0x0000
OP_GuildWar=0x0000
OP_GuildLeader=0x0000
OP_GuildDelete=0x0000
OP_GuildInviteAccept=0x0000
OP_GuildDemote=0x0000
OP_GuildPromote=0x0000
OP_GuildPublicNote=0x0000
OP_GuildManageBanker=0x0000
OP_GuildBank=0x0000
OP_GuildBankItemList=0x0000
OP_SetGuildRank=0x0000
OP_GuildUpdate=0x0000
OP_GuildStatus=0x0000
OP_GuildCreate=0x0000
OP_GuildOpenGuildWindow=0x0000
OP_GuildMemberLevel=0x0000
OP_GuildMemberRankAltBanker=0x0000
OP_GuildMemberPublicNote=0x0000
OP_GuildMemberAdd=0x0000
OP_GuildMemberRename=0x0000
OP_GuildMemberDelete=0x0000
OP_GuildMemberDetails=0x0000
OP_GuildRenameGuild=0x0000
OP_LFGuild=0x0000
OP_GuildDeleteGuild=0x0000
# GM/Guide Opcodes
OP_GMServers=0x0000
OP_GMBecomeNPC=0x0000
OP_GMZoneRequest=0x0000
OP_GMZoneRequest2=0x0000
OP_GMGoto=0x0000
OP_GMSearchCorpse=0x0000
OP_GMHideMe=0x0000
OP_GMDelCorpse=0x0000
OP_GMApproval=0x0000
OP_GMToggle=0x0000
OP_GMSummon=0x0000
OP_GMEmoteZone=0x0000
OP_GMEmoteWorld=0x0000
OP_GMFind=0x0000
OP_GMKick=0x0000
OP_GMKill=0x0000
OP_GMNameChange=0x0000
OP_GMLastName=0x0000
# Misc Opcodes
OP_QueryUCSServerStatus=0x0000
OP_InspectRequest=0x0000
OP_InspectAnswer=0x0000
OP_InspectMessageUpdate=0x0000
OP_BeginCast=0x0000
OP_ColoredText=0x0000
OP_ConsentResponse=0x0000
OP_MemorizeSpell=0x0000
OP_LinkedReuse=0x0000
OP_SwapSpell=0x0000
OP_CastSpell=0x0000
OP_Consider=0x0000
OP_FormattedMessage=0x0000
OP_SimpleMessage=0x0000
OP_Buff=0x0000
OP_Illusion=0x0000
OP_MoneyOnCorpse=0x0000
OP_RandomReply=0x0000
OP_DenyResponse=0x0000
OP_SkillUpdate=0x04c
OP_GMTrainSkillConfirm=0x0000
OP_RandomReq=0x0000
OP_Death=0x0000
OP_GMTraining=0x0000
OP_GMEndTraining=0x0000
OP_GMTrainSkill=0x0000
OP_Animation=0x0000
OP_Begging=0x0000
OP_Consent=0x0000
OP_ConsentDeny=0x0000
OP_AutoFire=0x0000
OP_PetCommands=0x0000
OP_PetCommandState=0x0000
OP_PetHoTT=0x0000
OP_DeleteSpell=0x0000
OP_Surname=0x0000
OP_ClearSurname=0x0000
OP_FaceChange=0x0000
OP_SetFace=0x0000
OP_SenseHeading=0x0000
OP_Action=0x0000
OP_ConsiderCorpse=0x0000
OP_HideCorpse=0x0000
OP_CorpseDrag=0x0000
OP_CorpseDrop=0x0000
OP_Bug=0x0000
OP_Feedback=0x0000
OP_Report=0x0000
OP_Damage=0x0000
OP_ChannelMessage=0x0000
OP_Assist=0x0000
OP_AssistGroup=0x0000
OP_MoveCoin=0x0000
OP_ZonePlayerToBind=0x0000
OP_KeyRing=0x0000
OP_WhoAllRequest=0x0000
OP_WhoAllResponse=0x0000
OP_FriendsWho=0x0000
OP_ConfirmDelete=0x0000
OP_Logout=0x0000
OP_Rewind=0x0000
OP_TargetCommand=0x0000
OP_Hide=0x0000
OP_Jump=0x0000
OP_Camp=0x0000
OP_Emote=0x0000
OP_SetRunMode=0x0000
OP_BankerChange=0x0000
OP_TargetMouse=0x0000
OP_MobHealth=0x0000
OP_InitialMobHealth=0x0000 # Unused?
OP_TargetHoTT=0x0000
OP_TargetBuffs=0x0000
OP_XTargetResponse=0x0000
OP_XTargetRequest=0x0000
OP_XTargetAutoAddHaters=0x0000
OP_XTargetOpen=0x0000
OP_XTargetOpenResponse=0x0000
OP_BuffCreate=0x0000
OP_BuffRemoveRequest=0x0000
OP_DeleteSpawn=0x0000
OP_AutoAttack=0x0000
OP_AutoAttack2=0x0000
OP_Consume=0x0000
OP_MoveItem=0x0000
OP_MoveMultipleItems=0x0000
OP_DeleteItem=0x0000
OP_DeleteCharge=0x0000
OP_ItemPacket=0x0000
OP_ItemLinkResponse=0x0000
OP_ItemLinkClick=0x0000
OP_ItemPreview=0x0000
OP_NewSpawn=0x0000
OP_Track=0x0000
OP_TrackTarget=0x0000
OP_TrackUnknown=0x0000
OP_ClickDoor=0x0000
OP_MoveDoor=0x0000
OP_RemoveAllDoors=0x0000
OP_EnvDamage=0x0000
OP_BoardBoat=0x0000
OP_LeaveBoat=0x0000
OP_ControlBoat=0x0000
OP_Forage=0x0000
OP_SafeFallSuccess=0x0000
OP_RezzComplete=0x0000
OP_RezzRequest=0x0000
OP_RezzAnswer=0x0000
OP_Shielding=0x0000
OP_RequestDuel=0x0000
OP_MobRename=0x0000
OP_AugmentItem=0x0000
OP_WeaponEquip1=0x0000
OP_PlayerStateAdd=0x0000
OP_PlayerStateRemove=0x0000
OP_ApplyPoison=0x0000
OP_Save=0x0000
OP_TestBuff=0x0000
OP_CustomTitles=0x0000
OP_Split=0x0000
OP_YellForHelp=0x0000
OP_LoadSpellSet=0x0000
OP_Bandolier=0x0000
OP_PotionBelt=0x0000
OP_DuelDecline=0x0000
OP_DuelAccept=0x0000
OP_SaveOnZoneReq=0x0000
OP_ReadBook=0x0000
OP_Dye=0x0000
OP_InterruptCast=0x0000
OP_AAAction=0x0000
OP_LeadershipExpToggle=0x0000
OP_LeadershipExpUpdate=0x0000
OP_PurchaseLeadershipAA=0x0000
OP_UpdateLeadershipAA=0x0000
OP_MarkNPC=0x0000
OP_ClearNPCMarks=0x0000
OP_DelegateAbility=0x0000
OP_SetGroupTarget=0x0000
OP_Charm=0x0000
OP_Stun=0x0000
OP_SendFindableNPCs=0x0000
OP_FindPersonRequest=0x0000
OP_FindPersonReply=0x0000
OP_Sound=0x0000
OP_CashReward=0x0000
OP_PetBuffWindow=0x0000
OP_LevelAppearance=0x0000
OP_Translocate=0x0000
OP_Sacrifice=0x0000
OP_PopupResponse=0x0000
OP_OnLevelMessage=0x0000
OP_AugmentInfo=0x0000
OP_Petition=0x0000
OP_SomeItemPacketMaybe=0x0000
OP_PVPStats=0x0000
OP_PVPLeaderBoardRequest=0x0000
OP_PVPLeaderBoardReply=0x0000
OP_PVPLeaderBoardDetailsRequest=0x0000
OP_PVPLeaderBoardDetailsReply=0x0000
OP_RestState=0x0000
OP_RespawnWindow=0x0000
OP_LDoNButton=0x0000
OP_SetStartCity=0x0000
OP_VoiceMacroIn=0x0000
OP_VoiceMacroOut=0x0000
OP_ItemViewUnknown=0x0000
OP_VetRewardsAvaliable=0x0000
OP_VetClaimRequest=0x0000
OP_VetClaimReply=0x0000
OP_DisciplineUpdate=0x0000
OP_DisciplineTimer=0x0000
OP_BecomeCorpse=0x0000 # Unused?
OP_Action2=0x0000 # Unused?
OP_MobUpdate=0x0000
OP_NPCMoveUpdate=0x0000
OP_CameraEffect=0x0000
OP_SpellEffect=0x0000
OP_AddNimbusEffect=0x0000
OP_RemoveNimbusEffect=0x0000
OP_AltCurrency=0x0000
OP_AltCurrencyMerchantRequest=0x0000
OP_AltCurrencyMerchantReply=0x0000
OP_AltCurrencyPurchase=0x0000
OP_AltCurrencySell=0x0000
OP_AltCurrencySellSelection=0x0000
OP_AltCurrencyReclaim=0x0000
OP_CrystalCountUpdate=0x0000
OP_CrystalCreate=0x0000
OP_CrystalReclaim=0x0000
OP_Untargetable=0x0000
OP_IncreaseStats=0x0000
OP_Weblink=0x0000
OP_OpenContainer=0x0000
OP_Marquee=0x0000
OP_ItemRecastDelay=0x0000
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
OP_ResetAA=0x0000
OP_Fling=0x0000
OP_CancelSneakHide=0x0000
OP_AggroMeterLockTarget=0x0000
OP_AggroMeterTargetInfo=0x0000
OP_AggroMeterUpdate=0x0000
OP_UnderWorld=0x0000 # clients sends up when they detect an underworld issue, might be useful for cheat detection
OP_KickPlayers=0x0000
OP_BookButton=0x0000
# Expeditions
OP_DzQuit=0x0000
OP_DzListTimers=0x0000
OP_DzAddPlayer=0x0000
OP_DzRemovePlayer=0x0000
OP_DzSwapPlayer=0x0000
OP_DzMakeLeader=0x0000
OP_DzPlayerList=0x0000
OP_DzExpeditionInvite=0x0000
OP_DzExpeditionInviteResponse=0x0000
OP_DzExpeditionInfo=0x0000
OP_DzExpeditionLockoutTimers=0x0000
OP_DzMemberList=0x0000
OP_DzMemberListName=0x0000
OP_DzMemberListStatus=0x0000
OP_DzSetLeaderName=0x0000
OP_DzExpeditionEndsWarning=0x0000
OP_DzCompass=0x0000
OP_DzChooseZone=0x0000
OP_DzChooseZoneReply=0x0000
# New Opcodes
OP_SpawnPositionUpdate=0x0000 # Actually OP_MobUpdate ?
OP_ManaUpdate=0x0000
OP_EnduranceUpdate=0x0000
OP_MobManaUpdate=0x0000
OP_MobEnduranceUpdate=0x0000
# Mercenary Opcodes
OP_MercenaryDataUpdateRequest=0x0000
OP_MercenaryDataUpdate=0x0000
OP_MercenaryDataRequest=0x0000
OP_MercenaryDataResponse=0x0000
OP_MercenaryHire=0x0000
OP_MercenaryDismiss=0x0000
OP_MercenaryTimerRequest=0x0000
OP_MercenaryTimer=0x0000
OP_MercenaryUnknown1=0x0000
OP_MercenaryCommand=0x0000
OP_MercenarySuspendRequest=0x0000
OP_MercenarySuspendResponse=0x0000
OP_MercenaryUnsuspendResponse=0x0000
# Looting
OP_LootRequest=0x0000
OP_EndLootRequest=0x0000
OP_LootItem=0x0000
OP_LootComplete=0x0000
# bazaar trader stuff:
OP_BazaarSearch=0x0000
OP_TraderDelItem=0x0000
OP_BecomeTrader=0x0000
OP_TraderShop=0x0000
OP_TraderBulkSend=0x0000
OP_Trader=0x0000
OP_Barter=0x0000
OP_BuyerItems=0x0000
OP_TraderBuy=0x0000
OP_ShopItem=0x0000
OP_BazaarInspect=0x0000
OP_Bazaar=0x0000
OP_TraderItemUpdate=0x0000
# pc/npc trading
OP_TradeRequest=0x0000
OP_TradeAcceptClick=0x0000
OP_TradeRequestAck=0x0000
OP_TradeCoins=0x0000
OP_FinishTrade=0x0000
OP_CancelTrade=0x0000
OP_TradeMoneyUpdate=0x0000
OP_MoneyUpdate=0x0000
OP_TradeBusy=0x0000
# Sent after canceling trade or after closing tradeskill object
OP_FinishWindow=0x0000
OP_FinishWindow2=0x0000
# Sent on Live for what seems to be item existance verification
# Ex. Before Right Click Effect happens from items
OP_ItemVerifyRequest=0x0000
OP_ItemVerifyReply=0x0000
OP_ItemAdvancedLoreText=0x0000
# merchant stuff
OP_ShopPlayerSell=0x0000
OP_ShopRequest=0x0000
OP_ShopEnd=0x0000
OP_ShopEndConfirm=0x0000
OP_ShopPlayerBuy=0x0000
OP_ShopDelItem=0x0000
OP_ShopSendParcel=0x0000
OP_ShopDeleteParcel=0x0000
OP_ShopRetrieveParcel=0x0000
OP_ShopParcelIcon=0x0000
# tradeskill stuff:
OP_ClickObject=0x0000
OP_ClickObjectAction=0x0000
OP_ClearObject=0x0000
OP_RecipeDetails=0x0000
OP_RecipesFavorite=0x0000
OP_RecipesSearch=0x0000
OP_RecipeReply=0x0000
OP_RecipeAutoCombine=0x0000
OP_TradeSkillCombine=0x0000
# Tribute Packets:
OP_OpenTributeMaster=0x0000
OP_SelectTribute=0x0000
OP_TributeItem=0x0000
OP_TributeMoney=0x0000
OP_TributeToggle=0x0000
OP_TributePointUpdate=0x0000
OP_TributeNPC=0x0000
OP_GuildTributeInfo=0x0000
OP_OpenTributeReply=0x0000
OP_GuildTributeStatus=0x0000
OP_GuildSaveActiveTributes=0x0000
OP_GuildSendActiveTributes=0x0000
OP_GuildTributeToggleReq=0x0000
OP_GuildTributeToggleReply=0x0000
OP_GuildTributeFavorAndTimer=0x0000
OP_GuildTributeDonateItem=0x0000
OP_GuildTributeDonatePlat=0x0000
OP_GuildSelectTribute=0x0000
OP_GuildModifyBenefits=0x0000
OP_GuildOptInOut=0x0000
OP_SendGuildTributes=0x0000
OP_OpenGuildTributeMaster=0x0000
# Adventure packets:
OP_LeaveAdventure=0x0000
OP_AdventureFinish=0x0000
OP_AdventureInfoRequest=0x0000
OP_AdventureInfo=0x0000
OP_AdventureRequest=0x0000
OP_AdventureDetails=0x0000
OP_AdventureData=0x0000
OP_AdventureUpdate=0x0000
OP_AdventureMerchantRequest=0x0000
OP_AdventureMerchantResponse=0x0000
OP_AdventureMerchantPurchase=0x0000
OP_AdventureMerchantSell=0x0000
OP_AdventurePointsUpdate=0x0000
OP_AdventureStatsRequest=0x0000
OP_AdventureStatsReply=0x0000
OP_AdventureLeaderboardRequest=0x0000
OP_AdventureLeaderboardReply=0x0000
# Group Opcodes
OP_GroupDisband=0x0000
OP_GroupInvite=0x0000
OP_GroupFollow=0x0000
OP_GroupUpdate=0x0000
OP_GroupUpdateB=0x0000
OP_GroupCancelInvite=0x0000
OP_GroupAcknowledge=0x0000
OP_GroupDelete=0x0000
OP_CancelInvite=0x0000
OP_GroupFollow2=0x0000
OP_GroupInvite2=0x0000
OP_GroupDisbandYou=0x0000
OP_GroupDisbandOther=0x0000
OP_GroupLeaderChange=0x0000
OP_GroupRoles=0x0000
OP_GroupMakeLeader=0x0000
OP_DoGroupLeadershipAbility=0x0000
OP_GroupLeadershipAAUpdate=0x0000
OP_GroupMentor=0x0000
OP_InspectBuffs=0x0000
# LFG/LFP Opcodes
OP_LFGCommand=0x0000
OP_LFGGetMatchesRequest=0x0000
OP_LFGGetMatchesResponse=0x0000
OP_LFPGetMatchesRequest=0x0000
OP_LFPGetMatchesResponse=0x0000
OP_LFPCommand=0x0000
OP_LFGAppearance=0x0000
OP_LFGResponse=0x0000
# Raid Opcodes
OP_RaidInvite=0x0000
OP_RaidUpdate=0x0000
OP_RaidJoin=0x0000
OP_RaidDelegateAbility=0x0000
OP_MarkRaidNPC=0x0000
OP_RaidClearNPCMarks=0x0000
# Button-push commands
OP_Taunt=0x0000
OP_CombatAbility=0x0000
OP_SenseTraps=0x0000
OP_PickPocket=0x0000
OP_DisarmTraps=0x0000
OP_Disarm=0x0000
OP_Sneak=0x0000
OP_Fishing=0x0000
OP_InstillDoubt=0x0000
OP_FeignDeath=0x0000
OP_Mend=0x0000
OP_Bind_Wound=0x0000
OP_LDoNOpen=0x0000
#OP_LDoNDisarmTraps= #Same as OP_DisarmTraps in RoF
OP_LDoNPickLock=0x0000
OP_LDoNInspect=0x0000
# Task packets
OP_TaskDescription=0x0000
OP_TaskActivity=0x0000
OP_CompletedTasks=0x0000
OP_TaskActivityComplete=0x0000
OP_AcceptNewTask=0x0000
OP_CancelTask=0x0000
OP_AvaliableTask=0x0000
OP_TaskHistoryRequest=0x0000
OP_TaskHistoryReply=0x0000
OP_DeclineAllTasks=0x0000
OP_TaskRequestTimer=0x0000
OP_TaskSelectWindow=0x0000
# Shared Tasks
OP_SharedTaskMemberList=0x0000 #
OP_SharedTaskRemovePlayer=0x0000 # /taskremoveplayer
OP_SharedTaskAddPlayer=0x0000 # /taskaddplayer
OP_SharedTaskMakeLeader=0x0000 # /taskmakeleader
OP_SharedTaskInvite=0x0000 # Dialog window
OP_SharedTaskInviteResponse=0x0000 # Dialog window response
OP_SharedTaskAcceptNew=0x0000 #
OP_SharedTaskMemberChange=0x0000 #
OP_TaskTimers=0x0000 # /tasktimers
OP_SharedTaskQuit=0x0000 # /taskquit
OP_SharedTaskSelectWindow=0x0000
OP_SharedTaskPlayerList=0x0000 # /taskplayerlist
# Title opcodes
OP_NewTitlesAvailable=0x0000
OP_RequestTitles=0x0000
OP_SendTitleList=0x0000
OP_SetTitle=0x0000
OP_SetTitleReply=0x0000
# mail opcodes
OP_Command=0x0000
OP_MailboxHeader=0x0000
OP_MailHeader=0x0000
OP_MailBody=0x0000
OP_NewMail=0x0000
OP_SentConfirm=0x0000
########### Below this point should not be needed ###########
# This section are all unknown in Titanium
OP_ForceFindPerson=0x0000
OP_LocInfo=0x0000
OP_ReloadUI=0x0000
OP_ItemName=0x0000
OP_ItemLinkText=0x0000
OP_MultiLineMsg=0x0000
OP_MendHPUpdate=0x0000
OP_TargetReject=0x0000
OP_SafePoint=0x0000
OP_ApproveZone=0x0000
OP_ZoneComplete=0x0000
OP_ClientError=0x0000
OP_DumpName=0x0000
OP_Heartbeat=0x0000
OP_CrashDump=0x0000
OP_LoginComplete=0x0000
# discovered opcodes not yet used:
OP_PickLockSuccess=0x0000
OP_PlayMP3=0x0000
OP_ReclaimCrystals=0x0000
OP_DynamicWall=0x0000
OP_OpenDiscordMerchant=0x0000
OP_DiscordMerchantInventory=0x0000
OP_GiveMoney=0x0000
OP_RequestKnowledgeBase=0x0000
OP_KnowledgeBase=0x0000
OP_SlashAdventure=0x0000 # /adventure
OP_BecomePVPPrompt=0x0000
OP_MoveLogRequest=0x0000 # gone I think
OP_MoveLogDisregard=0x0000 # gone I think
# named unknowns, to make looking for real unknown easier
OP_AnnoyingZoneUnknown=0x0000
OP_Some6ByteHPUpdate=0x0000 #seems to happen when you target group members
OP_QueryResponseThing=0x0000
# realityincarnate: these are just here to stop annoying several thousand byte packet dumps
#OP_LoginUnknown1=0x0000 # OP_SendSpellChecksum
#OP_LoginUnknown2=0x0000 # OP_SendSkillCapsChecksum
# Petition Opcodes
OP_PetitionSearch=0x0000 #search term for petition
OP_PetitionSearchResults=0x0000 #(list of?) matches from search
OP_PetitionSearchText=0x0000 #text results of search
OP_PetitionUpdate=0x0000
OP_PetitionCheckout=0x0000
OP_PetitionCheckIn=0x0000
OP_PetitionQue=0x0000
OP_PetitionUnCheckout=0x0000
OP_PetitionDelete=0x0000
OP_DeletePetition=0x0000
OP_PetitionResolve=0x0000
OP_PDeletePetition=0x0000
OP_PetitionBug=0x0000
OP_PetitionRefresh=0x0000
OP_PetitionCheckout2=0x0000
OP_PetitionViewPetition=0x0000
# Login opcodes
OP_SessionReady=0x0000
OP_Login=0x0000
OP_ServerListRequest=0x0000
OP_PlayEverquestRequest=0x0000
OP_PlayEverquestResponse=0x0000
OP_ChatMessage=0x0000
OP_LoginAccepted=0x0000
OP_ServerListResponse=0x0000
OP_Poll=0x0000
OP_EnterChat=0x0000
OP_PollResponse=0x0000
# raw opcodes
OP_RAWSessionRequest=0x0000
OP_RAWSessionResponse=0x0000
OP_RAWCombined=0x0000
OP_RAWSessionDisconnect=0x0000
OP_RAWKeepAlive=0x0000
OP_RAWSessionStatRequest=0x0000
OP_RAWSessionStatResponse=0x0000
OP_RAWPacket=0x0000
OP_RAWFragment=0x0000
OP_RAWOutOfOrderAck=0x0000
OP_RAWAck=0x0000
OP_RAWAppCombined=0x0000
OP_RAWOutOfSession=0x0000
# we need to document the differences between these packets to make identifying them easier
OP_Some3ByteHPUpdate=0x0000 # initial HP update for mobs
OP_InitialHPUpdate=0x0000
#aura related
OP_UpdateAura=0x0000
OP_RemoveTrap=0x0000
+17 -1
View File
@@ -261,6 +261,7 @@ OP_ItemPacket=0x368e
OP_ItemLinkResponse=0x70c0
OP_ItemLinkClick=0x4cef
OP_ItemPreview=0x6b5c
OP_ItemPreviewRequest=0x7f80
OP_NewSpawn=0x6097
OP_Track=0x17e5
OP_TrackTarget=0x695e
@@ -566,7 +567,7 @@ OP_RaidUpdate=0x3973
OP_RaidJoin=0x0000
OP_RaidDelegateAbility=0x2b33
OP_MarkRaidNPC=0x5a58
OP_RaidClearNPCMarks=0x20d3
OP_RaidClearNPCMarks=0x20d3
# Button-push commands
OP_Taunt=0x2703
@@ -728,3 +729,18 @@ OP_InitialHPUpdate=0x0000
#aura related
OP_UpdateAura=0x1456
OP_RemoveTrap=0x71da
OP_PickZoneWindow=0x72d8
OP_PickZone=0xaaba
#evolve item related
OP_EvolveItem=0x7cfb
# This is bugged in ROF2
# OP_InvokeChangePetNameImmediate is supposed to write DisablePetNameChangeReminder=0 to reset the 'nag reminder'
# It actually sets DisableNameChangeReminder=0 (player name change nag reminder). Additionally, clicking the
# 'Don't remind me later' button sets DisableNameChangeReminder=1
# This can be fixed with a client patch.
OP_InvokeChangePetNameImmediate=0x046d
OP_InvokeChangePetName=0x4506
OP_ChangePetName=0x5dab
+2 -2
View File
@@ -10,7 +10,7 @@ require (
require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
)
+4 -4
View File
@@ -10,12 +10,12 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

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