mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-13 02:38:45 +00:00
Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4befe32c61 | |||
| ef8e1cf6e6 | |||
| c718ddbbf9 | |||
| 8eb20efabb | |||
| 9a18b7772a | |||
| 33164dc47a | |||
| 4d05e4b53e | |||
| 24dbe6da0e | |||
| 0241a90505 | |||
| bd2798f2cc | |||
| a42d6e8ee1 | |||
| 745eeb6eae | |||
| 91bd9ccf26 | |||
| 45db09303f | |||
| d9132e84ab | |||
| 2cb4c55613 | |||
| f040bbdb03 | |||
| 852667016d | |||
| 62a84388c0 | |||
| 33ab28c1e0 | |||
| be0c6b5e05 | |||
| 6070e73b16 | |||
| ef5fdafdbe | |||
| 6d5424e7b0 | |||
| 0fdfda9c53 | |||
| 0da381c272 | |||
| b761f1cdf9 | |||
| ce98118cc8 | |||
| 13f57f3c5d | |||
| 7083a74b31 | |||
| d3ac751dd1 | |||
| 2db1b1b9b0 | |||
| c4a7fcc063 | |||
| 2c48ec39ef | |||
| 352f52e65d | |||
| 32a1d7c43e | |||
| af8f85cfd9 | |||
| 392998325b | |||
| 591fa0eb1d | |||
| 1e35d30c8f | |||
| 2d8b777120 | |||
| b95cd989c4 | |||
| fe9df46a24 | |||
| f9918d47d7 | |||
| e74d4b6e67 | |||
| 11636225b1 | |||
| 3d7cf4235c | |||
| 187ee10218 | |||
| 6bd758b3dd | |||
| 9938755517 | |||
| 630da0eee6 | |||
| 3158386aa3 | |||
| 12ada57ee8 | |||
| 7a841c11c5 | |||
| a49d1446b7 | |||
| 4e53f5464f | |||
| 233a0dda6a | |||
| 1ab0e78f00 | |||
| 9d5a9ee6df | |||
| d713ff69bf | |||
| b2d0fa6a2f | |||
| 8947058465 | |||
| 429d6fd87d | |||
| 0eedbea060 | |||
| 63331b678b | |||
| 62ac015fff | |||
| ebb657153a | |||
| 2c5c28b808 | |||
| 3a7afb48cb | |||
| b167f05006 | |||
| f6f9d275e8 | |||
| 004b0e1176 | |||
| 8ff0e5614c | |||
| 027d95bbb8 | |||
| b85344f779 | |||
| 018308bfca | |||
| 29066cf847 | |||
| 4977a7c2e0 | |||
| da9a95fd83 | |||
| 7888fb2655 | |||
| 45d39f44f2 | |||
| 2f46da5d99 | |||
| 200b7fa604 | |||
| c20439dbb4 | |||
| fa91559a85 | |||
| 9967384ab8 | |||
| d3da2e5501 | |||
| 33f5c4c6a7 | |||
| e4aa6a6957 | |||
| e4d812f4b4 | |||
| bcedfe7032 | |||
| c1df3fbcb0 | |||
| 011e1d05e7 | |||
| ce728c4d0d | |||
| 3f0f95976c | |||
| 77de9619b5 | |||
| 20d3ab2ac5 | |||
| 0ea47fadee | |||
| d29937cba6 | |||
| 799593c394 | |||
| 1ce51ca3b0 | |||
| 25ef3d2cdb | |||
| 95249889a6 | |||
| 428cccfa50 | |||
| b7c93e12de | |||
| c1651b7dca | |||
| 4093b505d3 | |||
| dbb0288a13 | |||
| 0a9a941b6b | |||
| 41dd8a5754 | |||
| d02d766563 | |||
| dfd2729b28 | |||
| 702024fe04 | |||
| acdd65b55c | |||
| 6db7c624e9 | |||
| b92eafd21b | |||
| d6d5d992cb | |||
| d524cb6a5a | |||
| e6469878ce | |||
| f485dfd8d3 | |||
| 823bacf08a | |||
| 9583099ace | |||
| cf3483b402 | |||
| b8ecb297ec | |||
| 311af7bbe9 | |||
| 7f7c80eab7 | |||
| 0c87af7d6b | |||
| 2e087cde5b | |||
| a7c1c85f71 | |||
| d1c7c00f19 | |||
| 999ccdcb19 | |||
| d3cd037fa7 | |||
| be42b73f5c | |||
| f76c798910 | |||
| dc1509e768 | |||
| 124b9c7abe | |||
| 534de0c414 | |||
| ae198ae043 | |||
| 520943ebf1 | |||
| 9ac306fe67 | |||
| 7a1d69d0d4 | |||
| c873fe5a22 | |||
| e06b0c4b0c | |||
| ed2130f649 | |||
| 448a33a60c | |||
| 8f86cb353e | |||
| 178129443f | |||
| a7c3b41afc | |||
| a5a568d548 | |||
| e3198edb86 | |||
| 8568cf7d49 | |||
| 1fb7a860a1 | |||
| 7eaee2649e | |||
| a17f467b98 | |||
| 3359839a9b | |||
| 7e51e629f9 | |||
| dc6c28a52d | |||
| 78aee0780a | |||
| bcd943a964 | |||
| 56608e84bd | |||
| 8d23e710ce | |||
| 4d11077b21 | |||
| 5c0bdfdc4c | |||
| 6130e10831 | |||
| c3e1c531d2 | |||
| b52719a535 | |||
| 1af252466f | |||
| 699d22fc28 | |||
| 5d1fe68906 | |||
| 52dcf35425 | |||
| a7550fbd9e | |||
| cc0171dfe1 | |||
| 913c5da70f | |||
| 40fecbfaf5 | |||
| b1646381b0 | |||
| bb1578796b | |||
| 0e5a38f072 | |||
| 39876ab858 | |||
| ff16a76481 | |||
| ffd68eb63d | |||
| 76c1da1aad | |||
| a91e03fa43 | |||
| 453106439f | |||
| 3da24fffa4 | |||
| 8d8ef6d480 | |||
| 1f9c4b3a22 | |||
| 7dfda95d86 | |||
| 40738b29e3 | |||
| 080865faa2 | |||
| e2b545991a | |||
| b7f8d0f179 | |||
| e3588781aa | |||
| e9b84f4d11 | |||
| 4f03970fd1 | |||
| 4979da6932 | |||
| 9987029791 | |||
| eece0a92e3 | |||
| 057f96796a | |||
| f475cecdb1 | |||
| 6296ed6d41 | |||
| ac0f729aa2 | |||
| 2937852cf9 | |||
| 2cf5bae571 | |||
| 2feb05be18 | |||
| 421767e1e5 | |||
| 6e9ff52dce | |||
| aa700f8960 | |||
| 2ef959c5ed | |||
| e49ab924cc | |||
| fc3c691588 | |||
| d465a3deba | |||
| 40c9c8044b | |||
| 70a96ea098 | |||
| d5cbec714e | |||
| 6903205484 | |||
| 4c81321847 | |||
| e5cea73e0c | |||
| 23308192b5 | |||
| 29fdf7e2ae | |||
| 098498dedd | |||
| b6fb8daae8 | |||
| 563f7d5564 | |||
| 1e5abc456b | |||
| 3b0fa015a7 | |||
| c73a1e8bea | |||
| 3bfdc0cf71 | |||
| a23ac4628f | |||
| 5ef4612249 | |||
| 17f66c5d60 | |||
| 51eb95ed31 | |||
| 080abaede1 | |||
| 97e332819d | |||
| 1e41c5517e | |||
| c7a88af11a | |||
| d8ddd0aab9 | |||
| 95cbadade5 | |||
| a85f4fb703 | |||
| e63f34638b | |||
| 7918fed81c | |||
| ac24c9bf5a | |||
| 7b914c731b | |||
| 7362c0ebb5 | |||
| ae213a4e4b | |||
| 187288f3aa | |||
| abc8c3d886 | |||
| 0b2493beb8 | |||
| 9cebba5911 | |||
| 4478328b2a | |||
| 55a7e1646d | |||
| b6b8491060 | |||
| 850053a136 | |||
| 1aa8758b0a | |||
| b1aa087b9f | |||
| 1e57a0372f | |||
| 9614ea59ec | |||
| 7a648cce16 | |||
| 8640776a21 |
+338
@@ -1,3 +1,341 @@
|
|||||||
|
## [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
|
||||||
|
|
||||||
|
* Fix issue with Client::SaveDisciplines() not specifying character ID ([#4481](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-23
|
||||||
|
|
||||||
|
## [22.56.2] 9/20/2024
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix Issue with Database::ReserveName ([#4477](https://github.com/EQEmu/Server/pull/4477)) @Kinglykrab 2024-09-20
|
||||||
|
|
||||||
|
### Quest API
|
||||||
|
|
||||||
|
* Add GrantAllAAPoints() Overload To Perl/Lua ([#4474](https://github.com/EQEmu/Server/pull/4474)) @Kinglykrab 2024-09-20
|
||||||
|
|
||||||
|
## [22.56.1] 9/20/2024
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix Untrained Disciplines in Client::SaveDisciplines() ([#4472](https://github.com/EQEmu/Server/pull/4472)) @Kinglykrab 2024-09-13
|
||||||
|
* Fix Infinite Loop in Adventure::Finished() ([#4473](https://github.com/EQEmu/Server/pull/4473)) @oddx2k 2024-09-13
|
||||||
|
|
||||||
|
## [22.56.0] 9/12/2024
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Add IsCloseToBanker method ([#4462](https://github.com/EQEmu/Server/pull/4462)) @Akkadius 2024-08-27
|
||||||
|
|
||||||
|
### Feature
|
||||||
|
|
||||||
|
* Add Rule to Limit Task Update Messages ([#4459](https://github.com/EQEmu/Server/pull/4459)) @Kinglykrab 2024-08-28
|
||||||
|
* Allow NPCs to cast Sacrifice ([#4470](https://github.com/EQEmu/Server/pull/4470)) @fuzzlecutter 2024-09-12
|
||||||
|
* Lazy Load Bank Contents ([#4453](https://github.com/EQEmu/Server/pull/4453)) @catapultam-habeo 2024-08-27
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Add RULE_STRING to RuleManager::ResetRules ([#4467](https://github.com/EQEmu/Server/pull/4467)) @Kinglykrab 2024-09-07
|
||||||
|
* Fix Bard Effect in Migration 9237 ([#4468](https://github.com/EQEmu/Server/pull/4468)) @Kinglykrab 2024-09-09
|
||||||
|
* ModernAAScalingEnabled() Calculation Error ([#4469](https://github.com/EQEmu/Server/pull/4469)) @carolus21rex 2024-09-11
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
* Move Discipline Loading to Client::CompleteConnect() ([#4466](https://github.com/EQEmu/Server/pull/4466)) @Kinglykrab 2024-09-09
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
* Add a Bandolier Swap Delay Rule ([#4465](https://github.com/EQEmu/Server/pull/4465)) @Kinglykrab 2024-09-08
|
||||||
|
|
||||||
|
## [22.55.1] 8/26/2024
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Remove unused methods ([#4449](https://github.com/EQEmu/Server/pull/4449)) @Kinglykrab 2024-08-22
|
||||||
|
|
||||||
|
### Feature
|
||||||
|
|
||||||
|
* Add Character:DefaultGuildRank Rule ([#4438](https://github.com/EQEmu/Server/pull/4438)) @Kinglykrab 2024-08-04
|
||||||
|
* Add Optional Return to EVENT_DAMAGE_TAKEN ([#4454](https://github.com/EQEmu/Server/pull/4454)) @Kinglykrab 2024-08-27
|
||||||
|
* Extend Spell Buckets Functionality ([#4441](https://github.com/EQEmu/Server/pull/4441)) @Kinglykrab 2024-08-22
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Apply Race & Class restrictions to Auto-Combines ([#4452](https://github.com/EQEmu/Server/pull/4452)) @catapultam-habeo 2024-08-20
|
||||||
|
* Attune Augments when Equipped ([#4446](https://github.com/EQEmu/Server/pull/4446)) @fryguy503 2024-08-10
|
||||||
|
* Correct missed maxlevel reference in exp.cpp ([#4463](https://github.com/EQEmu/Server/pull/4463)) @N0ctrnl 2024-08-27
|
||||||
|
* Ensure close of Tribute Item search ([#4439](https://github.com/EQEmu/Server/pull/4439)) @joligario 2024-08-04
|
||||||
|
* Fix AddCrystals() in Perl/Lua ([#4445](https://github.com/EQEmu/Server/pull/4445)) @Kinglykrab 2024-08-10
|
||||||
|
* Fix Bot Spell Entries IDs Capping at 32,767 ([#4444](https://github.com/EQEmu/Server/pull/4444)) @Kinglykrab 2024-08-27
|
||||||
|
* Fix Character ID of 0 being inserted into character_stats_record ([#4458](https://github.com/EQEmu/Server/pull/4458)) @Kinglykrab 2024-08-22
|
||||||
|
* Fix Issue with Removed #setfaction Command ([#4448](https://github.com/EQEmu/Server/pull/4448)) @Kinglykrab 2024-08-11
|
||||||
|
* Fix Lua Client FilteredMessage ([#4437](https://github.com/EQEmu/Server/pull/4437)) @Kinglykrab 2024-07-31
|
||||||
|
* Fix client hotbar exchanging items when zoning ([#4460](https://github.com/EQEmu/Server/pull/4460)) @neckkola 2024-08-27
|
||||||
|
* Fix issue with killed mob coordinates ([#4457](https://github.com/EQEmu/Server/pull/4457)) @Kinglykrab 2024-08-22
|
||||||
|
* Imitate Death should also clear zone feign aggro ([#4436](https://github.com/EQEmu/Server/pull/4436)) @fryguy503 2024-07-31
|
||||||
|
* client_max_level allow leveling to end of level ([#4455](https://github.com/EQEmu/Server/pull/4455)) @fryguy503 2024-08-20
|
||||||
|
|
||||||
|
### Improvement
|
||||||
|
|
||||||
|
* Filtered Messages Extension ([#4435](https://github.com/EQEmu/Server/pull/4435)) @fryguy503 2024-07-31
|
||||||
|
|
||||||
|
### Quest API
|
||||||
|
|
||||||
|
* Add AreTasksCompleted() to Perl/Lua. ([#4456](https://github.com/EQEmu/Server/pull/4456)) @Kinglykrab 2024-08-23
|
||||||
|
* Add Area-Based Quest Methods to Perl/Lua ([#4447](https://github.com/EQEmu/Server/pull/4447)) @Kinglykrab 2024-08-27
|
||||||
|
* Add Several Door Methods to Perl/Lua ([#4451](https://github.com/EQEmu/Server/pull/4451)) @Kinglykrab 2024-08-16
|
||||||
|
|
||||||
|
### World
|
||||||
|
|
||||||
|
* Fix slow world bootup bug ([#4461](https://github.com/EQEmu/Server/pull/4461)) @Akkadius 2024-08-27
|
||||||
|
|
||||||
|
## [22.54.0] 7/30/2024
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Cleanup Client File Exporting ([#4348](https://github.com/EQEmu/Server/pull/4348)) @Kinglykrab 2024-07-31
|
||||||
|
* Cleanup Stance Code ([#4368](https://github.com/EQEmu/Server/pull/4368)) @Kinglykrab 2024-07-03
|
||||||
|
* Mask GM Show Buff message behind EntityVariable ([#4419](https://github.com/EQEmu/Server/pull/4419)) @nytmyr 2024-07-22
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
* Extend #devtools Functionality ([#4425](https://github.com/EQEmu/Server/pull/4425)) @Kinglykrab 2024-07-23
|
||||||
|
|
||||||
|
### Databuckets
|
||||||
|
|
||||||
|
* Remove memory reserve from bulk load ([#4427](https://github.com/EQEmu/Server/pull/4427)) @Akkadius 2024-07-23
|
||||||
|
|
||||||
|
### Feature
|
||||||
|
|
||||||
|
* Add Barter/Buyer Features ([#4405](https://github.com/EQEmu/Server/pull/4405)) @neckkola 2024-07-30
|
||||||
|
* Add Parcel notification for online players when using the Quest API ([#4418](https://github.com/EQEmu/Server/pull/4418)) @neckkola 2024-07-22
|
||||||
|
* Implement Move Multiple Items ([#4259](https://github.com/EQEmu/Server/pull/4259)) @catapultam-habeo 2024-07-30
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Aegolism Spell line stacking ([#4399](https://github.com/EQEmu/Server/pull/4399)) @KayenEQ 2024-07-07
|
||||||
|
* AllowRaidTargetBlind logic backwards ([#4400](https://github.com/EQEmu/Server/pull/4400)) @fryguy503 2024-07-01
|
||||||
|
* AutoSplit unknown bug and cleanup. ([#4401](https://github.com/EQEmu/Server/pull/4401)) @fryguy503 2024-07-07
|
||||||
|
* Corpse Call removing Resurrection Effects ([#4410](https://github.com/EQEmu/Server/pull/4410)) @fryguy503 2024-07-22
|
||||||
|
* Fix #parcels add subcommand ([#4431](https://github.com/EQEmu/Server/pull/4431)) @neckkola 2024-07-29
|
||||||
|
* Fix #setlevel Allowing Skills Above Max ([#4423](https://github.com/EQEmu/Server/pull/4423)) @Kinglykrab 2024-07-23
|
||||||
|
* Fix Bot::SetBotStance ([#4426](https://github.com/EQEmu/Server/pull/4426)) @Kinglykrab 2024-07-23
|
||||||
|
* Fix Client::RemoveTitle ([#4421](https://github.com/EQEmu/Server/pull/4421)) @Kinglykrab 2024-07-23
|
||||||
|
* Fix EVENT_USE_SKILL with Sense Heading ([#4424](https://github.com/EQEmu/Server/pull/4424)) @Kinglykrab 2024-07-23
|
||||||
|
* Fix for random disconnects when a large number of guild members zone or disconnect ([#4402](https://github.com/EQEmu/Server/pull/4402)) @neckkola 2024-07-10
|
||||||
|
* Fix issue with quest::echo and quest::me ([#4433](https://github.com/EQEmu/Server/pull/4433)) @Kinglykrab 2024-07-30
|
||||||
|
* Personal tributes for bard items were not applying correctly ([#4416](https://github.com/EQEmu/Server/pull/4416)) @neckkola 2024-07-16
|
||||||
|
* Potential fix for some undesired ranged explotative behavior. ([#4413](https://github.com/EQEmu/Server/pull/4413)) @fryguy503 2024-07-22
|
||||||
|
* Proximity Aggro for Frustrated and Undead ([#4411](https://github.com/EQEmu/Server/pull/4411)) @fryguy503 2024-07-22
|
||||||
|
* Slay Adjustments ([#4389](https://github.com/EQEmu/Server/pull/4389)) @fryguy503 2024-07-07
|
||||||
|
* Stop DOSing ourselves with OP_WearChange ([#4432](https://github.com/EQEmu/Server/pull/4432)) @catapultam-habeo 2024-07-30
|
||||||
|
* [Quest API] Fix getraididbycharid and getgroupidbycharid ([#4417](https://github.com/EQEmu/Server/pull/4417)) @nytmyr 2024-07-16
|
||||||
|
|
||||||
|
### Improvement
|
||||||
|
|
||||||
|
* Flee Overhaul ([#4407](https://github.com/EQEmu/Server/pull/4407)) @fryguy503 2024-07-30
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
* Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs ([#4406](https://github.com/EQEmu/Server/pull/4406)) @nytmyr 2024-07-22
|
||||||
|
|
||||||
|
### Zone Instances
|
||||||
|
|
||||||
|
* Revert " Handle routing to instances when using evac/succor " (#4429) ([#4297](https://github.com/EQEmu/Server/pull/4297)) @Akkadius 2024-07-30
|
||||||
|
|
||||||
|
### Zoning
|
||||||
|
|
||||||
|
* Improve zone routing ([#4428](https://github.com/EQEmu/Server/pull/4428)) @Akkadius 2024-07-30
|
||||||
|
|
||||||
|
## [22.53.1] 6/16/2024
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix trader mode ([#4397](https://github.com/EQEmu/Server/pull/4397)) @joligario 2024-06-17
|
||||||
|
|
||||||
|
## [22.53.0] 6/14/2024
|
||||||
|
|
||||||
|
### Bug
|
||||||
|
|
||||||
|
* Anon players should not show in /who all ([#4392](https://github.com/EQEmu/Server/pull/4392)) @fryguy503 2024-06-14
|
||||||
|
* Escape should put player into SOS if owned. ([#4388](https://github.com/EQEmu/Server/pull/4388)) @fryguy503 2024-06-07
|
||||||
|
* Prevent Resurrection Spells from being resisted ([#4393](https://github.com/EQEmu/Server/pull/4393)) @fryguy503 2024-06-14
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Cleanup Account Status Code ([#4376](https://github.com/EQEmu/Server/pull/4376)) @Kinglykrab 2024-06-02
|
||||||
|
* Cleanup Body Type Code ([#4366](https://github.com/EQEmu/Server/pull/4366)) @Kinglykrab 2024-06-02
|
||||||
|
* Cleanup Object Type Code ([#4375](https://github.com/EQEmu/Server/pull/4375)) @Kinglykrab 2024-06-14
|
||||||
|
* Remove unused code in emu_constants.h ([#4384](https://github.com/EQEmu/Server/pull/4384)) @Kinglykrab 2024-06-14
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix #goto Target ([#4382](https://github.com/EQEmu/Server/pull/4382)) @Kinglykrab 2024-06-03
|
||||||
|
* Fix Swarm Pet Damage Messages ([#4383](https://github.com/EQEmu/Server/pull/4383)) @Kinglykrab 2024-06-04
|
||||||
|
* Fix for players having empty bazaar window dropdown list, even though trader is tagged as a trader. ([#4391](https://github.com/EQEmu/Server/pull/4391)) @neckkola 2024-06-14
|
||||||
|
* Fix potential trader crash when serialized item not found ([#4386](https://github.com/EQEmu/Server/pull/4386)) @joligario 2024-06-14
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
* Add Invisible Augment Rules ([#4385](https://github.com/EQEmu/Server/pull/4385)) @Kinglykrab 2024-06-14
|
||||||
|
* Classic Harm Touch Formula ([#4394](https://github.com/EQEmu/Server/pull/4394)) @fryguy503 2024-06-14
|
||||||
|
* Mend/Sneak allow success tuning ([#4390](https://github.com/EQEmu/Server/pull/4390)) @fryguy503 2024-06-14
|
||||||
|
* Snare Override Movement Bonus ([#4381](https://github.com/EQEmu/Server/pull/4381)) @fryguy503 2024-06-02
|
||||||
|
|
||||||
## [22.52.0] 6/1/2024
|
## [22.52.0] 6/1/2024
|
||||||
|
|
||||||
### Code
|
### Code
|
||||||
|
|||||||
+40
-141
@@ -29,7 +29,10 @@
|
|||||||
#include "../../common/content/world_content_service.h"
|
#include "../../common/content/world_content_service.h"
|
||||||
#include "../../common/zone_store.h"
|
#include "../../common/zone_store.h"
|
||||||
#include "../../common/path_manager.h"
|
#include "../../common/path_manager.h"
|
||||||
|
#include "../../common/repositories/base_data_repository.h"
|
||||||
|
#include "../../common/repositories/db_str_repository.h"
|
||||||
#include "../../common/repositories/skill_caps_repository.h"
|
#include "../../common/repositories/skill_caps_repository.h"
|
||||||
|
#include "../../common/repositories/spells_new_repository.h"
|
||||||
#include "../../common/file.h"
|
#include "../../common/file.h"
|
||||||
#include "../../common/events/player_event_logs.h"
|
#include "../../common/events/player_event_logs.h"
|
||||||
#include "../../common/skill_caps.h"
|
#include "../../common/skill_caps.h"
|
||||||
@@ -99,25 +102,22 @@ int main(int argc, char **argv)
|
|||||||
->LoadLogDatabaseSettings()
|
->LoadLogDatabaseSettings()
|
||||||
->StartFileLogs();
|
->StartFileLogs();
|
||||||
|
|
||||||
std::string arg_1;
|
std::string export_type;
|
||||||
|
|
||||||
if (argv[1]) {
|
if (argv[1]) {
|
||||||
arg_1 = argv[1];
|
export_type = argv[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_1 == "spells") {
|
if (Strings::EqualFold(export_type, "spells")) {
|
||||||
ExportSpells(&content_db);
|
ExportSpells(&content_db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else if (Strings::EqualFold(export_type, "skills")) {
|
||||||
if (arg_1 == "skills") {
|
|
||||||
ExportSkillCaps(&content_db);
|
ExportSkillCaps(&content_db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else if (Strings::EqualFold(export_type, "basedata") || Strings::EqualFold(export_type, "base_data")) {
|
||||||
if (arg_1 == "basedata") {
|
|
||||||
ExportBaseData(&content_db);
|
ExportBaseData(&content_db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else if (Strings::EqualFold(export_type, "dbstr") || Strings::EqualFold(export_type, "dbstring")) {
|
||||||
if (arg_1 == "dbstring") {
|
|
||||||
ExportDBStrings(&database);
|
ExportDBStrings(&database);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -134,178 +134,77 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
void ExportSpells(SharedDatabase* db)
|
void ExportSpells(SharedDatabase* db)
|
||||||
{
|
{
|
||||||
LogInfo("Exporting Spells");
|
std::ofstream file(fmt::format("{}/export/spells_us.txt", path.GetServerPath()));
|
||||||
|
if (!file || !file.is_open()) {
|
||||||
std::string file = fmt::format("{}/export/spells_us.txt", path.GetServerPath());
|
|
||||||
FILE *f = fopen(file.c_str(), "w");
|
|
||||||
if (!f) {
|
|
||||||
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
LogError("Unable to open export/spells_us.txt to write, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string query = "SELECT * FROM spells_new ORDER BY id";
|
const auto& lines = SpellsNewRepository::GetSpellFileLines(*db);
|
||||||
auto results = db->QueryDatabase(query);
|
|
||||||
|
|
||||||
if (results.Success()) {
|
const std::string& file_string = Strings::Implode("\n", lines);
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
|
||||||
std::string line;
|
|
||||||
unsigned int fields = results.ColumnCount();
|
|
||||||
for (unsigned int i = 0; i < fields; ++i) {
|
|
||||||
if (i != 0) {
|
|
||||||
line.push_back('^');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row[i] != nullptr) {
|
file << file_string;
|
||||||
line += row[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%s\n", line.c_str());
|
file.close();
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
LogInfo("Exported [{}] Spell{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||||
}
|
|
||||||
|
|
||||||
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
|
|
||||||
{
|
|
||||||
const auto& l = SkillCapsRepository::GetWhere(
|
|
||||||
*db,
|
|
||||||
fmt::format(
|
|
||||||
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
|
|
||||||
class_id,
|
|
||||||
skill_id
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return !l.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
|
|
||||||
{
|
|
||||||
const auto& l = SkillCapsRepository::GetWhere(
|
|
||||||
*db,
|
|
||||||
fmt::format(
|
|
||||||
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
|
|
||||||
class_id,
|
|
||||||
skill_id,
|
|
||||||
level
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (l.empty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto e = l.front();
|
|
||||||
|
|
||||||
return e.cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportSkillCaps(SharedDatabase* db)
|
void ExportSkillCaps(SharedDatabase* db)
|
||||||
{
|
{
|
||||||
LogInfo("Exporting Skill Caps");
|
|
||||||
|
|
||||||
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
|
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
|
||||||
if (!file || !file.is_open()) {
|
if (!file || !file.is_open()) {
|
||||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
|
const auto& lines = SkillCapsRepository::GetSkillCapFileLines(*db);
|
||||||
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
|
|
||||||
if (SkillUsable(db, skill_id, class_id)) {
|
|
||||||
uint32 previous_cap = 0;
|
|
||||||
|
|
||||||
for (
|
const std::string& file_string = Strings::Implode("\n", lines);
|
||||||
uint8 level = 1;
|
|
||||||
level <= SkillCaps::GetSkillCapMaxLevel(class_id, static_cast<EQ::skills::SkillType>(skill_id));
|
|
||||||
level++
|
|
||||||
) {
|
|
||||||
uint32 cap = GetSkill(db, skill_id, class_id, level);
|
|
||||||
if (cap < previous_cap) {
|
|
||||||
cap = previous_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
|
file << file_string;
|
||||||
|
|
||||||
previous_cap = cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
LogInfo("Exported [{}] Skill Cap{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportBaseData(SharedDatabase *db)
|
void ExportBaseData(SharedDatabase *db)
|
||||||
{
|
{
|
||||||
LogInfo("Exporting Base Data");
|
std::ofstream file(fmt::format("{}/export/BaseData.txt", path.GetServerPath()));
|
||||||
|
if (!file || !file.is_open()) {
|
||||||
std::string file = fmt::format("{}/export/BaseData.txt", path.GetServerPath());
|
|
||||||
FILE *f = fopen(file.c_str(), "w");
|
|
||||||
if (!f) {
|
|
||||||
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
LogError("Unable to open export/BaseData.txt to write, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string query = "SELECT * FROM base_data ORDER BY level, class";
|
const auto& lines = BaseDataRepository::GetBaseDataFileLines(*db);
|
||||||
auto results = db->QueryDatabase(query);
|
|
||||||
if (results.Success()) {
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
|
||||||
std::string line;
|
|
||||||
unsigned int fields = results.ColumnCount();
|
|
||||||
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
|
|
||||||
if (rowIndex != 0) {
|
|
||||||
line.push_back('^');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row[rowIndex] != nullptr) {
|
const std::string& file_string = Strings::Implode("\n", lines);
|
||||||
line += row[rowIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%s\n", line.c_str());
|
file << file_string;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
file.close();
|
||||||
|
|
||||||
|
LogInfo("Exported [{}] Base Data Entr{}", lines.size(), lines.size() != 1 ? "ies" : "y");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportDBStrings(SharedDatabase *db)
|
void ExportDBStrings(SharedDatabase *db)
|
||||||
{
|
{
|
||||||
LogInfo("Exporting DB Strings");
|
std::ofstream file(fmt::format("{}/export/dbstr_us.txt", path.GetServerPath()));
|
||||||
|
if (!file || !file.is_open()) {
|
||||||
std::string file = fmt::format("{}/export/dbstr_us.txt", path.GetServerPath());
|
|
||||||
FILE *f = fopen(file.c_str(), "w");
|
|
||||||
if (!f) {
|
|
||||||
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
LogError("Unable to open export/dbstr_us.txt to write, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f, "Major^Minor^String(New)\n");
|
const auto& lines = DbStrRepository::GetDBStrFileLines(*db);
|
||||||
const std::string query = "SELECT * FROM db_str ORDER BY id, type";
|
|
||||||
auto results = db->QueryDatabase(query);
|
const std::string& file_string = Strings::Implode("\n", lines);
|
||||||
if (results.Success()) {
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
file << file_string;
|
||||||
std::string line;
|
|
||||||
unsigned int fields = results.ColumnCount();
|
file.close();
|
||||||
for (unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) {
|
|
||||||
if (rowIndex != 0) {
|
LogInfo("Exported [{}] Database String{}", lines.size(), lines.size() != 1 ? "s" : "");
|
||||||
line.push_back('^');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row[rowIndex] != nullptr) {
|
|
||||||
line += row[rowIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%s\n", line.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-1
@@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
|
|||||||
SET(common_sources
|
SET(common_sources
|
||||||
base_packet.cpp
|
base_packet.cpp
|
||||||
bazaar.cpp
|
bazaar.cpp
|
||||||
|
bodytypes.cpp
|
||||||
classes.cpp
|
classes.cpp
|
||||||
cli/eqemu_command_handler.cpp
|
cli/eqemu_command_handler.cpp
|
||||||
compression.cpp
|
compression.cpp
|
||||||
@@ -61,6 +62,7 @@ SET(common_sources
|
|||||||
mutex.cpp
|
mutex.cpp
|
||||||
mysql_request_result.cpp
|
mysql_request_result.cpp
|
||||||
mysql_request_row.cpp
|
mysql_request_row.cpp
|
||||||
|
mysql_stmt.cpp
|
||||||
opcode_map.cpp
|
opcode_map.cpp
|
||||||
opcodemgr.cpp
|
opcodemgr.cpp
|
||||||
packet_dump.cpp
|
packet_dump.cpp
|
||||||
@@ -110,6 +112,8 @@ SET(common_sources
|
|||||||
net/websocket_server.cpp
|
net/websocket_server.cpp
|
||||||
net/websocket_server_connection.cpp
|
net/websocket_server_connection.cpp
|
||||||
patches/patches.cpp
|
patches/patches.cpp
|
||||||
|
patches/laurion.cpp
|
||||||
|
patches/laurion_limits.cpp
|
||||||
patches/sod.cpp
|
patches/sod.cpp
|
||||||
patches/sod_limits.cpp
|
patches/sod_limits.cpp
|
||||||
patches/sof.cpp
|
patches/sof.cpp
|
||||||
@@ -157,6 +161,7 @@ SET(repositories
|
|||||||
repositories/base/base_bugs_repository.h
|
repositories/base/base_bugs_repository.h
|
||||||
repositories/base/base_bug_reports_repository.h
|
repositories/base/base_bug_reports_repository.h
|
||||||
repositories/base/base_buyer_repository.h
|
repositories/base/base_buyer_repository.h
|
||||||
|
repositories/base/base_buyer_trade_items_repository.h
|
||||||
repositories/base/base_character_activities_repository.h
|
repositories/base/base_character_activities_repository.h
|
||||||
repositories/base/base_character_alternate_abilities_repository.h
|
repositories/base/base_character_alternate_abilities_repository.h
|
||||||
repositories/base/base_character_alt_currency_repository.h
|
repositories/base/base_character_alt_currency_repository.h
|
||||||
@@ -338,7 +343,8 @@ SET(repositories
|
|||||||
repositories/books_repository.h
|
repositories/books_repository.h
|
||||||
repositories/bugs_repository.h
|
repositories/bugs_repository.h
|
||||||
repositories/bug_reports_repository.h
|
repositories/bug_reports_repository.h
|
||||||
repositories/buyer_repository.h
|
repositories/buyer_buy_lines_repository.h
|
||||||
|
repositories/buyer_trade_items_repository.h
|
||||||
repositories/character_activities_repository.h
|
repositories/character_activities_repository.h
|
||||||
repositories/character_alternate_abilities_repository.h
|
repositories/character_alternate_abilities_repository.h
|
||||||
repositories/character_alt_currency_repository.h
|
repositories/character_alt_currency_repository.h
|
||||||
@@ -583,6 +589,7 @@ SET(common_headers
|
|||||||
mutex.h
|
mutex.h
|
||||||
mysql_request_result.h
|
mysql_request_result.h
|
||||||
mysql_request_row.h
|
mysql_request_row.h
|
||||||
|
mysql_stmt.h
|
||||||
op_codes.h
|
op_codes.h
|
||||||
opcode_dispatch.h
|
opcode_dispatch.h
|
||||||
opcodemgr.h
|
opcodemgr.h
|
||||||
@@ -650,6 +657,10 @@ SET(common_headers
|
|||||||
net/websocket_server.h
|
net/websocket_server.h
|
||||||
net/websocket_server_connection.h
|
net/websocket_server_connection.h
|
||||||
patches/patches.h
|
patches/patches.h
|
||||||
|
patches/laurion.h
|
||||||
|
patches/laurion_limits.h
|
||||||
|
patches/laurion_ops.h
|
||||||
|
patches/laurion_structs.h
|
||||||
patches/sod.h
|
patches/sod.h
|
||||||
patches/sod_limits.h
|
patches/sod_limits.h
|
||||||
patches/sod_ops.h
|
patches/sod_ops.h
|
||||||
@@ -736,6 +747,10 @@ SOURCE_GROUP(Net FILES
|
|||||||
|
|
||||||
SOURCE_GROUP(Patches FILES
|
SOURCE_GROUP(Patches FILES
|
||||||
patches/patches.h
|
patches/patches.h
|
||||||
|
patches/laurion.h
|
||||||
|
patches/laurion_limits.h
|
||||||
|
patches/laurion_ops.h
|
||||||
|
patches/laurion_structs.h
|
||||||
patches/sod.h
|
patches/sod.h
|
||||||
patches/sod_limits.h
|
patches/sod_limits.h
|
||||||
patches/sod_ops.h
|
patches/sod_ops.h
|
||||||
@@ -764,6 +779,8 @@ SOURCE_GROUP(Patches FILES
|
|||||||
patches/uf_ops.h
|
patches/uf_ops.h
|
||||||
patches/uf_structs.h
|
patches/uf_structs.h
|
||||||
patches/patches.cpp
|
patches/patches.cpp
|
||||||
|
patches/laurion.cpp
|
||||||
|
patches/laurion_limits.cpp
|
||||||
patches/sod.cpp
|
patches/sod.cpp
|
||||||
patches/sod_limits.cpp
|
patches/sod_limits.cpp
|
||||||
patches/sof.cpp
|
patches/sof.cpp
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public:
|
|||||||
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
|
void WriteUInt8(uint8 value) { *(uint8 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint8); }
|
||||||
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
|
void WriteUInt32(uint32 value) { *(uint32 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint32); }
|
||||||
void WriteUInt64(uint64 value) { *(uint64 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint64); }
|
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 WriteUInt16(uint32 value) { *(uint16 *)(pBuffer + _wpos) = value; _wpos += sizeof(uint16); }
|
||||||
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
|
void WriteSInt32(int32 value) { *(int32 *)(pBuffer + _wpos) = value; _wpos += sizeof(int32); }
|
||||||
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
||||||
|
|||||||
+3
-2
@@ -47,7 +47,7 @@ Bazaar::GetSearchResults(
|
|||||||
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
||||||
}
|
}
|
||||||
if (search.min_cost != 0) {
|
if (search.min_cost != 0) {
|
||||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost));
|
search_criteria_trader.append(fmt::format(" AND trader.item_cost >= {}", search.min_cost * 1000));
|
||||||
}
|
}
|
||||||
if (search.max_cost != 0) {
|
if (search.max_cost != 0) {
|
||||||
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
|
search_criteria_trader.append(fmt::format(" AND trader.item_cost <= {}", (uint64) search.max_cost * 1000));
|
||||||
@@ -235,7 +235,8 @@ Bazaar::GetSearchResults(
|
|||||||
std::vector<ItemSearchType> item_search_types = {
|
std::vector<ItemSearchType> item_search_types = {
|
||||||
{EQ::item::ItemType::ItemTypeAll, true},
|
{EQ::item::ItemType::ItemTypeAll, true},
|
||||||
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
|
{EQ::item::ItemType::ItemTypeBook, item->ItemClass == EQ::item::ItemType::ItemTypeBook},
|
||||||
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer},
|
{EQ::item::ItemType::ItemTypeContainer, item->ItemClass == EQ::item::ItemType::ItemTypeContainer ||
|
||||||
|
item->IsClassBag()},
|
||||||
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
|
{EQ::item::ItemType::ItemTypeAllEffects, item->Scroll.Effect > 0 && item->Scroll.Effect < 65000},
|
||||||
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
|
{EQ::item::ItemType::ItemTypeUnknown9, item->Worn.Effect == 998},
|
||||||
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
|
{EQ::item::ItemType::ItemTypeUnknown10, item->Worn.Effect >= 1298 && item->Worn.Effect <= 1307},
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "../common/global_define.h"
|
||||||
|
#include "../common/bodytypes.h"
|
||||||
|
|
||||||
|
std::string BodyType::GetName(uint8 body_type_id)
|
||||||
|
{
|
||||||
|
return IsValid(body_type_id) ? body_type_names[body_type_id] : "UNKNOWN BODY TYPE";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BodyType::IsValid(uint8 body_type_id)
|
||||||
|
{
|
||||||
|
return body_type_names.find(body_type_id) != body_type_names.end();
|
||||||
|
}
|
||||||
+90
-46
@@ -18,52 +18,96 @@
|
|||||||
#ifndef BODYTYPES_H
|
#ifndef BODYTYPES_H
|
||||||
#define BODYTYPES_H
|
#define BODYTYPES_H
|
||||||
|
|
||||||
typedef enum {
|
#include "types.h"
|
||||||
BT_Humanoid = 1,
|
#include <map>
|
||||||
BT_Lycanthrope = 2,
|
#include <string>
|
||||||
BT_Undead = 3,
|
|
||||||
BT_Giant = 4,
|
|
||||||
BT_Construct = 5,
|
|
||||||
BT_Extraplanar = 6,
|
|
||||||
BT_Magical = 7, //this name might be a bit off,
|
|
||||||
BT_SummonedUndead = 8,
|
|
||||||
BT_RaidGiant = 9, //Velious era Raid Giant
|
|
||||||
BT_RaidColdain = 10, //Velious era Raid Coldain
|
|
||||||
BT_NoTarget = 11, //no name, can't target this bodytype
|
|
||||||
BT_Vampire = 12,
|
|
||||||
BT_Atenha_Ra = 13,
|
|
||||||
BT_Greater_Akheva = 14,
|
|
||||||
BT_Khati_Sha = 15,
|
|
||||||
BT_Seru = 16,
|
|
||||||
BT_Grieg_Veneficus = 17,
|
|
||||||
BT_Draz_Nurakk = 18,
|
|
||||||
BT_Zek = 19, //"creatures from the Plane of War."
|
|
||||||
BT_Luggald = 20,
|
|
||||||
BT_Animal = 21,
|
|
||||||
BT_Insect = 22,
|
|
||||||
BT_Monster = 23,
|
|
||||||
BT_Summoned = 24, //Elemental?
|
|
||||||
BT_Plant = 25,
|
|
||||||
BT_Dragon = 26,
|
|
||||||
BT_Summoned2 = 27,
|
|
||||||
BT_Summoned3 = 28,
|
|
||||||
BT_Dragon2 = 29, //database data indicates this is a dragon type (kunark and DoN?)
|
|
||||||
BT_VeliousDragon = 30, //might not be a tight set
|
|
||||||
BT_Familiar = 31,
|
|
||||||
BT_Dragon3 = 32,
|
|
||||||
BT_Boxes = 33,
|
|
||||||
BT_Muramite = 34, //tribal dudes
|
|
||||||
// ...
|
|
||||||
BT_NoTarget2 = 60,
|
|
||||||
// ...
|
|
||||||
BT_SwarmPet = 63, //Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
|
|
||||||
BT_MonsterSummon = 64,
|
|
||||||
// 65, trap or effect related?
|
|
||||||
BT_InvisMan = 66, //no name, seen on 'InvisMan', can be /targeted
|
|
||||||
BT_Special = 67
|
|
||||||
} bodyType;
|
|
||||||
/* bodytypes above 64 make the mob not show up */
|
|
||||||
|
|
||||||
constexpr int format_as(bodyType type) { return static_cast<int>(type); }
|
// body types above 64 make the mob invisible
|
||||||
|
namespace BodyType {
|
||||||
|
constexpr uint8 Humanoid = 1;
|
||||||
|
constexpr uint8 Lycanthrope = 2;
|
||||||
|
constexpr uint8 Undead = 3;
|
||||||
|
constexpr uint8 Giant = 4;
|
||||||
|
constexpr uint8 Construct = 5;
|
||||||
|
constexpr uint8 Extraplanar = 6;
|
||||||
|
constexpr uint8 Magical = 7; // this name might be a bit off,
|
||||||
|
constexpr uint8 SummonedUndead = 8;
|
||||||
|
constexpr uint8 RaidGiant = 9; // Velious era Raid Giant
|
||||||
|
constexpr uint8 RaidColdain = 10; // Velious era Raid Coldain
|
||||||
|
constexpr uint8 NoTarget = 11; // no name, can't target this bodytype
|
||||||
|
constexpr uint8 Vampire = 12;
|
||||||
|
constexpr uint8 AtenHaRa = 13;
|
||||||
|
constexpr uint8 GreaterAkheva = 14;
|
||||||
|
constexpr uint8 KhatiSha = 15;
|
||||||
|
constexpr uint8 Seru = 16;
|
||||||
|
constexpr uint8 GriegVeneficus = 17;
|
||||||
|
constexpr uint8 DrazNurakk = 18;
|
||||||
|
constexpr uint8 Zek = 19; //"creatures from the Plane of War."
|
||||||
|
constexpr uint8 Luggald = 20;
|
||||||
|
constexpr uint8 Animal = 21;
|
||||||
|
constexpr uint8 Insect = 22;
|
||||||
|
constexpr uint8 Monster = 23;
|
||||||
|
constexpr uint8 Summoned = 24; // Elemental?
|
||||||
|
constexpr uint8 Plant = 25;
|
||||||
|
constexpr uint8 Dragon = 26;
|
||||||
|
constexpr uint8 Summoned2 = 27;
|
||||||
|
constexpr uint8 Summoned3 = 28;
|
||||||
|
constexpr uint8 Dragon2 = 29; // database data indicates this is a dragon type (Kunark and DoN?)
|
||||||
|
constexpr uint8 VeliousDragon = 30; // might not be a tight set
|
||||||
|
constexpr uint8 Familiar = 31;
|
||||||
|
constexpr uint8 Dragon3 = 32;
|
||||||
|
constexpr uint8 Boxes = 33;
|
||||||
|
constexpr uint8 Muramite = 34; // tribal dudes
|
||||||
|
constexpr uint8 NoTarget2 = 60;
|
||||||
|
constexpr uint8 SwarmPet = 63; // Looks like weapon proc related temp pets and few misc pets, should not be used for checking swarm pets in general.
|
||||||
|
constexpr uint8 MonsterSummon = 64;
|
||||||
|
constexpr uint8 InvisibleMan = 66; // no name, seen on 'InvisMan', can be /targeted
|
||||||
|
constexpr uint8 Special = 67;
|
||||||
|
|
||||||
|
std::string GetName(uint8 body_type_id);
|
||||||
|
bool IsValid(uint8 body_type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint8, std::string> body_type_names = {
|
||||||
|
{ BodyType::Humanoid, "Humanoid" },
|
||||||
|
{ BodyType::Lycanthrope, "Lycanthrope" },
|
||||||
|
{ BodyType::Undead, "Undead" },
|
||||||
|
{ BodyType::Giant, "Giant" },
|
||||||
|
{ BodyType::Construct, "Construct" },
|
||||||
|
{ BodyType::Extraplanar, "Extraplanar" },
|
||||||
|
{ BodyType::Magical, "Magical" },
|
||||||
|
{ BodyType::SummonedUndead, "Summoned Undead" },
|
||||||
|
{ BodyType::RaidGiant, "Raid Giant" },
|
||||||
|
{ BodyType::RaidColdain, "Raid Coldain" },
|
||||||
|
{ BodyType::NoTarget, "Untargetable" },
|
||||||
|
{ BodyType::Vampire, "Vampire" },
|
||||||
|
{ BodyType::AtenHaRa, "Aten Ha Ra" },
|
||||||
|
{ BodyType::GreaterAkheva, "Greater Akheva" },
|
||||||
|
{ BodyType::KhatiSha, "Khati Sha" },
|
||||||
|
{ BodyType::Seru, "Seru" },
|
||||||
|
{ BodyType::GriegVeneficus, "Grieg Veneficus" },
|
||||||
|
{ BodyType::DrazNurakk, "Draz Nurakk" },
|
||||||
|
{ BodyType::Zek, "Zek" },
|
||||||
|
{ BodyType::Luggald, "Luggald" },
|
||||||
|
{ BodyType::Animal, "Animal" },
|
||||||
|
{ BodyType::Insect, "Insect" },
|
||||||
|
{ BodyType::Monster, "Monster" },
|
||||||
|
{ BodyType::Summoned, "Summoned" },
|
||||||
|
{ BodyType::Plant, "Plant" },
|
||||||
|
{ BodyType::Dragon, "Dragon" },
|
||||||
|
{ BodyType::Summoned2, "Summoned 2" },
|
||||||
|
{ BodyType::Summoned3, "Summoned 3" },
|
||||||
|
{ BodyType::Dragon2, "Dragon 2" },
|
||||||
|
{ BodyType::VeliousDragon, "Velious Dragon" },
|
||||||
|
{ BodyType::Familiar, "Familiar" },
|
||||||
|
{ BodyType::Dragon3, "Dragon 3" },
|
||||||
|
{ BodyType::Boxes, "Boxes" },
|
||||||
|
{ BodyType::Muramite, "Muramite" },
|
||||||
|
{ BodyType::NoTarget2, "Untargetable 2" },
|
||||||
|
{ BodyType::SwarmPet, "Swarm Pet" },
|
||||||
|
{ BodyType::MonsterSummon, "Monster Summon" },
|
||||||
|
{ BodyType::InvisibleMan, "Invisible Man" },
|
||||||
|
{ BodyType::Special, "Special" },
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ namespace Class {
|
|||||||
constexpr uint8 FellowshipMaster = 69;
|
constexpr uint8 FellowshipMaster = 69;
|
||||||
constexpr uint8 AlternateCurrencyMerchant = 70;
|
constexpr uint8 AlternateCurrencyMerchant = 70;
|
||||||
constexpr uint8 MercenaryLiaison = 71;
|
constexpr uint8 MercenaryLiaison = 71;
|
||||||
|
constexpr uint8 RealEstateMerchant = 72;
|
||||||
|
constexpr uint8 LoyaltyMerchant = 73;
|
||||||
|
constexpr uint8 TributeMaster2 = 74;
|
||||||
|
|
||||||
constexpr uint8 PLAYER_CLASS_COUNT = 16;
|
constexpr uint8 PLAYER_CLASS_COUNT = 16;
|
||||||
constexpr uint16 ALL_CLASSES_BITMASK = 65535;
|
constexpr uint16 ALL_CLASSES_BITMASK = 65535;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "../rulesys.h"
|
#include "../rulesys.h"
|
||||||
#include "../eqemu_logsys.h"
|
#include "../eqemu_logsys.h"
|
||||||
#include "../repositories/instance_list_repository.h"
|
#include "../repositories/instance_list_repository.h"
|
||||||
|
#include "../zone_store.h"
|
||||||
|
|
||||||
|
|
||||||
WorldContentService::WorldContentService()
|
WorldContentService::WorldContentService()
|
||||||
@@ -183,8 +184,8 @@ void WorldContentService::ReloadContentFlags()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetContentFlags(set_content_flags);
|
SetContentFlags(set_content_flags);
|
||||||
LoadZones();
|
|
||||||
LoadStaticGlobalZoneInstances();
|
LoadStaticGlobalZoneInstances();
|
||||||
|
zone_store.LoadZones(*m_content_database);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database *WorldContentService::GetDatabase() const
|
Database *WorldContentService::GetDatabase() const
|
||||||
@@ -236,18 +237,6 @@ void WorldContentService::SetContentFlag(const std::string &content_flag_name, b
|
|||||||
ReloadContentFlags();
|
ReloadContentFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleZoneRoutingMiddleware is meant to handle content and context aware zone routing
|
|
||||||
//
|
|
||||||
// example # 1
|
|
||||||
// lavastorm (pre-don) version 0 (classic)
|
|
||||||
// lavastorm (don) version 1
|
|
||||||
// we want to route players to the correct version of lavastorm based on the current server side expansion
|
|
||||||
// in order to do that the simplest and cleanest way we intercept the zoning process and route players to an "instance" of the zone
|
|
||||||
// the reason why we're doing this is because all of the zoning logic already is handled by two keys "zone_id" and "instance_id"
|
|
||||||
// we can leverage static, never expires instances to handle this but to the client they don't see it any other way than a public normal zone
|
|
||||||
// scripts handle all the same way, you don't have to think about instances, the middleware will handle the magic
|
|
||||||
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
|
||||||
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
|
||||||
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
||||||
{
|
{
|
||||||
auto r = FindZone(zc->zoneID, zc->instanceID);
|
auto r = FindZone(zc->zoneID, zc->instanceID);
|
||||||
@@ -263,63 +252,59 @@ void WorldContentService::HandleZoneRoutingMiddleware(ZoneChange_Struct *zc)
|
|||||||
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
|
// these are used commonly in v1/v2/v3 versions of the same zone for expansion routing
|
||||||
WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
|
WorldContentService *WorldContentService::LoadStaticGlobalZoneInstances()
|
||||||
{
|
{
|
||||||
m_zone_instances = InstanceListRepository::GetWhere(*GetDatabase(), fmt::format("never_expires = 1 AND is_global = 1"));
|
m_zone_static_instances = InstanceListRepository::GetWhere(
|
||||||
|
*GetDatabase(),
|
||||||
LogInfo("Loaded [{}] zone_instances", m_zone_instances.size());
|
fmt::format("never_expires = 1 AND is_global = 1")
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadZones sets the zones for the world content service
|
|
||||||
// this is used for zone routing middleware
|
|
||||||
// we pull the zone list from the zone repository and feed from the zone store for now
|
|
||||||
// we're holding a copy in the content service - but we're talking 250kb of data in memory to handle routing of zoning
|
|
||||||
WorldContentService * WorldContentService::LoadZones()
|
|
||||||
{
|
|
||||||
m_zones = ZoneRepository::All(*GetContentDatabase());
|
|
||||||
|
|
||||||
LogInfo("Loaded [{}] zones", m_zones.size());
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindZone is critical to the zone routing middleware and any logic that needs to route players to the correct zone
|
|
||||||
// era contextual routing, multiple version of zones, etc
|
|
||||||
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
|
|
||||||
{
|
|
||||||
// if there's an active dynamic instance, we don't need to route
|
|
||||||
if (instance_id > 0) {
|
|
||||||
auto inst = InstanceListRepository::FindOne(*GetDatabase(), instance_id);
|
|
||||||
if (inst.id != 0 && !inst.is_global && !inst.never_expires) {
|
|
||||||
return WorldContentService::FindZoneResult{
|
|
||||||
.zone_id = 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &z: m_zones) {
|
|
||||||
if (z.zoneidnumber == zone_id) {
|
|
||||||
auto f = ContentFlags{
|
|
||||||
.min_expansion = z.min_expansion,
|
|
||||||
.max_expansion = z.max_expansion,
|
|
||||||
.content_flags = z.content_flags,
|
|
||||||
.content_flags_disabled = z.content_flags_disabled
|
|
||||||
};
|
|
||||||
|
|
||||||
if (DoesPassContentFiltering(f)) {
|
|
||||||
LogInfo(
|
|
||||||
"Attempting to route player to zone [{}] ({}) version [{}] long_name [{}]",
|
|
||||||
z.short_name,
|
|
||||||
z.zoneidnumber,
|
|
||||||
z.version,
|
|
||||||
z.long_name
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// first pass, explicit match on public static global zone instances
|
LogInfo("Loaded [{}] zone_instances", m_zone_static_instances.size());
|
||||||
for (auto &i: m_zone_instances) {
|
|
||||||
if (i.zone == zone_id && i.version == z.version) {
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindZone handles content and context aware zone routing (middleware)
|
||||||
|
//
|
||||||
|
// this is a middleware function that is meant to be used in the zone change process
|
||||||
|
// this hooks all core zone changes within the server and routes the player to the correct zone
|
||||||
|
// returning a zone_id of non-zero means the middleware will route the player
|
||||||
|
// returning a zone_id of 0 means the middleware will not route the player
|
||||||
|
// this is useful for handling multiple versions of the same zone
|
||||||
|
//
|
||||||
|
// implementation >
|
||||||
|
// the zoning and process spawning logic already is handled by two keys "zone_id" and "instance_id"
|
||||||
|
// we leverage static, never expires instances to handle this and client still sees it as a normal zone
|
||||||
|
//
|
||||||
|
// content awareness >
|
||||||
|
// simply use the zone_id, server content settings and the middleware will handle the rest
|
||||||
|
// you don't have to think about instances in any data tables (use instance_id 0)
|
||||||
|
// you don't have to keep track of instance ids in scripts (use instance_id 0)
|
||||||
|
// the versions of zones are represented by two zone entries that have potentially different min/max expansion and/or different content flags
|
||||||
|
// we decide to route the client to the correct version of the zone based on the current server side expansion
|
||||||
|
//
|
||||||
|
// example >
|
||||||
|
// we want to route players to the correct version of lavastorm based on the current server side expansion (DoesZonePassContentFiltering)
|
||||||
|
// lavastorm (pre-don) version 0 (classic)
|
||||||
|
// zone table entry for version = 0, min_expansion = 0, max_expansion = 8
|
||||||
|
// instance_list table entry for lavastorm has version = 0, is_global = 1, never_expires = 1
|
||||||
|
// lavastorm (don) version 1
|
||||||
|
// zone table entry for version = 1, min_expansion = 9, max_expansion = 99
|
||||||
|
// instance_list table entry for lavastorm has version = 1, is_global = 1, never_expires = 1
|
||||||
|
WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id, uint32 instance_id)
|
||||||
|
{
|
||||||
|
for (const auto &z: zone_store.GetZones()) {
|
||||||
|
for (auto &i: m_zone_static_instances) {
|
||||||
|
if (
|
||||||
|
z.zoneidnumber == zone_id &&
|
||||||
|
DoesZonePassContentFiltering(z) &&
|
||||||
|
i.zone == zone_id &&
|
||||||
|
i.version == z.version) {
|
||||||
|
|
||||||
|
if (instance_id > 0 && i.id != instance_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
LogInfo(
|
LogInfo(
|
||||||
"Routed player to instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
"Routed player to public static instance [{}] of zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
||||||
i.id,
|
i.id,
|
||||||
z.short_name,
|
z.short_name,
|
||||||
z.zoneidnumber,
|
z.zoneidnumber,
|
||||||
@@ -335,23 +320,6 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo(
|
|
||||||
"Routed player to non-instance zone [{}] ({}) version [{}] long_name [{}] notes [{}]",
|
|
||||||
z.short_name,
|
|
||||||
z.zoneidnumber,
|
|
||||||
z.version,
|
|
||||||
z.long_name,
|
|
||||||
z.note
|
|
||||||
);
|
|
||||||
|
|
||||||
return WorldContentService::FindZoneResult{
|
|
||||||
.zone_id = static_cast<uint32>(z.zoneidnumber),
|
|
||||||
.instance = InstanceListRepository::NewEntity(),
|
|
||||||
.zone = z
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return WorldContentService::FindZoneResult{.zone_id = 0};
|
return WorldContentService::FindZoneResult{.zone_id = 0};
|
||||||
@@ -359,7 +327,7 @@ WorldContentService::FindZoneResult WorldContentService::FindZone(uint32 zone_id
|
|||||||
|
|
||||||
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
||||||
{
|
{
|
||||||
for (auto &i: m_zone_instances) {
|
for (auto &i: m_zone_static_instances) {
|
||||||
if (i.id == instance_id) {
|
if (i.id == instance_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -367,3 +335,15 @@ bool WorldContentService::IsInPublicStaticInstance(uint32 instance_id)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldContentService::DoesZonePassContentFiltering(const ZoneRepository::Zone &z)
|
||||||
|
{
|
||||||
|
auto f = ContentFlags{
|
||||||
|
.min_expansion = z.min_expansion,
|
||||||
|
.max_expansion = z.max_expansion,
|
||||||
|
.content_flags = z.content_flags,
|
||||||
|
.content_flags_disabled = z.content_flags_disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
return DoesPassContentFiltering(f);
|
||||||
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ public:
|
|||||||
WorldContentService * SetExpansionContext();
|
WorldContentService * SetExpansionContext();
|
||||||
|
|
||||||
bool DoesPassContentFiltering(const ContentFlags& f);
|
bool DoesPassContentFiltering(const ContentFlags& f);
|
||||||
|
bool DoesZonePassContentFiltering(const ZoneRepository::Zone& z);
|
||||||
|
|
||||||
WorldContentService * SetDatabase(Database *database);
|
WorldContentService * SetDatabase(Database *database);
|
||||||
Database *GetDatabase() const;
|
Database *GetDatabase() const;
|
||||||
@@ -189,10 +190,8 @@ private:
|
|||||||
Database *m_content_database;
|
Database *m_content_database;
|
||||||
|
|
||||||
// holds a record of the zone table from the database
|
// holds a record of the zone table from the database
|
||||||
std::vector<ZoneRepository::Zone> m_zones = {};
|
|
||||||
WorldContentService *LoadStaticGlobalZoneInstances();
|
WorldContentService *LoadStaticGlobalZoneInstances();
|
||||||
std::vector<InstanceListRepository::InstanceList> m_zone_instances;
|
std::vector<InstanceListRepository::InstanceList> m_zone_static_instances;
|
||||||
WorldContentService * LoadZones();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern WorldContentService content_service;
|
extern WorldContentService content_service;
|
||||||
|
|||||||
@@ -101,6 +101,24 @@ void CRC32::SetEQChecksum(uchar* in_data, uint32 in_length, uint32 start_at)
|
|||||||
memcpy(in_data, (char*)&check, 4);
|
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) {
|
uint32 CRC32::Update(const uint8* buf, uint32 bufsize, uint32 crc32var) {
|
||||||
for(uint32 i=0; i < bufsize; i++)
|
for(uint32 i=0; i < bufsize; i++)
|
||||||
Calc(buf[i], crc32var);
|
Calc(buf[i], crc32var);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public:
|
|||||||
static uint32 Generate(const uint8* buf, uint32 bufsize);
|
static uint32 Generate(const uint8* buf, uint32 bufsize);
|
||||||
static uint32 GenerateNoFlip(const uint8* buf, uint32 bufsize); // Same as Generate(), but without the ~
|
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 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
|
// Multiple buffer CRC32
|
||||||
static uint32 Update(const uint8* buf, uint32 bufsize, uint32 crc32 = 0xFFFFFFFF);
|
static uint32 Update(const uint8* buf, uint32 bufsize, uint32 crc32 = 0xFFFFFFFF);
|
||||||
|
|||||||
+55
-12
@@ -66,6 +66,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "data_verification.h"
|
||||||
#include "eq_packet_structs.h"
|
#include "eq_packet_structs.h"
|
||||||
#include "extprofile.h"
|
#include "extprofile.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
@@ -77,6 +78,8 @@
|
|||||||
#include "zone_store.h"
|
#include "zone_store.h"
|
||||||
#include "repositories/merchantlist_temp_repository.h"
|
#include "repositories/merchantlist_temp_repository.h"
|
||||||
#include "repositories/bot_data_repository.h"
|
#include "repositories/bot_data_repository.h"
|
||||||
|
#include "repositories/trader_repository.h"
|
||||||
|
#include "repositories/buyer_repository.h"
|
||||||
|
|
||||||
extern Client client;
|
extern Client client;
|
||||||
|
|
||||||
@@ -282,16 +285,31 @@ bool Database::SetAccountStatus(const std::string& account_name, int16 status)
|
|||||||
|
|
||||||
bool Database::ReserveName(uint32 account_id, const std::string& name)
|
bool Database::ReserveName(uint32 account_id, const std::string& name)
|
||||||
{
|
{
|
||||||
const auto& l = CharacterDataRepository::GetWhere(
|
const std::string& where_filter = fmt::format(
|
||||||
*this,
|
|
||||||
fmt::format(
|
|
||||||
"`name` = '{}'",
|
"`name` = '{}'",
|
||||||
Strings::Escape(name)
|
Strings::Escape(name)
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!l.empty()) {
|
if (RuleB(Bots, Enabled)) {
|
||||||
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
|
const auto& b = BotDataRepository::GetWhere(*this, where_filter);
|
||||||
|
|
||||||
|
if (!b.empty()) {
|
||||||
|
LogInfo("Account [{}] requested name [{}] but name is already taken by a bot", account_id, name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& c = CharacterDataRepository::GetWhere(*this, where_filter);
|
||||||
|
|
||||||
|
if (!c.empty()) {
|
||||||
|
LogInfo("Account [{}] requested name [{}] but name is already taken by a character", account_id, name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& n = NpcTypesRepository::GetWhere(*this, where_filter);
|
||||||
|
|
||||||
|
if (!n.empty()) {
|
||||||
|
LogInfo("Account [{}] requested name [{}] but name is already taken by an NPC", account_id, name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,13 +324,15 @@ bool Database::ReserveName(uint32 account_id, const std::string& name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int guild_id = RuleI(Character, DefaultGuild);
|
const uint32 guild_id = RuleI(Character, DefaultGuild);
|
||||||
|
const uint8 guild_rank = EQ::Clamp(RuleI(Character, DefaultGuildRank), 0, 8);
|
||||||
if (guild_id != 0) {
|
if (guild_id != 0) {
|
||||||
if (e.id) {
|
if (e.id) {
|
||||||
auto g = GuildMembersRepository::NewEntity();
|
auto g = GuildMembersRepository::NewEntity();
|
||||||
|
|
||||||
g.char_id = e.id;
|
g.char_id = e.id;
|
||||||
g.guild_id = guild_id;
|
g.guild_id = guild_id;
|
||||||
|
g.rank_ = guild_rank;
|
||||||
|
|
||||||
GuildMembersRepository::InsertOne(*this, g);
|
GuildMembersRepository::InsertOne(*this, g);
|
||||||
}
|
}
|
||||||
@@ -1628,16 +1648,29 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
|
|||||||
|
|
||||||
uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
uint32 Database::GetGroupIDByCharID(uint32 character_id)
|
||||||
{
|
{
|
||||||
const auto& e = GroupIdRepository::FindOne(*this, character_id);
|
const auto& e = GroupIdRepository::GetWhere(
|
||||||
|
*this,
|
||||||
|
fmt::format(
|
||||||
|
"`character_id` = {}",
|
||||||
|
character_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return e.character_id ? e.group_id : 0;
|
return e.size() == 1 ? e.front().group_id : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Database::GetRaidIDByCharID(uint32 character_id)
|
uint32 Database::GetRaidIDByCharID(uint32 character_id)
|
||||||
{
|
{
|
||||||
const auto& e = RaidMembersRepository::FindOne(*this, character_id);
|
|
||||||
|
|
||||||
return e.charid ? e.raidid : 0;
|
const auto& e = RaidMembersRepository::GetWhere(
|
||||||
|
*this,
|
||||||
|
fmt::format(
|
||||||
|
"`charid` = {}",
|
||||||
|
character_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return e.size() == 1 ? e.front().raidid : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 Database::CountInvSnapshots()
|
int64 Database::CountInvSnapshots()
|
||||||
@@ -1827,7 +1860,7 @@ bool Database::CopyCharacter(
|
|||||||
|
|
||||||
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
|
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
|
||||||
|
|
||||||
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets" };
|
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
|
||||||
|
|
||||||
TransactionBegin();
|
TransactionBegin();
|
||||||
|
|
||||||
@@ -2104,3 +2137,13 @@ void Database::ClearGuildOnlineStatus()
|
|||||||
{
|
{
|
||||||
GuildMembersRepository::ClearOnlineStatus(*this);
|
GuildMembersRepository::ClearOnlineStatus(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::ClearTraderDetails()
|
||||||
|
{
|
||||||
|
TraderRepository::Truncate(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::ClearBuyerDetails()
|
||||||
|
{
|
||||||
|
BuyerRepository::DeleteBuyer(*this, 0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -244,6 +244,8 @@ public:
|
|||||||
|
|
||||||
void PurgeAllDeletedDataBuckets();
|
void PurgeAllDeletedDataBuckets();
|
||||||
void ClearGuildOnlineStatus();
|
void ClearGuildOnlineStatus();
|
||||||
|
void ClearTraderDetails();
|
||||||
|
void ClearBuyerDetails();
|
||||||
|
|
||||||
|
|
||||||
/* Database Variables */
|
/* Database Variables */
|
||||||
|
|||||||
@@ -4947,7 +4947,7 @@ UPDATE `aa_ability` SET `auto_grant_enabled` = 1 WHERE `grant_only` = 0 AND `cha
|
|||||||
.version = 9237,
|
.version = 9237,
|
||||||
.description = "2023_10_15_import_13th_floor.sql",
|
.description = "2023_10_15_import_13th_floor.sql",
|
||||||
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
|
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
|
||||||
.condition = "contains",
|
.condition = "missing",
|
||||||
.match = "mediumint",
|
.match = "mediumint",
|
||||||
.sql = R"(
|
.sql = R"(
|
||||||
ALTER TABLE `items`
|
ALTER TABLE `items`
|
||||||
@@ -5660,6 +5660,116 @@ ALTER TABLE `trader`
|
|||||||
DROP PRIMARY KEY,
|
DROP PRIMARY KEY,
|
||||||
ADD PRIMARY KEY (`id`),
|
ADD PRIMARY KEY (`id`),
|
||||||
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
|
ADD INDEX `charid_slotid` (`char_id`, `slot_id`);
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9281,
|
||||||
|
.description = "2024_06_24_update_buyer_support.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `buyer` LIKE 'id'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `buyer`
|
||||||
|
ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||||
|
CHANGE COLUMN `charid` `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`,
|
||||||
|
ADD COLUMN `char_entity_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_id`,
|
||||||
|
ADD COLUMN `char_name` VARCHAR(64) NULL DEFAULT NULL AFTER `char_entity_id`,
|
||||||
|
ADD COLUMN `char_zone_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_name`,
|
||||||
|
ADD COLUMN `char_zone_instance_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `char_zone_id`,
|
||||||
|
ADD COLUMN `transaction_date` DATETIME NULL DEFAULT NULL AFTER `char_zone_instance_id`,
|
||||||
|
ADD COLUMN `welcome_message` VARCHAR(256) NULL DEFAULT NULL AFTER `transaction_date`,
|
||||||
|
DROP COLUMN `buyslot`,
|
||||||
|
DROP COLUMN `itemid`,
|
||||||
|
DROP COLUMN `itemname`,
|
||||||
|
DROP COLUMN `quantity`,
|
||||||
|
DROP COLUMN `price`,
|
||||||
|
DROP PRIMARY KEY,
|
||||||
|
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
ADD INDEX `charid` (`char_id`);
|
||||||
|
|
||||||
|
CREATE TABLE `buyer_buy_lines` (
|
||||||
|
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`buyer_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
`char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
`buy_slot_id` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_id` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_qty` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_price` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
`item_name` VARCHAR(64) NOT NULL DEFAULT '' COLLATE 'latin1_swedish_ci',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
INDEX `buyerid_charid_buyslotid` (`buyer_id`, `char_id`, `buy_slot_id`) USING BTREE
|
||||||
|
)
|
||||||
|
COLLATE='latin1_swedish_ci'
|
||||||
|
ENGINE=InnoDB
|
||||||
|
AUTO_INCREMENT=1;
|
||||||
|
|
||||||
|
CREATE TABLE `buyer_trade_items` (
|
||||||
|
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`buyer_buy_lines_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
`item_id` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_qty` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_icon` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`item_name` VARCHAR(64) NOT NULL DEFAULT '0' COLLATE 'latin1_swedish_ci',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
INDEX `buyerbuylinesid` (`buyer_buy_lines_id`) USING BTREE
|
||||||
|
)
|
||||||
|
COLLATE='latin1_swedish_ci'
|
||||||
|
ENGINE=InnoDB
|
||||||
|
AUTO_INCREMENT=1;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9282,
|
||||||
|
.description = "2024_08_02_spell_buckets_comparison.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `spell_buckets` LIKE 'bucket_comparison'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `spell_buckets`
|
||||||
|
CHANGE COLUMN `spellid` `spell_id` int UNSIGNED NOT NULL FIRST,
|
||||||
|
CHANGE COLUMN `key` `bucket_name` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `spell_id`,
|
||||||
|
CHANGE COLUMN `value` `bucket_value` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `bucket_name`,
|
||||||
|
ADD COLUMN `bucket_comparison` tinyint UNSIGNED NOT NULL DEFAULT 0 AFTER `bucket_value`,
|
||||||
|
DROP PRIMARY KEY,
|
||||||
|
ADD PRIMARY KEY (`spell_id`) USING BTREE;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9283,
|
||||||
|
.description = "2024_08_05_fix_client_hotbar",
|
||||||
|
.check = "SHOW COLUMNS FROM `inventory` LIKE 'guid'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `inventory`
|
||||||
|
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||||
|
ALTER TABLE `inventory_snapshots`
|
||||||
|
ADD COLUMN `guid` BIGINT UNSIGNED NULL DEFAULT '0' AFTER `ornament_hero_model`;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9284,
|
||||||
|
.description = "2024_10_08_character_exp_modifiers_default.sql",
|
||||||
|
.check = "SHOW CREATE TABLE `character_exp_modifiers`",
|
||||||
|
.condition = "contains",
|
||||||
|
.match = "`exp_modifier` float NOT NULL,",
|
||||||
|
.sql = R"(
|
||||||
|
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);
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
|
|||||||
@@ -150,6 +150,17 @@ ADD COLUMN `augment_six` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `augment_five
|
|||||||
.sql = R"(
|
.sql = R"(
|
||||||
ALTER TABLE `bot_data`
|
ALTER TABLE `bot_data`
|
||||||
ADD COLUMN `extra_haste` mediumint(8) NOT NULL DEFAULT 0 AFTER `wis`;
|
ADD COLUMN `extra_haste` mediumint(8) NOT NULL DEFAULT 0 AFTER `wis`;
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9045,
|
||||||
|
.description = "2024_08_05_bot_spells_entries_unsigned_spell_id.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `bot_spells_entries` LIKE 'spell_id'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `bot_spells_entries`
|
||||||
|
CHANGE COLUMN `spellid` `spell_id` smallint(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `npc_spells_id`;
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ namespace DatabaseSchema {
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
{"adventure_stats", "player_id"},
|
{"adventure_stats", "player_id"},
|
||||||
{"buyer", "charid"},
|
|
||||||
{"char_recipe_list", "char_id"},
|
{"char_recipe_list", "char_id"},
|
||||||
{"character_activities", "charid"},
|
{"character_activities", "charid"},
|
||||||
{"character_alt_currency", "char_id"},
|
{"character_alt_currency", "char_id"},
|
||||||
@@ -107,6 +106,8 @@ namespace DatabaseSchema {
|
|||||||
"adventure_details",
|
"adventure_details",
|
||||||
"adventure_stats",
|
"adventure_stats",
|
||||||
"buyer",
|
"buyer",
|
||||||
|
"buyer_buy_lines",
|
||||||
|
"buyer_trade_items",
|
||||||
"char_recipe_list",
|
"char_recipe_list",
|
||||||
"character_activities",
|
"character_activities",
|
||||||
"character_alt_currency",
|
"character_alt_currency",
|
||||||
@@ -325,6 +326,9 @@ namespace DatabaseSchema {
|
|||||||
"banned_ips",
|
"banned_ips",
|
||||||
"bug_reports",
|
"bug_reports",
|
||||||
"bugs",
|
"bugs",
|
||||||
|
"buyer",
|
||||||
|
"buyer_buy_lines",
|
||||||
|
"buyer_trade_items",
|
||||||
"completed_shared_task_activity_state",
|
"completed_shared_task_activity_state",
|
||||||
"completed_shared_task_members",
|
"completed_shared_task_members",
|
||||||
"completed_shared_tasks",
|
"completed_shared_tasks",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
#include "dbcore.h"
|
#include "dbcore.h"
|
||||||
|
#include "mysql_stmt.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -436,3 +437,8 @@ MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
|
|||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mysql::PreparedStmt DBcore::Prepare(std::string query)
|
||||||
|
{
|
||||||
|
return mysql::PreparedStmt(*mysql, std::move(query), m_mutex);
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#define CR_SERVER_GONE_ERROR 2006
|
#define CR_SERVER_GONE_ERROR 2006
|
||||||
#define CR_SERVER_LOST 2013
|
#define CR_SERVER_LOST 2013
|
||||||
|
|
||||||
|
namespace mysql { class PreparedStmt; }
|
||||||
|
|
||||||
class DBcore {
|
class DBcore {
|
||||||
public:
|
public:
|
||||||
enum eStatus {
|
enum eStatus {
|
||||||
@@ -48,6 +50,11 @@ public:
|
|||||||
}
|
}
|
||||||
void SetMutex(Mutex *mutex);
|
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:
|
protected:
|
||||||
bool Open(
|
bool Open(
|
||||||
const char *iHost,
|
const char *iHost,
|
||||||
|
|||||||
+24
-203
@@ -80,39 +80,19 @@ bool Bug::IsValid(uint32 category_id)
|
|||||||
return bug_category_names.find(category_id) != bug_category_names.end();
|
return bug_category_names.find(category_id) != bug_category_names.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *EQ::constants::GetStanceName(StanceType stance_type) {
|
std::string Stance::GetName(uint8 stance_id)
|
||||||
switch (stance_type) {
|
{
|
||||||
case stanceUnknown:
|
return IsValid(stance_id) ? stance_names[stance_id] : "UNKNOWN STANCE";
|
||||||
return "Unknown";
|
|
||||||
case stancePassive:
|
|
||||||
return "Passive";
|
|
||||||
case stanceBalanced:
|
|
||||||
return "Balanced";
|
|
||||||
case stanceEfficient:
|
|
||||||
return "Efficient";
|
|
||||||
case stanceReactive:
|
|
||||||
return "Reactive";
|
|
||||||
case stanceAggressive:
|
|
||||||
return "Aggressive";
|
|
||||||
case stanceAssist:
|
|
||||||
return "Assist";
|
|
||||||
case stanceBurn:
|
|
||||||
return "Burn";
|
|
||||||
case stanceEfficient2:
|
|
||||||
return "Efficient2";
|
|
||||||
case stanceBurnAE:
|
|
||||||
return "BurnAE";
|
|
||||||
default:
|
|
||||||
return "Invalid";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int EQ::constants::ConvertStanceTypeToIndex(StanceType stance_type) {
|
bool Stance::IsValid(uint8 stance_id)
|
||||||
if (EQ::ValueWithin(stance_type, EQ::constants::stancePassive, EQ::constants::stanceBurnAE)) {
|
{
|
||||||
return (stance_type - EQ::constants::stancePassive);
|
return stance_names.find(stance_id) != stance_names.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
uint8 Stance::GetIndex(uint8 stance_id)
|
||||||
|
{
|
||||||
|
return IsValid(stance_id) ? (stance_id - Stance::Passive) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<uint8, std::string>& EQ::constants::GetLanguageMap()
|
const std::map<uint8, std::string>& EQ::constants::GetLanguageMap()
|
||||||
@@ -206,102 +186,6 @@ std::string EQ::constants::GetFlyModeName(int8 flymode_id)
|
|||||||
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
return EQ::constants::GetFlyModeMap().find(flymode_id)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<bodyType, std::string>& EQ::constants::GetBodyTypeMap()
|
|
||||||
{
|
|
||||||
static const std::map<bodyType, std::string> bodytype_map = {
|
|
||||||
{ BT_Humanoid, "Humanoid" },
|
|
||||||
{ BT_Lycanthrope, "Lycanthrope" },
|
|
||||||
{ BT_Undead, "Undead" },
|
|
||||||
{ BT_Giant, "Giant" },
|
|
||||||
{ BT_Construct, "Construct" },
|
|
||||||
{ BT_Extraplanar, "Extraplanar" },
|
|
||||||
{ BT_Magical, "Magical" },
|
|
||||||
{ BT_SummonedUndead, "Summoned Undead" },
|
|
||||||
{ BT_RaidGiant, "Raid Giant" },
|
|
||||||
{ BT_RaidColdain, "Raid Coldain" },
|
|
||||||
{ BT_NoTarget, "Untargetable" },
|
|
||||||
{ BT_Vampire, "Vampire" },
|
|
||||||
{ BT_Atenha_Ra, "Aten Ha Ra" },
|
|
||||||
{ BT_Greater_Akheva, "Greater Akheva" },
|
|
||||||
{ BT_Khati_Sha, "Khati Sha" },
|
|
||||||
{ BT_Seru, "Seru" },
|
|
||||||
{ BT_Grieg_Veneficus, "Grieg Veneficus" },
|
|
||||||
{ BT_Draz_Nurakk, "Draz Nurakk" },
|
|
||||||
{ BT_Zek, "Zek" },
|
|
||||||
{ BT_Luggald, "Luggald" },
|
|
||||||
{ BT_Animal, "Animal" },
|
|
||||||
{ BT_Insect, "Insect" },
|
|
||||||
{ BT_Monster, "Monster" },
|
|
||||||
{ BT_Summoned, "Summoned" },
|
|
||||||
{ BT_Plant, "Plant" },
|
|
||||||
{ BT_Dragon, "Dragon" },
|
|
||||||
{ BT_Summoned2, "Summoned 2" },
|
|
||||||
{ BT_Summoned3, "Summoned 3" },
|
|
||||||
{ BT_Dragon2, "Dragon 2" },
|
|
||||||
{ BT_VeliousDragon, "Velious Dragon" },
|
|
||||||
{ BT_Familiar, "Familiar" },
|
|
||||||
{ BT_Dragon3, "Dragon 3" },
|
|
||||||
{ BT_Boxes, "Boxes" },
|
|
||||||
{ BT_Muramite, "Muramite" },
|
|
||||||
{ BT_NoTarget2, "Untargetable 2" },
|
|
||||||
{ BT_SwarmPet, "Swarm Pet" },
|
|
||||||
{ BT_MonsterSummon, "Monster Summon" },
|
|
||||||
{ BT_InvisMan, "Invisible Man" },
|
|
||||||
{ BT_Special, "Special" },
|
|
||||||
};
|
|
||||||
|
|
||||||
return bodytype_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQ::constants::GetBodyTypeName(bodyType bodytype_id)
|
|
||||||
{
|
|
||||||
if (EQ::constants::GetBodyTypeMap().find(bodytype_id) != EQ::constants::GetBodyTypeMap().end()) {
|
|
||||||
return EQ::constants::GetBodyTypeMap().find(bodytype_id)->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<uint8, std::string>& EQ::constants::GetAccountStatusMap()
|
|
||||||
{
|
|
||||||
static const std::map<uint8, std::string> account_status_map = {
|
|
||||||
{ AccountStatus::Player, "Player" },
|
|
||||||
{ AccountStatus::Steward, "Steward" },
|
|
||||||
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
|
|
||||||
{ AccountStatus::Guide, "Guide" },
|
|
||||||
{ AccountStatus::QuestTroupe, "Quest Troupe" },
|
|
||||||
{ AccountStatus::SeniorGuide, "Senior Guide" },
|
|
||||||
{ AccountStatus::GMTester, "GM Tester" },
|
|
||||||
{ AccountStatus::EQSupport, "EQ Support" },
|
|
||||||
{ AccountStatus::GMStaff, "GM Staff" },
|
|
||||||
{ AccountStatus::GMAdmin, "GM Admin" },
|
|
||||||
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
|
|
||||||
{ AccountStatus::QuestMaster, "Quest Master" },
|
|
||||||
{ AccountStatus::GMAreas, "GM Areas" },
|
|
||||||
{ AccountStatus::GMCoder, "GM Coder" },
|
|
||||||
{ AccountStatus::GMMgmt, "GM Mgmt" },
|
|
||||||
{ AccountStatus::GMImpossible, "GM Impossible" },
|
|
||||||
{ AccountStatus::Max, "GM Max" }
|
|
||||||
};
|
|
||||||
|
|
||||||
return account_status_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQ::constants::GetAccountStatusName(uint8 account_status)
|
|
||||||
{
|
|
||||||
for (
|
|
||||||
auto status_level = EQ::constants::GetAccountStatusMap().rbegin();
|
|
||||||
status_level != EQ::constants::GetAccountStatusMap().rend();
|
|
||||||
++status_level
|
|
||||||
) {
|
|
||||||
if (account_status >= status_level->first) {
|
|
||||||
return status_level->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
const std::map<uint8, std::string>& EQ::constants::GetConsiderLevelMap()
|
||||||
{
|
{
|
||||||
static const std::map<uint8, std::string> consider_level_map = {
|
static const std::map<uint8, std::string> consider_level_map = {
|
||||||
@@ -392,84 +276,6 @@ std::string EQ::constants::GetSpawnAnimationName(uint8 animation_id)
|
|||||||
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
return EQ::constants::GetSpawnAnimationMap().find(animation_id)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<int, std::string>& EQ::constants::GetObjectTypeMap()
|
|
||||||
{
|
|
||||||
static const std::map<int, std::string> object_type_map = {
|
|
||||||
{ ObjectTypes::SmallBag, "Small Bag" },
|
|
||||||
{ ObjectTypes::LargeBag, "Large Bag" },
|
|
||||||
{ ObjectTypes::Quiver, "Quiver" },
|
|
||||||
{ ObjectTypes::BeltPouch, "Belt Pouch" },
|
|
||||||
{ ObjectTypes::WristPouch, "Wrist Pouch" },
|
|
||||||
{ ObjectTypes::Backpack, "Backpack" },
|
|
||||||
{ ObjectTypes::SmallChest, "Small Chest" },
|
|
||||||
{ ObjectTypes::LargeChest, "Large Chest" },
|
|
||||||
{ ObjectTypes::Bandolier, "Bandolier" },
|
|
||||||
{ ObjectTypes::Medicine, "Medicine" },
|
|
||||||
{ ObjectTypes::Tinkering, "Tinkering" },
|
|
||||||
{ ObjectTypes::Lexicon, "Lexicon" },
|
|
||||||
{ ObjectTypes::PoisonMaking, "Mortar and Pestle" },
|
|
||||||
{ ObjectTypes::Quest, "Quest" },
|
|
||||||
{ ObjectTypes::MixingBowl, "Mixing Bowl" },
|
|
||||||
{ ObjectTypes::Baking, "Baking" },
|
|
||||||
{ ObjectTypes::Tailoring, "Tailoring" },
|
|
||||||
{ ObjectTypes::Blacksmithing, "Blacksmithing" },
|
|
||||||
{ ObjectTypes::Fletching, "Fletching" },
|
|
||||||
{ ObjectTypes::Brewing, "Brewing" },
|
|
||||||
{ ObjectTypes::JewelryMaking, "Jewelry Making" },
|
|
||||||
{ ObjectTypes::Pottery, "Pottery" },
|
|
||||||
{ ObjectTypes::Kiln, "Kiln" },
|
|
||||||
{ ObjectTypes::KeyMaker, "Key Maker" },
|
|
||||||
{ ObjectTypes::ResearchWIZ, "Lexicon" },
|
|
||||||
{ ObjectTypes::ResearchMAG, "Lexicon" },
|
|
||||||
{ ObjectTypes::ResearchNEC, "Lexicon" },
|
|
||||||
{ ObjectTypes::ResearchENC, "Lexicon" },
|
|
||||||
{ ObjectTypes::Unknown, "Unknown" },
|
|
||||||
{ ObjectTypes::ResearchPractice, "Lexicon" },
|
|
||||||
{ ObjectTypes::Alchemy, "Alchemy" },
|
|
||||||
{ ObjectTypes::HighElfForge, "High Elf Forge" },
|
|
||||||
{ ObjectTypes::DarkElfForge, "Dark Elf Forge" },
|
|
||||||
{ ObjectTypes::OgreForge, "Ogre Forge" },
|
|
||||||
{ ObjectTypes::DwarfForge, "Dwarf Forge" },
|
|
||||||
{ ObjectTypes::GnomeForge, "Gnome Forge" },
|
|
||||||
{ ObjectTypes::BarbarianForge, "Barbarian Forge" },
|
|
||||||
{ ObjectTypes::IksarForge, "Iksar Forge" },
|
|
||||||
{ ObjectTypes::HumanForgeOne, "Human Forge" },
|
|
||||||
{ ObjectTypes::HumanForgeTwo, "Human Forge" },
|
|
||||||
{ ObjectTypes::HalflingTailoringOne, "Halfling Tailoring" },
|
|
||||||
{ ObjectTypes::HalflingTailoringTwo, "Halfling Tailoring" },
|
|
||||||
{ ObjectTypes::EruditeTailoring, "Erudite Tailoring" },
|
|
||||||
{ ObjectTypes::WoodElfTailoring, "Wood Elf Tailoring" },
|
|
||||||
{ ObjectTypes::WoodElfFletching, "Wood Elf Fletching" },
|
|
||||||
{ ObjectTypes::IksarPottery, "Iksar Pottery" },
|
|
||||||
{ ObjectTypes::Fishing, "Fishing" },
|
|
||||||
{ ObjectTypes::TrollForge, "Troll Forge" },
|
|
||||||
{ ObjectTypes::WoodElfForge, "Wood Elf Forge" },
|
|
||||||
{ ObjectTypes::HalflingForge, "Halfling Forge" },
|
|
||||||
{ ObjectTypes::EruditeForge, "Erudite Forge" },
|
|
||||||
{ ObjectTypes::Merchant, "Merchant" },
|
|
||||||
{ ObjectTypes::FroglokForge, "Froglok Forge" },
|
|
||||||
{ ObjectTypes::Augmenter, "Augmenter" },
|
|
||||||
{ ObjectTypes::Churn, "Churn" },
|
|
||||||
{ ObjectTypes::TransformationMold, "Transformation Mold" },
|
|
||||||
{ ObjectTypes::DetransformationMold, "Detransformation Mold" },
|
|
||||||
{ ObjectTypes::Unattuner, "Unattuner" },
|
|
||||||
{ ObjectTypes::TradeskillBag, "Tradeskill Bag" },
|
|
||||||
{ ObjectTypes::CollectibleBag, "Collectible Bag" },
|
|
||||||
{ ObjectTypes::NoDeposit, "No Deposit" }
|
|
||||||
};
|
|
||||||
|
|
||||||
return object_type_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQ::constants::GetObjectTypeName(int object_type)
|
|
||||||
{
|
|
||||||
if (!EQ::ValueWithin(object_type, ObjectTypes::SmallBag, ObjectTypes::NoDeposit)) {
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EQ::constants::GetObjectTypeMap().find(object_type)->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
|
const std::map<uint8, std::string> &EQ::constants::GetWeatherTypeMap()
|
||||||
{
|
{
|
||||||
static const std::map<uint8, std::string> weather_type_map = {
|
static const std::map<uint8, std::string> weather_type_map = {
|
||||||
@@ -629,6 +435,21 @@ std::string EQ::constants::GetConsiderColorName(uint32 consider_color)
|
|||||||
return c != EQ::constants::GetConsiderColorMap().end() ? c->second : std::string();
|
return c != EQ::constants::GetConsiderColorMap().end() ? c->second : std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AccountStatus::GetName(uint8 account_status)
|
||||||
|
{
|
||||||
|
for (
|
||||||
|
auto e = account_status_names.rbegin();
|
||||||
|
e != account_status_names.rend();
|
||||||
|
++e
|
||||||
|
) {
|
||||||
|
if (account_status >= e->first) {
|
||||||
|
return e->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNKNOWN ACCOUNT STATUS";
|
||||||
|
}
|
||||||
|
|
||||||
std::string ComparisonType::GetName(uint8 type)
|
std::string ComparisonType::GetName(uint8 type)
|
||||||
{
|
{
|
||||||
return IsValid(type) ? comparison_types[type] : "UNKNOWN COMPARISON TYPE";
|
return IsValid(type) ? comparison_types[type] : "UNKNOWN COMPARISON TYPE";
|
||||||
|
|||||||
+84
-115
@@ -26,6 +26,48 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace AccountStatus {
|
||||||
|
constexpr uint8 Player = 0;
|
||||||
|
constexpr uint8 Steward = 10;
|
||||||
|
constexpr uint8 ApprenticeGuide = 20;
|
||||||
|
constexpr uint8 Guide = 50;
|
||||||
|
constexpr uint8 QuestTroupe = 80;
|
||||||
|
constexpr uint8 SeniorGuide = 81;
|
||||||
|
constexpr uint8 GMTester = 85;
|
||||||
|
constexpr uint8 EQSupport = 90;
|
||||||
|
constexpr uint8 GMStaff = 95;
|
||||||
|
constexpr uint8 GMAdmin = 100;
|
||||||
|
constexpr uint8 GMLeadAdmin = 150;
|
||||||
|
constexpr uint8 QuestMaster = 160;
|
||||||
|
constexpr uint8 GMAreas = 170;
|
||||||
|
constexpr uint8 GMCoder = 180;
|
||||||
|
constexpr uint8 GMMgmt = 200;
|
||||||
|
constexpr uint8 GMImpossible = 250;
|
||||||
|
constexpr uint8 Max = 255;
|
||||||
|
|
||||||
|
std::string GetName(uint8 account_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint8, std::string> account_status_names = {
|
||||||
|
{ AccountStatus::Player, "Player" },
|
||||||
|
{ AccountStatus::Steward, "Steward" },
|
||||||
|
{ AccountStatus::ApprenticeGuide, "Apprentice Guide" },
|
||||||
|
{ AccountStatus::Guide, "Guide" },
|
||||||
|
{ AccountStatus::QuestTroupe, "Quest Troupe" },
|
||||||
|
{ AccountStatus::SeniorGuide, "Senior Guide" },
|
||||||
|
{ AccountStatus::GMTester, "GM Tester" },
|
||||||
|
{ AccountStatus::EQSupport, "EQ Support" },
|
||||||
|
{ AccountStatus::GMStaff, "GM Staff" },
|
||||||
|
{ AccountStatus::GMAdmin, "GM Admin" },
|
||||||
|
{ AccountStatus::GMLeadAdmin, "GM Lead Admin" },
|
||||||
|
{ AccountStatus::QuestMaster, "Quest Master" },
|
||||||
|
{ AccountStatus::GMAreas, "GM Areas" },
|
||||||
|
{ AccountStatus::GMCoder, "GM Coder" },
|
||||||
|
{ AccountStatus::GMMgmt, "GM Mgmt" },
|
||||||
|
{ AccountStatus::GMImpossible, "GM Impossible" },
|
||||||
|
{ AccountStatus::Max, "GM Max" }
|
||||||
|
};
|
||||||
|
|
||||||
namespace ComparisonType {
|
namespace ComparisonType {
|
||||||
constexpr uint8 Equal = 0;
|
constexpr uint8 Equal = 0;
|
||||||
constexpr uint8 NotEqual = 1;
|
constexpr uint8 NotEqual = 1;
|
||||||
@@ -55,7 +97,6 @@ static std::map<uint8, std::string> comparison_types = {
|
|||||||
{ ComparisonType::NotBetween, "Not Between" },
|
{ ComparisonType::NotBetween, "Not Between" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// local definitions are the result of using hybrid-client or server-only values and methods
|
// local definitions are the result of using hybrid-client or server-only values and methods
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
@@ -233,19 +274,6 @@ namespace EQ
|
|||||||
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
const size_t SAY_LINK_CLOSER_SIZE = 1;
|
||||||
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
const size_t SAY_LINK_MAXIMUM_SIZE = (SAY_LINK_OPENER_SIZE + SAY_LINK_BODY_SIZE + SAY_LINK_TEXT_SIZE + SAY_LINK_CLOSER_SIZE);
|
||||||
|
|
||||||
enum StanceType : int {
|
|
||||||
stanceUnknown = 0,
|
|
||||||
stancePassive,
|
|
||||||
stanceBalanced,
|
|
||||||
stanceEfficient,
|
|
||||||
stanceReactive,
|
|
||||||
stanceAggressive,
|
|
||||||
stanceAssist,
|
|
||||||
stanceBurn,
|
|
||||||
stanceEfficient2,
|
|
||||||
stanceBurnAE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BotSpellIDs : int {
|
enum BotSpellIDs : int {
|
||||||
Warrior = 3001,
|
Warrior = 3001,
|
||||||
Cleric,
|
Cleric,
|
||||||
@@ -296,70 +324,6 @@ namespace EQ
|
|||||||
Looting
|
Looting
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ObjectTypes : int {
|
|
||||||
SmallBag,
|
|
||||||
LargeBag,
|
|
||||||
Quiver,
|
|
||||||
BeltPouch,
|
|
||||||
WristPouch,
|
|
||||||
Backpack,
|
|
||||||
SmallChest,
|
|
||||||
LargeChest,
|
|
||||||
Bandolier,
|
|
||||||
Medicine,
|
|
||||||
Tinkering,
|
|
||||||
Lexicon,
|
|
||||||
PoisonMaking,
|
|
||||||
Quest,
|
|
||||||
MixingBowl,
|
|
||||||
Baking,
|
|
||||||
Tailoring,
|
|
||||||
Blacksmithing,
|
|
||||||
Fletching,
|
|
||||||
Brewing,
|
|
||||||
JewelryMaking,
|
|
||||||
Pottery,
|
|
||||||
Kiln,
|
|
||||||
KeyMaker,
|
|
||||||
ResearchWIZ,
|
|
||||||
ResearchMAG,
|
|
||||||
ResearchNEC,
|
|
||||||
ResearchENC,
|
|
||||||
Unknown,
|
|
||||||
ResearchPractice,
|
|
||||||
Alchemy,
|
|
||||||
HighElfForge,
|
|
||||||
DarkElfForge,
|
|
||||||
OgreForge,
|
|
||||||
DwarfForge,
|
|
||||||
GnomeForge,
|
|
||||||
BarbarianForge,
|
|
||||||
IksarForge,
|
|
||||||
HumanForgeOne,
|
|
||||||
HumanForgeTwo,
|
|
||||||
HalflingTailoringOne,
|
|
||||||
HalflingTailoringTwo,
|
|
||||||
EruditeTailoring,
|
|
||||||
WoodElfTailoring,
|
|
||||||
WoodElfFletching,
|
|
||||||
IksarPottery,
|
|
||||||
Fishing,
|
|
||||||
TrollForge,
|
|
||||||
WoodElfForge,
|
|
||||||
HalflingForge,
|
|
||||||
EruditeForge,
|
|
||||||
Merchant,
|
|
||||||
FroglokForge,
|
|
||||||
Augmenter,
|
|
||||||
Churn,
|
|
||||||
TransformationMold,
|
|
||||||
DetransformationMold,
|
|
||||||
Unattuner,
|
|
||||||
TradeskillBag,
|
|
||||||
CollectibleBag,
|
|
||||||
NoDeposit
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WeatherTypes : uint8 {
|
enum WeatherTypes : uint8 {
|
||||||
None,
|
None,
|
||||||
Raining,
|
Raining,
|
||||||
@@ -385,9 +349,6 @@ namespace EQ
|
|||||||
Proximity
|
Proximity
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *GetStanceName(StanceType stance_type);
|
|
||||||
int ConvertStanceTypeToIndex(StanceType stance_type);
|
|
||||||
|
|
||||||
extern const std::map<uint8, std::string>& GetLanguageMap();
|
extern const std::map<uint8, std::string>& GetLanguageMap();
|
||||||
std::string GetLanguageName(uint8 language_id);
|
std::string GetLanguageName(uint8 language_id);
|
||||||
|
|
||||||
@@ -397,12 +358,6 @@ namespace EQ
|
|||||||
extern const std::map<int8, std::string>& GetFlyModeMap();
|
extern const std::map<int8, std::string>& GetFlyModeMap();
|
||||||
std::string GetFlyModeName(int8 flymode_id);
|
std::string GetFlyModeName(int8 flymode_id);
|
||||||
|
|
||||||
extern const std::map<bodyType, std::string>& GetBodyTypeMap();
|
|
||||||
std::string GetBodyTypeName(bodyType bodytype_id);
|
|
||||||
|
|
||||||
extern const std::map<uint8, std::string>& GetAccountStatusMap();
|
|
||||||
std::string GetAccountStatusName(uint8 account_status);
|
|
||||||
|
|
||||||
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
|
extern const std::map<uint8, std::string>& GetConsiderLevelMap();
|
||||||
std::string GetConsiderLevelName(uint8 consider_level);
|
std::string GetConsiderLevelName(uint8 consider_level);
|
||||||
|
|
||||||
@@ -415,9 +370,6 @@ namespace EQ
|
|||||||
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
|
extern const std::map<uint8, std::string>& GetSpawnAnimationMap();
|
||||||
std::string GetSpawnAnimationName(uint8 animation_id);
|
std::string GetSpawnAnimationName(uint8 animation_id);
|
||||||
|
|
||||||
extern const std::map<int, std::string>& GetObjectTypeMap();
|
|
||||||
std::string GetObjectTypeName(int object_type);
|
|
||||||
|
|
||||||
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
|
extern const std::map<uint8, std::string>& GetWeatherTypeMap();
|
||||||
std::string GetWeatherTypeName(uint8 weather_type);
|
std::string GetWeatherTypeName(uint8 weather_type);
|
||||||
|
|
||||||
@@ -433,10 +385,6 @@ namespace EQ
|
|||||||
extern const std::map<uint32, std::string>& GetConsiderColorMap();
|
extern const std::map<uint32, std::string>& GetConsiderColorMap();
|
||||||
std::string GetConsiderColorName(uint32 consider_color);
|
std::string GetConsiderColorName(uint32 consider_color);
|
||||||
|
|
||||||
const int STANCE_TYPE_FIRST = stancePassive;
|
|
||||||
const int STANCE_TYPE_LAST = stanceBurnAE;
|
|
||||||
const int STANCE_TYPE_COUNT = stanceBurnAE;
|
|
||||||
|
|
||||||
} /*constants*/
|
} /*constants*/
|
||||||
|
|
||||||
namespace profile {
|
namespace profile {
|
||||||
@@ -503,7 +451,7 @@ namespace EQ
|
|||||||
Raid,
|
Raid,
|
||||||
Guild
|
Guild
|
||||||
};
|
};
|
||||||
}; // namespace consent
|
};
|
||||||
} /*EQEmu*/
|
} /*EQEmu*/
|
||||||
|
|
||||||
enum ServerLockType : int {
|
enum ServerLockType : int {
|
||||||
@@ -512,26 +460,6 @@ enum ServerLockType : int {
|
|||||||
Unlock
|
Unlock
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AccountStatus : uint8 {
|
|
||||||
Player = 0,
|
|
||||||
Steward = 10,
|
|
||||||
ApprenticeGuide = 20,
|
|
||||||
Guide = 50,
|
|
||||||
QuestTroupe = 80,
|
|
||||||
SeniorGuide = 81,
|
|
||||||
GMTester = 85,
|
|
||||||
EQSupport = 90,
|
|
||||||
GMStaff = 95,
|
|
||||||
GMAdmin = 100,
|
|
||||||
GMLeadAdmin = 150,
|
|
||||||
QuestMaster = 160,
|
|
||||||
GMAreas = 170,
|
|
||||||
GMCoder = 180,
|
|
||||||
GMMgmt = 200,
|
|
||||||
GMImpossible = 250,
|
|
||||||
Max = 255
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Invisibility : uint8 {
|
enum Invisibility : uint8 {
|
||||||
Visible,
|
Visible,
|
||||||
Invisible,
|
Invisible,
|
||||||
@@ -793,4 +721,45 @@ static std::map<uint32, std::string> bug_category_names = {
|
|||||||
{ Bug::Category::Mercenaries, "Mercenaries" }
|
{ Bug::Category::Mercenaries, "Mercenaries" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Stance {
|
||||||
|
constexpr uint32 Unknown = 0;
|
||||||
|
constexpr uint32 Passive = 1;
|
||||||
|
constexpr uint32 Balanced = 2;
|
||||||
|
constexpr uint32 Efficient = 3;
|
||||||
|
constexpr uint32 Reactive = 4;
|
||||||
|
constexpr uint32 Aggressive = 5;
|
||||||
|
constexpr uint32 Assist = 6;
|
||||||
|
constexpr uint32 Burn = 7;
|
||||||
|
constexpr uint32 Efficient2 = 8;
|
||||||
|
constexpr uint32 AEBurn = 9;
|
||||||
|
|
||||||
|
std::string GetName(uint8 stance_id);
|
||||||
|
uint8 GetIndex(uint8 stance_id);
|
||||||
|
bool IsValid(uint8 stance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint32, std::string> stance_names = {
|
||||||
|
{ Stance::Unknown, "Unknown" },
|
||||||
|
{ Stance::Passive, "Passive" },
|
||||||
|
{ Stance::Balanced, "Balanced" },
|
||||||
|
{ Stance::Efficient, "Efficient" },
|
||||||
|
{ Stance::Reactive, "Reactive" },
|
||||||
|
{ Stance::Aggressive, "Aggressive" },
|
||||||
|
{ Stance::Assist, "Assist" },
|
||||||
|
{ Stance::Burn, "Burn" },
|
||||||
|
{ Stance::Efficient2, "Efficient" },
|
||||||
|
{ Stance::AEBurn, "AE Burn" }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace PCNPCOnlyFlagType {
|
||||||
|
constexpr int PC = 1;
|
||||||
|
constexpr int NPC = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BookType {
|
||||||
|
constexpr uint8 Scroll = 0;
|
||||||
|
constexpr uint8 Book = 1;
|
||||||
|
constexpr uint8 ItemInfo = 2;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /*COMMON_EMU_CONSTANTS_H*/
|
#endif /*COMMON_EMU_CONSTANTS_H*/
|
||||||
|
|||||||
+4
-2
@@ -1,8 +1,6 @@
|
|||||||
// system use
|
// system use
|
||||||
N(OP_ExploreUnknown),
|
N(OP_ExploreUnknown),
|
||||||
// start (please add new opcodes in descending order and re-order any name changes where applicable)
|
// start (please add new opcodes in descending order and re-order any name changes where applicable)
|
||||||
N(OP_0x0193),
|
|
||||||
N(OP_0x0347),
|
|
||||||
N(OP_AAAction),
|
N(OP_AAAction),
|
||||||
N(OP_AAExpUpdate),
|
N(OP_AAExpUpdate),
|
||||||
N(OP_AcceptNewTask),
|
N(OP_AcceptNewTask),
|
||||||
@@ -67,6 +65,7 @@ N(OP_Buff),
|
|||||||
N(OP_BuffCreate),
|
N(OP_BuffCreate),
|
||||||
N(OP_BuffRemoveRequest),
|
N(OP_BuffRemoveRequest),
|
||||||
N(OP_Bug),
|
N(OP_Bug),
|
||||||
|
N(OP_BuyerItems),
|
||||||
N(OP_CameraEffect),
|
N(OP_CameraEffect),
|
||||||
N(OP_Camp),
|
N(OP_Camp),
|
||||||
N(OP_CancelSneakHide),
|
N(OP_CancelSneakHide),
|
||||||
@@ -355,6 +354,7 @@ N(OP_MercenaryTimer),
|
|||||||
N(OP_MercenaryTimerRequest),
|
N(OP_MercenaryTimerRequest),
|
||||||
N(OP_MercenaryUnknown1),
|
N(OP_MercenaryUnknown1),
|
||||||
N(OP_MercenaryUnsuspendResponse),
|
N(OP_MercenaryUnsuspendResponse),
|
||||||
|
N(OP_MerchantBulkItems),
|
||||||
N(OP_MobEnduranceUpdate),
|
N(OP_MobEnduranceUpdate),
|
||||||
N(OP_MobHealth),
|
N(OP_MobHealth),
|
||||||
N(OP_MobManaUpdate),
|
N(OP_MobManaUpdate),
|
||||||
@@ -373,6 +373,7 @@ N(OP_MultiLineMsg),
|
|||||||
N(OP_NewSpawn),
|
N(OP_NewSpawn),
|
||||||
N(OP_NewTitlesAvailable),
|
N(OP_NewTitlesAvailable),
|
||||||
N(OP_NewZone),
|
N(OP_NewZone),
|
||||||
|
N(OP_NPCMoveUpdate),
|
||||||
N(OP_OnLevelMessage),
|
N(OP_OnLevelMessage),
|
||||||
N(OP_OpenContainer),
|
N(OP_OpenContainer),
|
||||||
N(OP_OpenDiscordMerchant),
|
N(OP_OpenDiscordMerchant),
|
||||||
@@ -533,6 +534,7 @@ N(OP_Stamina),
|
|||||||
N(OP_Stun),
|
N(OP_Stun),
|
||||||
N(OP_Surname),
|
N(OP_Surname),
|
||||||
N(OP_SwapSpell),
|
N(OP_SwapSpell),
|
||||||
|
N(OP_SystemFingerprint),
|
||||||
N(OP_TargetBuffs),
|
N(OP_TargetBuffs),
|
||||||
N(OP_TargetCommand),
|
N(OP_TargetCommand),
|
||||||
N(OP_TargetHoTT),
|
N(OP_TargetHoTT),
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ const char* EQ::versions::ClientVersionName(ClientVersion client_version)
|
|||||||
return "RoF";
|
return "RoF";
|
||||||
case ClientVersion::RoF2:
|
case ClientVersion::RoF2:
|
||||||
return "RoF2";
|
return "RoF2";
|
||||||
|
case ClientVersion::Laurion:
|
||||||
|
return "Laurion";
|
||||||
default:
|
default:
|
||||||
return "Invalid Version";
|
return "Invalid Version";
|
||||||
};
|
};
|
||||||
@@ -76,6 +78,8 @@ uint32 EQ::versions::ConvertClientVersionToClientVersionBit(ClientVersion client
|
|||||||
return bitRoF;
|
return bitRoF;
|
||||||
case ClientVersion::RoF2:
|
case ClientVersion::RoF2:
|
||||||
return bitRoF2;
|
return bitRoF2;
|
||||||
|
case ClientVersion::Laurion:
|
||||||
|
return bitLaurion;
|
||||||
default:
|
default:
|
||||||
return bitUnknown;
|
return bitUnknown;
|
||||||
}
|
}
|
||||||
@@ -96,6 +100,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertClientVersionBitToClientVersion
|
|||||||
return ClientVersion::RoF;
|
return ClientVersion::RoF;
|
||||||
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF2) - 1)) :
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF2) - 1)) :
|
||||||
return ClientVersion::RoF2;
|
return ClientVersion::RoF2;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::Laurion) - 1)):
|
||||||
|
return ClientVersion::Laurion;
|
||||||
default:
|
default:
|
||||||
return ClientVersion::Unknown;
|
return ClientVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -184,6 +190,8 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
|
|||||||
return "RoF";
|
return "RoF";
|
||||||
case MobVersion::RoF2:
|
case MobVersion::RoF2:
|
||||||
return "RoF2";
|
return "RoF2";
|
||||||
|
case MobVersion::Laurion:
|
||||||
|
return "Laurion";
|
||||||
case MobVersion::NPC:
|
case MobVersion::NPC:
|
||||||
return "NPC";
|
return "NPC";
|
||||||
case MobVersion::NPCMerchant:
|
case MobVersion::NPCMerchant:
|
||||||
@@ -212,6 +220,8 @@ const char* EQ::versions::MobVersionName(MobVersion mob_version)
|
|||||||
return "Offline RoF";
|
return "Offline RoF";
|
||||||
case MobVersion::OfflineRoF2:
|
case MobVersion::OfflineRoF2:
|
||||||
return "Offline RoF2";
|
return "Offline RoF2";
|
||||||
|
case MobVersion::OfflineLaurion:
|
||||||
|
return "Offline Laurion";
|
||||||
default:
|
default:
|
||||||
return "Invalid Version";
|
return "Invalid Version";
|
||||||
};
|
};
|
||||||
@@ -235,6 +245,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertMobVersionToClientVersion(MobVe
|
|||||||
return ClientVersion::RoF;
|
return ClientVersion::RoF;
|
||||||
case MobVersion::RoF2:
|
case MobVersion::RoF2:
|
||||||
return ClientVersion::RoF2;
|
return ClientVersion::RoF2;
|
||||||
|
case MobVersion::Laurion:
|
||||||
|
return ClientVersion::Laurion;
|
||||||
default:
|
default:
|
||||||
return ClientVersion::Unknown;
|
return ClientVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -258,6 +270,8 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToMobVersion(ClientVe
|
|||||||
return MobVersion::RoF;
|
return MobVersion::RoF;
|
||||||
case ClientVersion::RoF2:
|
case ClientVersion::RoF2:
|
||||||
return MobVersion::RoF2;
|
return MobVersion::RoF2;
|
||||||
|
case ClientVersion::Laurion:
|
||||||
|
return MobVersion::Laurion;
|
||||||
default:
|
default:
|
||||||
return MobVersion::Unknown;
|
return MobVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -278,6 +292,8 @@ EQ::versions::MobVersion EQ::versions::ConvertPCMobVersionToOfflinePCMobVersion(
|
|||||||
return MobVersion::OfflineRoF;
|
return MobVersion::OfflineRoF;
|
||||||
case MobVersion::RoF2:
|
case MobVersion::RoF2:
|
||||||
return MobVersion::OfflineRoF2;
|
return MobVersion::OfflineRoF2;
|
||||||
|
case MobVersion::Laurion:
|
||||||
|
return MobVersion::OfflineLaurion;
|
||||||
default:
|
default:
|
||||||
return MobVersion::Unknown;
|
return MobVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -298,6 +314,8 @@ EQ::versions::MobVersion EQ::versions::ConvertOfflinePCMobVersionToPCMobVersion(
|
|||||||
return MobVersion::RoF;
|
return MobVersion::RoF;
|
||||||
case MobVersion::OfflineRoF2:
|
case MobVersion::OfflineRoF2:
|
||||||
return MobVersion::RoF2;
|
return MobVersion::RoF2;
|
||||||
|
case MobVersion::OfflineLaurion:
|
||||||
|
return MobVersion::Laurion;
|
||||||
default:
|
default:
|
||||||
return MobVersion::Unknown;
|
return MobVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -318,6 +336,8 @@ EQ::versions::ClientVersion EQ::versions::ConvertOfflinePCMobVersionToClientVers
|
|||||||
return ClientVersion::RoF;
|
return ClientVersion::RoF;
|
||||||
case MobVersion::OfflineRoF2:
|
case MobVersion::OfflineRoF2:
|
||||||
return ClientVersion::RoF2;
|
return ClientVersion::RoF2;
|
||||||
|
case MobVersion::OfflineLaurion:
|
||||||
|
return ClientVersion::Laurion;
|
||||||
default:
|
default:
|
||||||
return ClientVersion::Unknown;
|
return ClientVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -338,6 +358,8 @@ EQ::versions::MobVersion EQ::versions::ConvertClientVersionToOfflinePCMobVersion
|
|||||||
return MobVersion::OfflineRoF;
|
return MobVersion::OfflineRoF;
|
||||||
case ClientVersion::RoF2:
|
case ClientVersion::RoF2:
|
||||||
return MobVersion::OfflineRoF2;
|
return MobVersion::OfflineRoF2;
|
||||||
|
case ClientVersion::Laurion:
|
||||||
|
return MobVersion::OfflineLaurion;
|
||||||
default:
|
default:
|
||||||
return MobVersion::Unknown;
|
return MobVersion::Unknown;
|
||||||
}
|
}
|
||||||
@@ -388,6 +410,27 @@ const char* EQ::expansions::ExpansionName(Expansion expansion)
|
|||||||
return "Rain of Fear";
|
return "Rain of Fear";
|
||||||
case Expansion::CotF:
|
case Expansion::CotF:
|
||||||
return "Call of the Forsaken";
|
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:
|
default:
|
||||||
return "Invalid Expansion";
|
return "Invalid Expansion";
|
||||||
}
|
}
|
||||||
@@ -441,6 +484,26 @@ uint32 EQ::expansions::ConvertExpansionToExpansionBit(Expansion expansion)
|
|||||||
return bitRoF;
|
return bitRoF;
|
||||||
case Expansion::CotF:
|
case Expansion::CotF:
|
||||||
return bitCotF;
|
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:
|
default:
|
||||||
return bitEverQuest;
|
return bitEverQuest;
|
||||||
}
|
}
|
||||||
@@ -489,6 +552,26 @@ EQ::expansions::Expansion EQ::expansions::ConvertExpansionBitToExpansion(uint32
|
|||||||
return Expansion::RoF;
|
return Expansion::RoF;
|
||||||
case bitCotF:
|
case bitCotF:
|
||||||
return Expansion::CotF;
|
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:
|
default:
|
||||||
return Expansion::EverQuest;
|
return Expansion::EverQuest;
|
||||||
}
|
}
|
||||||
@@ -537,6 +620,26 @@ uint32 EQ::expansions::ConvertExpansionToExpansionsMask(Expansion expansion)
|
|||||||
return maskRoF;
|
return maskRoF;
|
||||||
case Expansion::CotF:
|
case Expansion::CotF:
|
||||||
return maskCotF;
|
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:
|
default:
|
||||||
return maskEverQuest;
|
return maskEverQuest;
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-9
@@ -36,7 +36,8 @@ namespace EQ
|
|||||||
SoD, // Build: 'Dec 19 2008 15:22:49'
|
SoD, // Build: 'Dec 19 2008 15:22:49'
|
||||||
UF, // Build: 'Jun 8 2010 16:44:32'
|
UF, // Build: 'Jun 8 2010 16:44:32'
|
||||||
RoF, // Build: 'Dec 10 2012 17:35:44'
|
RoF, // Build: 'Dec 10 2012 17:35:44'
|
||||||
RoF2 // Build: 'May 10 2013 23:30:08'
|
RoF2, // Build: 'May 10 2013 23:30:08'
|
||||||
|
Laurion
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ClientVersionBitmask : uint32 {
|
enum ClientVersionBitmask : uint32 {
|
||||||
@@ -48,6 +49,7 @@ namespace EQ
|
|||||||
bitUF = 0x00000010,
|
bitUF = 0x00000010,
|
||||||
bitRoF = 0x00000020,
|
bitRoF = 0x00000020,
|
||||||
bitRoF2 = 0x00000040,
|
bitRoF2 = 0x00000040,
|
||||||
|
bitLaurion = 0x00000080,
|
||||||
maskUnknown = 0x00000000,
|
maskUnknown = 0x00000000,
|
||||||
maskTitaniumAndEarlier = 0x00000003,
|
maskTitaniumAndEarlier = 0x00000003,
|
||||||
maskSoFAndEarlier = 0x00000007,
|
maskSoFAndEarlier = 0x00000007,
|
||||||
@@ -59,10 +61,11 @@ namespace EQ
|
|||||||
maskUFAndLater = 0xFFFFFFF0,
|
maskUFAndLater = 0xFFFFFFF0,
|
||||||
maskRoFAndLater = 0xFFFFFFE0,
|
maskRoFAndLater = 0xFFFFFFE0,
|
||||||
maskRoF2AndLater = 0xFFFFFFC0,
|
maskRoF2AndLater = 0xFFFFFFC0,
|
||||||
|
maskLaurionAndLater = 0xFFFFFF80,
|
||||||
maskAllClients = 0xFFFFFFFF
|
maskAllClients = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
const ClientVersion LastClientVersion = ClientVersion::RoF2;
|
const ClientVersion LastClientVersion = ClientVersion::Laurion;
|
||||||
const size_t ClientVersionCount = (static_cast<size_t>(LastClientVersion) + 1);
|
const size_t ClientVersionCount = (static_cast<size_t>(LastClientVersion) + 1);
|
||||||
|
|
||||||
bool IsValidClientVersion(ClientVersion client_version);
|
bool IsValidClientVersion(ClientVersion client_version);
|
||||||
@@ -80,6 +83,7 @@ namespace EQ
|
|||||||
UF,
|
UF,
|
||||||
RoF,
|
RoF,
|
||||||
RoF2,
|
RoF2,
|
||||||
|
Laurion,
|
||||||
NPC,
|
NPC,
|
||||||
NPCMerchant,
|
NPCMerchant,
|
||||||
Merc,
|
Merc,
|
||||||
@@ -93,13 +97,14 @@ namespace EQ
|
|||||||
OfflineSoD,
|
OfflineSoD,
|
||||||
OfflineUF,
|
OfflineUF,
|
||||||
OfflineRoF,
|
OfflineRoF,
|
||||||
OfflineRoF2
|
OfflineRoF2,
|
||||||
|
OfflineLaurion
|
||||||
};
|
};
|
||||||
|
|
||||||
const MobVersion LastMobVersion = MobVersion::OfflineRoF2;
|
const MobVersion LastMobVersion = MobVersion::OfflineLaurion;
|
||||||
const MobVersion LastPCMobVersion = MobVersion::RoF2;
|
const MobVersion LastPCMobVersion = MobVersion::Laurion;
|
||||||
const MobVersion LastNonPCMobVersion = MobVersion::BotPet;
|
const MobVersion LastNonPCMobVersion = MobVersion::BotPet;
|
||||||
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineRoF2;
|
const MobVersion LastOfflinePCMobVersion = MobVersion::OfflineLaurion;
|
||||||
const size_t MobVersionCount = (static_cast<size_t>(LastMobVersion) + 1);
|
const size_t MobVersionCount = (static_cast<size_t>(LastMobVersion) + 1);
|
||||||
|
|
||||||
bool IsValidMobVersion(MobVersion mob_version);
|
bool IsValidMobVersion(MobVersion mob_version);
|
||||||
@@ -131,7 +136,8 @@ namespace EQ
|
|||||||
ucsSoDCombined = 'D',
|
ucsSoDCombined = 'D',
|
||||||
ucsUFCombined = 'E',
|
ucsUFCombined = 'E',
|
||||||
ucsRoFCombined = 'F',
|
ucsRoFCombined = 'F',
|
||||||
ucsRoF2Combined = 'G'
|
ucsRoF2Combined = 'G',
|
||||||
|
ucsLaurionCombined = 'G'
|
||||||
};
|
};
|
||||||
|
|
||||||
} /*versions*/
|
} /*versions*/
|
||||||
@@ -158,7 +164,17 @@ namespace EQ
|
|||||||
HoT,
|
HoT,
|
||||||
VoA,
|
VoA,
|
||||||
RoF,
|
RoF,
|
||||||
CotF
|
CotF,
|
||||||
|
TDS,
|
||||||
|
TBM,
|
||||||
|
EoK,
|
||||||
|
RoS,
|
||||||
|
TBL,
|
||||||
|
ToV,
|
||||||
|
CoV,
|
||||||
|
ToL,
|
||||||
|
NoS,
|
||||||
|
LS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExpansionBitmask : uint32 {
|
enum ExpansionBitmask : uint32 {
|
||||||
@@ -183,6 +199,16 @@ namespace EQ
|
|||||||
bitVoA = 0x00020000,
|
bitVoA = 0x00020000,
|
||||||
bitRoF = 0x00040000,
|
bitRoF = 0x00040000,
|
||||||
bitCotF = 0x00080000,
|
bitCotF = 0x00080000,
|
||||||
|
bitTDS = 0x00100000,
|
||||||
|
bitTBM = 0x00200000,
|
||||||
|
bitEoK = 0x00400000,
|
||||||
|
bitRoS = 0x00800000,
|
||||||
|
bitTBL = 0x01000000,
|
||||||
|
bitToV = 0x02000000,
|
||||||
|
bitCoV = 0x04000000,
|
||||||
|
bitToL = 0x08000000,
|
||||||
|
bitNoS = 0x10000000,
|
||||||
|
bitLS = 0x20000000,
|
||||||
maskEverQuest = 0x00000000,
|
maskEverQuest = 0x00000000,
|
||||||
maskRoK = 0x00000001,
|
maskRoK = 0x00000001,
|
||||||
maskSoV = 0x00000003,
|
maskSoV = 0x00000003,
|
||||||
@@ -203,7 +229,17 @@ namespace EQ
|
|||||||
maskHoT = 0x0001FFFF,
|
maskHoT = 0x0001FFFF,
|
||||||
maskVoA = 0x0003FFFF,
|
maskVoA = 0x0003FFFF,
|
||||||
maskRoF = 0x0007FFFF,
|
maskRoF = 0x0007FFFF,
|
||||||
maskCotF = 0x000FFFFF
|
maskCotF = 0x000FFFFF,
|
||||||
|
maskTDS = 0x001FFFFF,
|
||||||
|
maskTBM = 0x003FFFFF,
|
||||||
|
maskEoK = 0x007FFFFF,
|
||||||
|
maskRoS = 0x00FFFFFF,
|
||||||
|
maskTBL = 0x01FFFFFF,
|
||||||
|
maskToV = 0x03FFFFFF,
|
||||||
|
maskCoV = 0x07FFFFFF,
|
||||||
|
maskToL = 0x0FFFFFFF,
|
||||||
|
maskNoS = 0x1FFFFFFF,
|
||||||
|
maskLS = 0x3FFFFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* ExpansionName(Expansion expansion);
|
const char* ExpansionName(Expansion expansion);
|
||||||
|
|||||||
+47
-4
@@ -758,10 +758,50 @@ typedef enum {
|
|||||||
FilterFocusEffects = 22, //0=show, 1=hide
|
FilterFocusEffects = 22, //0=show, 1=hide
|
||||||
FilterPetSpells = 23, //0=show, 1=hide
|
FilterPetSpells = 23, //0=show, 1=hide
|
||||||
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
|
FilterHealOverTime = 24, //0=show, 1=mine only, 2=hide
|
||||||
FilterUnknown25 = 25,
|
FilterItemSpeech = 25, //0=show, 1=hide // RoF2 Confirmed
|
||||||
FilterUnknown26 = 26,
|
FilterStrikethrough = 26, //0=show, 1=hide // RoF2 Confirmed
|
||||||
FilterUnknown27 = 27,
|
FilterStuns = 27, //0=show, 1=hide // RoF2 Confirmed
|
||||||
FilterUnknown28 = 28,
|
FilterBardSongsOnPets = 28, //0=show, 1=hide // RoF2 Confirmed
|
||||||
|
FilterSwarmPetDeath = 29,
|
||||||
|
FilterFellowshipChat = 30,
|
||||||
|
FilterMercenaryMessages = 31,
|
||||||
|
FilterSpam = 32,
|
||||||
|
FilterAchievements = 33,
|
||||||
|
FilterPvPMessages = 34,
|
||||||
|
FilterSpellNameInCast = 35,
|
||||||
|
FilterRandomMine = 36,
|
||||||
|
FilterRandomGroupRaid = 37,
|
||||||
|
FilterRandomOthers = 38,
|
||||||
|
FilterEnvironmentalDamage = 39,
|
||||||
|
FilterMessages = 40,
|
||||||
|
FilterOverwriteDetrimental = 41,
|
||||||
|
FilterOverwriteBeneficial = 42,
|
||||||
|
FilterCantUseCommand = 43,
|
||||||
|
FilterCombatAbilityReuse = 44,
|
||||||
|
FilterAAAbilityReuse = 45,
|
||||||
|
FilterProcBeginCasting = 46,
|
||||||
|
FilterDestroyedItems = 47,
|
||||||
|
FilterYourAuras = 48,
|
||||||
|
FilterOtherAuras = 49,
|
||||||
|
FilterYourHeals = 50,
|
||||||
|
FilterOtherHeals = 51,
|
||||||
|
FilterYourDoTs = 52,
|
||||||
|
FilterOtherDoTs = 53,
|
||||||
|
FilterOtherDirectDamage = 54,
|
||||||
|
FilterSpellEmotes = 55,
|
||||||
|
FilterFactionMessages = 56,
|
||||||
|
FilterTauntMessages = 57,
|
||||||
|
FilterYourDisciplines = 58,
|
||||||
|
FilterOtherDisplines = 59,
|
||||||
|
FilterAchievementsOthers = 60,
|
||||||
|
FilterRaidVictory = 61,
|
||||||
|
FilterOtherDirectDamageCrits = 62,
|
||||||
|
FilterDoTYoursCritical = 63,
|
||||||
|
FilterDoTOthersCritical = 64,
|
||||||
|
FilterDoTDamageTaken = 65,
|
||||||
|
FilterHealsReceived = 66,
|
||||||
|
FilterHealsYoursCritical = 67,
|
||||||
|
FilterHealsOthersCritical = 68,
|
||||||
_FilterCount
|
_FilterCount
|
||||||
} eqFilterType;
|
} eqFilterType;
|
||||||
|
|
||||||
@@ -1129,4 +1169,7 @@ enum ExpSource
|
|||||||
#define PARCEL_LIMIT 5
|
#define PARCEL_LIMIT 5
|
||||||
#define PARCEL_BEGIN_SLOT 1
|
#define PARCEL_BEGIN_SLOT 1
|
||||||
|
|
||||||
|
namespace DoorType {
|
||||||
|
constexpr uint32 BuyerStall = 155;
|
||||||
|
}
|
||||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers
|
|||||||
RoF2::constants::EXPANSIONS_MASK,
|
RoF2::constants::EXPANSIONS_MASK,
|
||||||
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
RoF2::constants::CHARACTER_CREATION_LIMIT,
|
||||||
RoF2::constants::SAY_LINK_BODY_SIZE
|
RoF2::constants::SAY_LINK_BODY_SIZE
|
||||||
|
),
|
||||||
|
/*[ClientVersion::Laurion] =*/
|
||||||
|
EQ::constants::LookupEntry(
|
||||||
|
Laurion::constants::EXPANSION,
|
||||||
|
Laurion::constants::EXPANSION_BIT,
|
||||||
|
Laurion::constants::EXPANSIONS_MASK,
|
||||||
|
Laurion::constants::CHARACTER_CREATION_LIMIT,
|
||||||
|
Laurion::constants::SAY_LINK_BODY_SIZE
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -370,6 +378,33 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
|||||||
RoF2::inventory::ConcatenateInvTypeLimbo,
|
RoF2::inventory::ConcatenateInvTypeLimbo,
|
||||||
RoF2::inventory::AllowOverLevelEquipment
|
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] =*/
|
/*[MobVersion::NPC] =*/
|
||||||
EQ::inventory::LookupEntry(
|
EQ::inventory::LookupEntry(
|
||||||
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
|
EQ::inventory::LookupEntry::InventoryTypeSize_Struct(
|
||||||
@@ -743,6 +778,33 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers
|
|||||||
RoF2::invbag::SLOT_COUNT,
|
RoF2::invbag::SLOT_COUNT,
|
||||||
RoF2::invaug::SOCKET_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,
|
false,
|
||||||
false,
|
false,
|
||||||
@@ -994,6 +1056,10 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
|
|||||||
EQ::behavior::LookupEntry(
|
EQ::behavior::LookupEntry(
|
||||||
RoF2::behavior::CoinHasWeight
|
RoF2::behavior::CoinHasWeight
|
||||||
),
|
),
|
||||||
|
/*[MobVersion::LS] =*/
|
||||||
|
EQ::behavior::LookupEntry(
|
||||||
|
RoF2::behavior::CoinHasWeight
|
||||||
|
),
|
||||||
/*[MobVersion::NPC] =*/
|
/*[MobVersion::NPC] =*/
|
||||||
EQ::behavior::LookupEntry(
|
EQ::behavior::LookupEntry(
|
||||||
EQ::behavior::CoinHasWeight
|
EQ::behavior::CoinHasWeight
|
||||||
@@ -1047,6 +1113,10 @@ static const EQ::behavior::LookupEntry behavior_static_lookup_entries[EQ::versio
|
|||||||
RoF::behavior::CoinHasWeight
|
RoF::behavior::CoinHasWeight
|
||||||
),
|
),
|
||||||
/*[MobVersion::OfflineRoF2] =*/
|
/*[MobVersion::OfflineRoF2] =*/
|
||||||
|
EQ::behavior::LookupEntry(
|
||||||
|
RoF2::behavior::CoinHasWeight
|
||||||
|
),
|
||||||
|
/*[MobVersion::OfflineLS] =*/
|
||||||
EQ::behavior::LookupEntry(
|
EQ::behavior::LookupEntry(
|
||||||
RoF2::behavior::CoinHasWeight
|
RoF2::behavior::CoinHasWeight
|
||||||
)
|
)
|
||||||
@@ -1202,6 +1272,19 @@ static const EQ::spells::LookupEntry spells_static_lookup_entries[EQ::versions::
|
|||||||
RoF2::spells::NPC_BUFFS,
|
RoF2::spells::NPC_BUFFS,
|
||||||
RoF2::spells::PET_BUFFS,
|
RoF2::spells::PET_BUFFS,
|
||||||
RoF2::spells::MERC_BUFFS
|
RoF2::spells::MERC_BUFFS
|
||||||
|
),
|
||||||
|
/*[ClientVersion::Laurion] =*/
|
||||||
|
EQ::spells::LookupEntry(
|
||||||
|
Laurion::spells::SPELL_ID_MAX,
|
||||||
|
Laurion::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
|
||||||
|
Laurion::spells::LONG_BUFFS,
|
||||||
|
Laurion::spells::SHORT_BUFFS,
|
||||||
|
Laurion::spells::DISC_BUFFS,
|
||||||
|
Laurion::spells::TOTAL_BUFFS,
|
||||||
|
Laurion::spells::NPC_BUFFS,
|
||||||
|
Laurion::spells::PET_BUFFS,
|
||||||
|
Laurion::spells::MERC_BUFFS
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@
|
|||||||
#include "../common/patches/uf_limits.h"
|
#include "../common/patches/uf_limits.h"
|
||||||
#include "../common/patches/rof_limits.h"
|
#include "../common/patches/rof_limits.h"
|
||||||
#include "../common/patches/rof2_limits.h"
|
#include "../common/patches/rof2_limits.h"
|
||||||
|
#include "../common/patches/laurion_limits.h"
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ
|
||||||
{
|
{
|
||||||
|
|||||||
+376
-48
@@ -47,6 +47,13 @@ static const uint32 ADVANCED_LORE_LENGTH = 8192;
|
|||||||
*/
|
*/
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
|
struct EqGuid
|
||||||
|
{
|
||||||
|
uint32_t Id;
|
||||||
|
uint16_t WorldId;
|
||||||
|
uint16_t Reserved;
|
||||||
|
};
|
||||||
|
|
||||||
struct LoginInfo_Struct {
|
struct LoginInfo_Struct {
|
||||||
/*000*/ char login_info[64];
|
/*000*/ char login_info[64];
|
||||||
/*064*/ uint8 unknown064[124];
|
/*064*/ uint8 unknown064[124];
|
||||||
@@ -323,6 +330,8 @@ union
|
|||||||
bool show_name;
|
bool show_name;
|
||||||
bool guild_show;
|
bool guild_show;
|
||||||
bool trader;
|
bool trader;
|
||||||
|
bool buyer;
|
||||||
|
EqGuid CharacterGuid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerState_Struct {
|
struct PlayerState_Struct {
|
||||||
@@ -1620,6 +1629,32 @@ struct MoveItem_Struct
|
|||||||
/*0012*/
|
/*0012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// New for RoF2 - Size: 12
|
||||||
|
struct InventorySlot_Struct
|
||||||
|
{
|
||||||
|
/*000*/ int16 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1
|
||||||
|
/*002*/ int16 Unknown02;
|
||||||
|
/*004*/ int16 Slot;
|
||||||
|
/*006*/ int16 SubIndex;
|
||||||
|
/*008*/ int16 AugIndex; // Guessing - Seen 0xffff
|
||||||
|
/*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID
|
||||||
|
/*012*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItemSub_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ InventorySlot_Struct from_slot;
|
||||||
|
/*0012*/ InventorySlot_Struct to_slot;
|
||||||
|
/*0024*/ uint32 number_in_stack;
|
||||||
|
/*0028*/ uint8 unknown[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiMoveItem_Struct
|
||||||
|
{
|
||||||
|
/*0000*/ uint32 count;
|
||||||
|
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||||
|
};
|
||||||
|
|
||||||
// both MoveItem_Struct/DeleteItem_Struct server structures will be changing to a structure-based slot format..this will
|
// both MoveItem_Struct/DeleteItem_Struct server structures will be changing to a structure-based slot format..this will
|
||||||
// be used for handling SoF/SoD/etc... time stamps sent using the MoveItem_Struct format. (nothing will be done with this
|
// be used for handling SoF/SoD/etc... time stamps sent using the MoveItem_Struct format. (nothing will be done with this
|
||||||
// info at the moment..but, it is forwarded on to the server for handling/future use)
|
// info at the moment..but, it is forwarded on to the server for handling/future use)
|
||||||
@@ -3113,11 +3148,14 @@ struct BazaarSearchResults_Struct {
|
|||||||
// Barter/Buyer
|
// Barter/Buyer
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
enum {
|
#define MAX_BUYER_COMPENSATION_ITEMS 10
|
||||||
|
|
||||||
|
enum BarterBuyerActions {
|
||||||
Barter_BuyerSearch = 0,
|
Barter_BuyerSearch = 0,
|
||||||
Barter_SellerSearch = 1,
|
Barter_SellerSearch = 1,
|
||||||
Barter_BuyerModeOn = 2,
|
Barter_BuyerModeOn = 2,
|
||||||
Barter_BuyerModeOff = 3,
|
Barter_BuyerModeOff = 3,
|
||||||
|
Barter_BuyerItemStart = 4,
|
||||||
Barter_BuyerItemUpdate = 5,
|
Barter_BuyerItemUpdate = 5,
|
||||||
Barter_BuyerItemRemove = 6,
|
Barter_BuyerItemRemove = 6,
|
||||||
Barter_SellItem = 7,
|
Barter_SellItem = 7,
|
||||||
@@ -3132,41 +3170,348 @@ enum {
|
|||||||
Barter_BuyerSearchResults = 16,
|
Barter_BuyerSearchResults = 16,
|
||||||
Barter_Welcome = 17,
|
Barter_Welcome = 17,
|
||||||
Barter_WelcomeMessageUpdate = 19,
|
Barter_WelcomeMessageUpdate = 19,
|
||||||
|
Barter_Greeting = 20,
|
||||||
Barter_BuyerItemInspect = 21,
|
Barter_BuyerItemInspect = 21,
|
||||||
Barter_Unknown23 = 23
|
Barter_OpenBarterWindow = 23,
|
||||||
|
Barter_AddToBarterWindow = 26,
|
||||||
|
Barter_RemoveFromBarterWindow = 27,
|
||||||
|
Barter_RemoveFromMerchantWindow = 50, //Not a client item. Used for internal communications.
|
||||||
|
Barter_FailedTransaction = 51,
|
||||||
|
Barter_BuyerCouldNotBeFound = 52,
|
||||||
|
Barter_FailedBuyerChecks = 53,
|
||||||
|
Barter_SellerCouldNotBeFound = 54,
|
||||||
|
Barter_FailedSellerChecks = 55
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BarterBuyerSubActions {
|
||||||
|
Barter_Success = 0,
|
||||||
|
Barter_Failure = 1,
|
||||||
|
Barter_DataOutOfDate = 4,
|
||||||
|
Barter_SellerDoesNotHaveItem = 6,
|
||||||
|
Barter_SameZone = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BuyerBarter {
|
||||||
|
Off = 0,
|
||||||
|
On = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerRemoveItem_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 buy_slot_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerRemoveItemFromMerchantWindow_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 unknown_004;
|
||||||
|
uint32 buy_slot_id;
|
||||||
|
uint32 unknown_012;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerGeneric_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char payload[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerMessaging_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 sub_action;
|
||||||
|
uint32 zone_id;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 buyer_entity_id;
|
||||||
|
char buyer_name[64];
|
||||||
|
uint32 buy_item_id;
|
||||||
|
uint32 buy_item_qty;
|
||||||
|
uint64 buy_item_cost;
|
||||||
|
uint32 buy_item_icon;
|
||||||
|
uint32 seller_entity_id;
|
||||||
|
char seller_name[64];
|
||||||
|
char item_name[64];
|
||||||
|
uint32 slot;
|
||||||
|
uint32 seller_quantity;
|
||||||
|
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerAddBuyertoBarterWindow_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 zone_id;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 buyer_entity_id;
|
||||||
|
char buyer_name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerRemoveBuyerFromBarterWindow_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 buyer_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerBrowsing_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char char_name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerGreeting_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 buyer_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuyerWelcomeMessageUpdate_Struct {
|
struct BuyerWelcomeMessageUpdate_Struct {
|
||||||
/*000*/ uint32 Action;
|
uint32 action;
|
||||||
/*004*/ char WelcomeMessage[256];
|
char welcome_message[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuyerItemSearch_Struct {
|
struct BuyerLineTradeItems_Struct {
|
||||||
/*000*/ uint32 Unknown000;
|
uint32 item_id;
|
||||||
/*004*/ char SearchString[64];
|
uint32 item_quantity;
|
||||||
|
uint32 item_icon;
|
||||||
|
std::string item_name;
|
||||||
|
|
||||||
|
void operator*=(uint32 multiplier)
|
||||||
|
{
|
||||||
|
this->item_quantity *= multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_quantity),
|
||||||
|
CEREAL_NVP(item_icon),
|
||||||
|
CEREAL_NVP(item_name)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuyerItemSearchResultEntry_Struct {
|
struct BuyerLineItems_Struct {
|
||||||
/*000*/ char ItemName[64];
|
uint32 slot;
|
||||||
/*064*/ uint32 ItemID;
|
uint8 enabled;
|
||||||
/*068*/ uint32 Unknown068;
|
uint32 item_id;
|
||||||
/*072*/ uint32 Unknown072;
|
std::string item_name;
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 item_toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(slot),
|
||||||
|
CEREAL_NVP(enabled),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(item_icon),
|
||||||
|
CEREAL_NVP(item_quantity),
|
||||||
|
CEREAL_NVP(item_toggle),
|
||||||
|
CEREAL_NVP(item_cost),
|
||||||
|
CEREAL_NVP(trade_items)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_BUYER_ITEMSEARCH_RESULTS 200
|
struct BuyerBuyLines_Struct {
|
||||||
|
uint32 action;
|
||||||
|
union {
|
||||||
|
uint32 no_items;
|
||||||
|
uint32 string_length;
|
||||||
|
};
|
||||||
|
std::vector<BuyerLineItems_Struct> buy_lines;
|
||||||
|
|
||||||
struct BuyerItemSearchResults_Struct {
|
template<class Archive>
|
||||||
uint32 Action;
|
void serialize(Archive &archive)
|
||||||
uint32 ResultCount;
|
{
|
||||||
BuyerItemSearchResultEntry_Struct Results[MAX_BUYER_ITEMSEARCH_RESULTS];
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(no_items),
|
||||||
|
CEREAL_NVP(buy_lines)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineSellItem_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 sub_action;
|
||||||
|
uint32 error_code;
|
||||||
|
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
|
||||||
|
uint32 buyer_entity_id;
|
||||||
|
uint32 buyer_id;
|
||||||
|
std::string buyer_name;
|
||||||
|
uint32 seller_entity_id;
|
||||||
|
std::string seller_name;
|
||||||
|
uint32 slot;
|
||||||
|
uint8 enabled;
|
||||||
|
uint32 item_id;
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 item_toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
uint32 no_trade_items;
|
||||||
|
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||||
|
uint32 seller_quantity;
|
||||||
|
uint32 zone_id;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(sub_action),
|
||||||
|
CEREAL_NVP(error_code),
|
||||||
|
CEREAL_NVP(purchase_method),
|
||||||
|
CEREAL_NVP(buyer_entity_id),
|
||||||
|
CEREAL_NVP(buyer_id),
|
||||||
|
CEREAL_NVP(buyer_name),
|
||||||
|
CEREAL_NVP(seller_entity_id),
|
||||||
|
CEREAL_NVP(seller_name),
|
||||||
|
CEREAL_NVP(slot),
|
||||||
|
CEREAL_NVP(enabled),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(item_icon),
|
||||||
|
CEREAL_NVP(item_quantity),
|
||||||
|
CEREAL_NVP(item_toggle),
|
||||||
|
CEREAL_NVP(item_cost),
|
||||||
|
CEREAL_NVP(no_trade_items),
|
||||||
|
CEREAL_NVP(trade_items),
|
||||||
|
CEREAL_NVP(seller_quantity),
|
||||||
|
CEREAL_NVP(zone_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineItemsSearch_Struct {
|
||||||
|
uint32 slot;
|
||||||
|
uint8 enabled;
|
||||||
|
uint32 item_id;
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 item_toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 buyer_entity_id;
|
||||||
|
uint32 buyer_zone_id;
|
||||||
|
uint32 buyer_zone_instance_id;
|
||||||
|
std::string buyer_name;
|
||||||
|
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(slot),
|
||||||
|
CEREAL_NVP(enabled),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(item_icon),
|
||||||
|
CEREAL_NVP(item_quantity),
|
||||||
|
CEREAL_NVP(item_toggle),
|
||||||
|
CEREAL_NVP(item_cost),
|
||||||
|
CEREAL_NVP(buyer_id),
|
||||||
|
CEREAL_NVP(buyer_entity_id),
|
||||||
|
CEREAL_NVP(buyer_zone_id),
|
||||||
|
CEREAL_NVP(buyer_zone_instance_id),
|
||||||
|
CEREAL_NVP(buyer_name),
|
||||||
|
CEREAL_NVP(trade_items)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineSearch_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 no_items;
|
||||||
|
std::string search_string;
|
||||||
|
uint32 transaction_id;
|
||||||
|
std::vector<BuyerLineItemsSearch_Struct> buy_line;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(no_items),
|
||||||
|
CEREAL_NVP(search_string),
|
||||||
|
CEREAL_NVP(transaction_id),
|
||||||
|
CEREAL_NVP(buy_line)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerSetAppearance_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 entity_id;
|
||||||
|
uint32 status; // 0 off 1 on
|
||||||
|
char buyer_name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BarterItemSearchLinkRequest_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 searcher_id;
|
||||||
|
uint32 unknown_008;
|
||||||
|
uint32 unknown_012;
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 unknown_020;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerInspectRequest_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 approval;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BarterSearchRequest_Struct {
|
struct BarterSearchRequest_Struct {
|
||||||
uint32 Action;
|
uint32 action;
|
||||||
char SearchString[64];
|
char search_string[64];
|
||||||
uint32 SearchID;
|
uint32 transaction_id;
|
||||||
|
uint32 unknown_072;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint8 search_scope; //0 All Buyers, 1 Local Buyers
|
||||||
|
uint16 zone_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BuyerItemSearch_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char search_string[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerItemSearchResultEntry_Struct {
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 unknown_072;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_icon),
|
||||||
|
CEREAL_NVP(unknown_072)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerItemSearchResults_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 result_count;
|
||||||
|
std::vector<BuyerItemSearchResultEntry_Struct> results;
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(result_count),
|
||||||
|
CEREAL_NVP(results)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//old below here
|
||||||
struct BuyerItemSearchLinkRequest_Struct {
|
struct BuyerItemSearchLinkRequest_Struct {
|
||||||
/*000*/ uint32 Action; // 0x00000015
|
/*000*/ uint32 Action; // 0x00000015
|
||||||
/*004*/ uint32 ItemID;
|
/*004*/ uint32 ItemID;
|
||||||
@@ -3174,31 +3519,6 @@ struct BuyerItemSearchLinkRequest_Struct {
|
|||||||
/*012*/ uint32 Unknown012;
|
/*012*/ uint32 Unknown012;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BarterItemSearchLinkRequest_Struct {
|
|
||||||
/*000*/ uint32 Action; // 0x0000000E
|
|
||||||
/*004*/ uint32 SearcherID;
|
|
||||||
/*008*/ uint32 Unknown008;
|
|
||||||
/*012*/ uint32 Unknown012;
|
|
||||||
/*016*/ uint32 ItemID;
|
|
||||||
/*020*/ uint32 Unknown020;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BuyerInspectRequest_Struct {
|
|
||||||
uint32 Action;
|
|
||||||
uint32 BuyerID;
|
|
||||||
uint32 Approval;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BuyerBrowsing_Struct {
|
|
||||||
uint32 Action;
|
|
||||||
char PlayerName[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BuyerRemoveItem_Struct {
|
|
||||||
uint32 Action;
|
|
||||||
uint32 BuySlot;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ServerSideFilters_Struct {
|
struct ServerSideFilters_Struct {
|
||||||
uint8 clientattackfilters; // 0) No, 1) All (players) but self, 2) All (players) but group
|
uint8 clientattackfilters; // 0) No, 1) All (players) but self, 2) All (players) but group
|
||||||
uint8 npcattackfilters; // 0) No, 1) Ignore NPC misses (all), 2) Ignore NPC Misses + Attacks (all but self), 3) Ignores NPC Misses + Attacks (all but group)
|
uint8 npcattackfilters; // 0) No, 1) Ignore NPC misses (all), 2) Ignore NPC Misses + Attacks (all but self), 3) Ignores NPC Misses + Attacks (all but group)
|
||||||
@@ -6040,9 +6360,12 @@ enum BazaarTraderBarterActions {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum BazaarPurchaseActions {
|
enum BazaarPurchaseActions {
|
||||||
ByVendor = 0,
|
BazaarByVendor = 0,
|
||||||
ByParcel = 1,
|
BazaarByParcel = 1,
|
||||||
ByDirectToInventory = 2
|
BazaarByDirectToInventory = 2,
|
||||||
|
BarterByVendor = 0,
|
||||||
|
BarterInBazaar = 1,
|
||||||
|
BarterOutsideBazaar = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BazaarPurchaseSubActions {
|
enum BazaarPurchaseSubActions {
|
||||||
@@ -6116,6 +6439,11 @@ struct BazaarSearchMessaging_Struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BuylineItemDetails_Struct {
|
||||||
|
uint64 item_cost;
|
||||||
|
uint32 item_quantity;
|
||||||
|
};
|
||||||
|
|
||||||
// Restore structure packing to default
|
// Restore structure packing to default
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ void EQEmuConfig::parse_config()
|
|||||||
auto_database_updates = true;
|
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());
|
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
|
||||||
|
|
||||||
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").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();
|
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
|
||||||
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
|
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
|
||||||
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
|
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
|
||||||
|
OpcodeDir = _root["server"]["directories"].get("opcodes", "./").asString();
|
||||||
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
||||||
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class EQEmuConfig
|
|||||||
std::string PluginDir;
|
std::string PluginDir;
|
||||||
std::string LuaModuleDir;
|
std::string LuaModuleDir;
|
||||||
std::string PatchDir;
|
std::string PatchDir;
|
||||||
|
std::string OpcodeDir;
|
||||||
std::string SharedMemDir;
|
std::string SharedMemDir;
|
||||||
std::string LogDir;
|
std::string LogDir;
|
||||||
|
|
||||||
|
|||||||
@@ -789,50 +789,36 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string npc_info = fmt::format(
|
||||||
|
"{} ({})\n",
|
||||||
|
e.npc_name,
|
||||||
|
e.npc_id
|
||||||
|
);
|
||||||
|
|
||||||
|
npc_info += fmt::format(
|
||||||
|
"Is Quest Handin: {}",
|
||||||
|
e.is_quest_handin ? "Yes" : "No"
|
||||||
|
);
|
||||||
|
|
||||||
std::vector<DiscordField> f = {};
|
std::vector<DiscordField> f = {};
|
||||||
|
|
||||||
|
|
||||||
|
BuildDiscordField(&f, "NPC", npc_info);
|
||||||
|
|
||||||
if (!handin_items_info.empty()) {
|
if (!handin_items_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Handin Items", handin_items_info);
|
||||||
&f,
|
|
||||||
"Handin Items",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
handin_items_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handin_money_info.empty()) {
|
if (!handin_money_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Handin Money", handin_money_info);
|
||||||
&f,
|
|
||||||
"Handin Money",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
handin_money_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_items_info.empty()) {
|
if (!return_items_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Return Items", return_items_info);
|
||||||
&f,
|
|
||||||
"Return Items",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
return_items_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!return_money_info.empty()) {
|
if (!return_money_info.empty()) {
|
||||||
BuildDiscordField(
|
BuildDiscordField(&f, "Return Money", return_money_info);
|
||||||
&f,
|
|
||||||
"Return Money",
|
|
||||||
fmt::format(
|
|
||||||
"{}",
|
|
||||||
return_money_info
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DiscordEmbed> embeds = {};
|
std::vector<DiscordEmbed> embeds = {};
|
||||||
|
|||||||
@@ -706,6 +706,7 @@ void PlayerEventLogs::SetSettingsDefaults()
|
|||||||
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
|
m_settings[PlayerEvent::PARCEL_SEND].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
|
m_settings[PlayerEvent::PARCEL_RETRIEVE].event_enabled = 1;
|
||||||
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
|
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
|
||||||
|
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
|
||||||
|
|
||||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||||
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ namespace PlayerEvent {
|
|||||||
PARCEL_SEND,
|
PARCEL_SEND,
|
||||||
PARCEL_RETRIEVE,
|
PARCEL_RETRIEVE,
|
||||||
PARCEL_DELETE,
|
PARCEL_DELETE,
|
||||||
|
BARTER_TRANSACTION,
|
||||||
MAX // dont remove
|
MAX // dont remove
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,7 +123,8 @@ namespace PlayerEvent {
|
|||||||
"Guild Tribute Donate Platinum",
|
"Guild Tribute Donate Platinum",
|
||||||
"Parcel Item Sent",
|
"Parcel Item Sent",
|
||||||
"Parcel Item Retrieved",
|
"Parcel Item Retrieved",
|
||||||
"Parcel Prune Routine"
|
"Parcel Prune Routine",
|
||||||
|
"Barter Transaction"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic struct used by all events
|
// Generic struct used by all events
|
||||||
@@ -860,6 +862,8 @@ namespace PlayerEvent {
|
|||||||
public:
|
public:
|
||||||
uint32 item_id;
|
uint32 item_id;
|
||||||
std::string item_name;
|
std::string item_name;
|
||||||
|
std::vector<uint32> augment_ids;
|
||||||
|
std::vector<std::string> augment_names;
|
||||||
uint16 charges;
|
uint16 charges;
|
||||||
bool attuned;
|
bool attuned;
|
||||||
|
|
||||||
@@ -870,6 +874,8 @@ namespace PlayerEvent {
|
|||||||
ar(
|
ar(
|
||||||
CEREAL_NVP(item_id),
|
CEREAL_NVP(item_id),
|
||||||
CEREAL_NVP(item_name),
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(augment_ids),
|
||||||
|
CEREAL_NVP(augment_names),
|
||||||
CEREAL_NVP(charges),
|
CEREAL_NVP(charges),
|
||||||
CEREAL_NVP(attuned)
|
CEREAL_NVP(attuned)
|
||||||
);
|
);
|
||||||
@@ -903,6 +909,7 @@ namespace PlayerEvent {
|
|||||||
HandinMoney handin_money;
|
HandinMoney handin_money;
|
||||||
std::vector<HandinEntry> return_items;
|
std::vector<HandinEntry> return_items;
|
||||||
HandinMoney return_money;
|
HandinMoney return_money;
|
||||||
|
bool is_quest_handin;
|
||||||
|
|
||||||
// cereal
|
// cereal
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
@@ -914,7 +921,8 @@ namespace PlayerEvent {
|
|||||||
CEREAL_NVP(handin_items),
|
CEREAL_NVP(handin_items),
|
||||||
CEREAL_NVP(handin_money),
|
CEREAL_NVP(handin_money),
|
||||||
CEREAL_NVP(return_items),
|
CEREAL_NVP(return_items),
|
||||||
CEREAL_NVP(return_money)
|
CEREAL_NVP(return_money),
|
||||||
|
CEREAL_NVP(is_quest_handin)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1081,6 +1089,32 @@ namespace PlayerEvent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BarterTransaction {
|
||||||
|
std::string status;
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 item_quantity;
|
||||||
|
std::string item_name;
|
||||||
|
std::vector<BuyerLineTradeItems_Struct> trade_items;
|
||||||
|
std::string buyer_name;
|
||||||
|
std::string seller_name;
|
||||||
|
uint64 total_cost;
|
||||||
|
// cereal
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &ar)
|
||||||
|
{
|
||||||
|
ar(
|
||||||
|
CEREAL_NVP(status),
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(item_quantity),
|
||||||
|
CEREAL_NVP(item_name),
|
||||||
|
CEREAL_NVP(trade_items),
|
||||||
|
CEREAL_NVP(buyer_name),
|
||||||
|
CEREAL_NVP(seller_name),
|
||||||
|
CEREAL_NVP(total_cost)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //EQEMU_PLAYER_EVENTS_H
|
#endif //EQEMU_PLAYER_EVENTS_H
|
||||||
|
|||||||
@@ -1743,3 +1743,68 @@ std::vector<uint32> EQ::InventoryProfile::GetAugmentIDsBySlotID(int16 slot_id)
|
|||||||
|
|
||||||
return augments;
|
return augments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int16> EQ::InventoryProfile::FindAllFreeSlotsThatFitItem(const EQ::ItemData *item_data)
|
||||||
|
{
|
||||||
|
std::vector<int16> free_slots{};
|
||||||
|
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||||
|
if ((((uint64) 1 << i) & GetLookup()->PossessionsBitmask) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::ItemInstance *inv_item = GetItem(i);
|
||||||
|
|
||||||
|
if (!inv_item) {
|
||||||
|
// Found available slot in personal inventory
|
||||||
|
free_slots.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inv_item->IsClassBag() &&
|
||||||
|
EQ::InventoryProfile::CanItemFitInContainer(item_data, inv_item->GetItem())) {
|
||||||
|
|
||||||
|
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||||
|
uint8 bag_size = inv_item->GetItem()->BagSlots;
|
||||||
|
|
||||||
|
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||||
|
auto bag_item = GetItem(base_slot_id + bag_slot);
|
||||||
|
if (!bag_item) {
|
||||||
|
// Found available slot within bag
|
||||||
|
free_slots.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return free_slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItem(const EQ::ItemData *item_data)
|
||||||
|
{
|
||||||
|
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||||
|
if ((((uint64) 1 << i) & GetLookup()->PossessionsBitmask) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::ItemInstance *inv_item = GetItem(i);
|
||||||
|
|
||||||
|
if (!inv_item) {
|
||||||
|
// Found available slot in personal inventory
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inv_item->IsClassBag() &&
|
||||||
|
EQ::InventoryProfile::CanItemFitInContainer(item_data, inv_item->GetItem())) {
|
||||||
|
|
||||||
|
int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN);
|
||||||
|
uint8 bag_size = inv_item->GetItem()->BagSlots;
|
||||||
|
|
||||||
|
for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||||
|
auto bag_item = GetItem(base_slot_id + bag_slot);
|
||||||
|
if (!bag_item) {
|
||||||
|
// Found available slot within bag
|
||||||
|
return base_slot_id + bag_slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -176,6 +176,8 @@ namespace EQ
|
|||||||
// Locate an available inventory slot
|
// Locate an available inventory slot
|
||||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
||||||
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
|
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
|
||||||
|
std::vector<int16> FindAllFreeSlotsThatFitItem(const EQ::ItemData *inst);
|
||||||
|
int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst);
|
||||||
|
|
||||||
// Calculate slot_id for an item within a bag
|
// Calculate slot_id for an item within a bag
|
||||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
||||||
|
|||||||
+53
-19
@@ -81,45 +81,79 @@ bool IpUtil::IsIpInPrivateRfc1918(const std::string &ip)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets local address - pings google to inspect what interface was used locally
|
#ifdef _WIN32
|
||||||
* @return
|
#include <winsock2.h>
|
||||||
*/
|
#include <ws2tcpip.h>
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
std::string IpUtil::GetLocalIPAddress()
|
std::string IpUtil::GetLocalIPAddress()
|
||||||
{
|
{
|
||||||
char my_ip_address[16];
|
#ifdef _WIN32
|
||||||
unsigned int my_port;
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char my_ip_address[INET_ADDRSTRLEN];
|
||||||
struct sockaddr_in server_address{};
|
struct sockaddr_in server_address{};
|
||||||
struct sockaddr_in my_address{};
|
struct sockaddr_in my_address{};
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
// Connect to server
|
// Create a UDP socket
|
||||||
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
#ifdef _WIN32
|
||||||
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sockfd == INVALID_SOCKET) {
|
||||||
|
WSACleanup();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set server_addr
|
// Set server_addr (dummy address)
|
||||||
memset(&server_address, 0, sizeof(server_address));
|
memset(&server_address, 0, sizeof(server_address));
|
||||||
server_address.sin_family = AF_INET;
|
server_address.sin_family = AF_INET;
|
||||||
server_address.sin_addr.s_addr = inet_addr("172.217.160.99");
|
server_address.sin_addr.s_addr = inet_addr("8.8.8.8"); // Google DNS
|
||||||
server_address.sin_port = htons(80);
|
server_address.sin_port = htons(53); // DNS port
|
||||||
|
|
||||||
// Connect to server
|
// Perform a dummy connection to the server (UDP)
|
||||||
if (connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
|
connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
|
||||||
close(sockfd);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get my ip address and port
|
// Get my IP address
|
||||||
memset(&my_address, 0, sizeof(my_address));
|
memset(&my_address, 0, sizeof(my_address));
|
||||||
socklen_t len = sizeof(my_address);
|
socklen_t len = sizeof(my_address);
|
||||||
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
|
getsockname(sockfd, (struct sockaddr *) &my_address, &len);
|
||||||
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
|
inet_ntop(AF_INET, &my_address.sin_addr, my_ip_address, sizeof(my_ip_address));
|
||||||
my_port = ntohs(my_address.sin_port);
|
|
||||||
|
|
||||||
return fmt::format("{}", my_ip_address);
|
#ifdef _WIN32
|
||||||
|
closesocket(sockfd);
|
||||||
|
WSACleanup();
|
||||||
|
#else
|
||||||
|
close(sockfd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LogInfo("Local IP Address [{}]", my_ip_address);
|
||||||
|
|
||||||
|
return std::string(my_ip_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets public address
|
* Gets public address
|
||||||
* Uses various websites as options to return raw public IP back to the client
|
* Uses various websites as options to return raw public IP back to the client
|
||||||
|
|||||||
+37
-34
@@ -32,10 +32,11 @@
|
|||||||
|
|
||||||
//#include <iostream>
|
//#include <iostream>
|
||||||
|
|
||||||
int32 NextItemInstSerialNumber = 1;
|
int32 next_item_serial_number = 1;
|
||||||
|
std::unordered_set<uint64> guids{};
|
||||||
static inline int32 GetNextItemInstSerialNumber() {
|
|
||||||
|
|
||||||
|
static inline int32 GetNextItemInstSerialNumber()
|
||||||
|
{
|
||||||
// The Bazaar relies on each item a client has up for Trade having a unique
|
// The Bazaar relies on each item a client has up for Trade having a unique
|
||||||
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
||||||
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
||||||
@@ -46,12 +47,18 @@ static inline int32 GetNextItemInstSerialNumber() {
|
|||||||
// NextItemInstSerialNumber is the next one to hand out.
|
// NextItemInstSerialNumber is the next one to hand out.
|
||||||
//
|
//
|
||||||
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
||||||
if(NextItemInstSerialNumber >= INT_MAX)
|
if (next_item_serial_number >= INT32_MAX) {
|
||||||
NextItemInstSerialNumber = 1;
|
next_item_serial_number = 1;
|
||||||
else
|
}
|
||||||
NextItemInstSerialNumber++;
|
else {
|
||||||
|
next_item_serial_number++;
|
||||||
|
}
|
||||||
|
|
||||||
return NextItemInstSerialNumber;
|
while (guids.contains(next_item_serial_number)) {
|
||||||
|
next_item_serial_number++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_item_serial_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -303,47 +310,34 @@ int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
|
|||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto i = invaug::SOCKET_BEGIN;
|
for (int16 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
|
||||||
for (; i <= invaug::SOCKET_END; ++i) {
|
if (IsAugmentSlotAvailable(augment_type, slot_id)) {
|
||||||
if (GetItem(i)) {
|
return slot_id;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
augment_type == -1 ||
|
|
||||||
(
|
|
||||||
m_item->AugSlotType[i] &&
|
|
||||||
((1 << (m_item->AugSlotType[i] - 1)) & augment_type)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
|
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
|
||||||
{
|
{
|
||||||
if (!m_item || !m_item->IsClassCommon()) {
|
if (!m_item || !m_item->IsClassCommon() || GetItem(slot)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
return (
|
||||||
(
|
(
|
||||||
!GetItem(slot) &&
|
|
||||||
m_item->AugSlotVisible[slot]
|
|
||||||
) &&
|
|
||||||
augment_type == -1 ||
|
augment_type == -1 ||
|
||||||
(
|
(
|
||||||
m_item->AugSlotType[slot] &&
|
m_item->AugSlotType[slot] &&
|
||||||
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
||||||
)
|
)
|
||||||
) {
|
) &&
|
||||||
return true;
|
(
|
||||||
}
|
RuleB(Items, AugmentItemAllowInvisibleAugments) ||
|
||||||
|
m_item->AugSlotVisible[slot]
|
||||||
return false;
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve item inside container
|
// Retrieve item inside container
|
||||||
@@ -1292,7 +1286,7 @@ int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
|||||||
return race;
|
return race;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EQ::ItemInstance::GetItemBaneDamageBody(bodyType against, bool augments) const
|
int EQ::ItemInstance::GetItemBaneDamageBody(uint8 against, bool augments) const
|
||||||
{
|
{
|
||||||
int64 damage = 0;
|
int64 damage = 0;
|
||||||
const auto item = GetItem();
|
const auto item = GetItem();
|
||||||
@@ -1948,6 +1942,15 @@ int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augmen
|
|||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EQ::ItemInstance::AddGUIDToMap(uint64 existing_serial_number)
|
||||||
|
{
|
||||||
|
guids.emplace(existing_serial_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EQ::ItemInstance::ClearGUIDMap()
|
||||||
|
{
|
||||||
|
guids.clear();
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// class EvolveInfo
|
// class EvolveInfo
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace EQ
|
|||||||
// these two are just quick checks
|
// these two are just quick checks
|
||||||
int GetItemBaneDamageBody(bool augments = false) const;
|
int GetItemBaneDamageBody(bool augments = false) const;
|
||||||
int GetItemBaneDamageRace(bool augments = false) const;
|
int GetItemBaneDamageRace(bool augments = false) const;
|
||||||
int GetItemBaneDamageBody(bodyType against, bool augments = false) const;
|
int GetItemBaneDamageBody(uint8 against, bool augments = false) const;
|
||||||
int GetItemBaneDamageRace(uint16 against, bool augments = false) const;
|
int GetItemBaneDamageRace(uint16 against, bool augments = false) const;
|
||||||
int GetItemMagical(bool augments = false) const;
|
int GetItemMagical(bool augments = false) const;
|
||||||
int GetItemHP(bool augments = false) const;
|
int GetItemHP(bool augments = false) const;
|
||||||
@@ -309,6 +309,8 @@ namespace EQ
|
|||||||
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
|
||||||
uint32 GetItemGuildFavor() const;
|
uint32 GetItemGuildFavor() const;
|
||||||
std::vector<uint32> GetAugmentIDs() const;
|
std::vector<uint32> GetAugmentIDs() const;
|
||||||
|
static void AddGUIDToMap(uint64 existing_serial_number);
|
||||||
|
static void ClearGUIDMap();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
|||||||
|
/* 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_LAURION_H
|
||||||
|
#define COMMON_LAURION_H
|
||||||
|
|
||||||
|
#include "../struct_strategy.h"
|
||||||
|
|
||||||
|
class EQStreamIdentifier;
|
||||||
|
|
||||||
|
namespace Laurion
|
||||||
|
{
|
||||||
|
|
||||||
|
//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 "laurion_ops.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
}; /*Laurion*/
|
||||||
|
|
||||||
|
#endif /*COMMON_LAURION_H*/
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
/* 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 "laurion_limits.h"
|
||||||
|
|
||||||
|
#include "../strings.h"
|
||||||
|
|
||||||
|
|
||||||
|
int16 Laurion::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* Laurion::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 Laurion::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* Laurion::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* Laurion::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* Laurion::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* Laurion::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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,355 @@
|
|||||||
|
/* 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_LAURION_LIMITS_H
|
||||||
|
#define COMMON_LAURION_LIMITS_H
|
||||||
|
|
||||||
|
#include "../types.h"
|
||||||
|
#include "../emu_versions.h"
|
||||||
|
#include "../skills.h"
|
||||||
|
|
||||||
|
namespace Laurion
|
||||||
|
{
|
||||||
|
const int16 IINVALID = -1;
|
||||||
|
const int16 INULL = 0;
|
||||||
|
|
||||||
|
namespace inventory {
|
||||||
|
inline EQ::versions::ClientVersion GetInventoryRef() { return EQ::versions::ClientVersion::Laurion; }
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
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,
|
||||||
|
typeMercenaryItems,
|
||||||
|
typeViewModMercenaryItems,
|
||||||
|
typeMountKeyRingItems,
|
||||||
|
typeViewModMountKeyRingItems,
|
||||||
|
typeIllusionKeyRingItems,
|
||||||
|
typeViewModIllusionKeyRingItems,
|
||||||
|
typeFamiliarKeyRingItems,
|
||||||
|
typeViewModFamiliarKeyRingItems,
|
||||||
|
typeHeroForgeKeyRingItems,
|
||||||
|
typeViewModHeroForgeKeyRingItems,
|
||||||
|
typeTeleportationKeyRingItems,
|
||||||
|
typeViewModTeleportationKeyRingItems,
|
||||||
|
typeOverflow,
|
||||||
|
typeDragonHoard,
|
||||||
|
typeTradeskillDepot,
|
||||||
|
typeGuildTradeskillDepot
|
||||||
|
};
|
||||||
|
|
||||||
|
} // 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::Laurion; }
|
||||||
|
|
||||||
|
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,
|
||||||
|
slotGeneral11,
|
||||||
|
slotGeneral12,
|
||||||
|
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;
|
||||||
|
|
||||||
|
//We support more if enabled but for now lets leave it at the 10 slots
|
||||||
|
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 = 0x00000007FF800000;
|
||||||
|
const uint64 CURSOR_BITMASK = 0x0000000800000000;
|
||||||
|
const uint64 POSSESSIONS_BITMASK = (EQUIPMENT_BITMASK | GENERAL_BITMASK | CURSOR_BITMASK); // based on 36-slot count (Laurion+)
|
||||||
|
const uint64 CORPSE_BITMASK = (GENERAL_BITMASK | CURSOR_BITMASK | (EQUIPMENT_BITMASK << 36)); // based on 36-slot count (Laurion+)
|
||||||
|
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
//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 = 0x64,
|
||||||
|
ItemPacketTradeView = 0x65,
|
||||||
|
ItemPacketLoot = 0x66,
|
||||||
|
ItemPacketTrade = 0x67,
|
||||||
|
//looks like they added something at 0x68 that didn't exist before and shifted everything after it up by 1
|
||||||
|
ItemPacketUnknown068 = 0x68, //Not sure but it seems to deal with the cursor somehow.
|
||||||
|
ItemPacketCharInventory = 0x6A, //Rof 0x69 -> Larion 0x6a (requires translation)
|
||||||
|
ItemPacketLimbo = 0x6B, //0x6A -> 0x6B
|
||||||
|
ItemPacketWorldContainer = 0x6C,
|
||||||
|
ItemPacketTributeItem = 0x6D,
|
||||||
|
ItemPacketGuildTribute = 0x6E,
|
||||||
|
ItemPacketCharmUpdate = 0x6f,
|
||||||
|
ItemPacketRecovery = 0x72,
|
||||||
|
ItemPacketParcel = 0x74,
|
||||||
|
ItemPacketUnknown075 = 0x75, //Not sure but uses a lot of the same logic as the trade and char inventory types
|
||||||
|
ItemPacketOverflow = 0x76,
|
||||||
|
ItemPacketDragonHoard = 0x77,
|
||||||
|
ItemPacketTradeskill = 0x78,
|
||||||
|
ItemPacketTradeskillDepot = 0x79,
|
||||||
|
ItemPacketInvalid = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*item*/
|
||||||
|
|
||||||
|
namespace profile {
|
||||||
|
inline EQ::versions::ClientVersion GetProfileRef() { return EQ::versions::ClientVersion::Laurion; }
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
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::Laurion; }
|
||||||
|
|
||||||
|
const bool CoinHasWeight = false;
|
||||||
|
|
||||||
|
} /*behavior*/
|
||||||
|
|
||||||
|
namespace skills {
|
||||||
|
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::Laurion; }
|
||||||
|
|
||||||
|
const size_t LastUsableSkill = EQ::skills::Skill2HPiercing;
|
||||||
|
|
||||||
|
} /*skills*/
|
||||||
|
|
||||||
|
namespace spells {
|
||||||
|
inline EQ::versions::ClientVersion GetSkillsRef() { return EQ::versions::ClientVersion::Laurion; }
|
||||||
|
|
||||||
|
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 = 30;
|
||||||
|
const int DISC_BUFFS = 1;
|
||||||
|
const int TOTAL_BUFFS = LONG_BUFFS + SHORT_BUFFS + DISC_BUFFS;
|
||||||
|
const int NPC_BUFFS = 400;
|
||||||
|
const int PET_BUFFS = NPC_BUFFS;
|
||||||
|
const int MERC_BUFFS = LONG_BUFFS;
|
||||||
|
|
||||||
|
} /*spells*/
|
||||||
|
|
||||||
|
}; /* Laurion */
|
||||||
|
|
||||||
|
#endif /*COMMON_LAURION_LIMITS_H*/
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
//list of packets we need to encode on the way out:
|
||||||
|
E(OP_Action)
|
||||||
|
E(OP_Animation)
|
||||||
|
E(OP_ApplyPoison)
|
||||||
|
E(OP_AugmentInfo)
|
||||||
|
E(OP_BeginCast)
|
||||||
|
E(OP_BlockedBuffs)
|
||||||
|
E(OP_Buff)
|
||||||
|
E(OP_BuffCreate)
|
||||||
|
E(OP_CancelTrade)
|
||||||
|
E(OP_CastSpell)
|
||||||
|
E(OP_ChannelMessage)
|
||||||
|
E(OP_CharInventory)
|
||||||
|
E(OP_ClickObjectAction)
|
||||||
|
E(OP_ClientUpdate)
|
||||||
|
E(OP_Consider)
|
||||||
|
E(OP_Damage)
|
||||||
|
E(OP_Death)
|
||||||
|
E(OP_DeleteCharge)
|
||||||
|
E(OP_DeleteItem)
|
||||||
|
E(OP_DeleteSpawn)
|
||||||
|
E(OP_DisciplineUpdate)
|
||||||
|
E(OP_ExpansionInfo)
|
||||||
|
E(OP_ExpUpdate)
|
||||||
|
E(OP_FormattedMessage)
|
||||||
|
E(OP_GMTraining)
|
||||||
|
E(OP_GMTrainSkillConfirm)
|
||||||
|
E(OP_GroundSpawn)
|
||||||
|
E(OP_HPUpdate)
|
||||||
|
E(OP_Illusion)
|
||||||
|
E(OP_ItemPacket)
|
||||||
|
E(OP_LogServer)
|
||||||
|
E(OP_ManaChange)
|
||||||
|
E(OP_MobHealth)
|
||||||
|
E(OP_MoneyOnCorpse)
|
||||||
|
E(OP_MoveItem)
|
||||||
|
E(OP_NewSpawn)
|
||||||
|
E(OP_NewZone)
|
||||||
|
E(OP_OnLevelMessage)
|
||||||
|
E(OP_PlayerProfile)
|
||||||
|
E(OP_RemoveBlockedBuffs)
|
||||||
|
E(OP_RespondAA)
|
||||||
|
E(OP_RequestClientZoneChange)
|
||||||
|
E(OP_RecipeAutoCombine)
|
||||||
|
E(OP_SendAATable)
|
||||||
|
E(OP_SendCharInfo)
|
||||||
|
E(OP_SendMaxCharacters)
|
||||||
|
E(OP_SendMembership)
|
||||||
|
E(OP_SendMembershipDetails)
|
||||||
|
E(OP_SendZonepoints)
|
||||||
|
E(OP_ShopPlayerBuy)
|
||||||
|
E(OP_ShopPlayerSell)
|
||||||
|
E(OP_ShopRequest)
|
||||||
|
E(OP_SkillUpdate)
|
||||||
|
E(OP_SpecialMesg)
|
||||||
|
E(OP_SpawnAppearance)
|
||||||
|
E(OP_SpawnDoor)
|
||||||
|
E(OP_Stun)
|
||||||
|
E(OP_WearChange)
|
||||||
|
E(OP_ZoneChange)
|
||||||
|
E(OP_ZoneEntry)
|
||||||
|
E(OP_ZonePlayerToBind)
|
||||||
|
E(OP_ZoneSpawns)
|
||||||
|
|
||||||
|
//list of packets we need to decode on the way in:
|
||||||
|
D(OP_Animation)
|
||||||
|
D(OP_ApplyPoison)
|
||||||
|
D(OP_AugmentInfo)
|
||||||
|
D(OP_AugmentItem)
|
||||||
|
D(OP_BlockedBuffs)
|
||||||
|
D(OP_CastSpell)
|
||||||
|
D(OP_ChannelMessage)
|
||||||
|
D(OP_ClientUpdate)
|
||||||
|
D(OP_ClickDoor)
|
||||||
|
D(OP_Consider)
|
||||||
|
D(OP_ConsiderCorpse)
|
||||||
|
D(OP_DeleteItem)
|
||||||
|
D(OP_EnterWorld)
|
||||||
|
D(OP_GMTraining)
|
||||||
|
D(OP_GroupDisband)
|
||||||
|
D(OP_GroupInvite)
|
||||||
|
D(OP_GroupInvite2)
|
||||||
|
D(OP_MoveItem)
|
||||||
|
D(OP_RemoveBlockedBuffs)
|
||||||
|
D(OP_SetServerFilter)
|
||||||
|
D(OP_ShopPlayerBuy)
|
||||||
|
D(OP_ShopPlayerSell)
|
||||||
|
D(OP_ShopRequest)
|
||||||
|
D(OP_SpawnAppearance)
|
||||||
|
D(OP_TradeSkillCombine)
|
||||||
|
D(OP_WearChange)
|
||||||
|
D(OP_ZoneEntry)
|
||||||
|
D(OP_ZoneChange)
|
||||||
|
#undef E
|
||||||
|
#undef D
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@
|
|||||||
#include "sod.h"
|
#include "sod.h"
|
||||||
#include "rof.h"
|
#include "rof.h"
|
||||||
#include "rof2.h"
|
#include "rof2.h"
|
||||||
|
#include "laurion.h"
|
||||||
|
|
||||||
void RegisterAllPatches(EQStreamIdentifier &into)
|
void RegisterAllPatches(EQStreamIdentifier &into)
|
||||||
{
|
{
|
||||||
@@ -36,6 +36,7 @@ void RegisterAllPatches(EQStreamIdentifier &into)
|
|||||||
UF::Register(into);
|
UF::Register(into);
|
||||||
RoF::Register(into);
|
RoF::Register(into);
|
||||||
RoF2::Register(into);
|
RoF2::Register(into);
|
||||||
|
Laurion::Register(into);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReloadAllPatches()
|
void ReloadAllPatches()
|
||||||
@@ -46,4 +47,5 @@ void ReloadAllPatches()
|
|||||||
UF::Reload();
|
UF::Reload();
|
||||||
RoF::Reload();
|
RoF::Reload();
|
||||||
RoF2::Reload();
|
RoF2::Reload();
|
||||||
|
Laurion::Reload();
|
||||||
}
|
}
|
||||||
|
|||||||
+544
-23
@@ -359,38 +359,88 @@ namespace RoF2
|
|||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
char *Buffer = (char *)in->pBuffer;
|
char *buffer = (char *) in->pBuffer;
|
||||||
|
uint32 sub_action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
|
||||||
uint32 SubAction = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
switch (sub_action) {
|
||||||
|
case Barter_BuyerAppearance: {
|
||||||
|
auto emu = (BuyerInspectRequest_Struct *) in->pBuffer;
|
||||||
|
|
||||||
if (SubAction != Barter_BuyerAppearance)
|
auto outapp = new EQApplicationPacket(OP_Barter, sizeof(structs::Buyer_SetAppearance_Struct));
|
||||||
{
|
auto eq = (structs::Buyer_SetAppearance_Struct *) outapp->pBuffer;
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
|
||||||
|
|
||||||
return;
|
eq->action = structs::RoF2BuyerActions::BuyerAppearance;
|
||||||
|
eq->entity_id = emu->buyer_id;
|
||||||
|
eq->enabled = emu->approval;
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
|
safe_delete(in);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case Barter_BuyerItemRemove: {
|
||||||
|
auto emu = (BuyerRemoveItem_Struct *) in->pBuffer;
|
||||||
|
|
||||||
unsigned char *__emu_buffer = in->pBuffer;
|
auto outapp = new EQApplicationPacket(OP_BuyerItems, sizeof(structs::BuyerRemoveItem_Struct));
|
||||||
|
auto eq = (structs::BuyerRemoveItem_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
in->size = 80;
|
eq->action = structs::RoF2BuyerActions::BuyerModifyBuyLine;
|
||||||
|
eq->slot_id = emu->buy_slot_id;
|
||||||
|
eq->toggle = 0;
|
||||||
|
|
||||||
in->pBuffer = new unsigned char[in->size];
|
dest->FastQueuePacket(&outapp);
|
||||||
|
safe_delete(in);
|
||||||
|
|
||||||
char *OutBuffer = (char *)in->pBuffer;
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerInspectBegin: {
|
||||||
|
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerInspectBegin;
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerInspectEnd: {
|
||||||
|
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerInspectEnd;
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_SellerBrowsing: {
|
||||||
|
*(uint32 *) in->pBuffer = structs::RoF2BuyerActions::BuyerBrowsingBuyLine;
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerSearchResults: {
|
||||||
|
BuyerItemSearchResults_Struct bisr{};
|
||||||
|
auto emu = (BuyerGeneric_Struct *) in->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(emu->payload),
|
||||||
|
in->size - sizeof(BuyerGeneric_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(bisr);
|
||||||
|
|
||||||
char Name[64];
|
LogTradingDetail("Sending item search results <green>[{}]", bisr.result_count);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, SubAction);
|
uint32 packet_size = bisr.result_count * sizeof(structs::BuyerItemSearchResultEntry_Struct) + 8;
|
||||||
uint32 EntityID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_Barter, packet_size);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, EntityID);
|
auto eq = (char *) outapp->pBuffer;
|
||||||
uint8 Toggle = VARSTRUCT_DECODE_TYPE(uint8, Buffer);
|
|
||||||
VARSTRUCT_DECODE_STRING(Name, Buffer);
|
|
||||||
VARSTRUCT_ENCODE_STRING(OutBuffer, Name);
|
|
||||||
OutBuffer = (char *)in->pBuffer + 72;
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, Toggle);
|
|
||||||
|
|
||||||
delete[] __emu_buffer;
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSearchResults);
|
||||||
dest->FastQueuePacket(&in, ack_req);
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bisr.result_count);
|
||||||
|
for (auto const &i: bisr.results) {
|
||||||
|
strn0cpy(eq, i.item_name, 64);
|
||||||
|
eq += 64;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||||
|
VARSTRUCT_SKIP_TYPE(uint32, eq);
|
||||||
|
}
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
LogTradingDetail("Unhandled action <red>[{}]", sub_action);
|
||||||
|
dest->FastQueuePacket(&in);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_BazaarSearch)
|
ENCODE(OP_BazaarSearch)
|
||||||
@@ -542,8 +592,8 @@ namespace RoF2
|
|||||||
LogTrading(
|
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>[{}]",
|
||||||
eq->action,
|
eq->action,
|
||||||
eq->entity_id,
|
|
||||||
eq->trader_id,
|
eq->trader_id,
|
||||||
|
eq->entity_id,
|
||||||
eq->zone_id
|
eq->zone_id
|
||||||
);
|
);
|
||||||
dest->FastQueuePacket(&outapp);
|
dest->FastQueuePacket(&outapp);
|
||||||
@@ -682,6 +732,243 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_BuyerItems)
|
||||||
|
{
|
||||||
|
EQApplicationPacket *inapp = *p;
|
||||||
|
*p = nullptr;
|
||||||
|
|
||||||
|
auto action = *(uint32 *) inapp->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case Barter_BuyerItemUpdate: {
|
||||||
|
BuyerLineItems_Struct bl{};
|
||||||
|
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(emu->payload),
|
||||||
|
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(bl);
|
||||||
|
|
||||||
|
//packet size
|
||||||
|
auto packet_size = bl.item_name.length() + 1 + 34;
|
||||||
|
for (auto const &b: bl.trade_items) {
|
||||||
|
packet_size += b.item_name.length() + 1;
|
||||||
|
packet_size += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||||
|
char *eq = (char *) outapp->pBuffer;
|
||||||
|
auto no_trade_items = bl.trade_items.size();
|
||||||
|
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerModifyBuyLine);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.slot);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, bl.enabled ? 1 : 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_id);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, bl.item_name.c_str());
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_icon);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, bl.item_toggle ? 1 : 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.item_cost);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_trade_items);
|
||||||
|
|
||||||
|
for (int i = 0; i < no_trade_items; i++) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bl.trade_items[i].item_icon);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, bl.trade_items[i].item_name.c_str());
|
||||||
|
}
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
safe_delete(inapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerInspectBegin: {
|
||||||
|
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||||
|
|
||||||
|
BuyerLineItems_Struct bli{};
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(emu->payload),
|
||||||
|
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(bli);
|
||||||
|
|
||||||
|
//packet size
|
||||||
|
auto packet_size = bli.item_name.length() + 1 + 34;
|
||||||
|
for (auto const &b: bli.trade_items) {
|
||||||
|
packet_size += b.item_name.length() + 1;
|
||||||
|
packet_size += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto packet = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||||
|
char *eq = (char *) packet->pBuffer;
|
||||||
|
auto no_trade_items = bli.trade_items.size();
|
||||||
|
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSendBuyLine);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.slot);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.slot);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, bli.enabled ? 1 : 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_id);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, bli.item_name.c_str());
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_icon);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, bli.item_toggle ? 1 : 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bli.item_cost);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_trade_items);
|
||||||
|
|
||||||
|
for (auto const &i: bli.trade_items) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||||
|
}
|
||||||
|
dest->QueuePacket(packet.get());
|
||||||
|
safe_delete(inapp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerSearch: {
|
||||||
|
BuyerLineSearch_Struct bls{};
|
||||||
|
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(emu->payload),
|
||||||
|
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(bls);
|
||||||
|
LogTrading("(RoF2) Barter_BuyerSearch action <green>[{}]", emu->action);
|
||||||
|
|
||||||
|
//Calculate size of packet
|
||||||
|
auto p_size = 0;
|
||||||
|
p_size += 5 * sizeof(uint32) + 1 * sizeof(uint8);
|
||||||
|
p_size += bls.search_string.length() + 1;
|
||||||
|
for (auto const &b: bls.buy_line) {
|
||||||
|
p_size += 6 * sizeof(uint32) + 2 * sizeof(uint8);
|
||||||
|
p_size += strlen(b.item_name) + 1;
|
||||||
|
p_size += b.buyer_name.length() + 1;
|
||||||
|
for (auto const &d: b.trade_items) {
|
||||||
|
if (d.item_id != 0) {
|
||||||
|
p_size += d.item_name.length() + 1;
|
||||||
|
p_size += 3 * sizeof(uint32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p_size += 3 * sizeof(uint32);
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyerBuyLines_Struct bl{};
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, p_size);
|
||||||
|
auto eq = (char *) outapp->pBuffer;
|
||||||
|
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 1);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, bls.search_string.c_str());
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bls.transaction_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, bls.no_items);
|
||||||
|
for (auto const &b: bls.buy_line) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.slot);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_id);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, b.item_name);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_icon);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint8, eq, 1);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.item_cost);
|
||||||
|
auto no_sub_items = b.trade_items.size();
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, no_sub_items);
|
||||||
|
for (auto const &i: b.trade_items) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_icon);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||||
|
}
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.buyer_entity_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, b.buyer_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint16, eq, b.buyer_zone_instance_id);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, b.buyer_name.c_str());
|
||||||
|
}
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_RemoveFromMerchantWindow: {
|
||||||
|
auto emu = (BuyerRemoveItemFromMerchantWindow_Struct *) inapp->pBuffer;
|
||||||
|
|
||||||
|
emu->action = structs::RoF2BuyerActions::BuyerSendBuyLine;
|
||||||
|
dest->FastQueuePacket(&inapp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_BuyerTransactionComplete:
|
||||||
|
case Barter_SellerTransactionComplete: {
|
||||||
|
BuyerLineSellItem_Struct blsi{};
|
||||||
|
auto emu = (BuyerGeneric_Struct *) inapp->pBuffer;
|
||||||
|
EQ::Util::MemoryStreamReader ss(
|
||||||
|
reinterpret_cast<char *>(emu->payload),
|
||||||
|
inapp->size - sizeof(BuyerGeneric_Struct)
|
||||||
|
);
|
||||||
|
cereal::BinaryInputArchive ar(ss);
|
||||||
|
ar(blsi);
|
||||||
|
|
||||||
|
//packet size
|
||||||
|
auto packet_size = strlen(blsi.item_name) * 2 + 2 + 48 + 30 + blsi.seller_name.length() + 1 +
|
||||||
|
blsi.buyer_name.length() + 1;
|
||||||
|
for (auto const &b: blsi.trade_items) {
|
||||||
|
packet_size += b.item_name.length() + 1;
|
||||||
|
packet_size += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outapp = std::make_unique<EQApplicationPacket>(OP_BuyerItems, packet_size);
|
||||||
|
auto eq = (char *) outapp->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case Barter_BuyerTransactionComplete: {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerBuyItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Barter_SellerTransactionComplete: {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, structs::RoF2BuyerActions::BuyerSellItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.sub_action);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.error_code);
|
||||||
|
eq += 16;
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, blsi.buyer_name.c_str());
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, blsi.item_name);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, blsi.seller_name.c_str());
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFFFF);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFFFF);
|
||||||
|
eq += 1;
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, blsi.item_name);
|
||||||
|
eq += 9;
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.item_cost);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.trade_items.size());
|
||||||
|
|
||||||
|
for (auto const &i: blsi.trade_items) {
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, i.item_quantity);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_STRING(eq, i.item_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0xFFFFFF);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, 0);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint32, eq, blsi.seller_quantity);
|
||||||
|
|
||||||
|
dest->QueuePacket(outapp.get());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
dest->FastQueuePacket(&inapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_CancelTrade)
|
ENCODE(OP_CancelTrade)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CancelTrade_Struct);
|
ENCODE_LENGTH_EXACT(CancelTrade_Struct);
|
||||||
@@ -2393,7 +2680,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
float instrument_mod = 0.0f;
|
float instrument_mod = 0.0f;
|
||||||
uint8 effect_type = emu->buffs[r].effect_type;
|
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)
|
if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0)
|
||||||
{
|
{
|
||||||
@@ -3316,6 +3603,21 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_ShopRequest)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(MerchantClick_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(MerchantClick_Struct, structs::MerchantClick_Struct);
|
||||||
|
|
||||||
|
OUT(npc_id);
|
||||||
|
OUT(player_id);
|
||||||
|
OUT(command);
|
||||||
|
OUT(rate);
|
||||||
|
OUT(tab_display);
|
||||||
|
eq->unknown02 = emu->unknown020;
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_SkillUpdate)
|
ENCODE(OP_SkillUpdate)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(SkillUpdate_Struct);
|
ENCODE_LENGTH_EXACT(SkillUpdate_Struct);
|
||||||
@@ -4348,6 +4650,9 @@ namespace RoF2
|
|||||||
if (emu->DestructibleObject) {
|
if (emu->DestructibleObject) {
|
||||||
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData
|
||||||
}
|
}
|
||||||
|
if (emu->buyer) {
|
||||||
|
OtherData = OtherData | 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData);
|
||||||
// float EmitterScalingRadius
|
// float EmitterScalingRadius
|
||||||
@@ -4664,6 +4969,66 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_Barter)
|
||||||
|
{
|
||||||
|
auto action = *(uint32 *) __packet->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case structs::RoF2BuyerActions::BuyerRemoveItem: {
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
emu->action = Barter_BuyerItemRemove;
|
||||||
|
LogTradingDetail("(RoF2) Buyer Remove Item");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BuyerActions::BuyerInspectBegin: {
|
||||||
|
LogTradingDetail("(RoF2) Buyer Inspect Begin Item");
|
||||||
|
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
emu->action = Barter_BuyerInspectBegin;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BuyerActions::BuyerInspectEnd: {
|
||||||
|
LogTradingDetail("(RoF2) Buyer Inspect End Item ");
|
||||||
|
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
emu->action = Barter_BuyerInspectEnd;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BuyerActions::BuyerWelcomeMessage: {
|
||||||
|
LogTradingDetail("(RoF2) Buyer Welcome Message Update");
|
||||||
|
SETUP_DIRECT_DECODE(BuyerWelcomeMessageUpdate_Struct, structs::BuyerWelcomeMessageUpdate_Struct);
|
||||||
|
|
||||||
|
emu->action = Barter_WelcomeMessageUpdate;
|
||||||
|
strn0cpy(emu->welcome_message, eq->welcome_message, sizeof(emu->welcome_message));
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BuyerActions::BuyerItemInspect: {
|
||||||
|
SETUP_DIRECT_DECODE(BarterItemSearchLinkRequest_Struct, structs::BarterItemSearchLinkRequest_Struct);
|
||||||
|
LogTradingDetail("(RoF2) Seller ID <green>[{}] Inspecting Item <green>[{}] from Buyer ID <green>[{}] ",
|
||||||
|
eq->seller_id,
|
||||||
|
eq->item_id,
|
||||||
|
eq->buyer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
emu->action = Barter_BarterItemInspect;
|
||||||
|
emu->item_id = eq->item_id;
|
||||||
|
emu->searcher_id = eq->seller_id;
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
LogTradingDetail("(RoF2) Pass thru OP_Barter packet action <red>[{}]", emu->action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_BazaarSearch)
|
DECODE(OP_BazaarSearch)
|
||||||
{
|
{
|
||||||
char *Buffer = (char *)__packet->pBuffer;
|
char *Buffer = (char *)__packet->pBuffer;
|
||||||
@@ -4742,6 +5107,147 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_BuyerItems)
|
||||||
|
{
|
||||||
|
auto action = *(uint32 *) __packet->pBuffer;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case structs::RoF2BuyerActions::BuyerModifyBuyLine:
|
||||||
|
case structs::RoF2BuyerActions::BuyerBuyLine: {
|
||||||
|
BuyerBuyLines_Struct buyer_buy_lines{};
|
||||||
|
auto buffer = (char *) __packet->pBuffer;
|
||||||
|
|
||||||
|
buyer_buy_lines.action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
|
||||||
|
buyer_buy_lines.no_items = 1;
|
||||||
|
if (action == structs::RoF2BuyerActions::BuyerBuyLine) {
|
||||||
|
buyer_buy_lines.no_items = VARSTRUCT_DECODE_TYPE(uint16, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
buyer_buy_lines.buy_lines.reserve(buyer_buy_lines.no_items);
|
||||||
|
for (int i = 0; i < buyer_buy_lines.no_items; i++) {
|
||||||
|
BuyerLineItems_Struct b{};
|
||||||
|
b.slot = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
b.enabled = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||||
|
b.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
b.item_name = std::string(buffer, strlen(buffer));
|
||||||
|
buffer += strlen(buffer) + 1;
|
||||||
|
b.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
b.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
b.item_toggle = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||||
|
b.item_cost = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
auto trade_items = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
buyer_buy_lines.buy_lines.push_back(b);
|
||||||
|
|
||||||
|
if (trade_items > 0) {
|
||||||
|
buyer_buy_lines.buy_lines[i].trade_items.reserve(trade_items);
|
||||||
|
for (int x = 0; x < trade_items; x++) {
|
||||||
|
BuyerLineTradeItems_Struct blti{};
|
||||||
|
blti.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_name = std::string(buffer, strlen(buffer));
|
||||||
|
buffer += strlen(buffer) + 1;
|
||||||
|
buyer_buy_lines.buy_lines[i].trade_items.push_back(blti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer += 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = nullptr;
|
||||||
|
std::stringstream ss{};
|
||||||
|
cereal::BinaryOutputArchive ar(ss);
|
||||||
|
{
|
||||||
|
ar(buyer_buy_lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_size = sizeof(BuyerGeneric_Struct) + ss.str().length();
|
||||||
|
auto new_packet = new unsigned char[new_size];
|
||||||
|
__packet->size = new_size;
|
||||||
|
__packet->pBuffer = new_packet;
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
emu->action = Barter_BuyerItemUpdate;
|
||||||
|
|
||||||
|
if (action == structs::RoF2BuyerActions::BuyerBuyLine) {
|
||||||
|
emu->action = Barter_BuyerItemStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(emu->payload, ss.str().data(), ss.str().length());
|
||||||
|
__packet->SetOpcode(OP_Barter);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case structs::RoF2BuyerActions::BuyerSellItem: {
|
||||||
|
BuyerLineSellItem_Struct sell_item{};
|
||||||
|
|
||||||
|
char *buffer = (char *) __packet->pBuffer;
|
||||||
|
|
||||||
|
sell_item.action = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.purchase_method = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
buffer += 4;
|
||||||
|
sell_item.buyer_entity_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.buyer_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
buffer += 11;
|
||||||
|
sell_item.slot = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.enabled = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||||
|
sell_item.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
VARSTRUCT_DECODE_STRING(sell_item.item_name, buffer);
|
||||||
|
sell_item.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.item_toggle = VARSTRUCT_DECODE_TYPE(uint8, buffer);
|
||||||
|
sell_item.item_cost = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.no_trade_items = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
|
||||||
|
if (sell_item.no_trade_items > 0) {
|
||||||
|
sell_item.trade_items.reserve(sell_item.no_trade_items);
|
||||||
|
for (int x = 0; x < sell_item.no_trade_items; x++) {
|
||||||
|
BuyerLineTradeItems_Struct blti{};
|
||||||
|
blti.item_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_icon = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
blti.item_name = std::string(buffer, strlen(buffer));
|
||||||
|
buffer += strlen(buffer) + 1;
|
||||||
|
sell_item.trade_items.push_back(blti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sell_item.purchase_method) {
|
||||||
|
sell_item.buyer_entity_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.buyer_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.zone_id = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
sell_item.buyer_name = std::string(buffer, strlen(buffer));
|
||||||
|
buffer += sell_item.buyer_name.length() + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffer += 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
sell_item.seller_quantity = VARSTRUCT_DECODE_TYPE(uint32, buffer);
|
||||||
|
|
||||||
|
buffer += 4;
|
||||||
|
|
||||||
|
buffer = nullptr;
|
||||||
|
std::stringstream ss{};
|
||||||
|
cereal::BinaryOutputArchive ar(ss);
|
||||||
|
{
|
||||||
|
ar(sell_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_size = sizeof(BuyerGeneric_Struct) + ss.str().length();
|
||||||
|
auto new_packet = new unsigned char[new_size];
|
||||||
|
__packet->size = new_size;
|
||||||
|
__packet->pBuffer = new_packet;
|
||||||
|
auto emu = (BuyerGeneric_Struct *) __packet->pBuffer;
|
||||||
|
emu->action = Barter_SellItem;
|
||||||
|
|
||||||
|
memcpy(emu->payload, ss.str().data(), ss.str().length());
|
||||||
|
__packet->SetOpcode(OP_Barter);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_CastSpell)
|
DECODE(OP_CastSpell)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
||||||
@@ -5502,6 +6008,21 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_ShopRequest)
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::MerchantClick_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(MerchantClick_Struct, structs::MerchantClick_Struct);
|
||||||
|
|
||||||
|
IN(npc_id);
|
||||||
|
IN(player_id);
|
||||||
|
IN(command);
|
||||||
|
IN(rate);
|
||||||
|
IN(tab_display);
|
||||||
|
emu->unknown020 = 0;
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_Save)
|
DECODE(OP_Save)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::Save_Struct);
|
DECODE_LENGTH_EXACT(structs::Save_Struct);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ E(OP_BeginCast)
|
|||||||
E(OP_BlockedBuffs)
|
E(OP_BlockedBuffs)
|
||||||
E(OP_Buff)
|
E(OP_Buff)
|
||||||
E(OP_BuffCreate)
|
E(OP_BuffCreate)
|
||||||
|
E(OP_BuyerItems)
|
||||||
E(OP_CancelTrade)
|
E(OP_CancelTrade)
|
||||||
E(OP_CastSpell)
|
E(OP_CastSpell)
|
||||||
E(OP_ChannelMessage)
|
E(OP_ChannelMessage)
|
||||||
@@ -117,6 +118,7 @@ E(OP_SendZonepoints)
|
|||||||
E(OP_SetGuildRank)
|
E(OP_SetGuildRank)
|
||||||
E(OP_ShopPlayerBuy)
|
E(OP_ShopPlayerBuy)
|
||||||
E(OP_ShopPlayerSell)
|
E(OP_ShopPlayerSell)
|
||||||
|
E(OP_ShopRequest)
|
||||||
E(OP_SkillUpdate)
|
E(OP_SkillUpdate)
|
||||||
E(OP_SomeItemPacketMaybe)
|
E(OP_SomeItemPacketMaybe)
|
||||||
E(OP_SpawnAppearance)
|
E(OP_SpawnAppearance)
|
||||||
@@ -149,11 +151,13 @@ D(OP_Animation)
|
|||||||
D(OP_ApplyPoison)
|
D(OP_ApplyPoison)
|
||||||
D(OP_AugmentInfo)
|
D(OP_AugmentInfo)
|
||||||
D(OP_AugmentItem)
|
D(OP_AugmentItem)
|
||||||
|
D(OP_Barter)
|
||||||
D(OP_BazaarSearch)
|
D(OP_BazaarSearch)
|
||||||
D(OP_BlockedBuffs)
|
D(OP_BlockedBuffs)
|
||||||
D(OP_BookButton)
|
D(OP_BookButton)
|
||||||
D(OP_Buff)
|
D(OP_Buff)
|
||||||
D(OP_BuffRemoveRequest)
|
D(OP_BuffRemoveRequest)
|
||||||
|
D(OP_BuyerItems)
|
||||||
D(OP_CastSpell)
|
D(OP_CastSpell)
|
||||||
D(OP_ChannelMessage)
|
D(OP_ChannelMessage)
|
||||||
D(OP_CharacterCreate)
|
D(OP_CharacterCreate)
|
||||||
@@ -200,6 +204,7 @@ D(OP_Save)
|
|||||||
D(OP_SetServerFilter)
|
D(OP_SetServerFilter)
|
||||||
D(OP_ShopPlayerBuy)
|
D(OP_ShopPlayerBuy)
|
||||||
D(OP_ShopPlayerSell)
|
D(OP_ShopPlayerSell)
|
||||||
|
D(OP_ShopRequest)
|
||||||
D(OP_ShopSendParcel)
|
D(OP_ShopSendParcel)
|
||||||
D(OP_Trader)
|
D(OP_Trader)
|
||||||
D(OP_TraderBuy)
|
D(OP_TraderBuy)
|
||||||
|
|||||||
@@ -354,15 +354,15 @@ struct Spawn_Struct_Bitfields
|
|||||||
/*29*/ unsigned showname:1;
|
/*29*/ unsigned showname:1;
|
||||||
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
|
/*30*/ unsigned idleanimationsoff:1; // what we called statue?
|
||||||
/*31*/ unsigned untargetable:1; // bClickThrough
|
/*31*/ unsigned untargetable:1; // bClickThrough
|
||||||
/* do these later
|
// byte 5
|
||||||
32 unsigned buyer:1;
|
/*32 unsigned buyer:1;
|
||||||
33 unsigned offline:1;
|
/*33 unsigned offline:1;
|
||||||
34 unsigned interactiveobject:1;
|
/*34 unsigned interactiveobject:1;
|
||||||
35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
|
/*35 unsigned flung:1; // hmm this vfunc appears to do stuff with leve and flung variables
|
||||||
36 unsigned title:1;
|
/*36 unsigned title:1;
|
||||||
37 unsigned suffix:1;
|
/*37 unsigned suffix:1;
|
||||||
38 unsigned padding1:1;
|
/*38 unsigned padding1:1;
|
||||||
39 unsigned padding2:1;
|
/*39 unsigned padding2:1;
|
||||||
40 unsinged padding3:1;
|
40 unsinged padding3:1;
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
@@ -3122,6 +3122,126 @@ enum RoF2BazaarTraderBuyerActions {
|
|||||||
ReconcileItems = 20
|
ReconcileItems = 20
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RoF2BuyerActions {
|
||||||
|
BuyerSearchResults = 0x00,
|
||||||
|
BuyerBuyLine = 0x06,
|
||||||
|
BuyerModifyBuyLine = 0x07,
|
||||||
|
BuyerRemoveItem = 0x08,
|
||||||
|
BuyerSellItem = 0x09,
|
||||||
|
BuyerBuyItem = 0x0a,
|
||||||
|
BuyerInspectBegin = 0x0b,
|
||||||
|
BuyerInspectEnd = 0x0c,
|
||||||
|
BuyerAppearance = 0x0d,
|
||||||
|
BuyerSendBuyLine = 0x0e,
|
||||||
|
BuyerItemInspect = 0x0f,
|
||||||
|
BuyerBrowsingBuyLine = 0x10,
|
||||||
|
BarterWelcomeMessage = 0x11,
|
||||||
|
BuyerWelcomeMessage = 0x13,
|
||||||
|
BuyerGreeting = 0x14,
|
||||||
|
BuyerInventoryFull = 0x16
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BarterItemSearchLinkRequest_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 unknown_004;
|
||||||
|
uint32 seller_id;
|
||||||
|
uint32 buyer_id;
|
||||||
|
uint32 unknown_016;
|
||||||
|
uint32 slot_id; // 0xffffffff main buy line 0x0 trade_item_1, 0x1 trade_item_2
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 unknown_028;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerWelcomeMessageUpdate_Struct {
|
||||||
|
uint32 action;
|
||||||
|
char unknown_004[64];
|
||||||
|
uint32 unknown_068;
|
||||||
|
char welcome_message[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Buyer_SetAppearance_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 entity_id;
|
||||||
|
char unknown[64];
|
||||||
|
uint32 enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerRemoveItem_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 unknown004;
|
||||||
|
uint32 slot_id;
|
||||||
|
uint32 toggle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineSellItem_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 purchase_method; // 0 direct merchant, 1 via /barter window
|
||||||
|
uint32 unknown008;
|
||||||
|
uint32 buyer_entity_id;
|
||||||
|
uint32 seller_entity_id;
|
||||||
|
char unknown[15];
|
||||||
|
uint32 slot;
|
||||||
|
uint8 enabled;
|
||||||
|
uint32 item_id;
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 item_toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
uint32 no_trade_items;
|
||||||
|
BuyerLineTradeItems_Struct trade_items[10];
|
||||||
|
char unknown2[13];
|
||||||
|
uint32 seller_quantity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineItemsSearch_Struct {
|
||||||
|
uint32 slot;
|
||||||
|
uint8 enabled;
|
||||||
|
uint32 item_id;
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 item_toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
uint32 buyer_id;
|
||||||
|
BuyerLineTradeItems_Struct trade_items[MAX_BUYER_COMPENSATION_ITEMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerLineSearch_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 no_items;
|
||||||
|
std::vector<BuyerLineItemsSearch_Struct> buy_line;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerStart_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint16 no_buyer_lines;
|
||||||
|
uint32 slot;
|
||||||
|
uint8 enabled;
|
||||||
|
uint32 item_id;
|
||||||
|
char item_name[1]; // vary length
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 item_quantity;
|
||||||
|
uint8 toggle;
|
||||||
|
uint32 item_cost;
|
||||||
|
uint32 no_trade_items;
|
||||||
|
BuyerLineTradeItems_Struct trade_items[1]; // size is actually no_trade_items. If 0, then this is not in packet
|
||||||
|
char unknown[13];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerItemSearchResultEntry_Struct {
|
||||||
|
char item_name[64];
|
||||||
|
uint32 item_id;
|
||||||
|
uint32 item_icon;
|
||||||
|
uint32 unknown_072;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BuyerItemSearchResults_Struct {
|
||||||
|
uint32 action;
|
||||||
|
uint32 result_count;
|
||||||
|
BuyerItemSearchResultEntry_Struct results[];
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BazaarTrader_StartTraderMode = 1,
|
BazaarTrader_StartTraderMode = 1,
|
||||||
BazaarTrader_EndTraderMode = 2,
|
BazaarTrader_EndTraderMode = 2,
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ void PathManager::LoadPaths()
|
|||||||
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
|
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// patches
|
||||||
|
if (File::Exists(fs::path{ m_server_path + "/" + c->OpcodeDir }.string())) {
|
||||||
|
m_opcode_path = fs::relative(fs::path{ m_server_path + "/" + c->OpcodeDir }).string();
|
||||||
|
}
|
||||||
|
|
||||||
// shared_memory_path
|
// shared_memory_path
|
||||||
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
|
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();
|
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
|
||||||
@@ -89,6 +94,7 @@ void PathManager::LoadPaths()
|
|||||||
LogInfo("lua_modules path [{}]", m_lua_modules_path);
|
LogInfo("lua_modules path [{}]", m_lua_modules_path);
|
||||||
LogInfo("maps path [{}]", m_maps_path);
|
LogInfo("maps path [{}]", m_maps_path);
|
||||||
LogInfo("patches path [{}]", m_patch_path);
|
LogInfo("patches path [{}]", m_patch_path);
|
||||||
|
LogInfo("opcode path [{}]", m_opcode_path);
|
||||||
LogInfo("plugins path [{}]", m_plugins_path);
|
LogInfo("plugins path [{}]", m_plugins_path);
|
||||||
LogInfo("quests path [{}]", m_quests_path);
|
LogInfo("quests path [{}]", m_quests_path);
|
||||||
LogInfo("shared_memory path [{}]", m_shared_memory_path);
|
LogInfo("shared_memory path [{}]", m_shared_memory_path);
|
||||||
@@ -129,6 +135,11 @@ const std::string &PathManager::GetPatchPath() const
|
|||||||
return m_patch_path;
|
return m_patch_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &PathManager::GetOpcodePath() const
|
||||||
|
{
|
||||||
|
return m_opcode_path;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &PathManager::GetLuaModulesPath() const
|
const std::string &PathManager::GetLuaModulesPath() const
|
||||||
{
|
{
|
||||||
return m_lua_modules_path;
|
return m_lua_modules_path;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
[[nodiscard]] const std::string &GetLuaModulesPath() const;
|
[[nodiscard]] const std::string &GetLuaModulesPath() const;
|
||||||
[[nodiscard]] const std::string &GetMapsPath() const;
|
[[nodiscard]] const std::string &GetMapsPath() const;
|
||||||
[[nodiscard]] const std::string &GetPatchPath() const;
|
[[nodiscard]] const std::string &GetPatchPath() const;
|
||||||
|
[[nodiscard]] const std::string &GetOpcodePath() const;
|
||||||
[[nodiscard]] const std::string &GetPluginsPath() const;
|
[[nodiscard]] const std::string &GetPluginsPath() const;
|
||||||
[[nodiscard]] const std::string &GetQuestsPath() const;
|
[[nodiscard]] const std::string &GetQuestsPath() const;
|
||||||
[[nodiscard]] const std::string &GetServerPath() const;
|
[[nodiscard]] const std::string &GetServerPath() const;
|
||||||
@@ -24,6 +25,7 @@ private:
|
|||||||
std::string m_lua_modules_path;
|
std::string m_lua_modules_path;
|
||||||
std::string m_maps_path;
|
std::string m_maps_path;
|
||||||
std::string m_patch_path;
|
std::string m_patch_path;
|
||||||
|
std::string m_opcode_path;
|
||||||
std::string m_plugins_path;
|
std::string m_plugins_path;
|
||||||
std::string m_quests_path;
|
std::string m_quests_path;
|
||||||
std::string m_server_path;
|
std::string m_server_path;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public:
|
|||||||
struct BotSpellsEntries {
|
struct BotSpellsEntries {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
int32_t npc_spells_id;
|
int32_t npc_spells_id;
|
||||||
int16_t spellid;
|
uint16_t spell_id;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint8_t minlevel;
|
uint8_t minlevel;
|
||||||
uint8_t maxlevel;
|
uint8_t maxlevel;
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
return {
|
return {
|
||||||
"id",
|
"id",
|
||||||
"npc_spells_id",
|
"npc_spells_id",
|
||||||
"spellid",
|
"spell_id",
|
||||||
"type",
|
"type",
|
||||||
"minlevel",
|
"minlevel",
|
||||||
"maxlevel",
|
"maxlevel",
|
||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
return {
|
return {
|
||||||
"id",
|
"id",
|
||||||
"npc_spells_id",
|
"npc_spells_id",
|
||||||
"spellid",
|
"spell_id",
|
||||||
"type",
|
"type",
|
||||||
"minlevel",
|
"minlevel",
|
||||||
"maxlevel",
|
"maxlevel",
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
|
|
||||||
e.id = 0;
|
e.id = 0;
|
||||||
e.npc_spells_id = 0;
|
e.npc_spells_id = 0;
|
||||||
e.spellid = 0;
|
e.spell_id = 0;
|
||||||
e.type = 0;
|
e.type = 0;
|
||||||
e.minlevel = 0;
|
e.minlevel = 0;
|
||||||
e.maxlevel = 255;
|
e.maxlevel = 255;
|
||||||
@@ -173,7 +173,7 @@ public:
|
|||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||||
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
|
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||||
@@ -220,7 +220,7 @@ public:
|
|||||||
auto columns = Columns();
|
auto columns = Columns();
|
||||||
|
|
||||||
v.push_back(columns[1] + " = " + std::to_string(e.npc_spells_id));
|
v.push_back(columns[1] + " = " + std::to_string(e.npc_spells_id));
|
||||||
v.push_back(columns[2] + " = " + std::to_string(e.spellid));
|
v.push_back(columns[2] + " = " + std::to_string(e.spell_id));
|
||||||
v.push_back(columns[3] + " = " + std::to_string(e.type));
|
v.push_back(columns[3] + " = " + std::to_string(e.type));
|
||||||
v.push_back(columns[4] + " = " + std::to_string(e.minlevel));
|
v.push_back(columns[4] + " = " + std::to_string(e.minlevel));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.maxlevel));
|
v.push_back(columns[5] + " = " + std::to_string(e.maxlevel));
|
||||||
@@ -256,7 +256,7 @@ public:
|
|||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.npc_spells_id));
|
v.push_back(std::to_string(e.npc_spells_id));
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.minlevel));
|
v.push_back(std::to_string(e.minlevel));
|
||||||
v.push_back(std::to_string(e.maxlevel));
|
v.push_back(std::to_string(e.maxlevel));
|
||||||
@@ -300,7 +300,7 @@ public:
|
|||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.npc_spells_id));
|
v.push_back(std::to_string(e.npc_spells_id));
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.minlevel));
|
v.push_back(std::to_string(e.minlevel));
|
||||||
v.push_back(std::to_string(e.maxlevel));
|
v.push_back(std::to_string(e.maxlevel));
|
||||||
@@ -348,7 +348,7 @@ public:
|
|||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||||
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
|
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||||
@@ -387,7 +387,7 @@ public:
|
|||||||
|
|
||||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.npc_spells_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||||
e.spellid = row[2] ? static_cast<int16_t>(atoi(row[2])) : 0;
|
e.spell_id = row[2] ? static_cast<uint16_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.minlevel = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
e.maxlevel = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 255;
|
||||||
@@ -476,7 +476,7 @@ public:
|
|||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.npc_spells_id));
|
v.push_back(std::to_string(e.npc_spells_id));
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.minlevel));
|
v.push_back(std::to_string(e.minlevel));
|
||||||
v.push_back(std::to_string(e.maxlevel));
|
v.push_back(std::to_string(e.maxlevel));
|
||||||
@@ -513,7 +513,7 @@ public:
|
|||||||
|
|
||||||
v.push_back(std::to_string(e.id));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.npc_spells_id));
|
v.push_back(std::to_string(e.npc_spells_id));
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back(std::to_string(e.type));
|
v.push_back(std::to_string(e.type));
|
||||||
v.push_back(std::to_string(e.minlevel));
|
v.push_back(std::to_string(e.minlevel));
|
||||||
v.push_back(std::to_string(e.maxlevel));
|
v.push_back(std::to_string(e.maxlevel));
|
||||||
|
|||||||
@@ -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_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../strings.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseBuyerBuyLinesRepository {
|
||||||
|
public:
|
||||||
|
struct BuyerBuyLines {
|
||||||
|
uint64_t id;
|
||||||
|
uint64_t buyer_id;
|
||||||
|
uint32_t char_id;
|
||||||
|
int32_t buy_slot_id;
|
||||||
|
int32_t item_id;
|
||||||
|
int32_t item_qty;
|
||||||
|
int32_t item_price;
|
||||||
|
uint32_t item_icon;
|
||||||
|
std::string item_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"buyer_id",
|
||||||
|
"char_id",
|
||||||
|
"buy_slot_id",
|
||||||
|
"item_id",
|
||||||
|
"item_qty",
|
||||||
|
"item_price",
|
||||||
|
"item_icon",
|
||||||
|
"item_name",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"buyer_id",
|
||||||
|
"char_id",
|
||||||
|
"buy_slot_id",
|
||||||
|
"item_id",
|
||||||
|
"item_qty",
|
||||||
|
"item_price",
|
||||||
|
"item_icon",
|
||||||
|
"item_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("buyer_buy_lines");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerBuyLines NewEntity()
|
||||||
|
{
|
||||||
|
BuyerBuyLines e{};
|
||||||
|
|
||||||
|
e.id = 0;
|
||||||
|
e.buyer_id = 0;
|
||||||
|
e.char_id = 0;
|
||||||
|
e.buy_slot_id = 0;
|
||||||
|
e.item_id = 0;
|
||||||
|
e.item_qty = 0;
|
||||||
|
e.item_price = 0;
|
||||||
|
e.item_icon = 0;
|
||||||
|
e.item_name = "";
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerBuyLines GetBuyerBuyLines(
|
||||||
|
const std::vector<BuyerBuyLines> &buyer_buy_liness,
|
||||||
|
int buyer_buy_lines_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &buyer_buy_lines : buyer_buy_liness) {
|
||||||
|
if (buyer_buy_lines.id == buyer_buy_lines_id) {
|
||||||
|
return buyer_buy_lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerBuyLines FindOne(
|
||||||
|
Database& db,
|
||||||
|
int buyer_buy_lines_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
|
buyer_buy_lines_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
BuyerBuyLines e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||||
|
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||||
|
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.item_name = row[8] ? row[8] : "";
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int buyer_buy_lines_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
buyer_buy_lines_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
const BuyerBuyLines &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
v.push_back(columns[1] + " = " + std::to_string(e.buyer_id));
|
||||||
|
v.push_back(columns[2] + " = " + std::to_string(e.char_id));
|
||||||
|
v.push_back(columns[3] + " = " + std::to_string(e.buy_slot_id));
|
||||||
|
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
|
||||||
|
v.push_back(columns[5] + " = " + std::to_string(e.item_qty));
|
||||||
|
v.push_back(columns[6] + " = " + std::to_string(e.item_price));
|
||||||
|
v.push_back(columns[7] + " = " + std::to_string(e.item_icon));
|
||||||
|
v.push_back(columns[8] + " = '" + Strings::Escape(e.item_name) + "'");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
Strings::Implode(", ", v),
|
||||||
|
PrimaryKey(),
|
||||||
|
e.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerBuyLines InsertOne(
|
||||||
|
Database& db,
|
||||||
|
BuyerBuyLines e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.buyer_id));
|
||||||
|
v.push_back(std::to_string(e.char_id));
|
||||||
|
v.push_back(std::to_string(e.buy_slot_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_price));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||||
|
|
||||||
|
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<BuyerBuyLines> &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.buyer_id));
|
||||||
|
v.push_back(std::to_string(e.char_id));
|
||||||
|
v.push_back(std::to_string(e.buy_slot_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_price));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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<BuyerBuyLines> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<BuyerBuyLines> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
BuyerBuyLines e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||||
|
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||||
|
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.item_name = row[8] ? row[8] : "";
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BuyerBuyLines> GetWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
std::vector<BuyerBuyLines> 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) {
|
||||||
|
BuyerBuyLines e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
|
e.buy_slot_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_qty = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
||||||
|
e.item_price = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
|
||||||
|
e.item_icon = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
|
e.item_name = row[8] ? row[8] : "";
|
||||||
|
|
||||||
|
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 BuyerBuyLines &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.buyer_id));
|
||||||
|
v.push_back(std::to_string(e.char_id));
|
||||||
|
v.push_back(std::to_string(e.buy_slot_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_price));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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<BuyerBuyLines> &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.buyer_id));
|
||||||
|
v.push_back(std::to_string(e.char_id));
|
||||||
|
v.push_back(std::to_string(e.buy_slot_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_price));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
@@ -19,40 +19,46 @@
|
|||||||
class BaseBuyerRepository {
|
class BaseBuyerRepository {
|
||||||
public:
|
public:
|
||||||
struct Buyer {
|
struct Buyer {
|
||||||
int32_t charid;
|
uint64_t id;
|
||||||
int32_t buyslot;
|
uint32_t char_id;
|
||||||
int32_t itemid;
|
uint32_t char_entity_id;
|
||||||
std::string itemname;
|
std::string char_name;
|
||||||
int32_t quantity;
|
uint32_t char_zone_id;
|
||||||
int32_t price;
|
uint32_t char_zone_instance_id;
|
||||||
|
time_t transaction_date;
|
||||||
|
std::string welcome_message;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
{
|
{
|
||||||
return std::string("charid");
|
return std::string("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> Columns()
|
static std::vector<std::string> Columns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"charid",
|
"id",
|
||||||
"buyslot",
|
"char_id",
|
||||||
"itemid",
|
"char_entity_id",
|
||||||
"itemname",
|
"char_name",
|
||||||
"quantity",
|
"char_zone_id",
|
||||||
"price",
|
"char_zone_instance_id",
|
||||||
|
"transaction_date",
|
||||||
|
"welcome_message",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> SelectColumns()
|
static std::vector<std::string> SelectColumns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"charid",
|
"id",
|
||||||
"buyslot",
|
"char_id",
|
||||||
"itemid",
|
"char_entity_id",
|
||||||
"itemname",
|
"char_name",
|
||||||
"quantity",
|
"char_zone_id",
|
||||||
"price",
|
"char_zone_instance_id",
|
||||||
|
"UNIX_TIMESTAMP(transaction_date)",
|
||||||
|
"welcome_message",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +99,14 @@ public:
|
|||||||
{
|
{
|
||||||
Buyer e{};
|
Buyer e{};
|
||||||
|
|
||||||
e.charid = 0;
|
e.id = 0;
|
||||||
e.buyslot = 0;
|
e.char_id = 0;
|
||||||
e.itemid = 0;
|
e.char_entity_id = 0;
|
||||||
e.itemname = "";
|
e.char_name = "";
|
||||||
e.quantity = 0;
|
e.char_zone_id = 0;
|
||||||
e.price = 0;
|
e.char_zone_instance_id = 0;
|
||||||
|
e.transaction_date = 0;
|
||||||
|
e.welcome_message = "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -109,7 +117,7 @@ public:
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
for (auto &buyer : buyers) {
|
for (auto &buyer : buyers) {
|
||||||
if (buyer.charid == buyer_id) {
|
if (buyer.id == buyer_id) {
|
||||||
return buyer;
|
return buyer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,12 +143,14 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
Buyer e{};
|
Buyer e{};
|
||||||
|
|
||||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.itemname = row[3] ? row[3] : "";
|
e.char_name = row[3] ? row[3] : "";
|
||||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||||
|
e.welcome_message = row[7] ? row[7] : "";
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -174,12 +184,13 @@ public:
|
|||||||
|
|
||||||
auto columns = Columns();
|
auto columns = Columns();
|
||||||
|
|
||||||
v.push_back(columns[0] + " = " + std::to_string(e.charid));
|
v.push_back(columns[1] + " = " + std::to_string(e.char_id));
|
||||||
v.push_back(columns[1] + " = " + std::to_string(e.buyslot));
|
v.push_back(columns[2] + " = " + std::to_string(e.char_entity_id));
|
||||||
v.push_back(columns[2] + " = " + std::to_string(e.itemid));
|
v.push_back(columns[3] + " = '" + Strings::Escape(e.char_name) + "'");
|
||||||
v.push_back(columns[3] + " = '" + Strings::Escape(e.itemname) + "'");
|
v.push_back(columns[4] + " = " + std::to_string(e.char_zone_id));
|
||||||
v.push_back(columns[4] + " = " + std::to_string(e.quantity));
|
v.push_back(columns[5] + " = " + std::to_string(e.char_zone_instance_id));
|
||||||
v.push_back(columns[5] + " = " + std::to_string(e.price));
|
v.push_back(columns[6] + " = FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||||
|
v.push_back(columns[7] + " = '" + Strings::Escape(e.welcome_message) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -187,7 +198,7 @@ public:
|
|||||||
TableName(),
|
TableName(),
|
||||||
Strings::Implode(", ", v),
|
Strings::Implode(", ", v),
|
||||||
PrimaryKey(),
|
PrimaryKey(),
|
||||||
e.charid
|
e.id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -201,12 +212,14 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.buyslot));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
v.push_back(std::to_string(e.price));
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||||
|
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -217,7 +230,7 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (results.Success()) {
|
if (results.Success()) {
|
||||||
e.charid = results.LastInsertedID();
|
e.id = results.LastInsertedID();
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,12 +249,14 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.buyslot));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
v.push_back(std::to_string(e.price));
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||||
|
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@@ -275,12 +290,14 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Buyer e{};
|
Buyer e{};
|
||||||
|
|
||||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.itemname = row[3] ? row[3] : "";
|
e.char_name = row[3] ? row[3] : "";
|
||||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||||
|
e.welcome_message = row[7] ? row[7] : "";
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -305,12 +322,14 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Buyer e{};
|
Buyer e{};
|
||||||
|
|
||||||
e.charid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.buyslot = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.itemid = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
e.char_entity_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.itemname = row[3] ? row[3] : "";
|
e.char_name = row[3] ? row[3] : "";
|
||||||
e.quantity = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
e.char_zone_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.price = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
|
e.char_zone_instance_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
|
e.transaction_date = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
|
||||||
|
e.welcome_message = row[7] ? row[7] : "";
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -385,12 +404,14 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.buyslot));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
v.push_back(std::to_string(e.price));
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||||
|
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -413,12 +434,14 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.charid));
|
v.push_back(std::to_string(e.id));
|
||||||
v.push_back(std::to_string(e.buyslot));
|
v.push_back(std::to_string(e.char_id));
|
||||||
v.push_back(std::to_string(e.itemid));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back("'" + Strings::Escape(e.itemname) + "'");
|
v.push_back("'" + Strings::Escape(e.char_name) + "'");
|
||||||
v.push_back(std::to_string(e.quantity));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
v.push_back(std::to_string(e.price));
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
|
v.push_back("FROM_UNIXTIME(" + (e.transaction_date > 0 ? std::to_string(e.transaction_date) : "null") + ")");
|
||||||
|
v.push_back("'" + Strings::Escape(e.welcome_message) + "'");
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,439 @@
|
|||||||
|
/**
|
||||||
|
* 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_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../strings.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseBuyerTradeItemsRepository {
|
||||||
|
public:
|
||||||
|
struct BuyerTradeItems {
|
||||||
|
uint64_t id;
|
||||||
|
uint64_t buyer_buy_lines_id;
|
||||||
|
int32_t item_id;
|
||||||
|
int32_t item_qty;
|
||||||
|
int32_t item_icon;
|
||||||
|
std::string item_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"buyer_buy_lines_id",
|
||||||
|
"item_id",
|
||||||
|
"item_qty",
|
||||||
|
"item_icon",
|
||||||
|
"item_name",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"buyer_buy_lines_id",
|
||||||
|
"item_id",
|
||||||
|
"item_qty",
|
||||||
|
"item_icon",
|
||||||
|
"item_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("buyer_trade_items");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerTradeItems NewEntity()
|
||||||
|
{
|
||||||
|
BuyerTradeItems e{};
|
||||||
|
|
||||||
|
e.id = 0;
|
||||||
|
e.buyer_buy_lines_id = 0;
|
||||||
|
e.item_id = 0;
|
||||||
|
e.item_qty = 0;
|
||||||
|
e.item_icon = 0;
|
||||||
|
e.item_name = "0";
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerTradeItems GetBuyerTradeItems(
|
||||||
|
const std::vector<BuyerTradeItems> &buyer_trade_itemss,
|
||||||
|
int buyer_trade_items_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &buyer_trade_items : buyer_trade_itemss) {
|
||||||
|
if (buyer_trade_items.id == buyer_trade_items_id) {
|
||||||
|
return buyer_trade_items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerTradeItems FindOne(
|
||||||
|
Database& db,
|
||||||
|
int buyer_trade_items_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {} = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
PrimaryKey(),
|
||||||
|
buyer_trade_items_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
BuyerTradeItems e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||||
|
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_name = row[5] ? row[5] : "0";
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int buyer_trade_items_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
buyer_trade_items_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
const BuyerTradeItems &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
v.push_back(columns[1] + " = " + std::to_string(e.buyer_buy_lines_id));
|
||||||
|
v.push_back(columns[2] + " = " + std::to_string(e.item_id));
|
||||||
|
v.push_back(columns[3] + " = " + std::to_string(e.item_qty));
|
||||||
|
v.push_back(columns[4] + " = " + std::to_string(e.item_icon));
|
||||||
|
v.push_back(columns[5] + " = '" + Strings::Escape(e.item_name) + "'");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
Strings::Implode(", ", v),
|
||||||
|
PrimaryKey(),
|
||||||
|
e.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerTradeItems InsertOne(
|
||||||
|
Database& db,
|
||||||
|
BuyerTradeItems e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.buyer_buy_lines_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_name) + "'");
|
||||||
|
|
||||||
|
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<BuyerTradeItems> &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.buyer_buy_lines_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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<BuyerTradeItems> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<BuyerTradeItems> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
BuyerTradeItems e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||||
|
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_name = row[5] ? row[5] : "0";
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BuyerTradeItems> GetWhere(Database& db, const std::string &where_filter)
|
||||||
|
{
|
||||||
|
std::vector<BuyerTradeItems> 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) {
|
||||||
|
BuyerTradeItems e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||||
|
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_name = row[5] ? row[5] : "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 BuyerTradeItems &e
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> v;
|
||||||
|
|
||||||
|
v.push_back(std::to_string(e.id));
|
||||||
|
v.push_back(std::to_string(e.buyer_buy_lines_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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<BuyerTradeItems> &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.buyer_buy_lines_id));
|
||||||
|
v.push_back(std::to_string(e.item_id));
|
||||||
|
v.push_back(std::to_string(e.item_qty));
|
||||||
|
v.push_back(std::to_string(e.item_icon));
|
||||||
|
v.push_back("'" + Strings::Escape(e.item_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_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
@@ -35,6 +35,7 @@ public:
|
|||||||
uint32_t ornamenticon;
|
uint32_t ornamenticon;
|
||||||
uint32_t ornamentidfile;
|
uint32_t ornamentidfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
|
uint64_t guid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -61,6 +62,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +85,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +142,7 @@ public:
|
|||||||
e.ornamenticon = 0;
|
e.ornamenticon = 0;
|
||||||
e.ornamentidfile = 0;
|
e.ornamentidfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
|
e.guid = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -191,6 +195,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -240,6 +245,7 @@ public:
|
|||||||
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
|
v.push_back(columns[13] + " = " + std::to_string(e.ornamenticon));
|
||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
|
v.push_back(columns[14] + " = " + std::to_string(e.ornamentidfile));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
|
v.push_back(columns[15] + " = " + std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(columns[16] + " = " + std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -277,6 +283,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -322,6 +329,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@@ -371,6 +379,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -411,6 +420,7 @@ public:
|
|||||||
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.ornamenticon = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamentidfile = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
e.ornament_hero_model = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.guid = row[16] ? strtoull(row[16], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -501,6 +511,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -539,6 +550,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
uint32_t ornamenticon;
|
uint32_t ornamenticon;
|
||||||
uint32_t ornamentidfile;
|
uint32_t ornamentidfile;
|
||||||
int32_t ornament_hero_model;
|
int32_t ornament_hero_model;
|
||||||
|
uint64_t guid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -63,6 +64,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +88,7 @@ public:
|
|||||||
"ornamenticon",
|
"ornamenticon",
|
||||||
"ornamentidfile",
|
"ornamentidfile",
|
||||||
"ornament_hero_model",
|
"ornament_hero_model",
|
||||||
|
"guid",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +146,7 @@ public:
|
|||||||
e.ornamenticon = 0;
|
e.ornamenticon = 0;
|
||||||
e.ornamentidfile = 0;
|
e.ornamentidfile = 0;
|
||||||
e.ornament_hero_model = 0;
|
e.ornament_hero_model = 0;
|
||||||
|
e.guid = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -196,6 +200,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||||
|
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -246,6 +251,7 @@ public:
|
|||||||
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
v.push_back(columns[14] + " = " + std::to_string(e.ornamenticon));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
v.push_back(columns[15] + " = " + std::to_string(e.ornamentidfile));
|
||||||
v.push_back(columns[16] + " = " + std::to_string(e.ornament_hero_model));
|
v.push_back(columns[16] + " = " + std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(columns[17] + " = " + std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -284,6 +290,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -330,6 +337,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@@ -380,6 +388,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||||
|
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -421,6 +430,7 @@ public:
|
|||||||
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.ornamenticon = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
e.ornamentidfile = row[15] ? static_cast<uint32_t>(strtoul(row[15], nullptr, 10)) : 0;
|
||||||
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
e.ornament_hero_model = row[16] ? static_cast<int32_t>(atoi(row[16])) : 0;
|
||||||
|
e.guid = row[17] ? strtoull(row[17], nullptr, 10) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -512,6 +522,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -551,6 +562,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.ornamenticon));
|
v.push_back(std::to_string(e.ornamenticon));
|
||||||
v.push_back(std::to_string(e.ornamentidfile));
|
v.push_back(std::to_string(e.ornamentidfile));
|
||||||
v.push_back(std::to_string(e.ornament_hero_model));
|
v.push_back(std::to_string(e.ornament_hero_model));
|
||||||
|
v.push_back(std::to_string(e.guid));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,31 +19,34 @@
|
|||||||
class BaseSpellBucketsRepository {
|
class BaseSpellBucketsRepository {
|
||||||
public:
|
public:
|
||||||
struct SpellBuckets {
|
struct SpellBuckets {
|
||||||
uint64_t spellid;
|
uint32_t spell_id;
|
||||||
std::string key_;
|
std::string bucket_name;
|
||||||
std::string value;
|
std::string bucket_value;
|
||||||
|
uint8_t bucket_comparison;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
{
|
{
|
||||||
return std::string("spellid");
|
return std::string("spell_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> Columns()
|
static std::vector<std::string> Columns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"spellid",
|
"spell_id",
|
||||||
"`key`",
|
"bucket_name",
|
||||||
"value",
|
"bucket_value",
|
||||||
|
"bucket_comparison",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> SelectColumns()
|
static std::vector<std::string> SelectColumns()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"spellid",
|
"spell_id",
|
||||||
"`key`",
|
"bucket_name",
|
||||||
"value",
|
"bucket_value",
|
||||||
|
"bucket_comparison",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,9 +87,10 @@ public:
|
|||||||
{
|
{
|
||||||
SpellBuckets e{};
|
SpellBuckets e{};
|
||||||
|
|
||||||
e.spellid = 0;
|
e.spell_id = 0;
|
||||||
e.key_ = "";
|
e.bucket_name = "";
|
||||||
e.value = "";
|
e.bucket_value = "";
|
||||||
|
e.bucket_comparison = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -97,7 +101,7 @@ public:
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
for (auto &spell_buckets : spell_bucketss) {
|
for (auto &spell_buckets : spell_bucketss) {
|
||||||
if (spell_buckets.spellid == spell_buckets_id) {
|
if (spell_buckets.spell_id == spell_buckets_id) {
|
||||||
return spell_buckets;
|
return spell_buckets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,9 +127,10 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
SpellBuckets e{};
|
SpellBuckets e{};
|
||||||
|
|
||||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.key_ = row[1] ? row[1] : "";
|
e.bucket_name = row[1] ? row[1] : "";
|
||||||
e.value = row[2] ? row[2] : "";
|
e.bucket_value = row[2] ? row[2] : "";
|
||||||
|
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -159,9 +164,10 @@ public:
|
|||||||
|
|
||||||
auto columns = Columns();
|
auto columns = Columns();
|
||||||
|
|
||||||
v.push_back(columns[0] + " = " + std::to_string(e.spellid));
|
v.push_back(columns[0] + " = " + std::to_string(e.spell_id));
|
||||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
|
v.push_back(columns[1] + " = '" + Strings::Escape(e.bucket_name) + "'");
|
||||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
|
v.push_back(columns[2] + " = '" + Strings::Escape(e.bucket_value) + "'");
|
||||||
|
v.push_back(columns[3] + " = " + std::to_string(e.bucket_comparison));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -169,7 +175,7 @@ public:
|
|||||||
TableName(),
|
TableName(),
|
||||||
Strings::Implode(", ", v),
|
Strings::Implode(", ", v),
|
||||||
PrimaryKey(),
|
PrimaryKey(),
|
||||||
e.spellid
|
e.spell_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -183,9 +189,10 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||||
|
v.push_back(std::to_string(e.bucket_comparison));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -196,7 +203,7 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (results.Success()) {
|
if (results.Success()) {
|
||||||
e.spellid = results.LastInsertedID();
|
e.spell_id = results.LastInsertedID();
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,9 +222,10 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||||
|
v.push_back(std::to_string(e.bucket_comparison));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
@@ -251,9 +259,10 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
SpellBuckets e{};
|
SpellBuckets e{};
|
||||||
|
|
||||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.key_ = row[1] ? row[1] : "";
|
e.bucket_name = row[1] ? row[1] : "";
|
||||||
e.value = row[2] ? row[2] : "";
|
e.bucket_value = row[2] ? row[2] : "";
|
||||||
|
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -278,9 +287,10 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
SpellBuckets e{};
|
SpellBuckets e{};
|
||||||
|
|
||||||
e.spellid = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.spell_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||||
e.key_ = row[1] ? row[1] : "";
|
e.bucket_name = row[1] ? row[1] : "";
|
||||||
e.value = row[2] ? row[2] : "";
|
e.bucket_value = row[2] ? row[2] : "";
|
||||||
|
e.bucket_comparison = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -355,9 +365,10 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||||
|
v.push_back(std::to_string(e.bucket_comparison));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -380,9 +391,10 @@ public:
|
|||||||
for (auto &e: entries) {
|
for (auto &e: entries) {
|
||||||
std::vector<std::string> v;
|
std::vector<std::string> v;
|
||||||
|
|
||||||
v.push_back(std::to_string(e.spellid));
|
v.push_back(std::to_string(e.spell_id));
|
||||||
v.push_back("'" + Strings::Escape(e.key_) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_name) + "'");
|
||||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
v.push_back("'" + Strings::Escape(e.bucket_value) + "'");
|
||||||
|
v.push_back(std::to_string(e.bucket_comparison));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
|
static std::vector<std::string> GetBaseDataFileLines(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY `level`, `class` ASC",
|
||||||
|
ColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto row : results) {
|
||||||
|
lines.emplace_back(row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_BASE_DATA_REPOSITORY_H
|
#endif //EQEMU_BASE_DATA_REPOSITORY_H
|
||||||
|
|||||||
@@ -0,0 +1,360 @@
|
|||||||
|
#ifndef EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
|
#define EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../strings.h"
|
||||||
|
#include "base/base_buyer_buy_lines_repository.h"
|
||||||
|
#include "buyer_trade_items_repository.h"
|
||||||
|
#include "character_data_repository.h"
|
||||||
|
#include "buyer_repository.h"
|
||||||
|
|
||||||
|
#include "../eq_packet_structs.h"
|
||||||
|
|
||||||
|
class BuyerBuyLinesRepository: public BaseBuyerBuyLinesRepository {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file was auto generated and can be modified and extended upon
|
||||||
|
*
|
||||||
|
* Base repository methods are automatically
|
||||||
|
* generated in the "base" version of this repository. The base repository
|
||||||
|
* is immutable and to be left untouched, while methods in this class
|
||||||
|
* are used as extension methods for more specific persistence-layer
|
||||||
|
* accessors or mutators.
|
||||||
|
*
|
||||||
|
* Base Methods (Subject to be expanded upon in time)
|
||||||
|
*
|
||||||
|
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||||
|
*
|
||||||
|
* InsertOne
|
||||||
|
* UpdateOne
|
||||||
|
* DeleteOne
|
||||||
|
* FindOne
|
||||||
|
* GetWhere(std::string where_filter)
|
||||||
|
* DeleteWhere(std::string where_filter)
|
||||||
|
* InsertMany
|
||||||
|
* All
|
||||||
|
*
|
||||||
|
* Example custom methods in a repository
|
||||||
|
*
|
||||||
|
* BuyerBuyLinesRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||||
|
* BuyerBuyLinesRepository::GetWhereNeverExpires()
|
||||||
|
* BuyerBuyLinesRepository::GetWhereXAndY()
|
||||||
|
* BuyerBuyLinesRepository::DeleteWhereXAndY()
|
||||||
|
*
|
||||||
|
* Most of the above could be covered by base methods, but if you as a developer
|
||||||
|
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||||
|
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||||
|
* method and encapsulate filters there
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
struct WelcomeData_Struct {
|
||||||
|
uint32 count_of_buyers;
|
||||||
|
uint32 count_of_items;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CreateBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
|
||||||
|
{
|
||||||
|
auto buyer = BuyerRepository::GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1", char_id));
|
||||||
|
if (buyer.empty()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyerBuyLinesRepository::BuyerBuyLines buy_lines{};
|
||||||
|
buy_lines.id = 0;
|
||||||
|
buy_lines.buyer_id = buyer.front().id;
|
||||||
|
buy_lines.char_id = char_id;
|
||||||
|
buy_lines.buy_slot_id = b.slot;
|
||||||
|
buy_lines.item_id = b.item_id;
|
||||||
|
buy_lines.item_name = b.item_name;
|
||||||
|
buy_lines.item_icon = b.item_icon;
|
||||||
|
buy_lines.item_qty = b.item_quantity;
|
||||||
|
buy_lines.item_price = b.item_cost;
|
||||||
|
auto e = InsertOne(db, buy_lines);
|
||||||
|
|
||||||
|
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
|
||||||
|
|
||||||
|
for (auto const &r: b.trade_items) {
|
||||||
|
BuyerTradeItemsRepository::BuyerTradeItems bti{};
|
||||||
|
bti.id = 0;
|
||||||
|
bti.buyer_buy_lines_id = e.id;
|
||||||
|
bti.item_id = r.item_id;
|
||||||
|
bti.item_qty = r.item_quantity;
|
||||||
|
bti.item_icon = r.item_icon;
|
||||||
|
bti.item_name = r.item_name;
|
||||||
|
|
||||||
|
if (bti.item_id) {
|
||||||
|
queue.push_back(bti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queue.empty()) {
|
||||||
|
BuyerTradeItemsRepository::InsertMany(db, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ModifyBuyLine(Database& db, const BuyerLineItems_Struct b, uint32 char_id)
|
||||||
|
{
|
||||||
|
auto b_lines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}';", char_id, b.slot));
|
||||||
|
if (b_lines.empty() || b_lines.size() > 1){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b_line = b_lines.front();
|
||||||
|
|
||||||
|
b_line.item_qty = b.item_quantity;
|
||||||
|
b_line.item_price = b.item_cost;
|
||||||
|
b_line.item_icon = b.item_icon;
|
||||||
|
auto e = UpdateOne(db, b_line);
|
||||||
|
|
||||||
|
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> queue;
|
||||||
|
|
||||||
|
BuyerTradeItemsRepository::DeleteWhere(db, fmt::format("`buyer_buy_lines_id` = '{}';", b_line.id));
|
||||||
|
for (auto const &r: b.trade_items) {
|
||||||
|
BuyerTradeItemsRepository::BuyerTradeItems bti{};
|
||||||
|
bti.id = 0;
|
||||||
|
bti.buyer_buy_lines_id = b_line.id;
|
||||||
|
bti.item_id = r.item_id;
|
||||||
|
bti.item_qty = r.item_quantity;
|
||||||
|
bti.item_icon = r.item_icon;
|
||||||
|
bti.item_name = r.item_name;
|
||||||
|
|
||||||
|
if (bti.item_id) {
|
||||||
|
queue.push_back(bti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queue.empty()) {
|
||||||
|
BuyerTradeItemsRepository::InsertMany(db, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DeleteBuyLine(Database &db, uint32 char_id, int32 slot_id = 0xffffffff)
|
||||||
|
{
|
||||||
|
std::vector<BuyerBuyLines> buylines{};
|
||||||
|
if (slot_id == 0xffffffff) {
|
||||||
|
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}'", char_id));
|
||||||
|
DeleteWhere(db, fmt::format("`char_id` = '{}'", char_id));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto buylines = GetWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
|
||||||
|
DeleteWhere(db, fmt::format("`char_id` = '{}' AND `buy_slot_id` = '{}'", char_id, slot_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buylines.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> buyline_ids{};
|
||||||
|
for (auto const &bl: buylines) {
|
||||||
|
buyline_ids.push_back((std::to_string(bl.id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buyline_ids.empty()) {
|
||||||
|
BuyerTradeItemsRepository::DeleteWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`buyer_buy_lines_id` IN({})",
|
||||||
|
Strings::Implode(", ", buyline_ids)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BuyerLineItems_Struct> GetBuyLines(Database &db, uint32 char_id)
|
||||||
|
{
|
||||||
|
std::vector<BuyerLineItems_Struct> all_entries{};
|
||||||
|
|
||||||
|
auto buy_line = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||||
|
if (buy_line.empty()){
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`buyer_buy_lines_id` IN (SELECT b.id FROM buyer_buy_lines AS b WHERE b.char_id = '{}')",
|
||||||
|
char_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(buy_line.size());
|
||||||
|
|
||||||
|
for (auto const &l: buy_line) {
|
||||||
|
BuyerLineItems_Struct bli{};
|
||||||
|
bli.item_id = l.item_id;
|
||||||
|
bli.item_cost = l.item_price;
|
||||||
|
bli.item_quantity = l.item_qty;
|
||||||
|
bli.slot = l.buy_slot_id;
|
||||||
|
bli.item_name = l.item_name;
|
||||||
|
|
||||||
|
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
|
||||||
|
BuyerLineTradeItems_Struct blti{};
|
||||||
|
blti.item_id = i.item_id;
|
||||||
|
blti.item_icon = i.item_icon;
|
||||||
|
blti.item_quantity = i.item_qty;
|
||||||
|
blti.item_id = i.item_id;
|
||||||
|
blti.item_name = i.item_name;
|
||||||
|
bli.trade_items.push_back(blti);
|
||||||
|
}
|
||||||
|
all_entries.push_back(bli);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuyerLineSearch_Struct SearchBuyLines(
|
||||||
|
Database &db,
|
||||||
|
std::string &search_string,
|
||||||
|
uint32 char_id = 0,
|
||||||
|
uint32 zone_id = 0,
|
||||||
|
uint32 zone_instance_id = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BuyerLineSearch_Struct all_entries{};
|
||||||
|
std::string where_clause(fmt::format("`item_name` LIKE \"%{}%\" ", search_string));
|
||||||
|
|
||||||
|
if (char_id) {
|
||||||
|
where_clause += fmt::format("AND `char_id` = '{}' ", char_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone_id) {
|
||||||
|
auto buyers = BuyerRepository::GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`char_zone_id` = '{}' AND char_zone_instance_id = '{}'",
|
||||||
|
zone_id,
|
||||||
|
zone_instance_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (buyers.empty()) {
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> char_ids{};
|
||||||
|
for (auto const &bl : buyers) {
|
||||||
|
char_ids.push_back((std::to_string(bl.char_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
where_clause += fmt::format("AND `char_id` IN ({}) ", Strings::Implode(", ", char_ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buy_line = GetWhere(db, where_clause);
|
||||||
|
if (buy_line.empty()){
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ids{};
|
||||||
|
std::vector<std::string> char_ids{};
|
||||||
|
for (auto const &bl : buy_line) {
|
||||||
|
if (std::find(ids.begin(), ids.end(), std::to_string(bl.id)) == std::end(ids)) {
|
||||||
|
ids.push_back(std::to_string(bl.id));
|
||||||
|
}
|
||||||
|
if (std::find(char_ids.begin(), char_ids.end(), std::to_string(bl.char_id)) == std::end(char_ids)) {
|
||||||
|
char_ids.push_back((std::to_string(bl.char_id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buy_line_trade_items = BuyerTradeItemsRepository::GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`buyer_buy_lines_id` IN ({});",
|
||||||
|
Strings::Implode(", ", ids)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto char_names = BuyerRepository::GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`char_id` IN ({});",
|
||||||
|
Strings::Implode(", ", char_ids)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.no_items = buy_line.size();
|
||||||
|
for (auto const &l: buy_line) {
|
||||||
|
BuyerLineItemsSearch_Struct blis{};
|
||||||
|
blis.slot = l.buy_slot_id;
|
||||||
|
blis.item_id = l.item_id;
|
||||||
|
blis.item_cost = l.item_price;
|
||||||
|
blis.item_icon = l.item_icon;
|
||||||
|
blis.item_quantity = l.item_qty;
|
||||||
|
blis.buyer_id = l.char_id;
|
||||||
|
auto it = std::find_if(
|
||||||
|
char_names.cbegin(),
|
||||||
|
char_names.cend(),
|
||||||
|
[&](BuyerRepository::Buyer e) { return e.char_id == l.char_id; }
|
||||||
|
);
|
||||||
|
blis.buyer_name = it != char_names.end() ? it->char_name : std::string("");
|
||||||
|
blis.buyer_entity_id = it != char_names.end() ? it->char_entity_id : 0;
|
||||||
|
blis.buyer_zone_id = it != char_names.end() ? it->char_zone_id : 0;
|
||||||
|
blis.buyer_zone_instance_id = it != char_names.end() ? it->char_zone_instance_id : 0;
|
||||||
|
strn0cpy(blis.item_name, l.item_name.c_str(), sizeof(blis.item_name));
|
||||||
|
|
||||||
|
for (auto const &i: GetSubIDs(buy_line_trade_items, l.id)) {
|
||||||
|
BuyerLineTradeItems_Struct e{};
|
||||||
|
e.item_id = i.item_id;
|
||||||
|
e.item_icon = i.item_icon;
|
||||||
|
e.item_quantity = i.item_qty;
|
||||||
|
e.item_id = i.item_id;
|
||||||
|
e.item_name = i.item_name;
|
||||||
|
|
||||||
|
blis.trade_items.push_back(e);
|
||||||
|
}
|
||||||
|
all_entries.buy_line.push_back(blis);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<BuyerTradeItemsRepository::BuyerTradeItems>
|
||||||
|
GetSubIDs(std::vector<BuyerTradeItemsRepository::BuyerTradeItems> &in, uint64 id)
|
||||||
|
{
|
||||||
|
std::vector<BuyerTradeItemsRepository::BuyerTradeItems> results{};
|
||||||
|
std::vector<uint64> indices{};
|
||||||
|
|
||||||
|
auto it = in.begin();
|
||||||
|
while ((it = std::find_if(
|
||||||
|
it,
|
||||||
|
in.end(),
|
||||||
|
[&](BuyerTradeItemsRepository::BuyerTradeItems const &e) {
|
||||||
|
return e.buyer_buy_lines_id == id;
|
||||||
|
}
|
||||||
|
))
|
||||||
|
!= in.end()
|
||||||
|
) {
|
||||||
|
indices.push_back(std::distance(in.begin(), it));
|
||||||
|
results.push_back(*it);
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WelcomeData_Struct GetWelcomeData(Database &db)
|
||||||
|
{
|
||||||
|
WelcomeData_Struct e{};
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase("SELECT COUNT(DISTINCT char_id), COUNT(char_id) FROM buyer;");
|
||||||
|
|
||||||
|
if (!results.RowCount()) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto r = results.begin();
|
||||||
|
e.count_of_buyers = Strings::ToInt(r[0]);
|
||||||
|
e.count_of_items = Strings::ToInt(r[1]);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BUYER_BUY_LINES_REPOSITORY_H
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "../database.h"
|
#include "../database.h"
|
||||||
#include "../strings.h"
|
#include "../strings.h"
|
||||||
#include "base/base_buyer_repository.h"
|
#include "base/base_buyer_repository.h"
|
||||||
|
#include "base/base_buyer_trade_items_repository.h"
|
||||||
|
#include "base/base_buyer_buy_lines_repository.h"
|
||||||
|
|
||||||
class BuyerRepository: public BaseBuyerRepository {
|
class BuyerRepository: public BaseBuyerRepository {
|
||||||
public:
|
public:
|
||||||
@@ -45,6 +47,97 @@ public:
|
|||||||
|
|
||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
static bool UpdateWelcomeMessage(Database& db, uint32 char_id, const char *message) {
|
||||||
|
|
||||||
|
auto const b = GetWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||||
|
|
||||||
|
if (b.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buyer = b.front();
|
||||||
|
buyer.welcome_message = message;
|
||||||
|
return UpdateOne(db, buyer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetWelcomeMessage(Database& db, uint32 char_id) {
|
||||||
|
|
||||||
|
auto const b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||||
|
if (b.empty()) {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.front().welcome_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateTransactionDate(Database& db, uint32 char_id, time_t transaction_date) {
|
||||||
|
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||||
|
if (b.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto e = b.front();
|
||||||
|
e.transaction_date = transaction_date;
|
||||||
|
|
||||||
|
return UpdateOne(db, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static time_t GetTransactionDate(Database& db, uint32 char_id) {
|
||||||
|
auto b = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||||
|
if (b.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto e = b.front();
|
||||||
|
|
||||||
|
return e.transaction_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DeleteBuyer(Database &db, uint32 char_id)
|
||||||
|
{
|
||||||
|
if (char_id == 0) {
|
||||||
|
Truncate(db);
|
||||||
|
BaseBuyerBuyLinesRepository::Truncate(db);
|
||||||
|
BaseBuyerTradeItemsRepository::Truncate(db);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto buyer = GetWhere(db, fmt::format("`char_id` = '{}' LIMIT 1;", char_id));
|
||||||
|
if (buyer.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buy_lines = BaseBuyerBuyLinesRepository::GetWhere(
|
||||||
|
db,
|
||||||
|
fmt::format("`buyer_id` = '{}'", buyer.front().id)
|
||||||
|
);
|
||||||
|
if (buy_lines.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> buy_line_ids{};
|
||||||
|
for (auto const &bl: buy_lines) {
|
||||||
|
buy_line_ids.push_back(std::to_string(bl.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteWhere(db, fmt::format("`char_id` = '{}';", char_id));
|
||||||
|
if (buy_line_ids.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseBuyerBuyLinesRepository::DeleteWhere(
|
||||||
|
db,
|
||||||
|
fmt::format("`id` IN({})", Strings::Implode(", ", buy_line_ids))
|
||||||
|
);
|
||||||
|
BaseBuyerTradeItemsRepository::DeleteWhere(
|
||||||
|
db,
|
||||||
|
fmt::format(
|
||||||
|
"`buyer_buy_lines_id` IN({})",
|
||||||
|
Strings::Implode(", ", buy_line_ids))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_BUYER_REPOSITORY_H
|
#endif //EQEMU_BUYER_REPOSITORY_H
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
|
#define EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../strings.h"
|
||||||
|
#include "base/base_buyer_trade_items_repository.h"
|
||||||
|
|
||||||
|
class BuyerTradeItemsRepository: public BaseBuyerTradeItemsRepository {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file was auto generated and can be modified and extended upon
|
||||||
|
*
|
||||||
|
* Base repository methods are automatically
|
||||||
|
* generated in the "base" version of this repository. The base repository
|
||||||
|
* is immutable and to be left untouched, while methods in this class
|
||||||
|
* are used as extension methods for more specific persistence-layer
|
||||||
|
* accessors or mutators.
|
||||||
|
*
|
||||||
|
* Base Methods (Subject to be expanded upon in time)
|
||||||
|
*
|
||||||
|
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||||
|
*
|
||||||
|
* InsertOne
|
||||||
|
* UpdateOne
|
||||||
|
* DeleteOne
|
||||||
|
* FindOne
|
||||||
|
* GetWhere(std::string where_filter)
|
||||||
|
* DeleteWhere(std::string where_filter)
|
||||||
|
* InsertMany
|
||||||
|
* All
|
||||||
|
*
|
||||||
|
* Example custom methods in a repository
|
||||||
|
*
|
||||||
|
* BuyerTradeItemsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||||
|
* BuyerTradeItemsRepository::GetWhereNeverExpires()
|
||||||
|
* BuyerTradeItemsRepository::GetWhereXAndY()
|
||||||
|
* BuyerTradeItemsRepository::DeleteWhereXAndY()
|
||||||
|
*
|
||||||
|
* Most of the above could be covered by base methods, but if you as a developer
|
||||||
|
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||||
|
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||||
|
* method and encapsulate filters there
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
static std::vector<BuyerTradeItems> GetTradeItems(Database& db, const uint32 char_id)
|
||||||
|
{
|
||||||
|
std::vector<BuyerTradeItems> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT bti.* "
|
||||||
|
"FROM buyer_trade_items AS bti "
|
||||||
|
"INNER JOIN buyer_buy_lines AS bbl ON bti.buyer_buy_lines_id = bbl.id "
|
||||||
|
"WHERE bbl.char_id = '{}';",
|
||||||
|
char_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
BuyerTradeItems e{};
|
||||||
|
|
||||||
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
|
e.buyer_buy_lines_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
|
||||||
|
e.item_id = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
|
||||||
|
e.item_qty = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
|
||||||
|
e.item_icon = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
|
||||||
|
e.item_name = row[5] ? row[5] : "0";
|
||||||
|
|
||||||
|
all_entries.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BUYER_TRADE_ITEMS_REPOSITORY_H
|
||||||
@@ -49,6 +49,7 @@ public:
|
|||||||
// these are the base definitions for command_subsettings and can be over-ridden by the database
|
// these are the base definitions for command_subsettings and can be over-ridden by the database
|
||||||
std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = {
|
std::vector<CommandSubsettingsRepository::CommandSubsettings> static_records = {
|
||||||
{.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"},
|
{.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"},
|
||||||
|
{.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"},
|
||||||
{.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"},
|
{.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"},
|
||||||
{.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"},
|
{.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"},
|
||||||
{.parent_command = "find", .sub_command = "class", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findclass"},
|
{.parent_command = "find", .sub_command = "class", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findclass"},
|
||||||
@@ -60,10 +61,12 @@ public:
|
|||||||
{.parent_command = "find", .sub_command = "item", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fi|finditem|itemsearch"},
|
{.parent_command = "find", .sub_command = "item", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fi|finditem|itemsearch"},
|
||||||
{.parent_command = "find", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findlanguage"},
|
{.parent_command = "find", .sub_command = "language", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findlanguage"},
|
||||||
{.parent_command = "find", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fn|findnpc|findnpctype"},
|
{.parent_command = "find", .sub_command = "npc_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fn|findnpc|findnpctype"},
|
||||||
|
{.parent_command = "find", .sub_command = "object_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findobjecttype"},
|
||||||
{.parent_command = "find", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrace"},
|
{.parent_command = "find", .sub_command = "race", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrace"},
|
||||||
{.parent_command = "find", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrecipe"},
|
{.parent_command = "find", .sub_command = "recipe", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findrecipe"},
|
||||||
{.parent_command = "find", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findskill"},
|
{.parent_command = "find", .sub_command = "skill", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findskill"},
|
||||||
{.parent_command = "find", .sub_command = "special_ability", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fsa|findspecialability"},
|
{.parent_command = "find", .sub_command = "special_ability", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fsa|findspecialability"},
|
||||||
|
{.parent_command = "find", .sub_command = "stance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findstance"},
|
||||||
{.parent_command = "find", .sub_command = "spell", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fs|findspell"},
|
{.parent_command = "find", .sub_command = "spell", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fs|findspell"},
|
||||||
{.parent_command = "find", .sub_command = "task", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findtask"},
|
{.parent_command = "find", .sub_command = "task", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findtask"},
|
||||||
{.parent_command = "find", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fz|findzone"},
|
{.parent_command = "find", .sub_command = "zone", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "fz|findzone"},
|
||||||
@@ -82,7 +85,6 @@ public:
|
|||||||
{.parent_command = "set", .sub_command = "endurance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setendurance"},
|
{.parent_command = "set", .sub_command = "endurance", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setendurance"},
|
||||||
{.parent_command = "set", .sub_command = "endurance_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "endurance"},
|
{.parent_command = "set", .sub_command = "endurance_full", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "endurance"},
|
||||||
{.parent_command = "set", .sub_command = "exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setxp|setexp"},
|
{.parent_command = "set", .sub_command = "exp", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setxp|setexp"},
|
||||||
{.parent_command = "set", .sub_command = "faction", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "setfaction"},
|
|
||||||
{.parent_command = "set", .sub_command = "flymode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flymode"},
|
{.parent_command = "set", .sub_command = "flymode", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "flymode"},
|
||||||
{.parent_command = "set", .sub_command = "freeze", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "freeze|unfreeze"},
|
{.parent_command = "set", .sub_command = "freeze", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "freeze|unfreeze"},
|
||||||
{.parent_command = "set", .sub_command = "gender", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gender"},
|
{.parent_command = "set", .sub_command = "gender", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "gender"},
|
||||||
|
|||||||
@@ -44,7 +44,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
|
static std::vector<std::string> GetDBStrFileLines(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT CONCAT(CONCAT_WS('^', {}), '^0') FROM {} ORDER BY `id`, `type` ASC",
|
||||||
|
ColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto row : results) {
|
||||||
|
lines.emplace_back(row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_DB_STR_REPOSITORY_H
|
#endif //EQEMU_DB_STR_REPOSITORY_H
|
||||||
|
|||||||
@@ -44,7 +44,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
|
static std::vector<std::string> GetSkillCapFileLines(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT CONCAT_WS('^', `class_id`, `skill_id`, `level`, `cap`, `class_`) FROM {} ORDER BY `class_id`, `skill_id`, `level` ASC",
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto row : results) {
|
||||||
|
lines.emplace_back(row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_SKILL_CAPS_REPOSITORY_H
|
#endif //EQEMU_SKILL_CAPS_REPOSITORY_H
|
||||||
|
|||||||
@@ -44,7 +44,25 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Custom extended repository methods here
|
// Custom extended repository methods here
|
||||||
|
static std::vector<std::string> GetSpellFileLines(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"SELECT CONCAT_WS('^', {}) FROM {} ORDER BY {} ASC",
|
||||||
|
ColumnsRaw(),
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (auto row : results) {
|
||||||
|
lines.emplace_back(row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_SPELLS_NEW_REPOSITORY_H
|
#endif //EQEMU_SPELLS_NEW_REPOSITORY_H
|
||||||
|
|||||||
@@ -164,38 +164,36 @@ public:
|
|||||||
return UpdateOne(db, m);
|
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{};
|
Trader e{};
|
||||||
const auto trader_item = GetWhere(
|
const auto trader_item = GetWhere(
|
||||||
db,
|
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()) {
|
if (trader_item.empty()) {
|
||||||
return e;
|
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{};
|
Trader e{};
|
||||||
auto sn = Strings::ToUnsignedBigInt(serial_number);
|
auto sn = Strings::ToUnsignedBigInt(serial_number);
|
||||||
const auto trader_item = GetWhere(
|
const auto trader_item = GetWhere(
|
||||||
db,
|
db,
|
||||||
fmt::format("`item_sn` = '{}' LIMIT 1", sn)
|
fmt::format("`char_id` = '{}' AND `item_sn` = '{}' LIMIT 1", trader_id, sn)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (trader_item.empty()) {
|
if (trader_item.empty()) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return trader_item.at(0);
|
return trader_item.at(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
|
static int UpdateActiveTransaction(Database &db, uint32 id, bool status)
|
||||||
{
|
{
|
||||||
@@ -217,6 +215,10 @@ public:
|
|||||||
delete_ids.push_back(std::to_string(e.id));
|
delete_ids.push_back(std::to_string(e.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delete_ids.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
return DeleteWhere(db, fmt::format("`id` IN({})", Strings::Implode(",", delete_ids)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -189,6 +189,8 @@ void RuleManager::ResetRules(bool reload) {
|
|||||||
m_RuleRealValues[ Real__##rule_name ] = default_value;
|
m_RuleRealValues[ Real__##rule_name ] = default_value;
|
||||||
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
|
#define RULE_BOOL(category_name, rule_name, default_value, notes) \
|
||||||
m_RuleBoolValues[ Bool__##rule_name ] = default_value;
|
m_RuleBoolValues[ Bool__##rule_name ] = default_value;
|
||||||
|
#define RULE_STRING(category_name, rule_name, default_value, notes) \
|
||||||
|
m_RuleStringValues[ String__##rule_name ] = default_value;
|
||||||
#include "ruletypes.h"
|
#include "ruletypes.h"
|
||||||
|
|
||||||
// restore these rules to their pre-reset values
|
// restore these rules to their pre-reset values
|
||||||
|
|||||||
+32
-2
@@ -178,6 +178,7 @@ RULE_BOOL(Character, NoSkillsOnHorse, false, "Enabling this will prevent Bind Wo
|
|||||||
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
|
RULE_BOOL(Character, UseNoJunkFishing, false, "Disregards junk items when fishing")
|
||||||
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
|
RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in character select, they are only soft deleted")
|
||||||
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
|
RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated")
|
||||||
|
RULE_INT(Character, DefaultGuildRank, 8, "Default guild rank when Character:DefaultGuild is a non-0 value, default is 8 (Recruit)")
|
||||||
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared")
|
||||||
RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-based experience modifiers.")
|
RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-based experience modifiers.")
|
||||||
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
|
RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.")
|
||||||
@@ -226,6 +227,9 @@ RULE_INT(Character, ClearXTargetDelay, 10, "Seconds between uses of the #clearxt
|
|||||||
RULE_BOOL(Character, PreventMountsFromZoning, false, "Enable to prevent mounts from zoning - Prior to December 15, 2004 this is enabled.")
|
RULE_BOOL(Character, PreventMountsFromZoning, false, "Enable to prevent mounts from zoning - Prior to December 15, 2004 this is enabled.")
|
||||||
RULE_BOOL(Character, GroupInvitesRequireTarget, false, "Enable to require players to have invitee on target (Disables /invite name) - Classic Style")
|
RULE_BOOL(Character, GroupInvitesRequireTarget, false, "Enable to require players to have invitee on target (Disables /invite name) - Classic Style")
|
||||||
RULE_BOOL(Character, PlayerTradingLoreFeedback, true, "If enabled, during a player to player trade, if lore items exist, it will output which items.")
|
RULE_BOOL(Character, PlayerTradingLoreFeedback, true, "If enabled, during a player to player trade, if lore items exist, it will output which items.")
|
||||||
|
RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will always succeed its skill check. Default: 199")
|
||||||
|
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
|
||||||
|
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Mercs)
|
RULE_CATEGORY(Mercs)
|
||||||
@@ -240,6 +244,9 @@ RULE_INT(Mercs, AggroRadiusPuller, 25, "Determines the distance from which a mer
|
|||||||
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
|
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
|
||||||
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
|
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
|
||||||
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
|
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
|
||||||
|
RULE_BOOL(Mercs, MercsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||||
|
RULE_INT(Mercs, MercsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||||
|
RULE_INT(Mercs, MercsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Guild)
|
RULE_CATEGORY(Guild)
|
||||||
@@ -331,6 +338,9 @@ RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclu
|
|||||||
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
||||||
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_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, 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_STRING(World, SupportedClients, "", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
|
||||||
|
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_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Zone)
|
RULE_CATEGORY(Zone)
|
||||||
@@ -468,7 +478,6 @@ RULE_BOOL(Spells, OldRainTargets, false, "Use old incorrectly implemented maximu
|
|||||||
RULE_REAL(Spells, CallOfTheHeroAggroClearDist, 250.0, "Distance at which CoTH will wipe aggro. To disable and always enable aggro wipe on any distance of CoTH, set to 0.")
|
RULE_REAL(Spells, CallOfTheHeroAggroClearDist, 250.0, "Distance at which CoTH will wipe aggro. To disable and always enable aggro wipe on any distance of CoTH, set to 0.")
|
||||||
RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
|
RULE_BOOL(Spells, NPCSpellPush, false, "Enable spell push on NPCs")
|
||||||
RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002")
|
RULE_BOOL(Spells, July242002PetResists, true, "Enable Pets using PCs resist change from July 24 2002")
|
||||||
RULE_INT(Spells, AOEMaxTargets, 0, "Max number of targets a Targeted AOE spell can cast on. Set to 0 for no limit.")
|
|
||||||
RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch to swap targets from pet to pet owner if a pet is tanking.")
|
RULE_BOOL(Spells, CazicTouchTargetsPetOwner, true, "If True, causes Cazic Touch to swap targets from pet to pet owner if a pet is tanking.")
|
||||||
RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.")
|
RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts and dot removal on charm break to prevent faction wars.")
|
||||||
RULE_BOOL(Spells, AllowDoubleInvis, true, "Allows you to cast invisibility spells on a player that is already invisible, live like behavior.")
|
RULE_BOOL(Spells, AllowDoubleInvis, true, "Allows you to cast invisibility spells on a player that is already invisible, live like behavior.")
|
||||||
@@ -503,9 +512,15 @@ RULE_BOOL(Spells, RequireMnemonicRetention, true, "Enabling will require spell s
|
|||||||
RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear charm from charm pets and detach buffs.")
|
RULE_BOOL(Spells, EvacClearCharmPet, false, "Enable to have evac in zone clear charm from charm pets and detach buffs.")
|
||||||
RULE_BOOL(Spells, ManaTapsRequireNPCMana, false, "Enabling will require target to have mana to tap. Default off as many npc's are caster class with 0 mana and need fixed.")
|
RULE_BOOL(Spells, ManaTapsRequireNPCMana, false, "Enabling will require target to have mana to tap. Default off as many npc's are caster class with 0 mana and need fixed.")
|
||||||
RULE_INT(Spells, HarmTouchCritRatio, 200, "Harmtouch crit bonus, on top of BaseCritRatio")
|
RULE_INT(Spells, HarmTouchCritRatio, 200, "Harmtouch crit bonus, on top of BaseCritRatio")
|
||||||
|
RULE_BOOL(Spells, UseClassicHarmTouchDamage, false, "Use pre 2007 Harm Touch calculations - Default: False")
|
||||||
RULE_BOOL(Spells, UseClassicSpellFocus, false, "Enabling will tell the server to handle random focus damage as classic spell imports lack the limit values.")
|
RULE_BOOL(Spells, UseClassicSpellFocus, false, "Enabling will tell the server to handle random focus damage as classic spell imports lack the limit values.")
|
||||||
RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to cast mana taps on any class, this will bypass ManaTapsRequireNPCMana rule.")
|
RULE_BOOL(Spells, ManaTapsOnAnyClass, false, "Enabling this will allow you to cast mana taps on any class, this will bypass ManaTapsRequireNPCMana rule.")
|
||||||
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
|
RULE_INT(Spells, HealAmountMessageFilterThreshold, 100, "Lifetaps below this threshold will not have a message sent to the client (Heal will still process) 0 to Disable.")
|
||||||
|
RULE_BOOL(Spells, SnareOverridesSpeedBonuses, false, "Enabling will allow snares to override any speed bonuses the entity may have. Default: False")
|
||||||
|
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_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
@@ -615,7 +630,8 @@ RULE_INT(Combat, PCAccuracyAvoidanceMod2Scale, 100, "Scale Factor for PC Accurac
|
|||||||
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
||||||
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
||||||
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
||||||
RULE_REAL(Combat, SlayDamageAdjustment, 0.5, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 0.5")
|
RULE_REAL(Combat, SlayDamageMultiplier, 1.0, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 1.0")
|
||||||
|
RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0")
|
||||||
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
|
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
|
||||||
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
|
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
|
||||||
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
|
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
|
||||||
@@ -663,6 +679,10 @@ RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if e
|
|||||||
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
|
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
|
||||||
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
|
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
|
||||||
RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
|
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_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Aggro)
|
RULE_CATEGORY(Aggro)
|
||||||
@@ -688,6 +708,7 @@ RULE_BOOL(Aggro, UndeadAlwaysAggro, true, "should undead always aggro?")
|
|||||||
RULE_INT(Aggro, BardAggroCap, 40, "per song bard aggro cap.")
|
RULE_INT(Aggro, BardAggroCap, 40, "per song bard aggro cap.")
|
||||||
RULE_INT(Aggro, InitialAggroBonus, 100, "Initial Aggro Bonus, Default: 100")
|
RULE_INT(Aggro, InitialAggroBonus, 100, "Initial Aggro Bonus, Default: 100")
|
||||||
RULE_INT(Aggro, InitialPetAggroBonus, 100, "Initial Pet Aggro Bonus, Default 100")
|
RULE_INT(Aggro, InitialPetAggroBonus, 100, "Initial Pet Aggro Bonus, Default 100")
|
||||||
|
RULE_STRING(Aggro, ExcludedFleeAllyFactionIDs, "0|5013|5014|5023|5032", "Common Faction IDs that are excluded from faction checks in EntityList::FleeAllyCount")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(TaskSystem)
|
RULE_CATEGORY(TaskSystem)
|
||||||
@@ -702,6 +723,7 @@ RULE_BOOL(TaskSystem, ExpRewardsIgnoreLevelBasedEXPMods, false, "Rewarding Level
|
|||||||
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
|
RULE_INT(TaskSystem, SharedTasksWorldProcessRate, 6000, "Timer interval (milliseconds) that shared tasks are processed in world")
|
||||||
RULE_INT(TaskSystem, SharedTasksTerminateTimerMS, 120000, "Delay (milliseconds) until a shared task is terminated if requirements are no longer met after member removal (default: 2 minutes)")
|
RULE_INT(TaskSystem, SharedTasksTerminateTimerMS, 120000, "Delay (milliseconds) until a shared task is terminated if requirements are no longer met after member removal (default: 2 minutes)")
|
||||||
RULE_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
|
RULE_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
|
||||||
|
RULE_INT(TaskSystem, MaxUpdateMessages, 50, "Maximum update messages for non-GiveCash activity types in IncrementDoneCount")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Range)
|
RULE_CATEGORY(Range)
|
||||||
@@ -713,6 +735,7 @@ RULE_INT(Range, SpellParticles, 135, "The packet range in which spell particles
|
|||||||
RULE_INT(Range, DamageMessages, 50, "The packet range in which damage messages are sent (non-crit)")
|
RULE_INT(Range, DamageMessages, 50, "The packet range in which damage messages are sent (non-crit)")
|
||||||
RULE_INT(Range, SpellMessages, 75, "The packet range in which spell damage messages are sent")
|
RULE_INT(Range, SpellMessages, 75, "The packet range in which spell damage messages are sent")
|
||||||
RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are sent")
|
RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are sent")
|
||||||
|
RULE_INT(Range, StunMessages, 75, "The packet range in which stun messages are sent")
|
||||||
RULE_INT(Range, ClientPositionUpdates, 300, "Distance in which the own changed position is communicated to other clients")
|
RULE_INT(Range, ClientPositionUpdates, 300, "Distance in which the own changed position is communicated to other clients")
|
||||||
RULE_INT(Range, CriticalDamage, 80, "The packet range in which critical hit messages are sent")
|
RULE_INT(Range, CriticalDamage, 80, "The packet range in which critical hit messages are sent")
|
||||||
RULE_INT(Range, MobCloseScanDistance, 600, "Close scan distance")
|
RULE_INT(Range, MobCloseScanDistance, 600, "Close scan distance")
|
||||||
@@ -754,6 +777,9 @@ RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hi
|
|||||||
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
|
||||||
RULE_BOOL(Bots, BotsCanClickItems, true, "Enables the ability for bots to click items they have equipped. Default TRUE")
|
RULE_BOOL(Bots, BotsCanClickItems, true, "Enables the ability for bots to click items they have equipped. Default TRUE")
|
||||||
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
|
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
|
||||||
|
RULE_BOOL(Bots, BotsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||||
|
RULE_INT(Bots, BotsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
|
||||||
|
RULE_INT(Bots, BotsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Chat)
|
RULE_CATEGORY(Chat)
|
||||||
@@ -800,6 +826,7 @@ RULE_INT(Bazaar, MaxBarterSearchResults, 200, "The maximum results returned in t
|
|||||||
RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a bazaar purchase as a percentage of item cost. Default is 20% of item cost. RoF+ Only.")
|
RULE_REAL(Bazaar, ParcelDeliveryCostMod, 0.20, "Cost of parcel delivery for a bazaar purchase as a percentage of item cost. Default is 20% of item cost. RoF+ Only.")
|
||||||
RULE_INT(Bazaar, VoucherDeliveryCost, 200, "Number of vouchers for direct delivery for a bazaar purchase. Default is 200 vouchers. RoF+ Only.")
|
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_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_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Mail)
|
RULE_CATEGORY(Mail)
|
||||||
@@ -891,6 +918,7 @@ RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any w
|
|||||||
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
|
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
|
||||||
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
|
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
|
||||||
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
|
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
|
||||||
|
RULE_BOOL(Inventory, LazyLoadBank, true, "Don't load bank during zoning, only when in proximinity to a banker. May increase zone speed and stability")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Client)
|
RULE_CATEGORY(Client)
|
||||||
@@ -993,6 +1021,8 @@ RULE_BOOL(Items, DisableNoRent, false, "Enable this to disable No Rent Items")
|
|||||||
RULE_BOOL(Items, DisableNoTransfer, false, "Enable this to disable No Transfer Items")
|
RULE_BOOL(Items, DisableNoTransfer, false, "Enable this to disable No Transfer Items")
|
||||||
RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt Items")
|
RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt Items")
|
||||||
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
|
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
|
||||||
|
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
|
||||||
|
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Parcel)
|
RULE_CATEGORY(Parcel)
|
||||||
|
|||||||
@@ -140,6 +140,7 @@
|
|||||||
|
|
||||||
#define ServerOP_TraderMessaging 0x0120
|
#define ServerOP_TraderMessaging 0x0120
|
||||||
#define ServerOP_BazaarPurchase 0x0121
|
#define ServerOP_BazaarPurchase 0x0121
|
||||||
|
#define ServerOP_BuyerMessaging 0x0122
|
||||||
|
|
||||||
#define ServerOP_InstanceUpdateTime 0x014F
|
#define ServerOP_InstanceUpdateTime 0x014F
|
||||||
#define ServerOP_AdventureRequest 0x0150
|
#define ServerOP_AdventureRequest 0x0150
|
||||||
@@ -1944,6 +1945,7 @@ struct ServerOP_GuildMessage_Struct {
|
|||||||
struct TraderMessaging_Struct {
|
struct TraderMessaging_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
uint32 zone_id;
|
uint32 zone_id;
|
||||||
|
uint32 instance_id;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 entity_id;
|
uint32 entity_id;
|
||||||
char trader_name[64];
|
char trader_name[64];
|
||||||
|
|||||||
+113
-82
@@ -46,6 +46,8 @@
|
|||||||
#include "repositories/character_item_recast_repository.h"
|
#include "repositories/character_item_recast_repository.h"
|
||||||
#include "repositories/character_corpses_repository.h"
|
#include "repositories/character_corpses_repository.h"
|
||||||
#include "repositories/skill_caps_repository.h"
|
#include "repositories/skill_caps_repository.h"
|
||||||
|
#include "repositories/inventory_repository.h"
|
||||||
|
#include "repositories/books_repository.h"
|
||||||
|
|
||||||
namespace ItemField
|
namespace ItemField
|
||||||
{
|
{
|
||||||
@@ -300,15 +302,15 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const EQ::ItemInstance*
|
|||||||
// Update/Insert item
|
// Update/Insert item
|
||||||
const std::string query = StringFormat("REPLACE INTO inventory "
|
const std::string query = StringFormat("REPLACE INTO inventory "
|
||||||
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
|
"(charid, slotid, itemid, charges, instnodrop, custom_data, color, "
|
||||||
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model) "
|
"augslot1, augslot2, augslot3, augslot4, augslot5, augslot6, ornamenticon, ornamentidfile, ornament_hero_model, guid) "
|
||||||
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
|
"VALUES( %lu, %lu, %lu, %lu, %lu, '%s', %lu, "
|
||||||
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
"%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)",
|
||||||
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
|
static_cast<unsigned long>(char_id), static_cast<unsigned long>(slot_id), static_cast<unsigned long>(inst->GetItem()->ID),
|
||||||
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
|
static_cast<unsigned long>(charges), static_cast<unsigned long>(inst->IsAttuned() ? 1 : 0),
|
||||||
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
|
inst->GetCustomDataString().c_str(), static_cast<unsigned long>(inst->GetColor()),
|
||||||
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
|
static_cast<unsigned long>(augslot[0]), static_cast<unsigned long>(augslot[1]), static_cast<unsigned long>(augslot[2]),
|
||||||
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
|
static_cast<unsigned long>(augslot[3]), static_cast<unsigned long>(augslot[4]), static_cast<unsigned long>(augslot[5]), static_cast<unsigned long>(inst->GetOrnamentationIcon()),
|
||||||
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()));
|
static_cast<unsigned long>(inst->GetOrnamentationIDFile()), static_cast<unsigned long>(inst->GetOrnamentHeroModel()), inst->GetSerialNumber());
|
||||||
const auto results = QueryDatabase(query);
|
const auto results = QueryDatabase(query);
|
||||||
|
|
||||||
// Save bag contents, if slot supports bag contents
|
// Save bag contents, if slot supports bag contents
|
||||||
@@ -651,48 +653,67 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Retrieve character inventory
|
// Retrieve character inventory
|
||||||
const std::string query =
|
auto results = InventoryRepository::GetWhere(*this, fmt::format("`charid` = '{}' ORDER BY `slotid`;", char_id));
|
||||||
StringFormat("SELECT slotid, itemid, charges, color, augslot1, augslot2, augslot3, augslot4, augslot5, "
|
if (results.empty()) {
|
||||||
"augslot6, instnodrop, custom_data, ornamenticon, ornamentidfile, ornament_hero_model FROM "
|
LogError("Error loading inventory for char_id {} from the database.", char_id);
|
||||||
"inventory WHERE charid = %i ORDER BY slotid",
|
|
||||||
char_id);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success()) {
|
|
||||||
LogError("If you got an error related to the 'instnodrop' field, run the "
|
|
||||||
"following SQL Queries:\nalter table inventory add instnodrop "
|
|
||||||
"tinyint(1) unsigned default 0 not null;\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto timestamps = GetItemRecastTimestamps(char_id);
|
for (auto const &row: results) {
|
||||||
|
if (row.guid != 0) {
|
||||||
|
EQ::ItemInstance::AddGUIDToMap(row.guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto timestamps = GetItemRecastTimestamps(char_id);
|
||||||
auto cv_conflict = false;
|
auto cv_conflict = false;
|
||||||
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
const auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||||
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
const auto bank_size = inv->GetLookup()->InventoryTypeSize.Bank;
|
||||||
|
|
||||||
for (auto& row = results.begin(); row != results.end(); ++row) {
|
std::vector<InventoryRepository::Inventory> queue{};
|
||||||
int16 slot_id = Strings::ToInt(row[0]);
|
for (auto &row: results) {
|
||||||
|
const int16 slot_id = row.slotid;
|
||||||
|
const uint32 item_id = row.itemid;
|
||||||
|
const uint16 charges = row.charges;
|
||||||
|
const uint32 color = row.color;
|
||||||
|
const bool instnodrop = row.instnodrop;
|
||||||
|
const uint32 ornament_icon = row.ornamenticon;
|
||||||
|
const uint32 ornament_idfile = row.ornamentidfile;
|
||||||
|
const uint32 ornament_hero_model = row.ornament_hero_model;
|
||||||
|
|
||||||
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) { // Titanium thru UF check
|
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
||||||
|
aug[0] = row.augslot1;
|
||||||
|
aug[1] = row.augslot2;
|
||||||
|
aug[2] = row.augslot3;
|
||||||
|
aug[3] = row.augslot4;
|
||||||
|
aug[4] = row.augslot5;
|
||||||
|
aug[5] = row.augslot6;
|
||||||
|
|
||||||
|
if (slot_id <= EQ::invslot::POSSESSIONS_END && slot_id >= EQ::invslot::POSSESSIONS_BEGIN) {
|
||||||
|
// Titanium thru UF check
|
||||||
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
|
if (((static_cast<uint64>(1) << slot_id) & pmask) == 0) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) { // Titanium thru UF check
|
else if (slot_id <= EQ::invbag::GENERAL_BAGS_END && slot_id >= EQ::invbag::GENERAL_BAGS_BEGIN) {
|
||||||
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + ((slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
// Titanium thru UF check
|
||||||
|
const auto parent_slot = EQ::invslot::GENERAL_BEGIN + (
|
||||||
|
(slot_id - EQ::invbag::GENERAL_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||||
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
|
if (((static_cast<uint64>(1) << parent_slot) & pmask) == 0) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) { // Titanium check
|
else if (slot_id <= EQ::invslot::BANK_END && slot_id >= EQ::invslot::BANK_BEGIN) {
|
||||||
|
// Titanium check
|
||||||
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
|
if ((slot_id - EQ::invslot::BANK_BEGIN) >= bank_size) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) { // Titanium check
|
else if (slot_id <= EQ::invbag::BANK_BAGS_END && slot_id >= EQ::invbag::BANK_BAGS_BEGIN) {
|
||||||
|
// Titanium check
|
||||||
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
const auto parent_index = ((slot_id - EQ::invbag::BANK_BAGS_BEGIN) / EQ::invbag::SLOT_COUNT);
|
||||||
if (parent_index >= bank_size) {
|
if (parent_index >= bank_size) {
|
||||||
cv_conflict = true;
|
cv_conflict = true;
|
||||||
@@ -700,64 +721,55 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 item_id = Strings::ToUnsignedInt(row[1]);
|
auto *item = GetItem(item_id);
|
||||||
const uint16 charges = Strings::ToUnsignedInt(row[2]);
|
|
||||||
const uint32 color = Strings::ToUnsignedInt(row[3]);
|
|
||||||
|
|
||||||
uint32 aug[EQ::invaug::SOCKET_COUNT];
|
|
||||||
|
|
||||||
aug[0] = Strings::ToUnsignedInt(row[4]);
|
|
||||||
aug[1] = Strings::ToUnsignedInt(row[5]);
|
|
||||||
aug[2] = Strings::ToUnsignedInt(row[6]);
|
|
||||||
aug[3] = Strings::ToUnsignedInt(row[7]);
|
|
||||||
aug[4] = Strings::ToUnsignedInt(row[8]);
|
|
||||||
aug[5] = Strings::ToUnsignedInt(row[9]);
|
|
||||||
|
|
||||||
const bool instnodrop = (row[10] && static_cast<uint16>(Strings::ToUnsignedInt(row[10])));
|
|
||||||
|
|
||||||
const uint32 ornament_icon = Strings::ToUnsignedInt(row[12]);
|
|
||||||
const uint32 ornament_idfile = Strings::ToUnsignedInt(row[13]);
|
|
||||||
uint32 ornament_hero_model = Strings::ToUnsignedInt(row[14]);
|
|
||||||
|
|
||||||
const EQ::ItemData *item = GetItem(item_id);
|
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
LogError("Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]", char_id, item_id,
|
LogError(
|
||||||
slot_id);
|
"Warning: charid [{}] has an invalid item_id [{}] in inventory slot [{}]",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::ItemInstance *inst = CreateBaseItem(item, charges);
|
auto *inst = CreateBaseItem(item, charges);
|
||||||
|
if (!inst) {
|
||||||
if (inst == nullptr)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (row[11]) {
|
if (!row.custom_data.empty()) {
|
||||||
std::string data_str(row[11]);
|
inst->SetCustomDataString(row.custom_data);
|
||||||
inst->SetCustomDataString(data_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->SetOrnamentIcon(ornament_icon);
|
inst->SetOrnamentIcon(ornament_icon);
|
||||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
||||||
|
|
||||||
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <= EQ::invslot::EQUIPMENT_END))
|
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQ::invslot::EQUIPMENT_BEGIN && slot_id <=
|
||||||
|
EQ::invslot::EQUIPMENT_END)) {
|
||||||
inst->SetAttuned(true);
|
inst->SetAttuned(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (color > 0)
|
if (color > 0) {
|
||||||
inst->SetColor(color);
|
inst->SetColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
if (charges == 0x7FFF)
|
if (charges == 0x7FFF) {
|
||||||
inst->SetCharges(-1);
|
inst->SetCharges(-1);
|
||||||
else if (charges == 0 && inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable.
|
}
|
||||||
|
else if (charges == 0 && inst->IsStackable()) {
|
||||||
|
// Stackable items need a minimum charge of 1 remain moveable.
|
||||||
inst->SetCharges(1);
|
inst->SetCharges(1);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
inst->SetCharges(charges);
|
inst->SetCharges(charges);
|
||||||
|
}
|
||||||
|
|
||||||
if (item->RecastDelay) {
|
if (item->RecastDelay) {
|
||||||
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
|
if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->RecastType)) {
|
||||||
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
inst->SetRecastTimestamp(timestamps.at(item->RecastType));
|
||||||
} else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
}
|
||||||
|
else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && timestamps.count(item->ID)) {
|
||||||
inst->SetRecastTimestamp(timestamps.at(item->ID));
|
inst->SetRecastTimestamp(timestamps.at(item->ID));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -767,35 +779,50 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
|
|
||||||
if (item->IsClassCommon()) {
|
if (item->IsClassCommon()) {
|
||||||
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
for (int i = EQ::invaug::SOCKET_BEGIN; i <= EQ::invaug::SOCKET_END; i++) {
|
||||||
if (aug[i])
|
if (aug[i]) {
|
||||||
inst->PutAugment(this, i, aug[i]);
|
inst->PutAugment(this, i, aug[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int16 put_slot_id;
|
int16 put_slot_id;
|
||||||
if (slot_id >= 8000 && slot_id <= 8999) {
|
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) {
|
}
|
||||||
|
else if (slot_id >= 3111 && slot_id <= 3179) {
|
||||||
// Admins: please report any occurrences of this error
|
// Admins: please report any occurrences of this error
|
||||||
LogError("Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
LogError(
|
||||||
char_id, item_id, slot_id);
|
"Warning: Defunct location for item in inventory: charid={}, item_id={}, slot_id={} .. pushing to cursor...",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
put_slot_id = inv->PushCursor(*inst);
|
put_slot_id = inv->PushCursor(*inst);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
put_slot_id = inv->PutItem(slot_id, *inst);
|
put_slot_id = inv->PutItem(slot_id, *inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
row.guid = inst->GetSerialNumber();
|
||||||
|
queue.push_back(row);
|
||||||
|
|
||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
|
|
||||||
// Save ptr to item in inventory
|
// Save ptr to item in inventory
|
||||||
if (put_slot_id == INVALID_INDEX) {
|
if (put_slot_id == INVALID_INDEX) {
|
||||||
LogError("Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
LogError(
|
||||||
char_id, item_id, slot_id);
|
"Warning: Invalid slot_id for item in inventory: charid=[{}], item_id=[{}], slot_id=[{}]",
|
||||||
|
char_id,
|
||||||
|
item_id,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv_conflict) {
|
if (cv_conflict) {
|
||||||
const std::string &char_name = GetCharName(char_id);
|
const std::string &char_name = GetCharName(char_id);
|
||||||
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
LogError(
|
||||||
|
"ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||||
char_name,
|
char_name,
|
||||||
char_id,
|
char_id,
|
||||||
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
EQ::versions::MobVersionName(inv->InventoryVersion()),
|
||||||
@@ -803,6 +830,12 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!queue.empty()) {
|
||||||
|
InventoryRepository::ReplaceMany(*this, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::ItemInstance::ClearGUIDMap();
|
||||||
|
|
||||||
// Retrieve shared inventory
|
// Retrieve shared inventory
|
||||||
return GetSharedBank(char_id, inv, true);
|
return GetSharedBank(char_id, inv, true);
|
||||||
}
|
}
|
||||||
@@ -1359,30 +1392,28 @@ const EQ::ItemData* SharedDatabase::IterateItems(uint32* id) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SharedDatabase::GetBook(const char *txtfile, int16 *language)
|
Book_Struct SharedDatabase::GetBook(const std::string& text_file)
|
||||||
{
|
{
|
||||||
char txtfile2[20];
|
const auto& l = BooksRepository::GetWhere(
|
||||||
std::string txtout;
|
*this,
|
||||||
strcpy(txtfile2, txtfile);
|
fmt::format(
|
||||||
|
"`name` = '{}'",
|
||||||
|
Strings::Escape(text_file)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const std::string query = StringFormat("SELECT txtfile, language FROM books WHERE name = '%s'", txtfile2);
|
Book_Struct b;
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success()) {
|
if (l.empty()) {
|
||||||
txtout.assign(" ",1);
|
return b;
|
||||||
return txtout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.RowCount() == 0) {
|
const auto& e = l.front();
|
||||||
LogError("No book to send, ({})", txtfile);
|
|
||||||
txtout.assign(" ",1);
|
|
||||||
return txtout;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& row = results.begin();
|
b.language = e.language;
|
||||||
txtout.assign(row[0],strlen(row[0]));
|
b.text = e.txtfile;
|
||||||
*language = static_cast<int16>(Strings::ToInt(row[1]));
|
|
||||||
|
|
||||||
return txtout;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create appropriate EQ::ItemInstance class
|
// Create appropriate EQ::ItemInstance class
|
||||||
|
|||||||
+8
-3
@@ -41,8 +41,7 @@ struct NPCFactionList;
|
|||||||
struct FactionAssociations;
|
struct FactionAssociations;
|
||||||
|
|
||||||
|
|
||||||
namespace EQ
|
namespace EQ {
|
||||||
{
|
|
||||||
|
|
||||||
struct ItemData;
|
struct ItemData;
|
||||||
class ItemInstance;
|
class ItemInstance;
|
||||||
@@ -50,6 +49,12 @@ namespace EQ
|
|||||||
class MemoryMappedFile;
|
class MemoryMappedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Book_Struct
|
||||||
|
{
|
||||||
|
uint8 language;
|
||||||
|
std::string text;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This object is inherited by world and zone's DB object,
|
This object is inherited by world and zone's DB object,
|
||||||
and is mainly here to facilitate shared memory, and other
|
and is mainly here to facilitate shared memory, and other
|
||||||
@@ -114,7 +119,7 @@ public:
|
|||||||
int admin
|
int admin
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string GetBook(const char *txtfile, int16 *language);
|
Book_Struct GetBook(const std::string& text_file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* items
|
* items
|
||||||
|
|||||||
@@ -249,7 +249,6 @@ const std::vector<EQ::skills::SkillType>& EQ::skills::GetExtraDamageSkills()
|
|||||||
EQ::skills::SkillFlyingKick,
|
EQ::skills::SkillFlyingKick,
|
||||||
EQ::skills::SkillKick,
|
EQ::skills::SkillKick,
|
||||||
EQ::skills::SkillRoundKick,
|
EQ::skills::SkillRoundKick,
|
||||||
EQ::skills::SkillRoundKick,
|
|
||||||
EQ::skills::SkillTigerClaw,
|
EQ::skills::SkillTigerClaw,
|
||||||
EQ::skills::SkillFrenzy
|
EQ::skills::SkillFrenzy
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -431,6 +431,16 @@ bool IsCharmSpell(uint16 spell_id)
|
|||||||
return IsEffectInSpell(spell_id, SE_Charm);
|
return IsEffectInSpell(spell_id, SE_Charm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsResurrectionSicknessSpell(uint16 spell_id) {
|
||||||
|
return (
|
||||||
|
spell_id == SPELL_RESURRECTION_SICKNESS ||
|
||||||
|
spell_id == SPELL_RESURRECTION_SICKNESS2 ||
|
||||||
|
spell_id == SPELL_RESURRECTION_SICKNESS3 ||
|
||||||
|
spell_id == SPELL_RESURRECTION_SICKNESS4 ||
|
||||||
|
spell_id == SPELL_REVIVAL_SICKNESS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsBlindSpell(uint16 spell_id)
|
bool IsBlindSpell(uint16 spell_id)
|
||||||
{
|
{
|
||||||
return IsEffectInSpell(spell_id, SE_Blind);
|
return IsEffectInSpell(spell_id, SE_Blind);
|
||||||
@@ -2315,3 +2325,108 @@ bool IsCastNotStandingSpell(uint16 spell_id) {
|
|||||||
*/
|
*/
|
||||||
return spells[spell_id].cast_not_standing;
|
return spells[spell_id].cast_not_standing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsAegolismSpell(uint16 spell_id) {
|
||||||
|
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_max_hp = false;
|
||||||
|
bool has_current_hp = false;
|
||||||
|
bool has_ac = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||||
|
|
||||||
|
if (i == 0 && spells[spell_id].effect_id[i] != SE_StackingCommand_Block) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 1 && spells[spell_id].effect_id[i] == SE_TotalHP) {
|
||||||
|
has_max_hp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 2 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
|
||||||
|
has_current_hp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
|
||||||
|
has_ac = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 4 && spells[spell_id].effect_id[i] != SE_StackingCommand_Overwrite) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_max_hp && has_current_hp && has_ac) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AegolismStackingIsSymbolSpell(uint16 spell_id) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is hardcoded to be specific to the type of HP buffs that are removed if a mob has an Aegolism buff.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_max_hp = false;
|
||||||
|
bool has_current_hp = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||||
|
|
||||||
|
if ((i < 2 && spells[spell_id].effect_id[i] != SE_CHA) ||
|
||||||
|
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
|
||||||
|
return 0;;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 2 && spells[spell_id].effect_id[i] == SE_TotalHP) {
|
||||||
|
has_max_hp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 3 && spells[spell_id].effect_id[i] == SE_CurrentHPOnce) {
|
||||||
|
has_current_hp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_max_hp && has_current_hp) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AegolismStackingIsArmorClassSpell(uint16 spell_id) {
|
||||||
|
/*
|
||||||
|
This is hardcoded to be specific to the type of AC buffs that are removed if a mob has an Aegolism buff.
|
||||||
|
*/
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_ac = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||||
|
|
||||||
|
if ((i < 3 && spells[spell_id].effect_id[i] != SE_CHA) ||
|
||||||
|
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 3 && spells[spell_id].effect_id[i] == SE_ArmorClass) {
|
||||||
|
has_ac = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_ac) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1522,6 +1522,7 @@ bool IsSummonPetSpell(uint16 spell_id);
|
|||||||
bool IsSummonPCSpell(uint16 spell_id);
|
bool IsSummonPCSpell(uint16 spell_id);
|
||||||
bool IsPetSpell(uint16 spell_id);
|
bool IsPetSpell(uint16 spell_id);
|
||||||
bool IsCharmSpell(uint16 spell_id);
|
bool IsCharmSpell(uint16 spell_id);
|
||||||
|
bool IsResurrectionSicknessSpell(uint16 spell_id);
|
||||||
bool IsBlindSpell(uint16 spell_id);
|
bool IsBlindSpell(uint16 spell_id);
|
||||||
bool IsHealthSpell(uint16 spell_id);
|
bool IsHealthSpell(uint16 spell_id);
|
||||||
bool IsCastTimeReductionSpell(uint16 spell_id);
|
bool IsCastTimeReductionSpell(uint16 spell_id);
|
||||||
@@ -1624,5 +1625,8 @@ bool IsSpellUsableInThisZoneType(uint16 spell_id, uint8 zone_type);
|
|||||||
const char *GetSpellName(uint16 spell_id);
|
const char *GetSpellName(uint16 spell_id);
|
||||||
int GetSpellStatValue(uint16 spell_id, const char* stat_identifier, uint8 slot = 0);
|
int GetSpellStatValue(uint16 spell_id, const char* stat_identifier, uint8 slot = 0);
|
||||||
bool IsCastRestrictedSpell(uint16 spell_id);
|
bool IsCastRestrictedSpell(uint16 spell_id);
|
||||||
|
bool IsAegolismSpell(uint16 spell_id);
|
||||||
|
bool AegolismStackingIsSymbolSpell(uint16 spell_id);
|
||||||
|
bool AegolismStackingIsArmorClassSpell(uint16 spell_id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+4
-3
@@ -83,7 +83,8 @@ struct ActivityInformation {
|
|||||||
if (zone_ids.empty()) {
|
if (zone_ids.empty()) {
|
||||||
return true;
|
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);
|
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.WriteInt32(activity_type == TaskActivityType::GiveCash ? 1 : goal_count);
|
||||||
out.WriteLengthString(skill_list); // used in SkillOn objective type string, "-1" for none
|
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.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
|
else
|
||||||
{
|
{
|
||||||
@@ -114,7 +115,7 @@ struct ActivityInformation {
|
|||||||
out.WriteString(description_override);
|
out.WriteString(description_override);
|
||||||
|
|
||||||
if (client_version >= EQ::versions::ClientVersion::RoF) {
|
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
-3
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
// Build variables
|
// Build variables
|
||||||
// these get injected during the build pipeline
|
// these get injected during the build pipeline
|
||||||
#define CURRENT_VERSION "22.52.0-dev" // always append -dev to the current version for custom-builds
|
#define CURRENT_VERSION "22.60.0-dev" // always append -dev to the current version for custom-builds
|
||||||
#define LOGIN_VERSION "0.8.0"
|
#define LOGIN_VERSION "0.8.0"
|
||||||
#define COMPILE_DATE __DATE__
|
#define COMPILE_DATE __DATE__
|
||||||
#define COMPILE_TIME __TIME__
|
#define COMPILE_TIME __TIME__
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9280
|
#define CURRENT_BINARY_DATABASE_VERSION 9285
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9044
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -251,4 +251,6 @@ private:
|
|||||||
scalar m_value;
|
scalar m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ref = reference;
|
||||||
|
|
||||||
} // namespace perlbind
|
} // namespace perlbind
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ struct pusher
|
|||||||
++m_pushed;
|
++m_pushed;
|
||||||
}
|
}
|
||||||
void push(const std::string& value) { mPUSHp(value.c_str(), value.size()); ++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(scalar value) { mPUSHs(value.release()); ++m_pushed; }
|
||||||
void push(reference value) { mPUSHs(value.release()); ++m_pushed; };
|
void push(reference value) { mPUSHs(value.release()); ++m_pushed; }
|
||||||
|
|
||||||
void push(array value)
|
void push(array value)
|
||||||
{
|
{
|
||||||
@@ -38,7 +38,8 @@ struct pusher
|
|||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
// mortalizes one reference to array element to avoid copying
|
// 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;
|
m_pushed += count;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ struct read_as<hash>
|
|||||||
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
static bool check(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||||
{
|
{
|
||||||
int remaining = items - i;
|
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)
|
static hash get(PerlInterpreter* my_perl, int i, int ax, int items)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
constexpr int perlbind_version_major = 1;
|
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_patch = 0;
|
||||||
|
|
||||||
constexpr int perlbind_version()
|
constexpr int perlbind_version()
|
||||||
|
|||||||
+42
-3
@@ -224,6 +224,23 @@ void Client::Handle_Login(const char *data, unsigned int size)
|
|||||||
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
|
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
|
||||||
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
|
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
|
||||||
|
|
||||||
|
#ifdef LSPX
|
||||||
|
// if user updated their password on the login server, update it here by validating their credentials with the login server
|
||||||
|
if (!result && db_loginserver == "eqemu") {
|
||||||
|
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(user, cred);
|
||||||
|
if (account_id > 0) {
|
||||||
|
auto encryption_mode = server.options.GetEncryptionMode();
|
||||||
|
server.db->UpdateLoginserverAccountPasswordHash(
|
||||||
|
user,
|
||||||
|
db_loginserver,
|
||||||
|
eqcrypt_hash(user, cred, encryption_mode)
|
||||||
|
);
|
||||||
|
LogInfo("Updating eqemu account [{}] password hash", account_id);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
LogDebug("Success [{0}]", (result ? "true" : "false"));
|
LogDebug("Success [{0}]", (result ? "true" : "false"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -556,10 +573,13 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
|
|||||||
{
|
{
|
||||||
SerializeBuffer buf;
|
SerializeBuffer buf;
|
||||||
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
|
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
|
||||||
int ExpansionLookup[20] = { 3007, 3008, 3009, 3010, 3012,
|
int ExpansionLookup[30] = { 3007, 3008, 3009, 3010, 3012,
|
||||||
3014, 3031, 3033, 3036, 3040,
|
3014, 3031, 3033, 3036, 3040,
|
||||||
3045, 3046, 3047, 3514, 3516,
|
3045, 3046, 3047, 3514, 3516,
|
||||||
3518, 3520, 3522, 3524 };
|
3518, 3520, 3522, 3524, 3526,
|
||||||
|
3528, 3530, 3532, 3534, 3535,
|
||||||
|
3536, 3537, 3538, 3539, 3540
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
if (server.options.IsDisplayExpansions()) {
|
if (server.options.IsDisplayExpansions()) {
|
||||||
@@ -567,7 +587,26 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
|
|||||||
int32_t expansion = server.options.GetMaxExpansions();
|
int32_t expansion = server.options.GetMaxExpansions();
|
||||||
int32_t owned_expansion = (expansion << 1) | 1;
|
int32_t owned_expansion = (expansion << 1) | 1;
|
||||||
|
|
||||||
if (m_client_version == cv_sod) {
|
if (m_client_version == cv_laurion) {
|
||||||
|
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) {
|
||||||
|
|
||||||
// header info of packet. Requires OP_LoginExpansionPacketData=0x0031 to be in login_opcodes_sod.conf
|
// header info of packet. Requires OP_LoginExpansionPacketData=0x0031 to be in login_opcodes_sod.conf
|
||||||
buf.WriteInt32(0x00);
|
buf.WriteInt32(0x00);
|
||||||
|
|||||||
@@ -138,6 +138,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
|
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the client version
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
LSClientVersion GetClientVersion() const { return m_client_version; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the connection for this client
|
* Gets the connection for this client
|
||||||
*
|
*
|
||||||
|
|||||||
+118
-11
@@ -7,6 +7,79 @@ extern bool run_server;
|
|||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
#include "../common/misc.h"
|
#include "../common/misc.h"
|
||||||
#include "../common/path_manager.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 CheckLaurionOpcodeFile(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()
|
ClientManager::ClientManager()
|
||||||
{
|
{
|
||||||
@@ -19,14 +92,12 @@ ClientManager::ClientManager()
|
|||||||
|
|
||||||
std::string opcodes_path = fmt::format(
|
std::string opcodes_path = fmt::format(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
path.GetServerPath(),
|
path.GetOpcodePath(),
|
||||||
server.config.GetVariableString(
|
|
||||||
"client_configuration",
|
|
||||||
"titanium_opcodes",
|
|
||||||
"login_opcodes.conf"
|
"login_opcodes.conf"
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CheckTitaniumOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
LogError(
|
LogError(
|
||||||
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
|
||||||
@@ -58,14 +129,12 @@ ClientManager::ClientManager()
|
|||||||
|
|
||||||
opcodes_path = fmt::format(
|
opcodes_path = fmt::format(
|
||||||
"{}/{}",
|
"{}/{}",
|
||||||
path.GetServerPath(),
|
path.GetOpcodePath(),
|
||||||
server.config.GetVariableString(
|
"login_opcodes_sod.conf"
|
||||||
"client_configuration",
|
|
||||||
"sod_opcodes",
|
|
||||||
"login_opcodes.conf"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CheckSoDOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
LogError(
|
LogError(
|
||||||
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
|
||||||
@@ -88,6 +157,44 @@ ClientManager::ClientManager()
|
|||||||
clients.push_back(c);
|
clients.push_back(c);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
int laurion_port = server.config.GetVariableInt("client_configuration", "laurion_port", 15900);
|
||||||
|
|
||||||
|
EQStreamManagerInterfaceOptions laurion_opts(laurion_port, false, false);
|
||||||
|
|
||||||
|
laurion_stream = new EQ::Net::EQStreamManager(laurion_opts);
|
||||||
|
laurion_ops = new RegularOpcodeManager;
|
||||||
|
|
||||||
|
opcodes_path = fmt::format(
|
||||||
|
"{}/{}",
|
||||||
|
path.GetOpcodePath(),
|
||||||
|
"login_opcodes_laurion.conf"
|
||||||
|
);
|
||||||
|
|
||||||
|
CheckLaurionOpcodeFile(opcodes_path);
|
||||||
|
|
||||||
|
if (!laurion_ops->LoadOpcodes(opcodes_path.c_str())) {
|
||||||
|
LogError(
|
||||||
|
"ClientManager fatal error: couldn't load opcodes for Laurion file [{0}]",
|
||||||
|
server.config.GetVariableString("client_configuration", "laurion_opcodes", "login_opcodes.conf")
|
||||||
|
);
|
||||||
|
|
||||||
|
run_server = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
laurion_stream->OnNewConnection(
|
||||||
|
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||||
|
LogInfo(
|
||||||
|
"New Laurion client connection from [{0}:{1}]",
|
||||||
|
long2ip(stream->GetRemoteIP()),
|
||||||
|
stream->GetRemotePort()
|
||||||
|
);
|
||||||
|
|
||||||
|
stream->SetOpcodeManager(&laurion_ops);
|
||||||
|
Client* c = new Client(stream, cv_laurion);
|
||||||
|
clients.push_back(c);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientManager::~ClientManager()
|
ClientManager::~ClientManager()
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ private:
|
|||||||
EQ::Net::EQStreamManager *titanium_stream;
|
EQ::Net::EQStreamManager *titanium_stream;
|
||||||
OpcodeManager *sod_ops;
|
OpcodeManager *sod_ops;
|
||||||
EQ::Net::EQStreamManager *sod_stream;
|
EQ::Net::EQStreamManager *sod_stream;
|
||||||
|
OpcodeManager *laurion_ops;
|
||||||
|
EQ::Net::EQStreamManager* laurion_stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ struct PlayEverquestResponse_Struct {
|
|||||||
|
|
||||||
enum LSClientVersion {
|
enum LSClientVersion {
|
||||||
cv_titanium,
|
cv_titanium,
|
||||||
cv_sod
|
cv_sod,
|
||||||
|
cv_laurion
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LSClientStatus {
|
enum LSClientStatus {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#EQEmu Public Login Server OPCodes
|
||||||
|
OP_SessionReady=0x0001
|
||||||
|
OP_Login=0x0002
|
||||||
|
OP_ServerListRequest=0x0004
|
||||||
|
OP_PlayEverquestRequest=0x000d
|
||||||
|
OP_PlayEverquestResponse=0x0022
|
||||||
|
OP_ChatMessage=0x0017
|
||||||
|
OP_LoginAccepted=0x0018
|
||||||
|
OP_ServerListResponse=0x0019
|
||||||
|
OP_Poll=0x0029
|
||||||
|
OP_EnterChat=0x000f
|
||||||
|
OP_PollResponse=0x0011
|
||||||
|
OP_SystemFingerprint=0x0016
|
||||||
|
OP_ExpansionList=0x0030
|
||||||
@@ -137,7 +137,7 @@ std::unique_ptr<EQApplicationPacket> ServerManager::CreateServerListPacket(Clien
|
|||||||
use_local_ip ? "Local" : "Remote"
|
use_local_ip ? "Local" : "Remote"
|
||||||
);
|
);
|
||||||
|
|
||||||
world_server->SerializeForClientServerList(buf, use_local_ip);
|
world_server->SerializeForClientServerList(buf, use_local_ip, client->GetClientVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
return std::make_unique<EQApplicationPacket>(OP_ServerListResponse, buf);
|
||||||
|
|||||||
@@ -977,8 +977,7 @@ bool WorldServer::ValidateWorldServerAdminLogin(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_local_ip) const
|
void WorldServer::SerializeForClientServerListLegacy(class SerializeBuffer& out, bool use_local_ip) const {
|
||||||
{
|
|
||||||
// see LoginClientServerData_Struct
|
// see LoginClientServerData_Struct
|
||||||
if (use_local_ip) {
|
if (use_local_ip) {
|
||||||
out.WriteString(GetLocalIP());
|
out.WriteString(GetLocalIP());
|
||||||
@@ -1000,6 +999,7 @@ void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.WriteUInt32(GetServerId());
|
out.WriteUInt32(GetServerId());
|
||||||
|
|
||||||
out.WriteString(GetServerLongName());
|
out.WriteString(GetServerLongName());
|
||||||
out.WriteString("us"); // country code
|
out.WriteString("us"); // country code
|
||||||
out.WriteString("en"); // language code
|
out.WriteString("en"); // language code
|
||||||
@@ -1020,6 +1020,61 @@ void WorldServer::SerializeForClientServerList(SerializeBuffer &out, bool use_lo
|
|||||||
out.WriteUInt32(GetPlayersOnline());
|
out.WriteUInt32(GetPlayersOnline());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldServer::SerializeForClientServerListLaurion(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_laurion) {
|
||||||
|
SerializeForClientServerListLaurion(out, use_local_ip);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SerializeForClientServerListLegacy(out, use_local_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param in_server_list_id
|
* @param in_server_list_id
|
||||||
* @return
|
* @return
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "../common/packet_dump.h"
|
#include "../common/packet_dump.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "../common/event/timer.h"
|
#include "../common/event/timer.h"
|
||||||
|
#include "login_types.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -148,8 +149,11 @@ public:
|
|||||||
|
|
||||||
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
|
bool HandleNewLoginserverRegisteredOnly(Database::DbWorldRegistration &world_registration);
|
||||||
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
|
bool HandleNewLoginserverInfoUnregisteredAllowed(Database::DbWorldRegistration &world_registration);
|
||||||
|
private:
|
||||||
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip) const;
|
void SerializeForClientServerListLegacy(class SerializeBuffer& out, bool use_local_ip) const;
|
||||||
|
void SerializeForClientServerListLaurion(class SerializeBuffer& out, bool use_local_ip) const;
|
||||||
|
public:
|
||||||
|
void SerializeForClientServerList(class SerializeBuffer& out, bool use_local_ip, LSClientVersion version) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "eqemu-server",
|
"name": "eqemu-server",
|
||||||
"version": "22.52.0",
|
"version": "22.60.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EQEmu/Server.git"
|
"url": "https://github.com/EQEmu/Server.git"
|
||||||
|
|||||||
@@ -0,0 +1,699 @@
|
|||||||
|
# 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_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=0x2df4
|
||||||
|
OP_CharacterCreate=0x6a3c
|
||||||
|
OP_DeleteCharacter=x67d7
|
||||||
|
OP_RandomNameGenerator=0x49d9
|
||||||
|
OP_ApproveName=0x11e5
|
||||||
|
OP_MOTD=0x0be4
|
||||||
|
OP_SetChatServer=0x0000
|
||||||
|
OP_SetChatServer2=0x2726
|
||||||
|
OP_ZoneServerInfo=0x2273
|
||||||
|
OP_WorldComplete=0x195c
|
||||||
|
OP_WorldUnknown001=0x2049
|
||||||
|
OP_FloatListThing=0x66fd
|
||||||
|
|
||||||
|
# Reasons for Disconnect:
|
||||||
|
OP_ZoneUnavail=0x582d
|
||||||
|
OP_WorldClientReady=0x7ed8
|
||||||
|
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=0x784a
|
||||||
|
OP_ReqNewZone=0x3895
|
||||||
|
OP_NewZone=0x4341
|
||||||
|
OP_ZoneSpawns=0x17d9
|
||||||
|
OP_PlayerProfile=0x1c76
|
||||||
|
OP_TimeOfDay=0x3736
|
||||||
|
OP_LevelUpdate=0x0eb2
|
||||||
|
OP_Stamina=0x1563
|
||||||
|
OP_RequestClientZoneChange=0x0191
|
||||||
|
OP_ZoneChange=0x17a3
|
||||||
|
OP_LockoutTimerInfo=0x0000
|
||||||
|
OP_ZoneServerReady=0x0000
|
||||||
|
OP_ZoneInUnknown=0x0000
|
||||||
|
OP_LogoutReply=0x0000
|
||||||
|
OP_PreLogoutReply=0x0000
|
||||||
|
|
||||||
|
# Required to fully log in
|
||||||
|
OP_SpawnAppearance=0x4eb0
|
||||||
|
OP_ChangeSize=0x2fdc
|
||||||
|
OP_Weather=0x6fe6
|
||||||
|
OP_ReqClientSpawn=0x6732
|
||||||
|
OP_SpawnDoor=0x4273
|
||||||
|
OP_GroundSpawn=0x49c5
|
||||||
|
OP_SendZonepoints=0x279f
|
||||||
|
OP_BlockedBuffs=0x4fdb
|
||||||
|
OP_RemoveBlockedBuffs=0x53cd
|
||||||
|
OP_ClearBlockedBuffs=0x5752
|
||||||
|
OP_WorldObjectsSent=0x2879
|
||||||
|
OP_SendExpZonein=0x02b4
|
||||||
|
OP_SendAATable=0x5f30
|
||||||
|
OP_ClearAA=0x3498
|
||||||
|
OP_ClearLeadershipAbilities=0x0000 #removed; leadership abilities are baked in and always on
|
||||||
|
OP_RespondAA=0x4c67
|
||||||
|
OP_UpdateAA=0x3b30
|
||||||
|
OP_SendAAStats=0x7d65 #i'll be honest i think this was removed at some point but this is the op at the spot in the list
|
||||||
|
OP_AAExpUpdate=0x642f #need to look into whether this has changed; exp did
|
||||||
|
OP_ExpUpdate=0x611d
|
||||||
|
OP_HPUpdate=0x775c
|
||||||
|
OP_ManaChange=0x700f
|
||||||
|
OP_TGB=0x0000 #removed; tgb is baked in and always on
|
||||||
|
OP_SpecialMesg=0x7d93
|
||||||
|
OP_CharInventory=0x21d6
|
||||||
|
OP_WearChange=0x44c0
|
||||||
|
OP_ClientUpdate=0x3a4b
|
||||||
|
OP_ClientReady=0x0831
|
||||||
|
OP_SetServerFilter=0x6b7f
|
||||||
|
|
||||||
|
# Guild Opcodes
|
||||||
|
OP_GuildsList=0x0000
|
||||||
|
OP_GuildMemberList=0x0000
|
||||||
|
OP_GuildMOTD=0x0000
|
||||||
|
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=0x2570
|
||||||
|
OP_InspectRequest=0x0000
|
||||||
|
OP_InspectAnswer=0x0000
|
||||||
|
OP_InspectMessageUpdate=0x0000
|
||||||
|
OP_BeginCast=0x31f9
|
||||||
|
OP_ColoredText=0x0f3c
|
||||||
|
OP_ConsentResponse=0x3229
|
||||||
|
OP_MemorizeSpell=0x1d31
|
||||||
|
OP_LinkedReuse=0x7a8e
|
||||||
|
OP_SwapSpell=0x63c7
|
||||||
|
OP_CastSpell=0x325b
|
||||||
|
OP_Consider=0x53e3
|
||||||
|
OP_FormattedMessage=0x7f7f
|
||||||
|
OP_SimpleMessage=0x1943
|
||||||
|
OP_Buff=0x6ce5
|
||||||
|
OP_Illusion=0x5a3f
|
||||||
|
OP_MoneyOnCorpse=0x39d3
|
||||||
|
OP_RandomReply=0x6603
|
||||||
|
OP_DenyResponse=0x3f2c
|
||||||
|
OP_SkillUpdate=0x6735
|
||||||
|
OP_GMTrainSkillConfirm=0x6fbc
|
||||||
|
OP_RandomReq=0x528a
|
||||||
|
OP_Death=0x429a
|
||||||
|
OP_GMTraining=0x7c7a
|
||||||
|
OP_GMEndTraining=0x3ec6
|
||||||
|
OP_GMTrainSkill=0x54e1
|
||||||
|
OP_Animation=0x79c7
|
||||||
|
OP_Begging=0x7ded
|
||||||
|
OP_Consent=0x44fc
|
||||||
|
OP_ConsentDeny=0x3df9
|
||||||
|
OP_AutoFire=0x5280
|
||||||
|
OP_PetCommands=0x0000
|
||||||
|
OP_PetCommandState=0x0000
|
||||||
|
OP_PetHoTT=0x0000
|
||||||
|
OP_DeleteSpell=0x4281
|
||||||
|
OP_Surname=0x0000
|
||||||
|
OP_ClearSurname=0x0000
|
||||||
|
OP_FaceChange=0x0000
|
||||||
|
OP_SetFace=0x0000
|
||||||
|
OP_SenseHeading=0x6fcf
|
||||||
|
OP_Action=0x4c13
|
||||||
|
OP_ConsiderCorpse=0x6092
|
||||||
|
OP_HideCorpse=0x3f5c
|
||||||
|
OP_CorpseDrag=0x234d
|
||||||
|
OP_CorpseDrop=0x4342
|
||||||
|
OP_Bug=0x770b
|
||||||
|
OP_Feedback=0x0000
|
||||||
|
OP_Report=0x5bcf
|
||||||
|
OP_Damage=0x7d07
|
||||||
|
OP_ChannelMessage=0x6adc
|
||||||
|
OP_Assist=0x51f1
|
||||||
|
OP_AssistGroup=0x3f23
|
||||||
|
OP_MoveCoin=0x4e6a
|
||||||
|
OP_ZonePlayerToBind=0x5643
|
||||||
|
OP_KeyRing=0x0000
|
||||||
|
OP_WhoAllRequest=0x2a09
|
||||||
|
OP_WhoAllResponse=0x6404
|
||||||
|
OP_FriendsWho=0x75a2
|
||||||
|
OP_ConfirmDelete=0x4dd0
|
||||||
|
OP_Logout=0x771d
|
||||||
|
OP_Rewind=0x2b19
|
||||||
|
OP_TargetCommand=0x3b18
|
||||||
|
OP_Hide=0x1cdf
|
||||||
|
OP_Jump=0x6fa0
|
||||||
|
OP_Camp=0x326f
|
||||||
|
OP_Emote=0x0000
|
||||||
|
OP_SetRunMode=0x1449
|
||||||
|
OP_BankerChange=0x2a33
|
||||||
|
OP_TargetMouse=0x5741
|
||||||
|
OP_MobHealth=0x5b77
|
||||||
|
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=0x27a1
|
||||||
|
OP_BuffRemoveRequest=0x4507
|
||||||
|
OP_DeleteSpawn=0x7712
|
||||||
|
OP_AutoAttack=0x3f03
|
||||||
|
OP_AutoAttack2=0x1c31
|
||||||
|
OP_Consume=0x5ef7
|
||||||
|
OP_MoveItem=0x11e3
|
||||||
|
OP_MoveMultipleItems=0x5205
|
||||||
|
OP_DeleteItem=0x0150
|
||||||
|
OP_DeleteCharge=0x1b7e
|
||||||
|
OP_ItemPacket=0x7d43
|
||||||
|
OP_ItemLinkResponse=0x0000
|
||||||
|
OP_ItemLinkClick=0x0000
|
||||||
|
OP_ItemPreview=0x0000
|
||||||
|
OP_NewSpawn=0x3ea8
|
||||||
|
OP_Track=0x5351
|
||||||
|
OP_TrackTarget=0x611a
|
||||||
|
OP_TrackUnknown=0x2c7a
|
||||||
|
OP_ClickDoor=0x733c
|
||||||
|
OP_MoveDoor=0x567c
|
||||||
|
OP_RemoveAllDoors=0x73e8
|
||||||
|
OP_EnvDamage=0x1ffd
|
||||||
|
OP_BoardBoat=0x7015
|
||||||
|
OP_LeaveBoat=0x2486
|
||||||
|
OP_ControlBoat=0x166f
|
||||||
|
OP_Forage=0x4c52
|
||||||
|
OP_SafeFallSuccess=0x6690
|
||||||
|
OP_RezzComplete=0x0000
|
||||||
|
OP_RezzRequest=0x0000
|
||||||
|
OP_RezzAnswer=0x0000
|
||||||
|
OP_Shielding=0x0000
|
||||||
|
OP_RequestDuel=0x0000
|
||||||
|
OP_MobRename=0x0000
|
||||||
|
OP_AugmentItem=0x3a1b
|
||||||
|
OP_WeaponEquip1=0x0000
|
||||||
|
OP_PlayerStateAdd=0x2178
|
||||||
|
OP_PlayerStateRemove=0x178e
|
||||||
|
OP_ApplyPoison=0x55b9
|
||||||
|
OP_Save=0x6da2
|
||||||
|
OP_TestBuff=0x0000
|
||||||
|
OP_CustomTitles=0x0000
|
||||||
|
OP_Split=0x7f6e
|
||||||
|
OP_YellForHelp=0x5fc9
|
||||||
|
OP_LoadSpellSet=0x0000
|
||||||
|
OP_Bandolier=0x0000
|
||||||
|
OP_PotionBelt=0x0000
|
||||||
|
OP_DuelDecline=0x0000
|
||||||
|
OP_DuelAccept=0x0000
|
||||||
|
OP_SaveOnZoneReq=0x3bfe
|
||||||
|
OP_ReadBook=0x51af
|
||||||
|
OP_Dye=0x0000
|
||||||
|
OP_InterruptCast=0x1d71
|
||||||
|
OP_AAAction=0x71BB
|
||||||
|
OP_LeadershipExpToggle=0x0000 #removed, these act as if all purchased now
|
||||||
|
OP_LeadershipExpUpdate=0x0000 #removed, these act as if all purchased now
|
||||||
|
OP_PurchaseLeadershipAA=0x0000 #removed, these act as if all purchased now
|
||||||
|
OP_UpdateLeadershipAA=0x0000 #removed, these act as if all purchased now
|
||||||
|
OP_MarkNPC=0x0000
|
||||||
|
OP_ClearNPCMarks=0x0000
|
||||||
|
OP_DelegateAbility=0x0000
|
||||||
|
OP_SetGroupTarget=0x0000
|
||||||
|
OP_Charm=0x66bb
|
||||||
|
OP_Stun=0x34be
|
||||||
|
OP_SendFindableNPCs=0x0000
|
||||||
|
OP_FindPersonRequest=0x0000
|
||||||
|
OP_FindPersonReply=0x0000
|
||||||
|
OP_Sound=0x2fa8
|
||||||
|
OP_CashReward=0x5e23
|
||||||
|
OP_PetBuffWindow=0x0000
|
||||||
|
OP_LevelAppearance=0x5d24
|
||||||
|
OP_Translocate=0x2772
|
||||||
|
OP_Sacrifice=0x2cbf
|
||||||
|
OP_PopupResponse=0x6be9
|
||||||
|
OP_OnLevelMessage=0x2a41
|
||||||
|
OP_AugmentInfo=0x2e11
|
||||||
|
OP_Petition=0x0000
|
||||||
|
OP_SomeItemPacketMaybe=0x0000
|
||||||
|
OP_PVPStats=0x0000
|
||||||
|
OP_PVPLeaderBoardRequest=0x0000
|
||||||
|
OP_PVPLeaderBoardReply=0x0000
|
||||||
|
OP_PVPLeaderBoardDetailsRequest=0x0000
|
||||||
|
OP_PVPLeaderBoardDetailsReply=0x0000
|
||||||
|
OP_RestState=0x0a92
|
||||||
|
OP_RespawnWindow=0x55ed
|
||||||
|
OP_LDoNButton=0x0000
|
||||||
|
OP_SetStartCity=0x0000
|
||||||
|
OP_VoiceMacroIn=0x703f
|
||||||
|
OP_VoiceMacroOut=0x72d1
|
||||||
|
OP_ItemViewUnknown=0x0000
|
||||||
|
OP_VetRewardsAvaliable=0x0000
|
||||||
|
OP_VetClaimRequest=0x0000
|
||||||
|
OP_VetClaimReply=0x0000
|
||||||
|
OP_DisciplineUpdate=0x6ce4
|
||||||
|
OP_DisciplineTimer=0x7436
|
||||||
|
OP_BecomeCorpse=0x0000 # Unused?
|
||||||
|
OP_Action2=0x0000 # Unused?
|
||||||
|
OP_MobUpdate=0x0000
|
||||||
|
OP_NPCMoveUpdate=0x0000
|
||||||
|
OP_CameraEffect=0x2f01
|
||||||
|
OP_SpellEffect=0x7378
|
||||||
|
OP_AddNimbusEffect=0x069f
|
||||||
|
OP_RemoveNimbusEffect=0x19ee
|
||||||
|
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=0x026f
|
||||||
|
OP_IncreaseStats=0x1005
|
||||||
|
OP_Weblink=0x16a3
|
||||||
|
OP_OpenContainer=0x6758
|
||||||
|
OP_Marquee=0x6bca
|
||||||
|
OP_ItemRecastDelay=0x547a
|
||||||
|
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
||||||
|
OP_ResetAA=0x53c0
|
||||||
|
OP_Fling=0x3731
|
||||||
|
OP_CancelSneakHide=0x7452
|
||||||
|
OP_AggroMeterLockTarget=0x0000
|
||||||
|
OP_AggroMeterTargetInfo=0x0000
|
||||||
|
OP_AggroMeterUpdate=0x0000
|
||||||
|
OP_UnderWorld=0x4ca9 # clients sends up when they detect an underworld issue, might be useful for cheat detection
|
||||||
|
OP_KickPlayers=0x7154
|
||||||
|
OP_BookButton=0x014d
|
||||||
|
|
||||||
|
# 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=0x60e5
|
||||||
|
OP_EndLootRequest=0x35f6
|
||||||
|
OP_LootItem=0x0856
|
||||||
|
OP_LootComplete=0x1f5e
|
||||||
|
|
||||||
|
# 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=0x7066
|
||||||
|
OP_TradeAcceptClick=0x34ad
|
||||||
|
OP_TradeRequestAck=0x1c6b
|
||||||
|
OP_TradeCoins=0x44fe
|
||||||
|
OP_FinishTrade=0x0ec6
|
||||||
|
OP_CancelTrade=0x5839
|
||||||
|
OP_TradeMoneyUpdate=0x5fb3
|
||||||
|
OP_MoneyUpdate=0x70bb
|
||||||
|
OP_TradeBusy=0x109f
|
||||||
|
|
||||||
|
# Sent after canceling trade or after closing tradeskill object
|
||||||
|
OP_FinishWindow=0x50d4
|
||||||
|
OP_FinishWindow2=0x6b03
|
||||||
|
|
||||||
|
# Sent on Live for what seems to be item existance verification
|
||||||
|
# Ex. Before Right Click Effect happens from items
|
||||||
|
OP_ItemVerifyRequest=0x2003
|
||||||
|
OP_ItemVerifyReply=0x43d0
|
||||||
|
|
||||||
|
OP_ItemAdvancedLoreText=0x0000
|
||||||
|
|
||||||
|
# merchant stuff
|
||||||
|
OP_ShopPlayerSell=0x6489
|
||||||
|
OP_ShopRequest=0x840
|
||||||
|
OP_ShopEnd=0x74bb
|
||||||
|
OP_ShopEndConfirm=0x2ed1
|
||||||
|
OP_ShopPlayerBuy=0x625e
|
||||||
|
OP_ShopDelItem=0x4ce4
|
||||||
|
OP_ShopSendParcel=0x0f16
|
||||||
|
OP_ShopDeleteParcel=0x4e2a
|
||||||
|
OP_ShopRetrieveParcel=0x27d1
|
||||||
|
OP_ShopParcelIcon=0x4f27
|
||||||
|
|
||||||
|
# tradeskill stuff:
|
||||||
|
OP_ClickObject=0x687e
|
||||||
|
OP_ClickObjectAction=0x110f
|
||||||
|
OP_ClearObject=0x6155
|
||||||
|
OP_RecipeDetails=0x01e7
|
||||||
|
OP_RecipesFavorite=0x0495
|
||||||
|
OP_RecipesSearch=0x2f4e
|
||||||
|
OP_RecipeReply=0x2cd2
|
||||||
|
OP_RecipeAutoCombine=0x5dba
|
||||||
|
OP_TradeSkillCombine=0x4ed8
|
||||||
|
|
||||||
|
# Tribute Packets:
|
||||||
|
OP_TributeUpdate=0x0000
|
||||||
|
OP_TributeTimer=0x0000
|
||||||
|
OP_SendTributes=0x0000
|
||||||
|
OP_RequestGuildTributes=0x0000
|
||||||
|
OP_TributeInfo=0x0000
|
||||||
|
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=0x78ef
|
||||||
|
OP_GroupInvite=0x1d90
|
||||||
|
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=0x1e7e
|
||||||
|
OP_GroupDisbandYou=0x0000
|
||||||
|
OP_GroupDisbandOther=0x0000
|
||||||
|
OP_GroupLeaderChange=0x0000
|
||||||
|
OP_GroupRoles=0x0000
|
||||||
|
OP_GroupMakeLeader=0x0000
|
||||||
|
OP_DoGroupLeadershipAbility=0x0000
|
||||||
|
OP_GroupLeadershipAAUpdate=0x0000 # removed these act as if you have always purchased them
|
||||||
|
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=0x5064
|
||||||
|
OP_CombatAbility=0xbf
|
||||||
|
OP_SenseTraps=0x579c
|
||||||
|
OP_PickPocket=0x53d1
|
||||||
|
OP_DisarmTraps=0x21bf
|
||||||
|
OP_Disarm=0x31e9
|
||||||
|
OP_Sneak=0x78a7
|
||||||
|
OP_Fishing=0x57cc
|
||||||
|
OP_InstillDoubt=0x57cc
|
||||||
|
OP_FeignDeath=0x14b8
|
||||||
|
OP_Mend=0x6b8
|
||||||
|
OP_Bind_Wound=0x650e
|
||||||
|
OP_LDoNOpen=0x448
|
||||||
|
OP_LDoNPickLock=0x61c8
|
||||||
|
OP_LDoNInspect=0xc1c
|
||||||
|
|
||||||
|
# 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=0x6451
|
||||||
|
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
|
||||||
|
|
||||||
|
#aura related
|
||||||
|
OP_UpdateAura=0x0000
|
||||||
|
OP_RemoveTrap=0x0000
|
||||||
|
|
||||||
|
OP_Fingerprint=0x7a5b
|
||||||
@@ -433,6 +433,7 @@ OP_TraderShop=0x31df
|
|||||||
OP_TraderBulkSend=0x6a96
|
OP_TraderBulkSend=0x6a96
|
||||||
OP_Trader=0x4ef5
|
OP_Trader=0x4ef5
|
||||||
OP_Barter=0x243a
|
OP_Barter=0x243a
|
||||||
|
OP_BuyerItems=0x1a6a
|
||||||
OP_TraderBuy=0x0000
|
OP_TraderBuy=0x0000
|
||||||
OP_ShopItem=0x0000
|
OP_ShopItem=0x0000
|
||||||
OP_BazaarInspect=0x0000
|
OP_BazaarInspect=0x0000
|
||||||
|
|||||||
@@ -0,0 +1,388 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Nuget personal access tokens and Credentials
|
||||||
|
nuget.config
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
@@ -0,0 +1,621 @@
|
|||||||
|
using Ionic.Zlib;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StreamParser.Common.Daybreak
|
||||||
|
{
|
||||||
|
public class Connection : IConnection
|
||||||
|
{
|
||||||
|
private class EncodeType
|
||||||
|
{
|
||||||
|
public const int None = 0;
|
||||||
|
public const int Compression = 1;
|
||||||
|
public const int XOR = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SequenceOrder
|
||||||
|
{
|
||||||
|
Past,
|
||||||
|
Current,
|
||||||
|
Future
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IParser _owner;
|
||||||
|
private readonly IPAddress _srcAddr;
|
||||||
|
private readonly int _srcPort;
|
||||||
|
private readonly IPAddress _dstAddr;
|
||||||
|
private readonly int _dstPort;
|
||||||
|
private readonly Util.Crc32 _crc_generator = new Util.Crc32();
|
||||||
|
private readonly Guid _id = Guid.NewGuid();
|
||||||
|
private uint _connect_code = 0;
|
||||||
|
private int _encode_key = 0;
|
||||||
|
private int _crc_bytes = 0;
|
||||||
|
private int[] _encode_pass = new int[2] { 0, 0 };
|
||||||
|
private ConnectionStream[] _client_streams = new ConnectionStream[4] {
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream()
|
||||||
|
};
|
||||||
|
private ConnectionStream[] _server_streams = new ConnectionStream[4] {
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream(),
|
||||||
|
new ConnectionStream()
|
||||||
|
};
|
||||||
|
|
||||||
|
public IConnection.OnPacketRecvHandler OnPacketRecv { get; set; }
|
||||||
|
|
||||||
|
public IPAddress ClientAddress => _srcAddr;
|
||||||
|
public int ClientPort => _srcPort;
|
||||||
|
public IPAddress ServerAddress => _dstAddr;
|
||||||
|
public int ServerPort => _dstPort;
|
||||||
|
public Guid Id => _id;
|
||||||
|
|
||||||
|
public ConnectionType ConnectionType {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
//World servers used to be coded to always be 9000 but live started using dynamic ports
|
||||||
|
//I've seen from 9000 to 9008 on live
|
||||||
|
if (_dstPort >= 9000 && _dstPort <= 9010)
|
||||||
|
{
|
||||||
|
return ConnectionType.World;
|
||||||
|
}
|
||||||
|
else if (_encode_pass[0] == EncodeType.None && _encode_pass[1] == EncodeType.None)
|
||||||
|
{
|
||||||
|
return ConnectionType.Login;
|
||||||
|
}
|
||||||
|
else if (_encode_pass[0] == EncodeType.XOR && _encode_pass[1] == EncodeType.None)
|
||||||
|
{
|
||||||
|
return ConnectionType.Chat;
|
||||||
|
}
|
||||||
|
else if (_encode_pass[0] == EncodeType.Compression && _encode_pass[1] == EncodeType.None)
|
||||||
|
{
|
||||||
|
return ConnectionType.Zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConnectionType.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection(IParser owner, IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort)
|
||||||
|
{
|
||||||
|
_owner = owner;
|
||||||
|
_srcAddr = srcAddr;
|
||||||
|
_srcPort = srcPort;
|
||||||
|
_dstAddr = dstAddr;
|
||||||
|
_dstPort = dstPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
if (data.Length < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var opcode = data[1];
|
||||||
|
if (data[0] == 0 && (opcode == Opcode.KeepAlive || opcode == Opcode.OutboundPing))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PacketCanBeDecoded(data))
|
||||||
|
{
|
||||||
|
if (!ValidateCRC(data))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_encode_pass[0] == EncodeType.None && _encode_pass[1] == EncodeType.None)
|
||||||
|
{
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data.Slice(0, data.Length - _crc_bytes));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//unfortunately we can't avoid a copy here
|
||||||
|
var temp = data.Slice(0, data.Length - _crc_bytes).ToArray();
|
||||||
|
for (int i = 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
switch(_encode_pass[i])
|
||||||
|
{
|
||||||
|
case EncodeType.Compression:
|
||||||
|
if(temp[0] == 0)
|
||||||
|
{
|
||||||
|
temp = Decompress(temp, 2, temp.Length - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = Decompress(temp, 1, temp.Length - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EncodeType.XOR:
|
||||||
|
if (temp[0] == 0)
|
||||||
|
{
|
||||||
|
temp = Decode(temp, 2, temp.Length - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = Decode(temp, 1, temp.Length - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessDecodedPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
if (data.Length < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] == 0)
|
||||||
|
{
|
||||||
|
if (data.Length < 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var opcode = data[1];
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case Opcode.SessionResponse:
|
||||||
|
if (_connect_code == 0)
|
||||||
|
{
|
||||||
|
//if(data.Length != 21)
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
_connect_code = BitConverter.ToUInt32(data.Slice(2, 4));
|
||||||
|
_encode_key = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.Slice(6, 4)));
|
||||||
|
_crc_bytes = data[10];
|
||||||
|
_encode_pass[0] = data[11];
|
||||||
|
_encode_pass[1] = data[12];
|
||||||
|
_owner.OnNewConnection?.Invoke(this, packetTime);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.SessionDisconnect:
|
||||||
|
if(_connect_code != 0)
|
||||||
|
{
|
||||||
|
_connect_code = 0;
|
||||||
|
_encode_key = 0;
|
||||||
|
_crc_bytes = 0;
|
||||||
|
_encode_pass[0] = 0;
|
||||||
|
_encode_pass[1] = 0;
|
||||||
|
_owner.OnLostConnection?.Invoke(this, packetTime);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.Combined:
|
||||||
|
{
|
||||||
|
int current = 2;
|
||||||
|
int end = data.Length;
|
||||||
|
while (current < end)
|
||||||
|
{
|
||||||
|
byte subpacket_length = data[current];
|
||||||
|
current += 1;
|
||||||
|
|
||||||
|
if (end < current + subpacket_length)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subpacket = data.Slice(current, subpacket_length);
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, subpacket);
|
||||||
|
current += subpacket_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.AppCombined:
|
||||||
|
{
|
||||||
|
int current = 2;
|
||||||
|
int end = data.Length;
|
||||||
|
while (current < end)
|
||||||
|
{
|
||||||
|
int subpacket_length = 0;
|
||||||
|
if (data[current] == 0xff)
|
||||||
|
{
|
||||||
|
if (end < current + 3)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[current + 1] == 0xff && data[current + 2] == 0xff)
|
||||||
|
{
|
||||||
|
if (end < current + 7)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
subpacket_length =
|
||||||
|
((data[current + 3]) << 24) |
|
||||||
|
((data[current + 4]) << 16) |
|
||||||
|
((data[current + 5]) << 8) |
|
||||||
|
(data[current + 6]);
|
||||||
|
|
||||||
|
current += 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subpacket_length =
|
||||||
|
((data[current + 1]) << 8) |
|
||||||
|
(data[current + 2]);
|
||||||
|
|
||||||
|
current += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subpacket_length = data[current];
|
||||||
|
current += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subpacket = data.Slice(current, subpacket_length);
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, subpacket);
|
||||||
|
current += subpacket_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.Packet:
|
||||||
|
case Opcode.Packet2:
|
||||||
|
case Opcode.Packet3:
|
||||||
|
case Opcode.Packet4:
|
||||||
|
{
|
||||||
|
var stream_id = opcode - Opcode.Packet;
|
||||||
|
var stream = FindStream(srcAddr, srcPort, stream_id);
|
||||||
|
var sequence = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data.Slice(2, 2)));
|
||||||
|
var order = CompareSequence(stream.Sequence, sequence);
|
||||||
|
if (order == SequenceOrder.Future)
|
||||||
|
{
|
||||||
|
if (!stream.PacketQueue.ContainsKey(sequence))
|
||||||
|
{
|
||||||
|
stream.PacketQueue.Add(sequence, new ConnectionStream.QueuedPacket
|
||||||
|
{
|
||||||
|
Data = data.ToArray(),
|
||||||
|
PacketTime = packetTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (order == SequenceOrder.Current)
|
||||||
|
{
|
||||||
|
if (stream.PacketQueue.ContainsKey(sequence))
|
||||||
|
{
|
||||||
|
stream.PacketQueue.Remove(sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Sequence++;
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime, data.Slice(4));
|
||||||
|
ProcessQueue(srcAddr, srcPort, stream_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.Fragment:
|
||||||
|
case Opcode.Fragment2:
|
||||||
|
case Opcode.Fragment3:
|
||||||
|
case Opcode.Fragment4:
|
||||||
|
{
|
||||||
|
var stream_id = opcode - Opcode.Fragment;
|
||||||
|
var stream = FindStream(srcAddr, srcPort, stream_id);
|
||||||
|
var sequence = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data.Slice(2, 2)));
|
||||||
|
var order = CompareSequence(stream.Sequence, sequence);
|
||||||
|
if (order == SequenceOrder.Future)
|
||||||
|
{
|
||||||
|
if (!stream.PacketQueue.ContainsKey(sequence))
|
||||||
|
{
|
||||||
|
stream.PacketQueue.Add(sequence, new ConnectionStream.QueuedPacket
|
||||||
|
{
|
||||||
|
Data = data.ToArray(),
|
||||||
|
PacketTime = packetTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (order == SequenceOrder.Current)
|
||||||
|
{
|
||||||
|
if (stream.PacketQueue.ContainsKey(sequence))
|
||||||
|
{
|
||||||
|
stream.PacketQueue.Remove(sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Sequence++;
|
||||||
|
|
||||||
|
if (stream.TotalFragmentedBytes == 0)
|
||||||
|
{
|
||||||
|
stream.TotalFragmentedBytes = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data.Slice(4, 4)));
|
||||||
|
stream.CurrentFragmentedBytes = (uint)(data.Length - 8);
|
||||||
|
|
||||||
|
if(stream.FragmentBuffer == null || stream.FragmentBuffer.Length < (stream.TotalFragmentedBytes + 512))
|
||||||
|
{
|
||||||
|
stream.FragmentBuffer = new byte[stream.TotalFragmentedBytes + 512];
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = stream.FragmentBuffer.AsSpan();
|
||||||
|
data.Slice(8).CopyTo(target);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var target = stream.FragmentBuffer.AsSpan((int)stream.CurrentFragmentedBytes);
|
||||||
|
data.Slice(4).CopyTo(target);
|
||||||
|
|
||||||
|
stream.CurrentFragmentedBytes += (uint)(data.Length - 4);
|
||||||
|
|
||||||
|
if (stream.CurrentFragmentedBytes >= stream.TotalFragmentedBytes)
|
||||||
|
{
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, packetTime,
|
||||||
|
stream.FragmentBuffer.AsSpan(0, (int)stream.TotalFragmentedBytes));
|
||||||
|
stream.CurrentFragmentedBytes = 0;
|
||||||
|
stream.TotalFragmentedBytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessQueue(srcAddr, srcPort, stream_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Opcode.Padding:
|
||||||
|
OnPacketRecv?.Invoke(this, GetDirection(srcAddr, srcPort), packetTime, data.Slice(1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
OnPacketRecv?.Invoke(this, GetDirection(srcAddr, srcPort), packetTime, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessQueue(IPAddress srcAddr, int srcPort, int stream_id)
|
||||||
|
{
|
||||||
|
var stream = FindStream(srcAddr, srcPort, stream_id);
|
||||||
|
var sequence = stream.Sequence;
|
||||||
|
|
||||||
|
//try to get the current sequence in the queue, if it exists then process it
|
||||||
|
ConnectionStream.QueuedPacket value;
|
||||||
|
if(stream.PacketQueue.TryGetValue(sequence, out value))
|
||||||
|
{
|
||||||
|
ProcessDecodedPacket(srcAddr, srcPort, value.PacketTime, value.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Match(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort)
|
||||||
|
{
|
||||||
|
var p1 = _srcAddr.Equals(srcAddr) && _srcPort == srcPort && _dstAddr.Equals(dstAddr) && _dstPort == dstPort;
|
||||||
|
var p2 = _srcAddr.Equals(dstAddr) && _srcPort == dstPort && _dstAddr.Equals(srcAddr) && _dstPort == srcPort;
|
||||||
|
return p1 || p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SequenceOrder CompareSequence(ushort expected, ushort actual)
|
||||||
|
{
|
||||||
|
int diff = (int)actual - (int)expected;
|
||||||
|
|
||||||
|
if (diff == 0)
|
||||||
|
{
|
||||||
|
return SequenceOrder.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
if (diff > 10000)
|
||||||
|
{
|
||||||
|
return SequenceOrder.Past;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SequenceOrder.Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff < -10000)
|
||||||
|
{
|
||||||
|
return SequenceOrder.Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SequenceOrder.Past;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PacketCanBeDecoded(ReadOnlySpan<byte> p)
|
||||||
|
{
|
||||||
|
if (p.Length < 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p[0] != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var opcode = p[1];
|
||||||
|
|
||||||
|
if (opcode == Opcode.SessionRequest || opcode == Opcode.SessionResponse || opcode == Opcode.OutOfSession)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateCRC(ReadOnlySpan<byte> p)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_crc_bytes == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int actual = 0;
|
||||||
|
int calculated = _crc_generator.Calculate(p.Slice(0, p.Length - _crc_bytes), _encode_key);
|
||||||
|
switch (_crc_bytes)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
actual = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(p.Slice(p.Length - 2, 2))) & 0xFFFF;
|
||||||
|
calculated = calculated & 0xFFFF;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
actual = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(p.Slice(p.Length - 4, 4)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return actual == calculated;
|
||||||
|
} catch(Exception ex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] Decompress(byte[] p, int offset, int length)
|
||||||
|
{
|
||||||
|
if (length < 2)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> header = p.AsSpan(0, offset);
|
||||||
|
byte flag = p[offset];
|
||||||
|
Span<byte> payload = p.AsSpan(offset + 1, length - 1);
|
||||||
|
|
||||||
|
if (flag == 0x5a)
|
||||||
|
{
|
||||||
|
var pl = payload.ToArray();
|
||||||
|
var inflated = Inflate(payload.ToArray());
|
||||||
|
byte[] ret = new byte[offset + inflated.Length];
|
||||||
|
Array.Copy(p, 0, ret, 0, offset);
|
||||||
|
Array.Copy(inflated, 0, ret, offset, inflated.Length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (flag == 0xa5)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[offset + length - 1];
|
||||||
|
Array.Copy(p, 0, ret, 0, offset);
|
||||||
|
Array.Copy(p, offset + 1, ret, offset, length - 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] Inflate(byte[] p)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var out_stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var in_stream = new MemoryStream(p))
|
||||||
|
{
|
||||||
|
var buffer = new byte[512];
|
||||||
|
using (var zs = new ZlibStream(in_stream, CompressionMode.Decompress))
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r = zs.Read(buffer, 0, 512);
|
||||||
|
out_stream.Write(buffer, 0, r);
|
||||||
|
} while (r == 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = out_stream.ToArray();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] Decode(byte[] p, int offset, int length)
|
||||||
|
{
|
||||||
|
int key = _encode_key;
|
||||||
|
Span<byte> buffer = p.AsSpan(offset, length);
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i + 4 <= length; i += 4)
|
||||||
|
{
|
||||||
|
int pt = BitConverter.ToInt32(buffer.Slice(i)) ^ key;
|
||||||
|
key = BitConverter.ToInt32(buffer.Slice(i));
|
||||||
|
|
||||||
|
if(BitConverter.TryWriteBytes(buffer.Slice(i), pt) == false)
|
||||||
|
{
|
||||||
|
throw new Exception("Error writing bytes back in decode.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte kc = (byte)(key & 0xFF);
|
||||||
|
for (; i < length; i++)
|
||||||
|
{
|
||||||
|
buffer[i] = (byte)(buffer[i] ^ kc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Direction GetDirection(IPAddress srcAddr, int srcPort)
|
||||||
|
{
|
||||||
|
if(srcAddr.Equals(_srcAddr) && srcPort == _srcPort)
|
||||||
|
{
|
||||||
|
return Direction.ClientToServer;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return Direction.ServerToClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionStream FindStream(IPAddress srcAddr, int srcPort, int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index > 3)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dir = GetDirection(srcAddr, srcPort);
|
||||||
|
|
||||||
|
if(dir == Direction.ClientToServer)
|
||||||
|
{
|
||||||
|
return _client_streams[index];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return _server_streams[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConnectionStream
|
||||||
|
{
|
||||||
|
public class QueuedPacket
|
||||||
|
{
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
public DateTime PacketTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionStream()
|
||||||
|
{
|
||||||
|
Sequence = 0;
|
||||||
|
CurrentFragmentedBytes = 0;
|
||||||
|
TotalFragmentedBytes = 0;
|
||||||
|
FragmentBuffer = null;
|
||||||
|
PacketQueue = new Dictionary<ushort, QueuedPacket>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort Sequence { get; set; }
|
||||||
|
public uint CurrentFragmentedBytes { get; set; }
|
||||||
|
public uint TotalFragmentedBytes { get; set; }
|
||||||
|
public byte[] FragmentBuffer { get; set; }
|
||||||
|
public Dictionary<ushort, QueuedPacket> PacketQueue { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StreamParser.Common.Daybreak
|
||||||
|
{
|
||||||
|
public ref struct GamePacket
|
||||||
|
{
|
||||||
|
private readonly ReadOnlySpan<byte> _data;
|
||||||
|
|
||||||
|
public GamePacket(ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly string ToString(int columns)
|
||||||
|
{
|
||||||
|
int rows = _data.Length / columns;
|
||||||
|
if (_data.Length % columns != 0)
|
||||||
|
{
|
||||||
|
rows += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expected = (10 + columns * 4) * rows;
|
||||||
|
var sb = new StringBuilder(expected);
|
||||||
|
|
||||||
|
for(var i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("{0} |", (i * columns).ToString("X5"));
|
||||||
|
|
||||||
|
for(var j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
var index = (i * 16) + j;
|
||||||
|
if (index >= _data.Length)
|
||||||
|
{
|
||||||
|
sb.Append(" ");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var c = _data[index];
|
||||||
|
sb.AppendFormat("{0,3}", c.ToString("X2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(" | ");
|
||||||
|
|
||||||
|
for (var j = 0; j < columns; ++j)
|
||||||
|
{
|
||||||
|
var index = (i * 16) + j;
|
||||||
|
if (index >= _data.Length)
|
||||||
|
{
|
||||||
|
sb.Append(" ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var c = _data[index];
|
||||||
|
var ch = (char)c;
|
||||||
|
if (char.IsLetterOrDigit(ch) || char.IsPunctuation(ch) || char.IsSymbol(ch) || (ch == ' '))
|
||||||
|
{
|
||||||
|
sb.Append(ch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly string ToModelString(int max_taken, bool hex)
|
||||||
|
{
|
||||||
|
int expected = Math.Min(_data.Length, max_taken) * (hex ? 2 : 1);
|
||||||
|
if(expected <= 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder(expected);
|
||||||
|
|
||||||
|
for(var i = 0; i < Math.Min(_data.Length, max_taken); ++i)
|
||||||
|
{
|
||||||
|
var c = _data[i];
|
||||||
|
if(hex)
|
||||||
|
{
|
||||||
|
sb.Append(c.ToString("X2"));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
var ch = (char)c;
|
||||||
|
if (char.IsLetterOrDigit(ch) || char.IsPunctuation(ch) || char.IsSymbol(ch) || (ch == ' '))
|
||||||
|
{
|
||||||
|
sb.Append(ch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StreamParser.Common.Daybreak
|
||||||
|
{
|
||||||
|
public enum Direction
|
||||||
|
{
|
||||||
|
ClientToServer,
|
||||||
|
ServerToClient
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ConnectionType
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Login,
|
||||||
|
World,
|
||||||
|
Chat,
|
||||||
|
Zone
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IConnection
|
||||||
|
{
|
||||||
|
delegate void OnPacketRecvHandler(Connection connection, Direction direction, DateTime packetTime, ReadOnlySpan<byte> data);
|
||||||
|
OnPacketRecvHandler OnPacketRecv { get; set; }
|
||||||
|
|
||||||
|
void ProcessPacket(IPAddress srcAddr, int srcPort, DateTime packetTime, ReadOnlySpan<byte> data);
|
||||||
|
bool Match(IPAddress srcAddr, int srcPort, IPAddress dstAddr, int dstPort);
|
||||||
|
|
||||||
|
ConnectionType ConnectionType { get; }
|
||||||
|
IPAddress ClientAddress { get; }
|
||||||
|
int ClientPort { get; }
|
||||||
|
IPAddress ServerAddress { get; }
|
||||||
|
int ServerPort { get; }
|
||||||
|
Guid Id { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StreamParser.Common.Daybreak
|
||||||
|
{
|
||||||
|
public interface IParser
|
||||||
|
{
|
||||||
|
delegate void ConnectionHandler(IConnection connection, DateTime connectionTime);
|
||||||
|
ConnectionHandler OnNewConnection { get; set; }
|
||||||
|
ConnectionHandler OnLostConnection { get; set; }
|
||||||
|
void Parse(string filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StreamParser.Common.Daybreak
|
||||||
|
{
|
||||||
|
public class Opcode
|
||||||
|
{
|
||||||
|
public const byte Padding = 0;
|
||||||
|
public const byte SessionRequest = 1;
|
||||||
|
public const byte SessionResponse = 2;
|
||||||
|
public const byte Combined = 3;
|
||||||
|
public const byte SessionDisconnect = 5;
|
||||||
|
public const byte KeepAlive = 6;
|
||||||
|
public const byte SessionStatRequest = 7;
|
||||||
|
public const byte SessionStatResponse = 8;
|
||||||
|
public const byte Packet = 9;
|
||||||
|
public const byte Packet2 = 10;
|
||||||
|
public const byte Packet3 = 11;
|
||||||
|
public const byte Packet4 = 12;
|
||||||
|
public const byte Fragment = 13;
|
||||||
|
public const byte Fragment2 = 14;
|
||||||
|
public const byte Fragment3 = 15;
|
||||||
|
public const byte Fragment4 = 16;
|
||||||
|
public const byte OutOfOrderAck = 17;
|
||||||
|
public const byte OutOfOrderAck2 = 18;
|
||||||
|
public const byte OutOfOrderAck3 = 19;
|
||||||
|
public const byte OutOfOrderAck4 = 20;
|
||||||
|
public const byte Ack = 21;
|
||||||
|
public const byte Ack2 = 22;
|
||||||
|
public const byte Ack3 = 23;
|
||||||
|
public const byte Ack4 = 22;
|
||||||
|
public const byte AppCombined = 25;
|
||||||
|
public const byte OutboundPing = 28;
|
||||||
|
public const byte OutOfSession = 29;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user