Compare commits

..

367 Commits

Author SHA1 Message Date
Aeadoin 090086f50c [Release] 22.9.0 (#3174) 2023-04-01 14:27:52 -04:00
Alex King 407b003f7d [Cleanup] Add client pointer validation to Zone::GetClosestZonePoint() (#3173)
# Notes
- We were not validating pointer here, could cause issues.
2023-04-01 14:22:52 -04:00
Alex King b6d315d803 [Cleanup] Remove unnecessary validation check in Zone::ClearBlockedSpells() (#3172)
# Notes
- This is unnecessary, since `safe_delete_array` checks for validity.
2023-04-01 13:59:03 -04:00
Aeadoin 6927177291 [Fix] Correct SE_SlayUndead & SE_HeadShotLevel limit Value when applied. (#3171) 2023-04-01 13:31:13 -04:00
Aeadoin 31ede355a8 [Cleanup] Cleanup excessive type casting: string -> char * -> string (#3169)
* [Cleanup] Cleanup excessive type casting: string -> char * -> string

* [Cleanup] Cleanup excessive type casting: string -> char * -> string
2023-04-01 12:45:16 -04:00
Aeadoin 0df84e1ee6 [Crash] Fix out of bound arrays, other potential crashes (#3166) 2023-04-01 12:44:41 -04:00
Aeadoin 0d509a7f3a [Crash] Add Checks for valid pointers or fix existing. (#3164) 2023-04-01 12:44:00 -04:00
Aeadoin 4c2271ff69 [Fix] Prevent VerifyGroup from setting OOZ membername to Null character. (#3168) 2023-04-01 12:40:55 -04:00
Aeadoin ca2072e7bf [Bots] Remove Bot Groups Functionality (#3165)
* [Bots] Remove Bot Groups Functionality

* in-class initializers for member variables.
2023-03-31 21:37:52 -04:00
Alex King e1eb1ff738 [Quest API] Add missing Luabind definitions to lua_general.cpp (#3167)
# Notes
- These definitions were missing somehow.
2023-03-31 21:05:01 -04:00
Aeadoin 25f5898bae [Release] 22.8.2 (#3161) 2023-03-30 09:22:58 -04:00
Aeadoin 934ff3dadf [Bug Fix] Correct logic checks for Bot rule AllowOwnerOptionAltCombat (#3158)
* [Bug Fix] Correct logic checks for Bot rule AllowOwnerOptionAltCombat

* fix ordering of raid/group checks
2023-03-30 08:31:57 -04:00
Aeadoin e4ff76dceb [Bug Fix] Fix for OOZ Group updates when removing/inviting Bots (#3159)
* [Bug Fix] Fix for Cross Zone Group updates with Bots when disbanding/joining groups.

* check for nullptr
2023-03-30 08:31:50 -04:00
Alex King 6960a1a682 [Bug Fix] Fix issues with Lua tables not starting at index 1 (#3160)
* [Bug Fix] Fix issues with Lua tables not starting at index 1

# Notes
- This would cause the first item in the table to be inaccessible since Lua tables start at index `1` instead of index `0`.
- All other spots using Lua tables have their indexes starting at `1`.

* Update lua_general.cpp
2023-03-30 06:02:53 -04:00
Aeadoin d4174ca236 [Fix] Fix strcpy-param-overlap (#3157) 2023-03-29 08:33:06 -04:00
Aeadoin 7854130a93 [Bug Fix] Check Rule "Bots Enabled" to prevent bot database calls on connect (#3154)
* [Bug Fix] Check for Rule "Bots Enabled" to prevent bot database calls if not enabled.

* formatting

* check if LoadBotsList failed, or is bots_list empty
2023-03-28 22:44:47 -04:00
Alex King e9c63c7d94 [Rules] Remove Guild Bank Zone ID Rule (#3156)
# notes
- This rule is useless as guild bank zone ID is hard-coded into the client.
2023-03-28 21:58:58 -04:00
Aeadoin 27e0665aae [Bug Fix] Fix bot_raid_members.sql for MYSQL. (#3155) 2023-03-28 15:25:16 -04:00
Alex King ea2f431fce [Fix] Fix an issue with EVENT_DISCONNECT not firing on regular /camp (#3153)
* [Fix] Fix an issue with EVENT_DISCONNECT not firing on regular /camp

# Notes
- We were only sending `EVENT_DISCONNECT` on GM instant camps or linkdeads.

* Update client_process.cpp
2023-03-27 21:45:02 -04:00
Aeadoin 8bdcf7cb94 [Crash] Add Checks for out of bounds & dereferencing nullptrs (#3151)
* [Crash] Add Checks for out of bounds/nullptr dereferences

* formatting

* formatting

* formatting

* Update bot.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-03-27 21:43:46 -04:00
Aeadoin 87cb74b851 [Release] 22.8.1 (#3152) 2023-03-27 17:55:48 -04:00
Alex King 26c267db1b [Cleanup] "equipped" not "equiped", "dual" not "duel". (#3149)
* [Cleanup] "equipped" not "equiped", "dual" not "duel".

# Notes
- These are spelled incorrectly.

* Update spdat.h

* Formatting further.

* Update api_service.cpp
2023-03-27 17:55:37 -04:00
Aeadoin 99f8e6cef5 [Bug Fix] Fix for NPCs having spells interrupted. (#3150) 2023-03-27 16:57:08 -04:00
Aeadoin b6917ec782 [Release] 22.8.0 (#3148) 2023-03-25 20:48:43 -04:00
Aeadoin eb51550109 [Cleanup] Cleanup Strings::ToInt uses. (#3142)
* [Cleanup] Cleanup Strings::ToInt uses.

* fix for conversion

* remove != 0

* cleanup
2023-03-25 20:32:30 -04:00
Alex King 9d1ace627c [Feature] Add support for -1 extradmgskill to allow all skills to be scaled. (#3136)
* [Feature] Add support for -1 extradmgskill to allow all skills to be scaled.

- `$mob->GetSkillDmgAmt(skill_id)` now uses `int` instead of `uint16`.

- `statbonuses:GetSkillDamageAmount(skill_id)` now uses `-1` properly.
- `mob:GetSkillDmgAmt(skill_id)` now uses `int` instead of `uint16`.

- A `-1` value in `extradmgskill` denotes the ability to scale all skills at once.
- Consolidated `AddItemBonuses()`, `AdditiveWornBonuses()`, `CalcItemBonuses()`, and `CalcRecommendedLevelBonus()` to mob-based methods to avoid code duplication.
- Bots, NPCs, and Mercs can now use additive worn effects if the rule is enabled, as well as all other proper stat bonuses that only clients had before.
- No SQL update required to change `extradmgskill` and `extradmgamt` to `int` as they already are this type in the database, just had to adjust `item_data.h` and `shareddb.cpp`.

* Update mob.cpp

* Cleanup.

* Cleanup.

* Move #include <vector> to header.

* Add method for GetExtraDamageSkills

* fix additembonuses

* Update bonuses.cpp

* Update mob.cpp

* Out of bounds.

* Update bonuses.cpp

---------

Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-03-25 20:26:01 -04:00
Aeadoin ec3ef411a1 [Fix] Fix for SQL Query in npc_scale_global_base (#3144) 2023-03-25 20:08:40 -04:00
Aeadoin 1394b6a4d2 [Hotfix] Fix for Items looted from corpses. (#3147) 2023-03-25 20:00:31 -04:00
Aeadoin 7f41547963 [Crash] Fix for crash in Raid::QueuePacket (#3145)
* [Crash] Fix for crash in Raid::QueuePacket

* bots can't be a part of BalanceMana

* corrected additions

* adding additional is_bot gates

* updating raid for loops to be range based.

* typo

* formatting

* formatting
2023-03-25 18:02:05 -04:00
Alex King 2e4071cdcf [Cleanup] Remove extern bool Critical (#3146)
# Notes
- This is unused.
2023-03-25 17:48:40 -04:00
Aeadoin dc475a1bd7 [Release] 22.7.0 (#3143) 2023-03-24 15:11:42 -05:00
Aeadoin 59ad91a140 [Feature] Add Data Bucket support for scaling of Heroic Stats. (#3058)
* [Feature] Add Data Bucket support for scaling of Heroic Stats.

* update

* fixes, still reworking logic

* fixes, still reworking logic

* logic done

* logic done

* fixes

* Cleanup

* Cleanup

* Cleanup naming, verify behaviors

* formatting

* formatting

* fix issue with endurance and mana.

* update rule desc

* cleanup

* DataBucket Struct

* Cleanup data_bucket.cpp and add constants

* cleanup

* changes

* formatting

* fix from merge

* escape keyword `key`

* Add `key` to generator, run repository-generator.pl

* fix for change to key

* cleanup

* formatting

* formatting

* typo
2023-03-23 21:42:13 -04:00
Aeadoin abc27ab423 [Bug Fix] Fix edge cases where camped bots would be left in a raid (#3139)
* [Bug Fix] Fix edge cases where camped bots would be left in a raid

* formatting
2023-03-23 19:23:34 -04:00
Aeadoin c975dc2412 [Bug Fix] Fix for transferring Raid Leader (#3140) 2023-03-23 19:04:59 -04:00
Aeadoin e085f271f5 [Bug Fix] Fix for incorrect bindpoint x,y,z,headings (#3141) 2023-03-23 18:55:56 -04:00
Alex 5a6314e1a9 [Fix] Fixes for corpses not properly saving some item instance data correctly. (#3123)
* Convert ZoneDb::LoadCharacterCorpseData to use a cleaner api that has a better layout.

* Update corpse save methods to use a new cleaner api.

* Add item to corpse will use a few new fields that don't yet save.

* Fix for some issues moving data to corpses.

* Make CreateItem more explicit to avoid overlooking places it's used and add more arguments.

* DB changes

* Revert of the changes to the database.CreateItem api change.

* Missed one.

* Fixes for mr Krab

* Small formatting

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-03-23 01:16:52 -05:00
Aeadoin dc45e0d280 [Fix] Change SPA 193 Weapon Damage to allow values over 65,535 (#3138) 2023-03-23 01:06:51 -05:00
Aeadoin 2e2c4d64fe [Cleanup] Cleanup uses of Strings::ToInt to match correct type. (#3054)
* [Cleanup] Cleanup uses of Strings::ToInt to match correct type.

* cleanup
2023-03-22 12:22:03 -04:00
Aeadoin c5add503ab [Bug Fix] Fix for Raid Disband if leader not in same zone. (#3135) 2023-03-21 19:16:01 -04:00
Aeadoin fe2dcb6544 [Crash] Fix dangling Group member pointers for Bots. (#3134)
* [Crash] Fix dangling Group member pointers for Bots.

* fixes for edge cases
2023-03-21 11:57:04 -04:00
Alex King 4fe44f4cb6 [Quest API] Add Timer related methods to Mobs in Perl/Lua (#3133)
* [Quest API] Add Timer related methods to Mobs in Perl/Lua

# Perl
- Add `quest::ispausedtimer(timer_name)`.
- Add `quest::pausetimer(timer_name)`.
- Add `quest::resumetimer(timer_name)`.
- Add `$mob->GetRemainingTimeMS(timer_name)`.
- Add `$mob->GetTimerDurationMS(timer_name)`.
- Add `$mob->HasTimer(timer_name)`.
- Add `$mob->IsPausedTimer(timer_name)`.
- Add `$mob->PauseTimer(timer_name)`.
- Add `$mob->ResumeTimer(timer_name)`.
- Add `$mob->SetTimer(timer_name)`.
- Add `$mob->SetTimerMS(timer_name)`.
- Add `$mob->StopTimer(timer_name)`.

# Lua
- Add `mob:GetRemainingTimeMS(timer_name)`.
- Add `mob:GetTimerDurationMS(timer_name)`.
- Add `mob:HasTimer(timer_name)`.
- Add `mob:IsPausedTimer(timer_name)`.
- Add `mob:PauseTimer(timer_name)`.
- Add `mob:ResumeTimer(timer_name)`.
- Add `mob:SetTimer(timer_name)`.
- Add `mob:SetTimerMS(timer_name)`.
- Add `mob:StopTimer(timer_name)`.

# Notes
- The mob-based methods allow operators to loop entity list or whatever to set, stop, resume, pause, etc for timers.

* StopAllTimers()

* Update questmgr.cpp
2023-03-20 16:18:51 -04:00
Alex King 63a8d2d641 [Cleanup] Delete zone_numbers.h (#3129)
* [Cleanup] Delete zone_numbers.h

# Notes
- This is unused.

* Update client_packet.cpp

* Update client_packet.cpp
2023-03-20 12:06:40 -04:00
Alex King abcb5d069f [Cleanup] Remove FindPatch() from struct_category.cpp and struct_category.h (#3130)
# Notes
- This is unused.
2023-03-20 12:06:10 -04:00
Aeadoin d6b954a4b9 [Cleanup] Cleaning up Raid.cpp (#3125)
* [Cleanup] Cleanup Raid.cpp

* cleanup

* fix is_bot instances

* bracket cleanup

* bracket cleanup

* rename variables in struct

* fix for merge
2023-03-20 11:39:14 -04:00
Alex King 2415645b86 [Fix] Fix typo for bot_id raid_members column in db_update_manifest.txt (#3132)
# Notes
- This was causing this query to run over and over.
2023-03-19 22:32:35 -04:00
Aeadoin e77a83f8c3 [Rule] Add Rule to allow ExtraDmgSkill/SPA 220 to effect Spell Skills (#3124)
* [Rule] Add Rule to allow ExtraDmgSkill/SPA 220 to effect Spell Skills

* add support for rule "ItemExtraSkillDamageCalcAsPercent"
2023-03-19 12:16:32 -04:00
Alex King a5d564a6fb [Cleanup] Remove ChangeHP() from mob.h (#3128)
# Notes
- This is unused.
2023-03-19 10:18:31 -04:00
Alex King 2f4c91824e [Feature] Add Item Extra Skill Damage Percent Modifier (#3127)
* [Feature] Add Item Extra Skill Damage Percent Modifier

# Notes
- Allows `Character:ItemExtraDmgCap` to be disabled if set to `-1` or lower.
- Allows operators to set `Character:ItemExtraSkillDamageCalcAsPercent` to `true` to allow skill damage for Frenzy, Backstab, Bash, Slam, Kick, and all Monk attacks to scale with a percentage based on `extradmgamt` values from items and spells.

* > 0
2023-03-19 09:59:13 -04:00
Aeadoin 53e6f931c9 [Crash] Fixes Crash when Zoning with XTarget when Bots are in group. (#3126) 2023-03-19 08:26:16 -04:00
Alex King a6efb1e8b5 [Cleanup] Remove GetStartCount() and InitStartTimer() from zone_launch.cpp and zone_launch.h (#3121)
# Notes
- These are unused.
2023-03-17 19:21:50 -04:00
Alex King b2757143a8 [Cleanup] Remove SetConnection() from loginserver/world_server.h (#3120)
# Notes
- This is unused.
2023-03-17 19:21:44 -04:00
Alex King 6e5da0e558 [Cleanup] Remove GetServerByAddress() from server_manager.h (#3119)
# Notes
- This is unused.
2023-03-17 19:21:38 -04:00
Alex King 6b8e74a29f [Cleanup] Remove PlayerLogin_Struct from login_types.h (#3118)
# Notes
- This is unused.
2023-03-17 19:21:30 -04:00
Alex King 203e63101a [Cleanup] Remove IsConnected() from loginserver/database.h (#3117)
# Notes
- This is unused.
2023-03-17 19:21:18 -04:00
Alex King 91257d599b [Cleanup] Remove unused methods in loginserver/client.h (#3116)
* [Cleanup] Remove LoginOnNewConnection(), LoginOnPacketRecv(), and LoginOnStatusChange() from loginserver/client.h

# Notes
- These are unused.

* Cleanup.
2023-03-17 19:21:08 -04:00
Alex King 491b358e28 [Cleanup] Remove UpdateLoginserverWorldAdminAccountPasswordById() from account_management.cpp (#3115)
# Notes
- This is unused.
2023-03-17 19:20:56 -04:00
Alex King 180c3088ca [Cleanup] Remove DBInitVars() and HandleMysqlError() from queryserv/database.h (#3114)
# Notes
- These are unused.
2023-03-17 19:20:47 -04:00
Alex King 97e4547192 [Cleanup] Remove DBInitVars(), HandleMysqlError(), and IsChatChannelInDB() in ucs/database.h (#3113)
# Notes
- These are unused.
2023-03-17 19:20:41 -04:00
Aeadoin 0caee9026a [Rule] Add Task System Rule ExpRewardsIgnoreLevelBasedEXPMods (#3112)
* [Rule] Add Task System Rule ExpRewardsIgnoreLevelBasedEXPMods

* description
2023-03-17 19:15:02 -04:00
Aeadoin 0be7ead1d1 [Bug Fix] Fix Bard Bot Casting (#3122) 2023-03-17 19:07:54 -04:00
Aeadoin 950489bc34 [Bug Fix] Fix Raid methods that could cause crashes with Bots in raid (#3111) 2023-03-17 16:19:29 -04:00
Mitch Freeman 45da8cab61 [Bots] Add Basic Bot Raiding Functionality (#2782)
* Fix for GENERIC_9_STRINGS

* Add Bot Heal Message Display

Creates a new rule to display Bot heal messages to the Bot Owner

* 2021-03-25 11L04pm

Spell and Heal Rule added to allow for Bot spell and heal damage to be sent to the Bot Owner's Group.  Also added a check to remove duplicate message for #damage on self.

* Update .gitignore

* BOT work

Added BOT logging damage/heals to owner
Added BOT message to owner for harmony fails
Made var Critical global to remove duplicate crit messages
Added a NULL check to Mob:GetCleanname()

* Bot Group Work

Fixed botid=charid spawn on zone issue
Added a group_list update on zone to refresh from database to fix a dangling pointer to a Bot object that was camped but was previously in a group within the zone being entered.
Modified Bot::ProcessBotGroupInvite to use the client of the bot when doing the Bot initialization so that a leader can invite another owner's Bot

* Jan 4

Basic structure in place for Raid::AddBot though not working

* Basement Jan 5

* End of day Jan 5
Working Raid Invite to a Bot.

* Update to Client::QueuePacket to not attempt to send a packet to a BoT.  Not clean, but a broad solution.

* Updated Raid::VerifyRaid

* Some Bot Raid working

* Before VS Crash

* Use Case 1, 2, 3,4,7 working.
Need to fix 5, 6, 8

* Work on usecase 5

* A few more use cases working

* New work on Raid invite with a invitor having a group

* Bot Raid inviting working for all use cases

* A few changes

* end of day jan 10

* Jan 11

* end of day Jan 11

* Bot Invite/Accept cleanup

* Start of moving raid bot functions to their own methods

* More bot raid changes

* More raid spell work

* end of day Jan 16

* spawn work

* Spawn on login working

* End of Day Jan 18

* Raid leader and mana/hp updates fixed

* Spell Tracking

* Issue with Bot Death in raid when casted upon.  1741 raid.cpp

* Bot Death fixed and few other crashes

* Working on botgroup removal

* Bot Disbanding Work 90%

* Looks like BOTs are working

* Fixed a bot crash

* bug tracing on entity list mismatch

* safe_delete resoves problem.  No to track down leak

* seems to be working

* Memory corruption found - sending packets to BoTs using Client class

* added Raid::IsRaidMemberBot()

* Update p_raid_instance

* g3

* Final - Bot Raid Working

* Fixed IsRaidMemberBot to remove memory leak
Fixed altcombat crash though RaidMainAssist (428) needs fixing

* add RaidMember.IsBot

* Repaired IsBot function to be more preformant.  Now works on standard performance machine

* Fixed Bard AE Target Spells
Removed assert for buffs

* updated based on Feb 2022 master updates

* Added bot_db_updates and version increment

* Cleanup of bot raid work and inclusion of bot_raid in cmake

* Delete .gitignore

* Revert "Delete .gitignore"

This reverts commit 8523658d3b.

* Fixed a packet issue

* Merged upstream/master

Merged upstream/master and removed ifdef BOTS as per recent dev approach for BOTS.  Functionality is there, compiles and tests ok.  A few problems to be resolved though this is a good baseline.

* Added sql update for raid_members to add isbot

* Updated Bot Follow Function

Bot will now follow the Group Leader if IsClient, otherwise follows the Bot Owner

* Updates to Bot Raid System

When camping a client, remove them from the raid.  If they are leader, place leadership to the next client.
Update a few crash checks in bot_raid.cpp

* [BOTS] Added RuleB Enabled checks and updated base repo for raid_members

Updated several RuleB(Bots, Enabled) checks
Updated the base repo to be autogenerated.
Raid functionality should work with a non-bots enabled database.

* Few quick updates

* Updates

Corrected a number of comments.  Compiled and tested against bot and non-bot database though requires the isbot column in raid_members for both.
Moved the db update out of the bot stream to make bot check code easier.

* Formatting and other small updates

* A few more RuleB(Bots, Enabled) additions

* Fix issue with conflict of bot ID versus character ID.

* Delete CMakeSettings.json

* Comment Updates and other

Several updates including
- fixed comments from PR
- added id to raid_members and unique index on name to avoid botid and charid conflicts
- updated a few raid functions for iterators
- reordered several raid operations to ensure send leader packet to be the last item to ensure proper updating on the client
- update sql to use Replace instead of Insert for botid conflicting with charid

* Exploit fix for Raid Bots

Added item from @Nite to disallow spawning or camping bots if Raid is engaged.  Avoids abusive situations.

* Initial Commit

* fix Raid Window after zoning

The raid window was not fully updating for clients not in the zone.

* Cleanup

* Update

Fixed comments

* Resolve crash for MOTD

Fixed a crash situation sending a raid MOTD to BOTS.

* Update ruletypes.h

* Updated to resolve a few recent comments

Fixed some comments within attack.cpp

* fix sql query

* update repository

* prevent duplicate entries in raid after group invite, and cleanup

* fixes for botgroups not following, and add already in raid messages.

* fix messagestring

* fixes

* Cleanup, and resolving issues with disbanding

* refactoring

* more cleanup/fixing.

* fixes for removing from ground in raid

* Refactoring/fixing multiple clients

* fix for compiling

* Bugs from refactoring fixed

* Testing completed, cleaning up unwanted items/duplicate code.

* Cleaned up AICastSpell

* fix typos

* Refactoring

* Adding Raid checks to AI_Process/cleanup

* Fix a typo

Was getting a SQL error on BOT spawn.  Fixed typo.

* fix for crash

* Fixed crash when inviting player, more refactoring

* AI_Process Refactoring work

* More Refactoring/fixes for follow

* Finish Refactoring AI_Process

* cleanup

* cleanup

* cleanup

* cleanup

* fix melee attack loop

* fix for leashowner.

* fix for leashowner.

* Bots persist in raid after client death/LD/Camp

* Fix Bot Groups when zoning after death.

* Fix Bots in group following after client death

* remove unnecessary query

* Allow Raid members to invite Bots if owner is in raid. cleanup

* optimization of raid verification

* remove this

* Code Cleanup

* formatting

* formatting

* formatting

* fix for macro

* add return for TryClassAttacks

* fix query

* fix for crash

* restrict camping/spawn in combat.

* Fix other crash issue.

* update learnmembers to use Strings::To, cleanup magic numbers

* fix for merge.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-03-17 11:19:59 -04:00
Alex King e778041198 [Cleanup] Remove ownHiddenTrigger from trap.cpp and trap.h (#3092)
# Notes
- This is unsued.
2023-03-17 08:37:36 -04:00
Alex King 97e50ced93 [Cleanup] Delete deprecated/perlxs folder (#3110)
# Notes
- This entire folder is unused.
2023-03-17 06:23:30 -04:00
Alex King 4491bb9a70 [Cleanup] Remove is_authenticatd, LSShutDownUpdate(), and SetInstanceID() from zoneserver.h (#3109)
# Notes
- These are unsued.
2023-03-17 06:23:19 -04:00
Alex King 04fba27467 [Cleanup] Remove StoreCharacter() from worlddb.h (#3108)
# Notes
- This is unused.
2023-03-17 06:23:10 -04:00
Alex King fa47dd7f93 [Cleanup] Remove DisableStats(), EnableStats(), DisableLoginserver(), and EnableLoginserver() from world_config.h (#3107)
# Notes
- These are unused.
2023-03-17 06:23:01 -04:00
Alex King b3fb5f00ab [Cleanup] Remove MakeGuildMembers() from wguild_mgr.h (#3106)
# Notes
- This is unused.
2023-03-17 06:22:51 -04:00
Alex King e17fad9ae0 [Cleanup] Cleanup unused methods and variables in world/main.cpp and world/main.h (#3105)
# Notes
- These are unused.
2023-03-17 06:22:41 -04:00
Alex King bbdaacd3b0 [Cleanup] Remove AllConnected(), CanUpdate(), and SendInfo() from login_server_list.cpp and login_server_list.h (#3104)
# Notes
- These are unused.
2023-03-17 06:22:34 -04:00
Alex King 61bd485449 [Cleanup] Remove unused methods in eql_config.cpp, eql_config.h, launcher_list.cpp, and launcher_list.h (#3103)
# Notes
- These are unused.
2023-03-17 06:22:01 -04:00
Alex King 4b405fe9fe [Cleanup] Remove authenticated from launcher_link.cpp and launcher_link.h (#3101)
# Notes
- This is unused.
2023-03-17 06:21:51 -04:00
Alex King d5aaf7cee5 [Cleanup] Remove CountZones() from launcher_link.h (#3100)
# Notes
- This is unused.
2023-03-17 06:21:41 -04:00
Alex King 12e9e0f71d [Cleanup] Delete world/console.old.cpp (#3099)
# Notes
- This is unused.
2023-03-17 06:21:23 -04:00
Alex King 0a64e26672 [Cleanup] Remove FindCLEByLSID(), GetCLE(), GetCLEIPCount(), and RemoveCLEByLSID() from clientlist.h (#3098)
# Notes
- These are unused.
2023-03-17 06:21:14 -04:00
Alex King 11fc5a9e93 [Cleanup] Remove SendGuildPacket() from clientlist.cpp, clientlist.h, and wguild_mgr.cpp (#3097)
# Notes
- This is unused.
2023-03-17 06:21:00 -04:00
Alex King 7bbcdfb479 [Cleanup] Remove FindByName(charname) from clientlist.h (#3096)
# Notes
- This is unused.
2023-03-17 06:20:46 -04:00
Alex King 3a530eb43b [Cleanup] Remove CheckAuth(), SetOnline(), and pMD5Pass from cliententry.h (#3095)
# Notes
- These are unused.
2023-03-17 06:20:36 -04:00
Alex King 48a60114b7 [Cleanup] Remove CommandRequirement() from zonedb.h (#3094)
# Notes
- This is unused.
2023-03-17 06:20:25 -04:00
Alex King 06f1f36c95 [Cleanup] Utilize GetScheduler() in zone/worldserver.cpp (#3093)
# Notes
- This was unused.
2023-03-17 06:20:13 -04:00
Alex King ccd9bd7d4c [Cleanup] Utilize SetHiddenTrigger in trap.cpp (#3091)
# Notes
- This was unused.
2023-03-17 06:17:53 -04:00
Alex King fea6cbf633 [Cleanup] Remove RemoveSpawnGroup() from spawngroup.h (#3090)
# Notes
- This is unused.
2023-03-17 06:17:44 -04:00
Alex King 460739d35c [Cleanup] Delete queues.h (#3089)
# Notes
- This is unsued.
2023-03-17 06:17:32 -04:00
Alex King 11e1edc99f [Cleanup] Remove IsOrigin(glm::vec2) from position.h (#3088)
# Notes
- This is unused.
2023-03-17 06:17:20 -04:00
Alex King 7374660045 [Cleanup] Remove last_insert_id from petitions.h (#3087)
# Notes
- This is unused.
2023-03-17 06:17:10 -04:00
Alex King 9e8d365ca7 [Cleanup] Remove SetSentTime2 in petitions.h (#3086)
# Notes
- This is unused.
2023-03-17 06:17:00 -04:00
Alex King 14d69a0a14 [Cleanup] Remove perlparser.h (#3085)
# Notes
- This is unused.
2023-03-17 06:16:51 -04:00
Alex King fe063637e9 [Cleanup] Remove GetTransformation() and GetInvertedTransformation() from oriented_bounding_box.h (#3084)
# Notes
- These are unused.
2023-03-17 06:16:40 -04:00
Alex King 232b1028d7 [Cleanup] Remove m_inuse, m_z, and m_heading from object.h (#3083)
# Notes
- These are unsued.
2023-03-16 21:47:27 -04:00
Alex King 3624307385 [Cleanup] Remove SetDBID() from object.h (#3082)
# Notes
- This is unused.
2023-03-16 21:36:03 -04:00
Alex King c0055cf357 [Cleanup] Remove npc_ai.cpp/npc_ai.cpp (#3081)
# Notes
- These files were unused.
2023-03-16 21:17:23 -04:00
Alex King f9c1683d36 [Cleanup] Remove GetAILevel() from npc.h (#3080)
# Notes
- This is unused.
2023-03-16 21:06:24 -04:00
Alex King 64df993c10 [Cleanup] Remove FlushLootStats() from npc.h (#3079)
# Notes
- This is unused.
2023-03-16 21:06:10 -04:00
Alex King 890ef696fe [Cleanup] Remove GetDestination() from doors.h (#3078)
# Notes
- This is unused.
2023-03-16 20:47:40 -04:00
Alex King 3f1848b01a [Cleanup] Remove can_corpse_be_rezzed from corpse.h (#3077)
# Notes
- This is unused.
2023-03-16 20:47:25 -04:00
Alex King f7c4f1ff75 [Cleanup] Remove _baseBotStance from bot.h (#3076)
# Notes
- This is unused.
2023-03-16 20:25:45 -04:00
Alex King dcb127f4b6 [Cleanup] Remove _botRole from bot.h (#3075)
# Notes
- This is unused.
2023-03-16 20:25:35 -04:00
Alex King 669b068978 [Cleanup] Remove _previousTarget from bot.h (#3074)
# Notes
- This is unused.
2023-03-16 20:25:25 -04:00
Alex King db2aeca38f [Cleanup] remove _botOrderAttack from bot.h (#3073)
# Notes
- This is unused.
2023-03-16 20:25:16 -04:00
Alex King 1b3ca95f8c [Cleanup] Remove firstlogin and realfirstlogin from world/client.h (#3072)
# Notes
- These are unused.
2023-03-16 20:25:03 -04:00
Alex King c05baac551 [Cleanup] Remove CLIENT_TIMEOUT from world/client.h and zone/client.h (#3071)
# Notes
- This is unused.
2023-03-16 20:24:53 -04:00
Alex King 939fc79d19 [Cleanup] Remove IsAffectedByBuff() (#3068)
# Notes
- This is unused.
2023-03-16 20:24:44 -04:00
Alex King a0e6fce057 [Cleanup] Remove fixedZ from mob.h (#3065)
# Notes
- This is unused.
2023-03-16 20:24:35 -04:00
Alex King 452389b7a5 [Cleanup] Remove class EQStream from client.h (#3070)
# Notes
- This is unused.
2023-03-16 20:24:08 -04:00
Alex King dd184fa8b6 [Cleanup] Remove inWater from mob.h (#3069)
# Notes
- This is unused.
2023-03-16 20:23:56 -04:00
Alex King 4a3e6b5edc [Cleanup] Remove current_buff_count (#3067)
# Notes
- This was unused.
2023-03-16 20:23:41 -04:00
Alex King 7961d7afa8 [Cleanup] Utilize GetPlayerState() in mob methods (#3066)
# Notes
- This method was unused, make use of it.
2023-03-16 20:23:34 -04:00
Alex King cc6bcf3295 [Cleanup] Remove casting_spell_type from mob.h (#3064)
# Notes
- This is unused.
2023-03-16 20:23:21 -04:00
Alex King b73c2016cf [Cleanup] Remove last_max_hp from mob.h (#3063)
# Notes
- This is unused.
2023-03-16 20:23:11 -04:00
Alex King db7e8241ac [Cleanup] Remove DoBuffWearOffEffect() from mob.h (#3062)
# Notes
- This is unused.
2023-03-16 20:12:01 -04:00
Paul Coene b7747b07db [Illusions] Fix bug where spells like Ignite Bones left NPC size incorrect. (#3061) 2023-03-16 18:59:09 -04:00
Alex King 02ada0e496 [Quest API] Add SendIllusion overloads/parameters to Perl/Lua (#3059)
* [Quest API] Add SendIllusion methods to Perl.

# Perl
- Add `$mob->SendIllusion(race, gender, texture, helmtexture, face, hairstyle, haircolor, beard, beardcolor, drakkin_heritage, drakkin_tattoo, drakkin_details, size, target)`.
- Add `$mob->SendIllusionPacket(illusion_table_ref)`.

* Change defaults.

* Remove debug message

* Cleanup.

* Cleanup

* Update perl_mob.cpp
2023-03-15 20:37:37 -04:00
Alex King 7c819539c8 [Quest API] Add Spell GetActX methods to Perl/Lua (#3056)
# Perl
- Add `$mob->GetActDoTDamage(spell_id, value, target)`.
- Add `$mob->GetActDoTDamage(spell_id, value, target, from_buff_tic)`.
- Add `$mob->GetActReflectedSpellDamage(spell_id, value, effectiveness)`.
- Add `$mob->GetActSpellDamage(spell_id, value, target)`.
- Add `$mob->GetActSpellHealing(spell_id, value, target)`.
- Add `$mob->GetActSpellHealing(spell_id, value, target, from_buff_tic)`.

# Lua
- Add `mob:GetActDoTDamage(spell_id, value, target)`.
- Add `mob:GetActDoTDamage(spell_id, value, target, from_buff_tic)`.
- Add `mob:GetActReflectedSpellDamage(spell_id, value, effectiveness)`.
- Add `mob:GetActSpellCasttime(spell_id, cast_time)`.
- Add `mob:GetActSpellCost(spell_id, cost)`.
- Add `mob:GetActSpellDamage(spell_id, value)`.
- Add `mob:GetActSpellDamage(spell_id, value, target)`.
- Add `mob:GetActSpellDuration(spell_id, duration)`.
- Add `mob:GetActSpellHealing(spell_id, value)`.
- Add `mob:GetActSpellHealing(spell_id, value, target)`.
- Add `mob:GetActSpellHealing(spell_id, value, target, from_buff_tic)`.
- Add `mob:GetActSpellRange(spell_id, range)`.

 # Notes
- Allows operators to get various spell related values.
2023-03-12 15:36:43 -04:00
Alex King e670c89163 [Cleanup] Remove unused lua_hate_entry.cpp (#3057)
# Notes
- This is unused and causes duplication of these methods in Spire Quest API Explorer.
2023-03-12 15:36:20 -04:00
Aeadoin 9ecdf057db [Feature] Add Heroic Strikethrough & HP Regen Per Second to GM Entity Info (#3055)
* [Feature] Add Heroic Strikethrough to GM Entity Info

* [Feature] Add Heroic Strikethrough to GM Entity Info

* typo
2023-03-11 20:46:31 -05:00
Aeadoin b6448c840f [Bug Fix] Fix Raid Invites causing client desync issues (#3053) 2023-03-11 11:42:52 -05:00
Aeadoin 0ba90df1f1 [Bug Fix] Fix issue with overflow on min/max hit dmg in npc scaling calculations (#3052)
* [Cleanup] Cleanup npc.cpp and npc scaling

* fix issue with min/max damage overflows

* formatting
2023-03-10 09:36:59 -05:00
Alex King 12dcbd0871 [Bug Fix] Fix Heal Scale and Spell Scale in NPC Scaling (#3051)
# Notes
- These had typos and didn't work.
2023-03-09 22:32:47 -05:00
Aeadoin b0be4ca8bd [Feature] Add Avoidance and HP Regen Per Second too NPC Scaling. (#3050) 2023-03-09 11:07:03 -05:00
nytmyr 412eb5deaa [Bots] Prevent interrupt spam when OOM (#3011)
Notes:

Bots currently do not do a mana check until the spell cast has already been started which results in an interrupt immediately after. If it is the last spell for a bot to cast, it tends to result in interrupt spam until the bot has enough mana. This will block the interrupt spam if the spell is invalid.
2023-03-07 18:17:09 -05:00
Alex King f030461bc7 [Feature] Add Heroic Strikethrough to NPC Scaling (#3028)
* [Feature] Add Heroic Strikethrough to NPC Scaling

# Notes
- Adds Heroic Strikethrough support to NPC scaling.
- Cleans up `std::stoul` to use `Strings::ToUnsignedInt` since recent changes.
- Sets default values to sane values and removes support for `NULL` values.

* Update 2023_03_04_npc_scale_global_base_heroic_strikethrough.sql
2023-03-05 22:36:53 -05:00
Alex King 8f5e7978ab [Commands] Remove #equipitem Command (#3040)
* [Commands] Remove #equipitem Command

# Notes
- This command causes issues with cursor and inventory slot desynchronizations and seems to largely be unused/unnecessary.

* Remove from command files.
2023-03-05 22:36:04 -05:00
Alex King 2e55da2b2d [Fix] Checkmarks and X characters in popup messages (#3041)
# Notes
- Due to changing the popups to use strings, these show as squares, instead of the proper character.
2023-03-05 22:35:52 -05:00
Alex King 16a8f88ae5 [Commands] Cleanup #haste Command (#3042)
* [Commands] Cleanup #haste Command

# Notes
- Cleanup messages and logic.
- No longer requires you to re-equip your weapon for the haste to take effect.
- Can now use on targeted client if you have `#gm on` enabled.

* Update haste.cpp
2023-03-05 22:35:42 -05:00
Alex King 22d7ef6763 [Commands] Cleanup #hideme Command (#3043)
# Notes
- Cleanup messages and logic.
2023-03-05 22:35:30 -05:00
Alex King 457e800c73 [Commands] Cleanup #interrupt Command (#3044)
* [Commands] Cleanup #interrupt Command

# Notes
- Cleanup messages and logic.

* Update command.cpp
2023-03-05 22:35:23 -05:00
Alex King 8393e50aa8 [Commands] Cleanup #level Command (#3045)
# Notes
- Cleanup messages and logic.
- Defaults target to GM so that you don't have to target yourself to use the command.
2023-03-05 22:34:33 -05:00
Alex King b6497cdd6a [Commands] Cleanup #resetaa and #resetaa_timer (#3047)
# Notes
- Cleanup messages and logic.
2023-03-05 22:34:21 -05:00
Alex King 218ef80f96 [Commands] Cleanup #picklock Command (#3046)
* [Commands] Cleanup #picklock Command

# Notes
- Cleanup messages and logic.

* Update picklock.cpp
2023-03-05 22:34:05 -05:00
Alex King a90d41480a [Commands] Cleanup #wc Command (#3049)
# Notes
- Cleanup messages and logic.
2023-03-05 22:18:35 -05:00
Alex King 67df6f62b7 [Cleanup] Remove unused ^evacuate and ^succor subcommands from bot_command.h (#3039)
# Notes
- These are unused.
2023-03-05 12:19:58 -05:00
Alex King 4572dbc426 [Cleanup] Remove unused BotAA struct in bot_structs.h (#3038)
# Notes
- This is unused.
2023-03-05 12:19:52 -05:00
Alex King e8cc160572 [Cleanup] Remove unused bot structs in bot_structs.h (#3037)
# Notes
- These are unused.
2023-03-05 12:19:42 -05:00
Alex King 8c9adca852 [Cleanup] Utilize SetFilter in client.cpp (#3036)
# Notes
- This function was unused, make use of it.
2023-03-05 12:19:22 -05:00
Alex King b53310e23b [Cleanup] Remove unused AbilityTimer variable in client.h (#3035)
# Notes
- This is unused.
2023-03-05 12:19:16 -05:00
Alex King 14f01dc2d7 [Cleanup] Remove unused client queued work variable in client.cpp/client.h (#3034)
# Notes
- This is unused.
2023-03-05 12:19:09 -05:00
Alex King a4d6509e6d [Cleanup] Remove unused player update variables in client.cpp/client.h (#3033)
# Notes
- These are unused.
2023-03-05 12:18:56 -05:00
Alex King fc835bfb0e [Cleanup] Remove unused HandleUpdateTasksOnKill in client.h (#3032)
# Notes
- This is unused.
2023-03-05 12:18:51 -05:00
Alex King 9ec4e5ade0 [Cleanup] Remove unused command variables in client.cpp (#3031)
# Notes
- These are unused.
2023-03-05 12:18:36 -05:00
Alex King 6b65e93a06 [Cleanup] Remove unused SaveBackup in client.h (#3030)
# Notes
- This is unused and does nothing in both Perl and Lua.
2023-03-05 12:18:26 -05:00
Chris Miles a0a28fef04 [Strings] Add exception handling to converters themselves (#3029) 2023-03-04 19:39:55 -06:00
Trent 034feb4ff4 [Bots] Place BOT_COMMAND_CHAR inside messages (#3027)
* Fix bot depart list

* Update bot_command.cpp

* Update bot_command.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-03-04 20:02:04 -05:00
nytmyr 65c14b160e [Rules] Add ResurrectionEffectsBlock (#2990)
* [Rules] Add ResurrectionEffectsBlock

Notes:

This adds the rule Spells:ResurrectionEffectsBlock that will prevent anything from overwrites Resurrection Sickness Effects. Currently they are able to be overwritten by certain spells.

Default state: Disabled/False.

* Update ruletypes.h

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2023-03-04 17:24:29 -06:00
Alex King c21d47f450 [Scaling] Add support for pipe-separated zone IDs and versions (#3015)
* [Scaling] Add support for pipe-separated zone IDs and versions

# Notes
- Allows `|` separated zone IDs and instance versions within the scaling data.
- Loads scaling data on zone bootup as well, without needing to repop for it to initialize.

* Cleanup
2023-03-04 17:24:16 -06:00
Aeadoin 83ea9816b8 [Rules] Add Multiplier for Heroic Stats. (#3014)
* initial work

* [Rules] Add Multiplier for Heroic Stats.

* Add bots

* update SendStatsWindow

* fix SendStatsWindow
2023-03-04 17:09:44 -06:00
Chris Miles e3f9b396ab [Console] Add IS_TTY to force terminal coloring output (#3021) 2023-03-04 17:01:39 -06:00
Alex King 2a6cf8c8e7 [Strings] Add more number formatters (#2873)
* [Strings] Add more number formatters

# Notes
- Adds `Strings::ToUnsignedInt` for `uint32` support.
- Adds `Strings::ToBigInt` for `int64` support.
- Adds `Strings::ToUnsignedBigInt` for `uint64` support.
- Adds `Strings::ToFloat` for `float` support.
- Replaces all `std::stoi` references with `Strings::ToInt`.
- Replaces all `atoi` references with `Strings::ToInt`.
- Replaces all `std::stoul` references with `Strings::ToUnsignedInt`.
- Replaces all `atoul` references with `Strings::ToUnsignedInt`.
- Replaces all `std::stoll` references with `Strings::ToBigInt`.
- Replaces all `atoll` references with `Strings::ToBigInt`.
- Replaces all `std::stoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `atoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `std::stof` references with `Strings::ToFloat`.

* [Strings] Add more number formatters

- Adds `Strings::ToUnsignedInt` for `uint32` support.
- Adds `Strings::ToBigInt` for `int64` support.
- Adds `Strings::ToUnsignedBigInt` for `uint64` support.
- Adds `Strings::ToFloat` for `float` support.
- Replaces all `std::stoi` references with `Strings::ToInt`.
- Replaces all `atoi` references with `Strings::ToInt`.
- Replaces all `std::stoul` references with `Strings::ToUnsignedInt`.
- Replaces all `atoul` references with `Strings::ToUnsignedInt`.
- Replaces all `std::stoll` references with `Strings::ToBigInt`.
- Replaces all `atoll` references with `Strings::ToBigInt`.
- Replaces all `std::stoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `atoull` references with `Strings::ToUnsignedBigInt`.
- Replaces all `std::stof` references with `Strings::ToFloat`.

* Rebase cleanup

* Changes/benchmarks/tests

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-03-04 17:01:19 -06:00
cybernine186 be567af70d [Bug Fix] Cursor Coin Upon Death (#3020)
* Update corpse.cpp

* Add rule toggle.

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-03-04 17:45:42 -05:00
Alex King 6494fbf916 [Bug Fix] Fix Discovered Items with Alternate Currency and LDoN Adventure Merchants (#3026)
* [Bug Fix] Fix Discovered Items with Alternate Currency Merchants

# Notes
- Before now, alternate currency merchants did not trigger item discovery.

* Update client_packet.cpp
2023-03-04 13:09:27 -05:00
catapultam-habeo 2cc61ef8c1 [Bug Fix] Ensure synchronization of pet taunt state with UI (#3025)
* fix to desync between pet taunt state and button

* Update npc.h

* Update npc.cpp

* Update npc.h

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-03-04 11:40:29 -05:00
dependabot[bot] 5d7a7bb4b2 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#3024)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20210817164053-32db794688a5 to 0.1.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 17:37:58 -06:00
dependabot[bot] 00f82f43a6 Bump golang.org/x/net in /utils/scripts/build/should-release (#3023)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20210226172049-e18ecbb05110 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 17:23:13 -06:00
Chris Miles d3ca636a70 [Release] 22.4.5 (#3022) 2023-03-03 17:09:39 -06:00
Vayle 01855d40df [Bug Fix] Fix log messages when players join channel (#2992)
* Fix log message when players join channels

* Formatting

* More formatting

* Update CurrentPlayerChannels to use vector of channel names

* Put log statement back in place

* Remove channel limit in db query

* Formatting tweak
2023-03-03 11:54:56 -06:00
Paul Coene 748602b04e [Bug Fix] Fix an issue where EVENT_TIMER timers would not be cleaned up after zone (#3018)
* [Bug Fix] Dangling client timers fixed.

* Remove all timers from mob in destructor instead of in QuestMgr::Process
2023-03-03 11:54:14 -06:00
Alex King a97a9a0d1c [Bug Fix] Fix npcfeature and playerfeature (#3017) 2023-03-01 20:42:37 -05:00
Aeadoin a78c754c0e [Cleanup] Remove unused iterator from LoadCharacterDisciplines (#3012) 2023-03-01 20:35:28 -05:00
Alex King ef214f91e9 [Bug Fix] Fix DoAnim quest method default speed (#3016)
# Notes
- Sets default speed to `0` which makes the animations run at normal speed instead of `1` that makes them run is slow motion.
2023-03-01 17:47:27 -05:00
Aeadoin 04a74df0b2 [Bots] Add additional Heroic Sta/Wis/Int bonuses for Bots. (#3013) 2023-03-01 10:58:04 -05:00
Chris Miles c15bfe12eb [Fix] Fix issue where quest saylink responses would occur before the NPC's response (#3010)
* [Fix] Fix issue where quest saylink responses would occur before the NPC's response

* Update client_packet.cpp

* Revert "[Fix] Fix issue where quest saylink responses would occur before the NPC's response"

This reverts commit a09e1bbbe9.
2023-02-28 21:27:05 -05:00
Alex King 5702f7bcd1 [Quest API] Add IsFindable() and IsTrackable() to Perl/Lua (#2996)
# Perl
- Add `$mob->IsFindable()`.
- Add `$mob->IsTrackable()`.

# Lua
- Add `mob:IsFindable()`.
- Add `mob:IsTrackable()`.

# Notes
- Allows operators to see if a mob is findable or trackable.
2023-02-28 21:26:11 -05:00
Alex King 9a5bf53e11 [Quest API] Add IsUnderwaterOnly() to Perl/Lua (#2995)
# Perl
- Add `$npc->IsUnderwaterOnly()`.

# Lua
- Add `npc:IsUnderwaterOnly()`.

# Notes
- Allows operators to chec k if an NPC is underwater only.
2023-02-28 21:13:43 -05:00
Alex King 69c6a7b89a [Quest API] Add IsBerserk() to Perl/Lua (#2997)
* [Quest API] Add IsBerserk() to Perl/Lua

# Perl
- Add `$client->IsBerserk()`.

# Lua
- Add `client:IsBerserk()`.
- Remove `mob:IsBerserk()` to move to client.

# Notes
- Allows operators to check if a client is berserk.

* Move to Mob.

* Update lua_client.cpp
2023-02-28 20:31:20 -05:00
Aeadoin 2f0dbc5d15 [Bug Fix] Fix for Discipline Loading from Database causing issues with slot_ids (#3008)
* [Bug Fix] Fix for Discipline Loading from Database causing issues with slot_ids

* cleanup per comments
2023-02-28 16:55:22 -05:00
Aeadoin 93c79817cd [Crash] Fix crash in CheckTradeskillLoreConflict (#3009) 2023-02-27 19:24:05 -06:00
Aeadoin 3296287d70 [Bug Fix] Fix for Lore Components where component is returned. (#3005)
* [Bug Fix] Fix for Lore Components where component is returned.

* Refactor, and take into account loregroups above 0 properly

* Update tradeskills.cpp

* formatting for suggestions.

* commenting, update formatting.

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-27 12:36:35 -06:00
Alex King 774a7fa779 [Cleanup] Delete unused zone/skills.h (#3007)
# Notes
- This is unused.
2023-02-26 21:35:49 -05:00
Alex King 1ff4541a9f [Cleanup] Remove NumberOfAvailableTitles() from titles.h (#3006)
# Notes
- This is unused.
2023-02-26 21:35:43 -05:00
Alex King 3448758c03 [Quest API] Add HasSpecialAbilities() to Perl/Lua (#2994)
* [Quest API] Add HasSpecialAbilities() to Perl/Lua

# Perl
- Add `$mob->HasSpecialAbilities()`.

# Lua
- Add `mob:HasSpecialAbilities()`

# Notes
- Allows operators to check if a mob has special abilities

* Move to NPC.

* Update lua_mob.cpp
2023-02-26 21:35:10 -05:00
Alex King ff4ccfa98f [Quest API] Add GetDefaultRaceSize() to Perl/Lua (#2993)
# Perl
- Add `$mob->GetDefaultRaceSize()`.

# Lua
- Add `mob:GetDefaultRaceSize()`.

# Notes
- Allows operators to get the default race size of a race if they want to use it in a script.
2023-02-26 21:35:03 -05:00
Aeadoin d2c3c14ae0 [Bots] Cleanup AI_IdleCastCheck Logic (#3004)
* [Bots] Cleanup AI_IdleCastCheck Logic

* cleanup logic
2023-02-25 20:16:09 -05:00
Alex King a470931fdd [Cleanup] Remove class EGNode from mob.h (#3003)
# Notes
- This is unused.
2023-02-25 20:10:23 -05:00
Alex King 078db3460d [Cleanup] Remove ReturnItemPacket from client.h/inventory.cpp (#3002)
# Notes
- This is unused.
2023-02-25 20:10:08 -05:00
Alex King 0980a780d0 [Cleanup] Remove GetDamageMultiplier() from client.h (#3001)
# Notes
- This is unused.
2023-02-25 19:50:42 -05:00
Alex King 7f01bb509c [Cleanup] Remove DumpPacketProfile() from client.h (#3000)
# Notes
- This is unused.
2023-02-25 19:38:09 -05:00
Alex King 4bb189cbf4 [Cleanup] Remove GetCombinedAC_TEST() from client.h (#2999)
# Notes
- This is unused.
2023-02-25 19:38:03 -05:00
Alex King b03e8ff0fb [Cleanup] Remove unused ClientFactory in client.h (#2998)
# Notes
- This is unused.
2023-02-25 19:37:57 -05:00
Aeadoin 6179b7481e [Bug Fix] Account for bad data in Tradeskill Recipe Entries (#2991) 2023-02-25 10:52:17 -06:00
Chris Miles 5f68e4a41a [Release] 24.4.4 (#2989) 2023-02-24 20:51:45 -06:00
Chris Miles e103422ca5 [Pathing] More z-clip improvements, Wurm and Spectral Iksar race adjustments (#2988) 2023-02-24 20:27:28 -06:00
Akkadius 0cbfad975d [Hotfix] Adjust database manifest to include .sql extension 2023-02-24 20:20:21 -06:00
Alex King 2a20c69c69 [Scaling] Add support for zone ID and instance version to NPC Scaling (#2968)
* [Scaling] Add support for zone ID and instance version to NPC Scaling

# Notes
- Adds `zone_id` and `instance_version` to `npc_scale_global_base` table to allow for zone and version-specific scaling.
- Defaults back to `zone_id` of `0` and `instance_version` of `0` for global scaling.
- Scaling load precedence is as follows:
- `zone_id` of current zone and `instance_version` of current instance
- `zone_id` of current zone and `instance_version` of `0`
- `zone_id` of `0` and `instance_version` of `0`

* Remove debug comment.

* Use zone not NPC.

* SQL
2023-02-24 20:17:07 -06:00
Alex de2dfc1a7e [Bug Fix] Fix for undefined MySQL library behavior. (#2834)
* MYSQL objects cannot be copied in a well defined way, this removes the copy and replaces it with another connection

* Change to share underlying pointers.

* Push up mutex changes

* Post rebase

* Formatting

---------

Co-authored-by: KimLS <KimLS@peqtgc.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-24 20:14:55 -06:00
Chris Miles bad631df59 [Player Events] Add QS processing, mutex tweaks (#2984)
* [Player Events] Add QS processing, mutex tweaks

* Update ucs.cpp

* Move the size process check out of the server to server networking thread
2023-02-24 18:01:59 -06:00
Chris Miles e8f1aa253a [Pathing] Smoother pathing z-correction (#2982) 2023-02-24 14:07:44 -06:00
Chris Miles 889e57a5af [Pathing] Improve roambox logic (#2983)
* [Pathing] Improve roambox logic

* Cleanup roambox logic
2023-02-24 14:07:34 -06:00
Aeadoin 5cfdeb928e [Bug Fix] Fix Beneficial Target of Target procs (#2987) 2023-02-24 13:23:29 -06:00
Chris Miles 7519b0225e [Doors] Fix doors triggering invalid zone fetches of dest_zone of "none" (#2985)
* [Doors] Fix doors triggering invalid zone fetches of dest_zone of "none"

* Update doors.cpp

* Tweaks

* PR comments
2023-02-24 13:22:56 -06:00
Chris Miles 04fdc54522 [Quest API] Fix EVENT_TIMER crash when entity is no longer available (#2986)
* [Quest API] Fix EVENT_TIMER crash when entity is no longer available

* Update questmgr.cpp
2023-02-24 13:22:47 -06:00
Aeadoin f39155952f [Tradeskills] Fix for Lore Conflict (#2977)
* [Tradeskills] Fix for Lore Conflict

* Cleanup

* formatting

* it's beautiful

* container fix
2023-02-24 14:14:36 -05:00
Aeadoin 5acc181d64 [Bots] Cleanup BotDatabase::LoadBuffs (#2981)
* [Bots] Cleanup BotDatabae::LoadBuffs

* cleanup formatting/syntax
2023-02-24 12:58:54 -05:00
nytmyr 2ae0b7dd3e [Bug Fix] Correct Mend reuse time and add reduction support. (#2972)
Notes:

Previously, the server-side reuse of Mend was set to 290 seconds rather than 360 seconds (6 minutes).

Mend was not accepting reduction timers from potential items, buffs or AAs (Hastened Mend).

Mend was outputting duplicate success messages on critical mends, it will now only output a regular Mend message upon success (You mend your wounds and heal some damage) or the critical message upon critical success (You magically mend your wounds and heal considerable damage), not both.

Co-authored-by: toxin06 <53322305+toxin06@users.noreply.github.com>
2023-02-23 02:39:45 -06:00
Alex King b0d4f095ef [Commands] Cleanup #peekinv Command (#2969)
* [Commands] Cleanup #peekinv Command

# Notes
- Cleanup messages and logic.

* Update peekinv.cpp
2023-02-23 02:38:37 -06:00
Aeadoin 7c7a88650b [Bots] Verify Bots Group Integrity on join (#2980) 2023-02-23 02:36:43 -06:00
Aeadoin afaa8f4100 [Bots] Add Caster Range Command, and IsValidSpellRange Checks (#2942)
* [Bots] Add Caster Range Command, and IsValidSpellRange Checks

* remove/add exceptions where makes sense like buffs

* fixes

* fixes
2023-02-23 02:36:17 -06:00
Alex King 0d72295cc9 [Quest API] Add IsAutoAttackEnabled() to Perl/Lua (#2979)
# Perl
- Add `$client->IsAutoAttackEnabled()`.

# Lua
- Add `client:IsAutoAttackEnabled()`.

# Notes
- Allows operators to check if a client has auto attack enabled.
2023-02-23 02:31:35 -06:00
Alex King 9d4f231619 [Quest API] Add IsAutoFireEnabled() to Perl/Lua (#2978)
# Perl
- Add `$client->IsAutoFireEnabled()`.

# Lua
- Add `client:IsAutoFireEnabled()`.

# Notes
- Allows operators to check if a client has auto fire enabled.
2023-02-22 23:30:04 -05:00
Chris Miles fcb0a47280 [Release] 22.4.3 (#2976) 2023-02-21 10:42:43 -06:00
Chris Miles 1e50f19f7e [Pathing] Improvements to z-clipping, z-recovery and z-calculations (#2975)
* zclip adjustments

* Remove debug
2023-02-21 10:24:25 -06:00
Chris Miles 33bb5aa8e5 [Database] Address deadlock in player events (#2974)
* DB mutex testing

* Mutex tweaks, native string escaping
2023-02-20 22:32:29 -06:00
Aeadoin 6a668f8aa5 [Crash] Fix crash with EVENT_UNEQUIP_ITEM_BOT (#2973) 2023-02-20 17:31:15 -05:00
Alex King df499b22ab [Bug Fix] Fix MIR LDoN Theme Items on LDoN Merchants (#2971)
# Notes
- These items weren't showing as MIR due to this condition being typo'd in https://github.com/EQEmu/Server/pull/1611/files.
2023-02-19 21:51:37 -05:00
Alex King 7bc00cb466 [Bug Fix] Fix OOCMute not functioning (#2970)
# Notes
- #oocmute was not functioning as the packet wasn't being handled by the server.
2023-02-19 20:39:24 -05:00
Paul Coene 51f6108aab [Pets] Client Pet summoned by NPC should not change guard location. (#2967)
* [Pets] Client Pet summoned by NPC should not change guard location.

* Update mob.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-19 16:56:34 -05:00
Aeadoin c13f9f80d9 [Bots] Change HasBotItem(item_id) to return slot_id instead of bool. (#2966) 2023-02-19 16:13:28 -05:00
JJ 443abf9199 [SQL] Add date to optional Drakkin Guktan Faction Update (#2965) 2023-02-19 16:11:07 -05:00
Alex King 1556e05b2f [Quest API] Add client->SignalClient() overload to Perl (#2963)
# Notes
- Fixes an issue with Guild Lobby quests not properly using `client` as first parameter in `mob->SignalClient(client, signal_id)` method.
2023-02-19 15:20:28 -05:00
Alex King 1d645aa5f6 [Quest API] Fix Perl SetSimpleRoamBox Overloads (#2961)
# Notes
- These overloads were non-functional as they didn't have a method to actually fall back to.
2023-02-19 11:17:35 -05:00
Chris Miles 9f42da5bad [Crash] Fix world crash in player event processing (#2960)
* [Crash] Fix world crash in player event processing

* Add rule BatchPlayerEventProcessChunkSize
2023-02-18 16:06:16 -06:00
Aeadoin 4a8222f243 [Bots] Fix output of ^spells while ^Enforcespellsettings is enabled (#2959) 2023-02-18 16:06:06 -06:00
Chris Miles db4c515853 [Player Events] Create new event ITEM_CREATION (#2944) 2023-02-18 16:05:23 -06:00
Chris Miles 462656a201 [Reload API] Add world handlers for certain opcodes (#2958) 2023-02-18 15:58:29 -06:00
Aeadoin ddd98be383 [Bot] Change SaveTimers to Replace instead of Insert. (#2951)
* [Bot] Change SaveTimers to Replace instead of Insert.

* [Bot] Change SaveTimers to Replace instead of Insert.

* fix formatting
2023-02-18 16:13:36 -05:00
Chris Miles 4ad3ebf36a [Release] 22.4.2 (#2957) 2023-02-18 10:18:32 -06:00
Chris Miles b5a2713a3a [Player Events] Add logging category to hold processing batch logs (#2954)
* [Player Events] Add logging category to hold processing batch logs

* Update player_event_logs.cpp
2023-02-18 05:41:14 -06:00
Chris Miles 999fe10d86 [Content] Added optional SQL 2023_02_17_fix_sseru_mischief_doors.sql to fix sseru/mischief doors (#2955) 2023-02-18 05:41:05 -06:00
Chris Miles ce1472db1e [MySQL] Add keepalives to UCS and Loginserver (#2953) 2023-02-18 05:40:51 -06:00
Chris Miles d6c6b78d8a [Logging] Remove noisy raid/group/forage errors (#2952) 2023-02-18 05:40:41 -06:00
Aeadoin ee6c9a2ad7 [Tradeskills] Fix regression caused by #2932 (#2956) 2023-02-18 05:40:15 -06:00
Chris Miles 3e4767269e [Release] 22.4.1 (#2950) 2023-02-17 14:48:46 -06:00
Aeadoin e0eb145081 [Bots] Set Taunt to enabled for SK/Paladin Bots by Default. (#2941) 2023-02-17 10:46:49 -05:00
Chris Miles a6dd65435f [DevTools] Fix NPC targetting dev tools display window (#2943) 2023-02-17 06:07:20 -06:00
Chris Miles 26dc05c0dc [Player Events] Fix issue with item instances not being validated properly before accessing causing crashes on handin (#2945) 2023-02-17 06:07:02 -06:00
Chris Miles da20a6ab67 [Player Events] Fix rare out of bound issue when loading event types (#2946) 2023-02-17 06:06:53 -06:00
Chris Miles 3949a31246 [Fix] Issue with AssignRaidToInstance that was using the groups repository instead of raid (#2947) 2023-02-17 06:06:45 -06:00
Chris Miles e898be1ce9 [Player Events] Turn off KILLED_NPC (trash) off by default (#2948) 2023-02-17 06:05:43 -06:00
Akkadius 2962575dda [Hotfix] Missing comma in schema list breaking dumps 2023-02-16 22:27:09 -06:00
Akkadius 6a6045a21c [Release] Update should-release 2023-02-16 13:23:53 -06:00
Akkadius 717fe7dc8c [Release] 22.4.0 2023-02-16 10:24:45 -06:00
Chris Miles df69d12c0c [Release] 22.4.0 (#2940)
* [Release] 22.4.0

* Update changelog notes [skip ci]
2023-02-16 10:23:01 -06:00
Aeadoin 99e49cb2ec [Tradeskills] Check if combine would result in lore conflict (#2932)
* [Tradeskills] Check if Combine would result in Lore Conflict.

* formatting

* Add Saylinks to lore message output.

* Aknowledgement packets to prevent client issues.
2023-02-15 21:03:16 -06:00
Aeadoin 5ee2856133 [Bug Fix] Replace uses of SPELL_UNKNOWN with IsValidSpell() (#2938) 2023-02-15 21:01:35 -06:00
JJ 4a64048744 [Crash] Fix crash issue with dropping items and order of operations (#2939)
Should wait to null out invalid_drop until after it is used in log message.
2023-02-15 20:55:15 -06:00
Chris Miles 2ae795fd61 [Crash] Crash fix where invalid input to #heromodel would crash zone (#2937) 2023-02-15 14:36:09 -05:00
Chris Miles 0829bc08b8 [Doors] Fix issue where NPC's wouldn't open doors because door param overflow (#2934) 2023-02-15 10:59:38 -06:00
Chris Miles 903a385229 [Hotfix] Fix crash where dropped items crash Lua logic (#2936) 2023-02-15 10:57:05 -06:00
Chris Miles fafa33e190 [Groundspawns] Fix issue where groundspawns appear floating high off the ground (#2930) 2023-02-15 10:52:03 -06:00
Chris Miles 90a01f7c53 [Quest] Fix SetSimpleRoamBox in Perl to have optional params again (#2935) 2023-02-15 10:49:33 -06:00
Alex King 19434197d4 [Bug Fix] Fix crash in EVENT_DISCOVER_ITEM (#2933)
* [Bug Fix] Fix crash in EVENT_DISCOVER_ITEM

# Notes
- `const` didn't like the `std::any_cast`, also was passing `EQ::ItemData*` instead of `EQ::ItemInstance*`.

* Update client.cpp
2023-02-15 10:49:14 -06:00
Paul Coene 18b62667f0 [Bug Fix] Self Only Spells will no longer check target level or buff restrictions (#2931)
* [Bug Fix] Self Only Spells now work again (BuffSpellRestrictions)

* Moved variables under quick checks per review
2023-02-14 19:47:32 -05:00
Akkadius 8ed7ca977f [Hotfix] Another doors fix 2023-02-14 06:28:42 -06:00
Chris Miles 665e336946 [Fix] Fix issue where Lore groundspawn pickups will desync ROF2+ (#2929)
* [Fix] Fix issue where Lore groundspawn pickups will desync ROF2+

* Update object.cpp
2023-02-14 04:36:22 -06:00
Chris Miles ccf8504dec [Hotfix] Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by #2897 (#2928)
* [Hotfix] Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by  #2897

* Update client_packet.cpp
2023-02-14 04:36:10 -06:00
Akkadius d107213fe1 [Cleanup] Doors EVENT_CLICK_DOOR syntax adjustment 2023-02-14 04:10:15 -06:00
Akkadius c115cbcd6a [Hotfix] Fix Door opening regression caused by #2880 2023-02-14 01:36:03 -06:00
Chris Miles 064ae7ba89 [Hotfix] Fix HP_EVENT regression (#2927)
* [Hotfix] Fix HP_EVENT regression

* Update mob.cpp
2023-02-13 23:28:40 -05:00
Chris Miles 02302802b8 [CI] Fix Windows stderr not bubbling properly (#2925)
* [CI] Fix Windows stderr not bubbling properly

* Update windows-build.ps1
2023-02-13 21:41:29 -06:00
Chris Miles 536e248424 [Windows] Fix MSVC compilation bug via workaround (#2926) 2023-02-13 21:21:05 -06:00
Chris Miles 5b56a23a8a [Hotfix] Fix issue with EVENT_HP firing regression from #2904 (#2924)
* [Hotfix] Fix issue with EVENT_HP firing from https://github.com/EQEmu/Server/pull/2904

* Fix

* Fix
2023-02-13 22:02:18 -05:00
Alex King 97edb09fba [Rules] Add Group/Raid Experience Rules (#2850)
# Notes
- Add `Character:EnableGroupMemberEXPModifier`, enables or disables member-based experience modifiers in groups, default `true`.
- Add `Character:EnableRaidEXPModifier`, enables or disables member-based experience modifiers in raids, default `true`.
- Add `Character:EnableRaidMemberEXPModifier`, enables or disables member-based experience modifiers in raids, default `true`.
2023-02-13 00:25:59 -06:00
Alex King 85f7b10f90 [Cleanup] Remove Unused Mod Hooks (#2856)
- Removes old `mod_` hooks that have gone unused for years in favor of Lua mods.
2023-02-13 00:24:23 -06:00
Aeadoin 0f49fbcfcd [Bots] Add Support for TryTriggerOnCastFocusEffect (#2864) 2023-02-13 00:19:50 -06:00
Vayle e57979c3a8 [Quest API] Add Additional XP Events EVENT_AA_EXP_GAIN, EVENT_EXP_GAIN (#2865)
* Add XP Events

* Tweak

* Formatting

* Additional tweak

* Adjustment

* Update export naming

* Formatting

* Indenting

* Finalizing formatting

* Indenting adjustments

* Use tab character setting

* Remove double tabs

* Update exp.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2023-02-13 00:19:02 -06:00
Aeadoin fc7c30977a [Bots & Mercs] Add Support for TrySympatheticProc (#2866)
* [Bots & Merrcs] Add Support for TrySympatheticProc

* [Bots & Merrcs] Add Support for TrySympatheticProc

* [Bots & Merrcs] Add Support for TrySympatheticProc

* Cleanup

* formatting

* auto
2023-02-13 00:16:18 -06:00
Aeadoin b3fd9dd88a [Crash] Fix Crash in FindType (#2867) 2023-02-13 00:15:40 -06:00
Alex King 4df9661903 [Quest API] Add EVENT_DROP_ITEM_CLIENT to Perl/Lua (#2869)
* [Quest API] Add EVENT_DROP_ITEM_CLIENT to Perl/Lua

- Add `EVENT_DROP_ITEM_CLIENT`, exports `$quantity,` $item_name`, `$item_id`, `$spell_id`, `$slot_id`, and `$item`.

- Add `event_drop_item_client`, exports `e.quantity`, `e.item_name`, `e.item_id`, `e.spell_id`, `e.slot_id`, and `e.item`.

* Update inventory.cpp

* Update inventory.cpp

* Update lua_general.cpp

* Update inventory.cpp
2023-02-13 00:15:19 -06:00
Alex King 8c363320d8 [Quest API] Export target to EVENT_TARGET_CHANGE in Perl/Lua. (#2870)
* [Quest API] Export target to EVENT_TARGET_CHANGE in Perl/Lua.

- Export `$target` to `EVENT_TARGET_CHANGE`.

- Export `e.other` to `event_target_change`.

- Allows operators to not have to grab bot, Client, or NPC's target in Perl with `GetTarget()`.
- Allows operators to not have to grab Client's target in Lua with `GetTarget()`.

* Update mob.cpp

* Update mob.cpp

* Update mob.cpp
2023-02-13 00:03:52 -06:00
Alex King d4afc78982 [Quest API] Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua. (#2871)
* [Quest API] Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua.

- Add `EVENT_DESTROY_ITEM_CLIENT`, exports `$item_id`, `$item_name`, `$quantity`, and `$item`.

- Add `event_destroy_item_client`, exports `e.item_id`, `e.item_name`, `e.quantity`, and `e.item`.

- Allows operators to use player scripts for item destroys.

* Update lua_parser_events.h

* Update inventory.cpp
2023-02-12 23:58:27 -06:00
Aeadoin 24de1d948a [Crash] Fix crash in Mob::CommonDamage when attacker was null (#2872) 2023-02-12 23:53:29 -06:00
Alex King ca0e85b4bc [Quest API] Export $item to EVENT_PLAYER_PICKUP in Perl. (#2875)
* [Quest API] Export $item to EVENT_PLAYER_PICKUP in Perl.

# Notes
- Exports `$item` to `EVENT_PLAYER_PICKUP` in Perl so that you have access to the item itself.

* Optional parsing.

* Update object.cpp

* Update object.cpp
2023-02-12 23:52:47 -06:00
Alex King 5b24d38d1e [Quest API] Export $item to Fishing and Forage Events in Perl (#2876)
* [Quest API] Export $item to Fishing and Forage Events in Perl

# Notes
- Exports `$item` to `EVENT_FISH_SUCCESS` in Perl.
- Exports `$item` to `EVENT_FORAGE_SUCCESS` in Perl.

* Add optional parsing to fish/forage events.

* Update forage.cpp

* Fix missing event param

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:50:21 -06:00
Alex King 4a1d026215 [Quest API] Export $spawned to EVENT_SPAWN_ZONE in Perl (#2877)
* [Quest API] Export $spawned to EVENT_SPAWN_ZONE in Perl

# Notes
- Exports `$spawned` to `EVENT_SPAWN_ZONE` in Perl.
- Allows operators to use the mob reference instead of having to grab it from entity list.

* Optional parsing.
2023-02-12 23:46:01 -06:00
Alex King 5ef8f8c3a8 [Quest API] Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl (#2878)
* [Quest API] Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl

# Notes
- Exports `$item` and `$corpse` to `EVENT_LOOT` in Perl.
- Exports `$item` and `$corpse` to `EVENT_LOOT_ZONE` in Perl.

* Optional parsing.

* Update corpse.cpp

* Cleanup

* Export changes

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:45:26 -06:00
Alex King 384de31989 [Quest API] (Performance) Check event exists before export and execute EVENT_BOT_CREATE (#2886)
* [Quest API] Optionally parse EVENT_BOT_CREATE

- Optionally parse this event instead of always doing so.

* Cleanup

* Cleanup
2023-02-12 23:40:03 -06:00
Alex King 5be3780a54 [Quest API] (Performance) Check event exists before export and execute EVENT_LEVEL_UP and EVENT_LEVEL_DOWN (#2889)
* [Quest API] Optionally parse EVENT_LEVEL_UP and EVENT_LEVEL_DOWN

- Optionally parses these events instead of always doing so.

* [Quest API] Optionally parse EVENT_LEVEL_UP and EVENT_LEVEL_DOWN

- Optionally parses these events instead of always doing so.
2023-02-12 23:36:45 -06:00
Alex King 21e42714eb [Quest API] (Performance) Check merchant events exist before export and execute (#2893)
* [Quest API] Optionally parse merchant events

- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 23:33:32 -06:00
Alex King 3474c00e7a [Quest API] (Performance) Check event EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, or EVENT_USE_SKILL exist before export and execute (#2894)
* [Quest API] Optionally parse EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, and EVENT_USE_SKILL

- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 23:30:48 -06:00
Alex King 3d6b0e5f74 [Quest API] (Performance) Check event EVENT_COMBINE, EVENT_COMBINE_SUCCESS, EVENT_COMBINE_FAILURE, or EVENT_COMBINE_VALIDATE exist before export and execute (#2896)
* [Quest API] Optionally parse EVENT_COMBINE_SUCCESS and EVENT_COMBINE_FAILURE

- Optionally parse these events instead of always doing so.

* Update tradeskills.cpp

* Update tradeskills.cpp
2023-02-12 23:28:27 -06:00
Alex King 9f619859d1 [Quest API] (Performance) Check spell or cast events exist before export and execute (#2897)
* [Quest API] Optionally parse spell/cast events

# Notes
- Optionally parses `EVENT_CAST`, `EVENT_CAST_BEGIN`, `EVENT_CAST_ON`, `EVENT_SPELL_EFFECT_NPC`, `EVENT_SPELL_EFFECT_CLIENT`, `EVENT_SPELL_EFFECT_BOT`, `EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT`, `EVENT_SPELL_EFFECT_BUFF_TIC_NPC`, `EVENT_SPELL_EFFECT_BUFF_TIC_BOT`, `EVENT_SPELL_FADE`, and `EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE`.

* Cleanup

* PR comment fixes

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:26:17 -06:00
Alex King 805a9c5f59 [Quest API] (Performance) Check event EVENT_DEATH, EVENT_DEATH_COMPLETE, or EVENT_DEATH_ZONE exist before export and execute (#2909)
* [Quest API] Optionally parse EVENT_DEATH and EVENT_DEATH_COMPLETE

- Optionally parse these events instead of always doing so.

* Update attack.cpp

* Update attack.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 23:15:57 -06:00
Alex King 43329dc583 [Quest API] (Performance) Check event exists before export and execute EVENT_KILLED_MERIT (#2911)
- Optionally parse this event instead of always doing so.
2023-02-12 23:09:34 -06:00
Alex King 66fee56c47 [Quest API] (Performance) Check event exists before export and execute EVENT_DISCOVER_ITEM (#2912)
- Optionally parse this event instead of always doing so.
2023-02-12 23:07:32 -06:00
Alex King efb2ab57aa [Quest API] Optionally parse EVENT_CONNECT and EVENT_DISCONNECT (#2913)
- Optionally parse these events instead of always doing so.
2023-02-12 23:01:48 -06:00
Alex King 0a7d482299 [Quest API] (Performance) Check event EVENT_ENVIRONMENTAL_DAMAGE exists before export and execute (#2899)
* [Quest API] Optionally parse EVENT_ENVIRONMENTAL_DAMAGE

# Notes
- Optionally parses this event instead of always doing so.

* Update client_packet.cpp
2023-02-12 23:00:04 -06:00
Alex King de047fb851 [Quest API] (Performance) Check event EVENT_FEIGN_DEATH exists before export and execute (#2916)
* [Quest API] Optionally parse EVENT_FEIGN_DEATH

# Notes
- Optionally parse this event instead of always doing so.

* Remove unused reference, fix other PR

* Update task_client_state.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-02-12 22:59:14 -06:00
Natedog2012 9836b5cf67 [Bug Fix] Fix for interrupting item casts to no longer lock the client if cast time of item greater than 0 (#2921) 2023-02-12 22:49:59 -06:00
Alex King c64591b8f7 [Quest API] Export $killed_npc to EVENT_NPC_SLAY to Perl (#2879)
# Notes
- Exports `$killed_npc` to `EVENT_NPC_SLAY` to Perl.
- Allows operators to use NPC reference in event instead of just NPC ID.
2023-02-12 22:49:16 -06:00
Alex King 3813162bac [Quest API] (Performance) Check task events exist before export and execute (#2883)
* [Quest API] Optionally parse task events

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

* Cleanup

* Update task_client_state.cpp

* [Quest API] Optionally parse task events

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

* Cleanup
2023-02-12 22:48:51 -06:00
Alex King 7099e17c7e [Quest API] Export $hate_entity to EVENT_HATE_LIST in Perl (#2885)
# Notes
- Exports `$hate_entity` to `EVENT_HATE_LIST`.
- Allows operators to see which mob is joining/leaving an NPC's hatelist.
2023-02-12 22:44:31 -06:00
Alex King 2c75e8fcd4 [Quest API] Add $target export to EVENT_INSPECT in Perl (#2891)
* [Quest API] Add $target export to EVENT_INSPECT in Perl

# Notes
- Exports `$target` to `EVENT_INSPECT`.
- Allows operators to get information from target directly instead of using entity list.

* Update client_packet.cpp
2023-02-12 22:43:38 -06:00
Alex King e8f01fb6ac [Quest API] Export $item and $augment to augment events in Perl (#2895)
* [Quest API] Export $item and $augment to augment events in Perl

# Notes
- Exports `$item` and `$augment` to `EVENT_AUGMENT_INSERT_CLIENT` in Perl.
- Exports `$item` and `$augment` to `EVENT_AUGMENT_REMOVE_CLIENT` in Perl.
- Allows operators to use item and augment reference instead of just item IDs.

* Cleanup
2023-02-12 22:42:27 -06:00
Alex King fd0764d4cb [Quest API] (Performance) Check event exists before export and execute EVENT_TIMER (#2903)
# Notes
- Parse this event optionally instead of always doing so.
2023-02-12 22:33:33 -06:00
Alex King 71b2bf6a64 [Quest API] (Performance) Check event exists before export and execute EVENT_ENTER_ZONE and EVENT_ZONE (#2900)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 22:32:37 -06:00
Alex King 2dcff247c8 [Quest API] Export targets to EVENT_CONSIDER and EVENT_CONSIDER_CORPSE (#2908)
# Perl
- Export `$target` to `EVENT_CONSIDER`.
- Export `$corpse` to `EVENT_CONSIDER_CORPSE`.

# Lua
- Export `e.other` to `EVENT_CONSIDER`.
- Export `e.corpse` to `EVENT_CONSIDER_CORPSE`.

 # Notes
- Allows operators to grab the target or corpse a player is considering.
2023-02-12 22:32:04 -06:00
Alex King 93f19d3971 [Quest API] (Performance) Check event EVENT_AGGRO, EVENT_ATTACK, or EVENT_COMBAT exist before export and execute (#2901)
* [Quest API] Optionally parse EVENT_COMBAT

# Notes
- Optionally parse this event instead of always doing so.

* Optional EVENT_ATTACK

* Update attack.cpp
2023-02-12 22:30:24 -06:00
Alex King bad44f35e2 [Quest API] (Performance) Check event EVENT_PAYLOAD or EVENT_SIGNAL exist before export and execute (#2902)
* [Quest API] Optionally parse EVENT_PAYLOAD and EVENT_SIGNAL

# Notes
- Optionally parse these events instead of always doing so.

* Update bot.cpp
2023-02-12 22:28:50 -06:00
Alex King 4a339d49df [Quest API] (Performance) Check event exists before export and execute EVENT_HP (#2904)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:27:57 -06:00
Alex King 57d0420399 [Quest API] (Performance) Check event EVENT_WAYPOINT_ARRIVE or EVENT_WAYPOINT_DEPART exist before export and execute (#2905)
* [Quest API] Optionally parse EVENT_WAYPOINT_ARRIVE and EVENT_WAYPOINT_DEPART

# Notes
- Optionally parse these events instead of always doing so.

* [Quest API] Optionally parse EVENT_WARP

# Notes
- Optionally parse this event instead of always doing so.

* Revert "[Quest API] Optionally parse EVENT_WARP"

This reverts commit d8acb9883d.
2023-02-12 22:27:15 -06:00
Alex King 90def9b882 [Quest API] (Performance) Check event exists before export and execute EVENT_TRADE (#2906)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:26:21 -06:00
Alex King 84156829a7 [Quest API] (Performance) Check event exists before export and execute EVENT_WARP (#2907)
# Notes
- Parse this event optionally instead of always doing so.
2023-02-12 22:25:42 -06:00
Alex King d210b1e5ff [Quest API] (Performance) Check event EVENT_SLAY exists before export and execute (#2910)
* [Quest API] Optionally parse EVENT_SLAY

# Notes
- Optionally parse this event instead of always doing so.

* Update attack.cpp
2023-02-12 22:24:38 -06:00
Alex King 086538754e [Quest API] (Performance) Check event EVENT_ITEM_TICK or EVENT_WEAPON_PROC exist before export and execute (#2914)
* [Quest API] Optionally parse EVENT_ITEM_TICK

# Notes
- Optionally parse this event instead of always doing so.

* Update mob.cpp
2023-02-12 22:22:22 -06:00
Alex King 241f900dc4 [Quest API] (Performance) Check event exists before export and execute EVENT_DUEL_LOSE and EVENT_DUEL_WIN (#2915)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 22:21:21 -06:00
Alex King 604256a223 [Quest API] (Performance) Check event exists before export and execute EVENT_RESPAWN (#2917)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:19:23 -06:00
Alex King 2dffc66c6f [Quest API] (Performance) Check event exists before export and execute EVENT_UNHANDLED_OPCODE (#2918)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:18:57 -06:00
Alex King 1bf24273d2 [Quest API] (Performance) Check event exists before export and execute EVENT_TICK (#2919)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:16:39 -06:00
Alex King c060280417 [Quest API] Optionally parse EVENT_TEST_BUFF (#2920)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:16:17 -06:00
Alex King bc6efd5f74 [Quest API] (Performance) Check equip or scale item events exist before export and execute (#2898)
* [Quest API] Optional parse equip and scale item events

# Notes
- Optionally parse `EVENT_SCALE_CALC`, `EVENT_ITEM_ENTER_ZONE`, `EVENT_UNEQUIP_ITEM_BOT`, `EVENT_EQUIP_ITEM_BOT`, `EVENT_EQUIP_ITEM`, `EVENT_UNEQUIP_ITEM`, `EVENT_EQUIP_ITEM_CLIENT`, `EVENT_UNEQUIP_ITEM_CLIENT`

* Cleanup
2023-02-12 22:15:54 -06:00
Alex King efd6d2f9b1 [Quest API] (Performance) Check event EVENT_AA_BUY or EVENT_AA_GAIN exist before export and execute (#2892)
* [Quest API] Optionally parse EVENT_AA_BUY and EVENT_AA_GAIN

# Notes
- Optionally parse these events instead of always doing so.

* Cleanup
2023-02-12 22:04:54 -06:00
Alex King 9dd4cf71f1 [Quest API] (Performance) Check event exists before export and execute EVENT_GM_COMMAND (#2890)
# Notes
- Optionally parse this event instead of always doing so.
2023-02-12 22:03:51 -06:00
Alex King cfec31457c [Quest API] (Performance) Check event exists before export and execute area events (#2888)
* [Quest API] Optionally parse area events

# Notes
- Optionally parse these events instead of always doing so.

* Update entity.cpp
2023-02-12 22:01:28 -06:00
Alex King 5ac5beb456 [Quest API] (Performance) Check event exists before export and execute EVENT_DESPAWN and EVENT_DESPAWN_ZONE (#2887)
# Notes
- Optionally parse these events instead of always doing so.
2023-02-12 21:59:01 -06:00
Alex King 0e51131d67 [Quest API] (Performance) Check event exists before export and execute EVENT_GROUP_CHANGE (#2884)
* [Quest API] Optionally parse EVENT_GROUP_CHANGE

# Notes
- Optionally parse this event instead of always doing so.

* Update embparser.cpp
2023-02-12 21:56:25 -06:00
Alex King f9a87e26c9 [Quest API] (Performance) Check event exists before export and execute EVENT_AGGRO_SAY, EVENT_SAY, and EVENT_PROXIMITY_SAY (#2882)
* [Quest API] Add optional parsing to EVENT_AGGRO_SAY and EVENT_SAY

# Notes
- Optionally parse these events instead of always doing so.

* Optionally parse EVENT_PROXIMITY_SAY
2023-02-12 21:54:20 -06:00
Alex King 9e16cd8ae8 [Quest API] (Performance) Check event exists before export and execute EVENT_POPUP_RESPONSE (#2881)
# Notes
- Optionally parses this event instead of always doing so.
2023-02-12 21:48:23 -06:00
Alex King 9644f14746 [Quest API] (Performance) Check event exists before export and execute EVENT_CLICK_DOOR and EVENT_CLICK_OBJECT (#2880)
* [Quest API] Add optional parsing to EVENT_CLICK_DOOR.

# Notes
- Optional parses this event instead of always doing so.

* Update client_packet.cpp
2023-02-12 21:47:17 -06:00
Chris Miles d9f545a5ec [Logging] Implement Player Event Logging system (#2833)
* Plumbing

* Batch processing in world

* Cleanup

* Cleanup

* Update player_event_logs.cpp

* Add player zoning event

* Use generics

* Comments

* Add events

* Add more events

* AA_GAIN, AA_PURCHASE, FORAGE_SUCCESS, FORAGE_FAILURE

* FISH_SUCCESS, FISH_FAILURE, ITEM_DESTROY

* Add charges to ITEM_DESTROY

* WENT_ONLINE, WENT_OFFLINE

* LEVEL_GAIN, LEVEL_LOSS

* LOOT_ITEM

* MERCHANT_PURCHASE

* MERCHANT_SELL

* SKILL_UP

* Add events

* Add more events

* TASK_ACCEPT, TASK_COMPLETE, and TASK_UPDATE

* GROUNDSPAWN_PICKUP

* SAY

* REZ_ACCEPTED

* COMBINE_FAILURE and COMBINE_SUCCESS

* DROPPED_ITEM

* DEATH

* SPLIT_MONEY

* TRADER_PURCHASE and TRADER_SELL

* DISCOVER_ITEM

* Convert GM_COMMAND to use new macro

* Convert ZONING event to use macro

* Revert some code changes

* Revert "Revert some code changes"

This reverts commit d53682f997e89a053a660761085913245db91e9d.

* Add cereal generation support to repositories

* TRADE

* Formatting

* Cleanup

* Relocate discord_manager to discord folder

* Discord sending plumbing

* Rename UCS's Database class to UCSDatabase to be more specific and not collide with base Database class for repository usage

* More discord sending plumbing

* More discord message formatting work

* More discord formatting work

* Discord formatting of events

* Format WENT_ONLINE, WENT_OFFLINE

* Add merchant purchase event

* Handle Discord MERCHANT_SELL formatter

* Update player_event_discord_formatter.cpp

* Tweaks

* Implement retention truncation

* Put mutex locking on batch queue, put processor on its own thread

* Process on initial bootup

* Implement optional QS processing, implement keepalive from world to QS

* Reload player event settings when logs are reloaded in game

* Set settings defaults

* Update player_event_logs.cpp

* Update player_event_logs.cpp

* Set retention days on boot

* Update player_event_logs.cpp

* Player Handin Event Testing.

Testing player handin stuff.

* Cleanup.

* Finish NPC Handin.

* set a reference to the client inside of the trade object as well for plugins to process

* Fix for windows _inline

* Bump to cpp20 default, ignore excessive warnings on windows

* Bump FMT to 6.1.2 for cpp20 compat and swap fmt::join for Strings::Join

* Windows compile fixes

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Create 2022_12_19_player_events_tables.sql

* [Formatters] Work on Discord Formatters

* Handin money.

* Format header

* [Formatters] Work on Discord Formatters

* Format

* Format

* [Formatters] More Formatter work, need to test further.

* [Formatters] More Work on Formatters.

* Add missing #endif

* [Formatters] Work on Formatters, fix Bot formatting in ^create help

* NPC Handin Discord Formatter

* Update player_event_logs.cpp

* Discover Item Discord Formatter

* Dropped Item Discord Formatter

* Split Money Discord Formatter

* Trader Discord Formatters

* Cleanup.

* Trade Event Discord Formatter Groundwork

* SAY don't record GM commands

* GM_Command don't record #help

* Update player_event_logs.cpp

* Fill in more event data

* Post rebase fixes

* Post rebase fix

* Discord formatting adjustments

* Add event deprecation or unimplemented tag support

* Trade events

* Add return money and sanity checks.

* Update schema

* Update ucs.cpp

* Update client.cpp

* Update 2022_12_19_player_events_tables.sql

* Implement archive single line

* Replace hackers table and functions with PossibleHack player event

* Replace very old eventlog table since the same events are covered by player event logs

* Update bot_command.cpp

* Record NPC kill events ALL / Named / Raid

* Add BatchEventProcessIntervalSeconds rule

* Naming

* Update CMakeLists.txt

* Update database_schema.h

* Remove logging function and methods

* DB version

* Cleanup SendPlayerHandinEvent

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Aeadoin <109764533+Aeadoin@users.noreply.github.com>
2023-02-12 21:31:01 -06:00
Aeadoin 1cc32d92cf [Bots] Add Lore Check for Augments. (#2874)
* [Bots] Add Lore Check for Augments.

* Add bot name
2023-02-12 16:43:58 -05:00
Aeadoin 924e91cf64 [Crash] Fix Bot Crash in Bot::Bot Constructor. (#2868)
* [Crash] Fix Bot Crash in Bot::Bot Constructor.

* fix another potential crash in bot contructor.
2023-02-12 14:27:29 -05:00
Aeadoin 9825c61a13 [Bots] Add Pet Power Support for Temp Pets. (#2853) 2023-02-11 10:57:02 -05:00
Alex King 5a0a1b1ffd [Quest API] Export $item to EVENT_DISCOVER_ITEM in Perl (#2863)
# Notes
- Exports `$item` to `EVENT_DISCOVER_ITEM`.
2023-02-10 23:56:50 -05:00
Alex King a3bb7e7741 [Quest API] Export $item to Client/Bot Equip Events in Perl (#2860)
* [Quest API] Add $item Export to Client/Bot Equip Events

# Notes
- Adds `$item` export to `EVENT_ITEM_EQUIP_CLIENT`, `EVENT_ITEM_UNEQUIP_CLIENT`, `EVENT_ITEM_EQUIP_BOT`, and `EVENT_UNEQUIP_ITEM_BOT`.

* Update bot.cpp

* Update embparser.cpp
2023-02-10 23:56:36 -05:00
Alex King a1251bdda8 [Quest API] Export $door to EVENT_CLICKDOOR in Perl (#2861)
# Notes
- Exports `$door` object to `EVENT_CLICKDOOR` in Perl so you don't have to grab it from entity list.
2023-02-10 23:56:24 -05:00
Alex King b90082d694 [Quest API] Export $object to EVENT_CLICK_OBJECT in Perl (#2862)
# Notes
- Exports `$object` to `EVENT_CLICK_OBJECT` in Perl so you don't have to grab it from entity list.
2023-02-10 23:34:52 -05:00
Aeadoin a49fa42f35 [Bots] Update ResistSpell to use temp_level_diff client formula (#2851) 2023-02-09 10:36:15 -05:00
Aeadoin 7064a4156f [Bots] Add IsBot() to methods in attack.cpp where applicable. (#2840)
* [Bots] add IsBot() to methods in attack.cpp where applicable.

* Add mercs where applicable

* Cleanup verbose if statements

* typo

* Fix other spots missed.
2023-02-09 10:36:01 -05:00
Aeadoin 106cb45b57 [Crash] Fix potential crash in Mob::CommonDamage (#2848)
out of bounds memory access.
2023-02-09 10:35:51 -05:00
Aeadoin 9a544650ee [Bots] ST_AreaClientOnly spells to land on Bots (#2849) 2023-02-09 10:35:38 -05:00
Aeadoin 032d423add [Bots] Add TotalDominationBonus modifiers. (#2852) 2023-02-09 10:35:26 -05:00
Akkadius 760b30ca0a [Crash] Fix issue where long short names overflow file_name 2023-02-09 01:03:51 -06:00
Chris Miles 6b08ca51cc [Logging] Add raw opcode when emu translated opcode is not found (OP_Unknown) via (C->S) (#2847) 2023-02-07 21:23:24 -06:00
Alex King 268879b414 [Quest API] Add Recipe-based methods to Perl/Lua. (#2844)
* [Quest API] Add Recipe-based methods to Perl/Lua.

# Perl
- Add `quest::get_recipe_component_item_ids(recipe_id)`.
- Add `quest::get_recipe_container_item_ids(recipe_id)`.
- Add `quest::get_recipe_fail_item_ids(recipe_id)`.
- Add `quest::get_recipe_salvage_item_ids(recipe_id)`.
- Add `quest::get_recipe_success_item_ids(recipe_id)`.
- Add `quest::get_recipe_component_count(recipe_id, item_id)`.
- Add `quest::get_recipe_fail_count(recipe_id, item_id)`.
- Add `quest::get_recipe_salvage_count(recipe_id, item_id)`.
- Add `quest::get_recipe_success_count(recipe_id, item_id)`.

# Lua
- Add `eq.get_recipe_component_item_ids(recipe_id)`.
- Add `eq.get_recipe_container_item_ids(recipe_id)`.
- Add `eq.get_recipe_fail_item_ids(recipe_id)`.
- Add `eq.get_recipe_salvage_item_ids(recipe_id)`.
- Add `eq.get_recipe_success_item_ids(recipe_id)`.
- Add `eq.get_recipe_component_count(recipe_id, item_id)`.
- Add `eq.get_recipe_fail_count(recipe_id, item_id)`.
- Add `eq.get_recipe_salvage_count(recipe_id, item_id)`.
- Add `eq.get_recipe_success_count(recipe_id, item_id)`.

# Notes
- Before these methods, you would have to use DBI from Perl or Lua in order to get the components and their counts, these methods allow easy access to these values via the scripting API.
- These should be used sparingly as they're each an individual database hit and could go crazy in a hot path.

* Update eq_constants.h

* Update zonedb.h

* Update tradeskills.cpp

* Reserve.
2023-02-07 21:42:34 -05:00
Alex King 4c6dc960e4 [Bug Fix] Fix CheckNumHitsRemaining() with 1H Blunt (#2846)
# Notes
- CheckNumHitsRemaining() wasn't working when skill ID was `0` (1H Blunt).
2023-02-06 23:41:32 -05:00
Aeadoin cc46b54f7f [Bots] Add Additional HeroicAgi/Dex Modifiers. (#2838)
* [Bots] Add Additional HeroicAgi/Dex Modifiers.

* Typo
2023-02-06 22:31:02 -05:00
Aeadoin 9e3b363d4a [Code] Add IsOfClientBot() virtual method. (#2845) 2023-02-06 22:30:49 -05:00
Aeadoin b0d1dc5f04 [Bots/Mercs] Add 100% Hit chance if sitting while attacked. (#2839)
* [BOT] Add 100% Hit chance if sitting while attacked.

* [BOT] Add 100% Hit chance if sitting while attacked.

* Add Mercs correctly

* Missed usage of IsSitting() in Mob::RollD20
2023-02-06 22:30:33 -05:00
Chris Miles 158396937a [Release] 22.3.0 (#2842)
* [Release] 22.3.0

* Update version.h

* Redirect stderr

* Update should-release to filter non-master

* Update should-release
2023-02-06 20:12:04 -06:00
Aeadoin fb1467284c [Bots] Add Additional HeroicStr modifiers. (#2837) 2023-02-06 21:07:38 -05:00
Aeadoin 14addd4869 [Feature] Add IsOfClientBotMerc() virtual method. (#2843) 2023-02-06 21:03:48 -05:00
Chris Miles 0a114fae9a [Doors] Have NPCs trigger double doors (#2821) 2023-02-06 17:47:03 -06:00
Chris Miles 2b224d42ad [Rules] Fix rule updates that affected bot booting checks (#2841) 2023-02-06 17:31:50 -06:00
Natedog2012 155ec9ac0d [Quest API] Add rule AlternateAugmentationSealer for using a different bagtype (#2831)
* [Quest API] Add rule AlternateAugmentationSealer for using a different bagtype as an alternate augmentation sealer. Use EVENT_COMBINE with UseAugmentContainer

* Default it to be off or bagtype 53 (BagTypeAugmentationSealer)
2023-02-06 17:30:16 -06:00
Chris Miles 25b4b97c41 [DB Updates] Add Windows MySQL path auto detection for users where the path is not found (#2836) 2023-02-06 17:25:34 -06:00
Joel 839f31b24d [Rule] Added rule to bypass level based haste caps (#2835) 2023-02-06 17:25:17 -06:00
Chris Miles 20728c31c4 [Crash] Fix crash in bot command botdyearmor (#2832)
* [Crash] Fix crash in bot command botdyearmor

* Update bot_command.cpp
2023-02-06 17:24:49 -06:00
Chris Miles c6eb12ac16 [Crash] Fix IsUnderwaterOnly crash where npc data references can be stale (#2830)
* [Crash] Fix IsUnderwaterOnly crash where npc data references can be stale

* m_ prefix
2023-02-06 17:24:38 -06:00
Chris Miles 34d21d4056 [Crash] Fix command crash with #npcedit weapon when second weapon not passed ni (#2829) 2023-02-06 17:24:24 -06:00
Chris Miles d369b47ef4 [Tasks] Implement alternate currency rewards (#2827)
* Reward currency on task completion

* Handle reward window

* Tweaks
2023-02-06 17:24:13 -06:00
Chris Miles 404f7cada8 [Pathing] Improvements to handling tight corridors pathing, clipping detection and recovery (#2826) 2023-02-06 17:24:03 -06:00
Chris Miles 823e73336d [Command] #list now searches without case sensitivity (#2825) 2023-02-06 17:23:50 -06:00
Chris Miles 0da6391be3 [Doors] Remove door dev tools spam on client controlled doors (#2824)
* [Doors] Remove door dev tools spam on client controlled doors

* Update client_packet.cpp

* Update client_packet.cpp

* Update ruletypes.h
2023-02-06 17:23:40 -06:00
Chris Miles 0348cb6b8e [Fix] Fix NPC ghosting at safe coordinates (#2823)
* [Fix] Fix NPC ghosting at safe coordinates

* Tweak order

* Handle another case
2023-02-06 17:23:29 -06:00
Vayle b385a4385f [Rules] Add rule to ignore name filter on chat channel creation. (#2820)
* [Rules] Add rule to ignore name filter on chat channel creation.

* Conditional reorder
2023-02-06 17:22:12 -06:00
Chris Miles 6a9228ed6e [Lua] Resolve stoi Exception (#2736)
* [Lua] Resolve stoi Exception

* Change fallback for wp, not really needed for safety

* Change to Strings::ToInt
2023-02-06 17:22:01 -06:00
Vayle 8031bf0bcb [Quest API] Add EVENT_TASKACCEPTED to Player scope (#2822)
* Add EVENT_TASKACCEPTED to player scope

* Formatting
2023-02-05 22:53:37 -05:00
Alex King c1584da9cc [Quest API] Default ScaleNPC to always scale. (#2818)
* [Quest API] Default ScaleNPC to always scale.

# Notes
- ScaleNPC will now always override stats, with the option to override special abilities.

* Update npc_scale_manager.h
2023-02-05 22:52:52 -05:00
Alex King ee6f6f683c [Commands] Remove extraneous else from #weather (#2819)
# Notes
- Condition falls back to sending message and can't turn weather off.
2023-02-01 06:05:32 -05:00
Akkadius 60707a14db [Hotfix] Post revert build fix for https://github.com/EQEmu/Server/commit/54050924d81d1f83268fe01f9c2b36fe10626601 2023-01-31 20:37:13 -06:00
Akkadius 54050924d8 Revert "[Quest API] Cleanup string copies and push_backs. (#2807)"
This reverts commit bcc2e022dc.
2023-01-31 20:30:34 -06:00
Aeadoin f727c9f75a [Bug Fix] Fix does_augment_fit_slot method. (#2817)
* [Bug Fix] DoesAugmentFit finds if an Aug Slot is free, changed overload method to check if Aug fits slot.

* Tweak/add lua
2023-01-31 21:11:12 -05:00
Alex King f410c89815 [Quest API] Add Override Parameters to ScaleNPC() in Perl/Lua. (#2816)
# Perl
- Add `$npc->ScaleNPC(level, always_scale_stats)`.
- Add `$npc->ScaleNPC(level, always_scale_stats, always_scale_special_abilities)`.

# Lua
- Add `npc:ScaleNPC(level, always_scale_stats)`.
- Add `npc:ScaleNPC(level, always_scale_stats, always_scale_special_abilities)`.

# Notes
- Allows operators to not have to set stats to 0 in order for scaling to kick in when scripting.
- Special ability override is separate in case you don't want to override some inherent special abilities the NPC has from a script or otherwise.
2023-01-31 21:11:05 -05:00
Natedog2012 2e575652f6 [Bug fix]#reload static should now properly fill the entity_lists for… (#2815)
* [Bug fix]#reload static should now properly fill the entity_lists for objects / doors / groundspawns
The individual #reload commands WILL still have issues when trying to use #list afterwards!

* Point ReloadDoors, ReloadGroundSpawns, ReloadObjects all to reload static to avoid entity_list data missing
2023-01-31 16:32:25 -06:00
Natedog2012 8e831dce36 [Bug fix]#reload aa will now refresh the AA table properly for every client when changes are made (#2814) 2023-01-30 20:24:02 -06:00
Alex King 040c092795 [Quest API] Add Augment Slot support to does_augment_fit (#2813)
* [Quest API] Add Augment Slot support to does_augment_fit

# Notes
- Allows you to check if the supplied augment ID fits in the specified augment slot of the item instance provided.

* Update item_instance.cpp
2023-01-30 21:18:16 -05:00
Alex King a25952910a [Quest API] Add EVENT_ITEM_CLICK_CLIENT and EVENT_ITEM_CLICK_CAST_CLIENT to Perl/Lua. (#2810)
* [Quest API] Add EVENT_ITEM_CLICK_CLIENT and EVENT_ITEM_CLICK_CAST_CLIENT to Perl/Lua.

# Perl
- Add `EVENT_ITEM_CLICK_CLIENT`.
- Add `EVENT_ITEM_CLICK_CAST_CLIENT`.
- Both events export `$item_id`, `$item_name`, `$slot_id`, and `$spell_id`.

# Lua
- Add `event_item_click_client`.
- Add `event_item_click_cast_client`.
- Both events export `e.item_id`, `e.item_name`, `e.slot_id`, `e.spell_id`, and `e.item`.

# Notes
- Allows operators to handle item clicks in player scripts instead of item-specific scripts.

* Update lua_parser_events.cpp

* Remove optional bool.
2023-01-30 05:01:12 -06:00
Natedog2012 66896a3121 [Quest API] Add GetItemCooldown to return the time remaining on items… (#2811)
* [Quest API] Add GetItemCooldown to return the time remaining on items in seconds

* Change GetItemCooldown to uint32 for timers up to 130 years
2023-01-30 00:04:06 -06:00
Paul Coene 4d2418af9d [Bug Fix] BuffLevelRestrictions were restricting group buffs if mob targeted (#2809) 2023-01-29 18:52:03 -05:00
Chris Miles 265b32f46f [Readme] Update build badges with Drone 2023-01-29 17:06:48 -06:00
Alex King 1cde55c535 [Quest API] Add LDoN Methods to Perl/Lua (#2799)
# Perl
- Add `$npc->GetLDoNLockedSkill()`.
- Add `$npc->GetLDoNTrapType()`.
- Add `$npc->GetLDoNTrapSpellID()`.
- Add `$npc->IsLDoNLocked()`.
- Add `$npc->IsLDoNTrapped()`.
- Add `$npc->IsLDoNTrapDetected()`.
- Add `$npc->SetLDoNLocked(is_locked)`.
- Add `$npc->SetLDoNLockedSkill(skill_value)`.
- Add `$npc->SetLDoNTrapped(is_trapped)`.
- Add `$npc->SetLDoNTrapDetected(is_detected)`.
- Add `$npc->SetLDoNTrapSpellID(spell_id)`.
- Add `$npc->SetLDoNTrapType(trap_type)`.

# Lua
- Add `npc:GetLDoNLockedSkill()`.
- Add `npc:GetLDoNTrapType()`.
- Add `npc:GetLDoNTrapSpellID()`.
- Add `npc:IsLDoNLocked()`.
- Add `npc:IsLDoNTrapped()`.
- Add `npc:IsLDoNTrapDetected()`.
- Add `npc:SetLDoNLocked(is_locked)`.
- Add `npc:SetLDoNLockedSkill(skill_value)`.
- Add `npc:SetLDoNTrapped(is_trapped)`.
- Add `npc:SetLDoNTrapDetected(is_detected)`.
- Add `npc:SetLDoNTrapSpellID(spell_id)`.
- Add `npc:SetLDoNTrapType(trap_type)`.

# Notes
- Adds these methods to allow LDoN traps to be set by a script.
2023-01-29 14:29:31 -06:00
Michael 369b5c2921 [Bug] Fixing % based mob see invis (#2802)
This was preventing anything other than 0 or 1 to be passed, but per the current design, the see_invis can be anything from 0 to MAX 25499, which can give you level 254 invis. See design notes in Mob::GetSeeInvisibleLevelFromNPCStat.
2023-01-29 14:26:55 -06:00
Alex King bcc2e022dc [Quest API] Cleanup string copies and push_backs. (#2807)
# Notes
- Several places use `push_back` instead of `emplace_back`.
- Several places use `std::string` instead of `const std::string&`.
2023-01-29 15:14:49 -05:00
Alex King 0fef46a6c1 [Feature] Add Min/Max Status to Merchants (#2806)
# Notes
- Allows operators to set a minimum and maximum status that an item will show for players.
- Allows operators to have items on a merchant that only a GM can see.
- Some servers may use status for different things, so having a minimum and a maximum will allow for more functionality.
- Default of `min_status` is `0` (Player) and default of `max_status` is `255` (Max).
2023-01-29 15:03:41 -05:00
Alex King b867d40774 [Quest API] Add EVENT_DAMAGE_GIVEN and EVENT_DAMAGE_TAKEN to Perl/Lua. (#2804)
* [Quest API] Add EVENT_DAMAGE_GIVEN and EVENT_DAMAGE_TAKEN to Perl/Lua.

# Perl
- Add `EVENT_DAMAGE_GIVEN`.
- Add `EVENT_DAMAGE_TAKEN`.
- Both events export `$entity_id`, `$damage`, `$spell_id`, `$skill_id`, `$is_damage_shield`, `$is_avoidable`, `$buff_slot`, `$is_buff_tic`, `$special_attack`.

# Lua
- Add `event_damage_given`.
- Add `event_damage_taken`.
- Both events export `e.entity_id`, `e.damage`, `e.spell_id`, `e.skill_id`, `e.is_damage_shield`, `e.is_avoidable`, `e.buff_slot`, `e.is_buff_tic`, `e.special_attack`, and `e.other`.

# Notes
- These events allow operators to have events fire based on damage given or taken, as well as keep better track of a Bot, Client, or NPC's damage per second or otherwise.
- Special Attack is only useful for NPCs, but allows you to see if the attack is Rampage, AERampage, or Chaotic Stab.

* Cleanup.
2023-01-29 14:35:17 -05:00
Aeadoin a489290eba [Bots] Add GetAugmentIDsBySlotID & AddItem with table ref Methods. (#2805)
* [Bots] Add GetAugmentIDsBySlotID & AddItem with table ref Methods.

* Return invalid slots to owner.
2023-01-29 12:49:44 -05:00
Alex King 549d731849 [Bug Fix] Resolve issue with max buff count being 25 in ROF2. (#2800)
# Notes
- This allows ROF2 to properly utilize their max buff count.
- May cause issues with older clients.
2023-01-28 17:40:11 -06:00
Natedog2012 68a34565f9 [Bugfix] Add SetItemCooldown to tell client exact timer of item when clicked and export to perl and lua (#2795)
Items that are on cooldown but client doesn't show.. clicking item will fix the timer in client
2023-01-27 17:31:14 -06:00
Aeadoin c05f951f81 [Bots] Add Override methods for GetMax Buffs/Songs/Total slots (#2801) 2023-01-27 18:00:50 -05:00
531 changed files with 26743 additions and 22359 deletions
+630
View File
@@ -1,3 +1,633 @@
## [22.9.0] - 04/01/2023
### Bots
* Remove Bot Groups Functionality ([#3165](https://github.com/EQEmu/Server/pull/3165)) @Aeadoin 2023-04-01
### Code
* Cleanup excessive type casting: string -> char * -> string ([#3169](https://github.com/EQEmu/Server/pull/3169)) @Aeadoin 2023-04-01
### Crash
* Add Checks for valid pointers or fix existing. ([#3164](https://github.com/EQEmu/Server/pull/3164)) @Aeadoin 2023-04-01
* Fix out of bound arrays, other potential crashes ([#3166](https://github.com/EQEmu/Server/pull/3166)) @Aeadoin 2023-04-01
### Fixes
* Correct SE_SlayUndead & SE_HeadShotLevel limit Value when applied. ([#3171](https://github.com/EQEmu/Server/pull/3171)) @Aeadoin 2023-04-01
* Prevent VerifyGroup from setting OOZ membername to Null character. ([#3168](https://github.com/EQEmu/Server/pull/3168)) @Aeadoin 2023-04-01
### Quest API
* Add missing Luabind definitions to lua_general.cpp ([#3167](https://github.com/EQEmu/Server/pull/3167)) @Kinglykrab 2023-04-01
## [22.8.2] - 03/30/2023
### Code
* "equipped" not "equiped", "dual" not "duel". ([#3149](https://github.com/EQEmu/Server/pull/3149)) @Kinglykrab 2023-03-27
### Crash
* Add Checks for out of bounds & dereferencing nullptrs ([#3151](https://github.com/EQEmu/Server/pull/3151)) @Aeadoin 2023-03-28
### Fixes
* Check Rule "Bots Enabled" to prevent bot database calls on connect ([#3154](https://github.com/EQEmu/Server/pull/3154)) @Aeadoin 2023-03-29
* Correct logic checks for Bot rule AllowOwnerOptionAltCombat ([#3158](https://github.com/EQEmu/Server/pull/3158)) @Aeadoin 2023-03-30
* Fix an issue with EVENT_DISCONNECT not firing on regular /camp ([#3153](https://github.com/EQEmu/Server/pull/3153)) @Kinglykrab 2023-03-28
* Fix bot_raid_members.sql for MYSQL. ([#3155](https://github.com/EQEmu/Server/pull/3155)) @Aeadoin 2023-03-28
* Fix for OOZ Group updates when removing/inviting Bots ([#3159](https://github.com/EQEmu/Server/pull/3159)) @Aeadoin 2023-03-30
* Fix issues with Lua tables not starting at index 1 ([#3160](https://github.com/EQEmu/Server/pull/3160)) @Kinglykrab 2023-03-30
* Fix strcpy-param-overlap ([#3157](https://github.com/EQEmu/Server/pull/3157)) @Aeadoin 2023-03-29
### Rules
* Remove Guild Bank Zone ID Rule ([#3156](https://github.com/EQEmu/Server/pull/3156)) @Kinglykrab 2023-03-29
## [22.8.1] - 03/27/2023
### Fixes
* Fix for NPCs having spells interrupted. ([#3150](https://github.com/EQEmu/Server/pull/3150)) @Aeadoin 2023-03-27
## [22.8.0] - 03/25/2023
### Code
* Cleanup Strings::ToInt uses. ([#3142](https://github.com/EQEmu/Server/pull/3142)) @Aeadoin 2023-03-26
* Remove extern bool Critical ([#3146](https://github.com/EQEmu/Server/pull/3146)) @Kinglykrab 2023-03-25
### Crash
* Fix for crash in Raid::QueuePacket ([#3145](https://github.com/EQEmu/Server/pull/3145)) @Aeadoin 2023-03-25
### Feature
* Add support for -1 extradmgskill to allow all skills to be scaled. ([#3136](https://github.com/EQEmu/Server/pull/3136)) @Kinglykrab 2023-03-26
### Fixes
* Fix for Items looted from corpses. ([#3147](https://github.com/EQEmu/Server/pull/3147)) @Aeadoin 2023-03-26
* Fix for SQL Query in npc_scale_global_base ([#3144](https://github.com/EQEmu/Server/pull/3144)) @Aeadoin 2023-03-26
## [22.7.0] - 03/24/2023
### Bots
* Place BOT_COMMAND_CHAR inside messages ([#3027](https://github.com/EQEmu/Server/pull/3027)) @trentdm 2023-03-05
* Prevent interrupt spam when OOM ([#3011](https://github.com/EQEmu/Server/pull/3011)) @nytmyr 2023-03-07
### Code
* Cleaning up Raid.cpp ([#3125](https://github.com/EQEmu/Server/pull/3125)) @Aeadoin 2023-03-20
* Cleanup unused methods and variables in world/main.cpp and world/main.h ([#3105](https://github.com/EQEmu/Server/pull/3105)) @Kinglykrab 2023-03-17
* Cleanup uses of Strings::ToInt to match correct type. ([#3054](https://github.com/EQEmu/Server/pull/3054)) @Aeadoin 2023-03-22
* Delete deprecated/perlxs folder ([#3110](https://github.com/EQEmu/Server/pull/3110)) @Kinglykrab 2023-03-17
* Delete queues.h ([#3089](https://github.com/EQEmu/Server/pull/3089)) @Kinglykrab 2023-03-17
* Delete world/console.old.cpp ([#3099](https://github.com/EQEmu/Server/pull/3099)) @Kinglykrab 2023-03-17
* Delete zone_numbers.h ([#3129](https://github.com/EQEmu/Server/pull/3129)) @Kinglykrab 2023-03-20
* Remove AllConnected(), CanUpdate(), and SendInfo() from login_server_list.cpp and login_server_list.h ([#3104](https://github.com/EQEmu/Server/pull/3104)) @Kinglykrab 2023-03-17
* Remove CLIENT_TIMEOUT from world/client.h and zone/client.h ([#3071](https://github.com/EQEmu/Server/pull/3071)) @Kinglykrab 2023-03-17
* Remove ChangeHP() from mob.h ([#3128](https://github.com/EQEmu/Server/pull/3128)) @Kinglykrab 2023-03-19
* Remove CheckAuth(), SetOnline(), and pMD5Pass from cliententry.h ([#3095](https://github.com/EQEmu/Server/pull/3095)) @Kinglykrab 2023-03-17
* Remove CommandRequirement() from zonedb.h ([#3094](https://github.com/EQEmu/Server/pull/3094)) @Kinglykrab 2023-03-17
* Remove CountZones() from launcher_link.h ([#3100](https://github.com/EQEmu/Server/pull/3100)) @Kinglykrab 2023-03-17
* Remove DBInitVars() and HandleMysqlError() from queryserv/database.h ([#3114](https://github.com/EQEmu/Server/pull/3114)) @Kinglykrab 2023-03-17
* Remove DBInitVars(), HandleMysqlError(), and IsChatChannelInDB() in ucs/database.h ([#3113](https://github.com/EQEmu/Server/pull/3113)) @Kinglykrab 2023-03-17
* Remove DisableStats(), EnableStats(), DisableLoginserver(), and EnableLoginserver() from world_config.h ([#3107](https://github.com/EQEmu/Server/pull/3107)) @Kinglykrab 2023-03-17
* Remove DoBuffWearOffEffect() from mob.h ([#3062](https://github.com/EQEmu/Server/pull/3062)) @Kinglykrab 2023-03-17
* Remove FindByName(charname) from clientlist.h ([#3096](https://github.com/EQEmu/Server/pull/3096)) @Kinglykrab 2023-03-17
* Remove FindCLEByLSID(), GetCLE(), GetCLEIPCount(), and RemoveCLEByLSID() from clientlist.h ([#3098](https://github.com/EQEmu/Server/pull/3098)) @Kinglykrab 2023-03-17
* Remove FindPatch() from struct_category.cpp and struct_category.h ([#3130](https://github.com/EQEmu/Server/pull/3130)) @Kinglykrab 2023-03-20
* Remove FlushLootStats() from npc.h ([#3079](https://github.com/EQEmu/Server/pull/3079)) @Kinglykrab 2023-03-17
* Remove GetAILevel() from npc.h ([#3080](https://github.com/EQEmu/Server/pull/3080)) @Kinglykrab 2023-03-17
* Remove GetDestination() from doors.h ([#3078](https://github.com/EQEmu/Server/pull/3078)) @Kinglykrab 2023-03-17
* Remove GetServerByAddress() from server_manager.h ([#3119](https://github.com/EQEmu/Server/pull/3119)) @Kinglykrab 2023-03-17
* Remove GetStartCount() and InitStartTimer() from zone_launch.cpp and zone_launch.h ([#3121](https://github.com/EQEmu/Server/pull/3121)) @Kinglykrab 2023-03-17
* Remove GetTransformation() and GetInvertedTransformation() from oriented_bounding_box.h ([#3084](https://github.com/EQEmu/Server/pull/3084)) @Kinglykrab 2023-03-17
* Remove IsAffectedByBuff() ([#3068](https://github.com/EQEmu/Server/pull/3068)) @Kinglykrab 2023-03-17
* Remove IsConnected() from loginserver/database.h ([#3117](https://github.com/EQEmu/Server/pull/3117)) @Kinglykrab 2023-03-17
* Remove IsOrigin(glm::vec2) from position.h ([#3088](https://github.com/EQEmu/Server/pull/3088)) @Kinglykrab 2023-03-17
* Remove MakeGuildMembers() from wguild_mgr.h ([#3106](https://github.com/EQEmu/Server/pull/3106)) @Kinglykrab 2023-03-17
* Remove PlayerLogin_Struct from login_types.h ([#3118](https://github.com/EQEmu/Server/pull/3118)) @Kinglykrab 2023-03-17
* Remove RemoveSpawnGroup() from spawngroup.h ([#3090](https://github.com/EQEmu/Server/pull/3090)) @Kinglykrab 2023-03-17
* Remove SendGuildPacket() from clientlist.cpp, clientlist.h, and wguild_mgr.cpp ([#3097](https://github.com/EQEmu/Server/pull/3097)) @Kinglykrab 2023-03-17
* Remove SetConnection() from loginserver/world_server.h ([#3120](https://github.com/EQEmu/Server/pull/3120)) @Kinglykrab 2023-03-17
* Remove SetDBID() from object.h ([#3082](https://github.com/EQEmu/Server/pull/3082)) @Kinglykrab 2023-03-17
* Remove SetSentTime2 in petitions.h ([#3086](https://github.com/EQEmu/Server/pull/3086)) @Kinglykrab 2023-03-17
* Remove StoreCharacter() from worlddb.h ([#3108](https://github.com/EQEmu/Server/pull/3108)) @Kinglykrab 2023-03-17
* Remove UpdateLoginserverWorldAdminAccountPasswordById() from account_management.cpp ([#3115](https://github.com/EQEmu/Server/pull/3115)) @Kinglykrab 2023-03-17
* Remove _baseBotStance from bot.h ([#3076](https://github.com/EQEmu/Server/pull/3076)) @Kinglykrab 2023-03-17
* Remove _botRole from bot.h ([#3075](https://github.com/EQEmu/Server/pull/3075)) @Kinglykrab 2023-03-17
* Remove _previousTarget from bot.h ([#3074](https://github.com/EQEmu/Server/pull/3074)) @Kinglykrab 2023-03-17
* Remove authenticated from launcher_link.cpp and launcher_link.h ([#3101](https://github.com/EQEmu/Server/pull/3101)) @Kinglykrab 2023-03-17
* Remove can_corpse_be_rezzed from corpse.h ([#3077](https://github.com/EQEmu/Server/pull/3077)) @Kinglykrab 2023-03-17
* Remove casting_spell_type from mob.h ([#3064](https://github.com/EQEmu/Server/pull/3064)) @Kinglykrab 2023-03-17
* Remove class EQStream from client.h ([#3070](https://github.com/EQEmu/Server/pull/3070)) @Kinglykrab 2023-03-17
* Remove current_buff_count ([#3067](https://github.com/EQEmu/Server/pull/3067)) @Kinglykrab 2023-03-17
* Remove firstlogin and realfirstlogin from world/client.h ([#3072](https://github.com/EQEmu/Server/pull/3072)) @Kinglykrab 2023-03-17
* Remove fixedZ from mob.h ([#3065](https://github.com/EQEmu/Server/pull/3065)) @Kinglykrab 2023-03-17
* Remove inWater from mob.h ([#3069](https://github.com/EQEmu/Server/pull/3069)) @Kinglykrab 2023-03-17
* Remove is_authenticatd, LSShutDownUpdate(), and SetInstanceID() from zoneserver.h ([#3109](https://github.com/EQEmu/Server/pull/3109)) @Kinglykrab 2023-03-17
* Remove last_insert_id from petitions.h ([#3087](https://github.com/EQEmu/Server/pull/3087)) @Kinglykrab 2023-03-17
* Remove last_max_hp from mob.h ([#3063](https://github.com/EQEmu/Server/pull/3063)) @Kinglykrab 2023-03-17
* Remove m_inuse, m_z, and m_heading from object.h ([#3083](https://github.com/EQEmu/Server/pull/3083)) @Kinglykrab 2023-03-17
* Remove npc_ai.cpp/npc_ai.cpp ([#3081](https://github.com/EQEmu/Server/pull/3081)) @Kinglykrab 2023-03-17
* Remove ownHiddenTrigger from trap.cpp and trap.h ([#3092](https://github.com/EQEmu/Server/pull/3092)) @Kinglykrab 2023-03-17
* Remove perlparser.h ([#3085](https://github.com/EQEmu/Server/pull/3085)) @Kinglykrab 2023-03-17
* Remove unused AbilityTimer variable in client.h ([#3035](https://github.com/EQEmu/Server/pull/3035)) @Kinglykrab 2023-03-05
* Remove unused BotAA struct in bot_structs.h ([#3038](https://github.com/EQEmu/Server/pull/3038)) @Kinglykrab 2023-03-05
* Remove unused HandleUpdateTasksOnKill in client.h ([#3032](https://github.com/EQEmu/Server/pull/3032)) @Kinglykrab 2023-03-05
* Remove unused SaveBackup in client.h ([#3030](https://github.com/EQEmu/Server/pull/3030)) @Kinglykrab 2023-03-05
* Remove unused ^evacuate and ^succor subcommands from bot_command.h ([#3039](https://github.com/EQEmu/Server/pull/3039)) @Kinglykrab 2023-03-05
* Remove unused bot structs in bot_structs.h ([#3037](https://github.com/EQEmu/Server/pull/3037)) @Kinglykrab 2023-03-05
* Remove unused client queued work variable in client.cpp/client.h ([#3034](https://github.com/EQEmu/Server/pull/3034)) @Kinglykrab 2023-03-05
* Remove unused command variables in client.cpp ([#3031](https://github.com/EQEmu/Server/pull/3031)) @Kinglykrab 2023-03-05
* Remove unused lua_hate_entry.cpp ([#3057](https://github.com/EQEmu/Server/pull/3057)) @Kinglykrab 2023-03-12
* Remove unused methods in eql_config.cpp, eql_config.h, launcher_list.cpp, and launcher_list.h ([#3103](https://github.com/EQEmu/Server/pull/3103)) @Kinglykrab 2023-03-17
* Remove unused methods in loginserver/client.h ([#3116](https://github.com/EQEmu/Server/pull/3116)) @Kinglykrab 2023-03-17
* Remove unused player update variables in client.cpp/client.h ([#3033](https://github.com/EQEmu/Server/pull/3033)) @Kinglykrab 2023-03-05
* Utilize GetPlayerState() in mob methods ([#3066](https://github.com/EQEmu/Server/pull/3066)) @Kinglykrab 2023-03-17
* Utilize GetScheduler() in zone/worldserver.cpp ([#3093](https://github.com/EQEmu/Server/pull/3093)) @Kinglykrab 2023-03-17
* Utilize SetFilter in client.cpp ([#3036](https://github.com/EQEmu/Server/pull/3036)) @Kinglykrab 2023-03-05
* Utilize SetHiddenTrigger in trap.cpp ([#3091](https://github.com/EQEmu/Server/pull/3091)) @Kinglykrab 2023-03-17
* remove _botOrderAttack from bot.h ([#3073](https://github.com/EQEmu/Server/pull/3073)) @Kinglykrab 2023-03-17
### Commands
* Cleanup #haste Command ([#3042](https://github.com/EQEmu/Server/pull/3042)) @Kinglykrab 2023-03-06
* Cleanup #hideme Command ([#3043](https://github.com/EQEmu/Server/pull/3043)) @Kinglykrab 2023-03-06
* Cleanup #interrupt Command ([#3044](https://github.com/EQEmu/Server/pull/3044)) @Kinglykrab 2023-03-06
* Cleanup #level Command ([#3045](https://github.com/EQEmu/Server/pull/3045)) @Kinglykrab 2023-03-06
* Cleanup #picklock Command ([#3046](https://github.com/EQEmu/Server/pull/3046)) @Kinglykrab 2023-03-06
* Cleanup #resetaa and #resetaa_timer ([#3047](https://github.com/EQEmu/Server/pull/3047)) @Kinglykrab 2023-03-06
* Cleanup #wc Command ([#3049](https://github.com/EQEmu/Server/pull/3049)) @Kinglykrab 2023-03-06
* Remove #equipitem Command ([#3040](https://github.com/EQEmu/Server/pull/3040)) @Kinglykrab 2023-03-06
### Console
* Add IS_TTY to force terminal coloring output ([#3021](https://github.com/EQEmu/Server/pull/3021)) @Akkadius 2023-03-04
### Crash
* Fix dangling Group member pointers for Bots. ([#3134](https://github.com/EQEmu/Server/pull/3134)) @Aeadoin 2023-03-21
* Fixes Crash when Zoning with XTarget when Bots are in group. ([#3126](https://github.com/EQEmu/Server/pull/3126)) @Aeadoin 2023-03-19
### Feature
* Add Basic Bot Raiding Functionality ([#2782](https://github.com/EQEmu/Server/pull/2782)) @neckkola 2023-03-17
* Add Data Bucket support for scaling of Heroic Stats. ([#3058](https://github.com/EQEmu/Server/pull/3058)) @Aeadoin 2023-03-24
* Add Item Extra Skill Damage Percent Modifier ([#3127](https://github.com/EQEmu/Server/pull/3127)) @Kinglykrab 2023-03-19
### Fixes
* Add Avoidance and HP Regen Per Second too NPC Scaling. ([#3050](https://github.com/EQEmu/Server/pull/3050)) @Aeadoin 2023-03-09
* Add Heroic Strikethrough & HP Regen Per Second to GM Entity Info ([#3055](https://github.com/EQEmu/Server/pull/3055)) @Aeadoin 2023-03-12
* Add Heroic Strikethrough to NPC Scaling ([#3028](https://github.com/EQEmu/Server/pull/3028)) @Kinglykrab 2023-03-06
* Change SPA 193 Weapon Damage to allow values over 65,535 ([#3138](https://github.com/EQEmu/Server/pull/3138)) @Aeadoin 2023-03-23
* Checkmarks and X characters in popup messages ([#3041](https://github.com/EQEmu/Server/pull/3041)) @Kinglykrab 2023-03-06
* Cursor Coin Upon Death ([#3020](https://github.com/EQEmu/Server/pull/3020)) @cybernine186 2023-03-04
* Ensure synchronization of pet taunt state with UI ([#3025](https://github.com/EQEmu/Server/pull/3025)) @catapultam-habeo 2023-03-04
* Fix Bard Bot Casting ([#3122](https://github.com/EQEmu/Server/pull/3122)) @Aeadoin 2023-03-17
* Fix Discovered Items with Alternate Currency and LDoN Adventure Merchants ([#3026](https://github.com/EQEmu/Server/pull/3026)) @Kinglykrab 2023-03-04
* Fix Heal Scale and Spell Scale in NPC Scaling ([#3051](https://github.com/EQEmu/Server/pull/3051)) @Kinglykrab 2023-03-10
* Fix Raid Invites causing client desync issues ([#3053](https://github.com/EQEmu/Server/pull/3053)) @Aeadoin 2023-03-11
* Fix Raid methods that could cause crashes with Bots in raid ([#3111](https://github.com/EQEmu/Server/pull/3111)) @Aeadoin 2023-03-17
* Fix edge cases where camped bots would be left in a raid ([#3139](https://github.com/EQEmu/Server/pull/3139)) @Aeadoin 2023-03-23
* Fix for Raid Disband if leader not in same zone. ([#3135](https://github.com/EQEmu/Server/pull/3135)) @Aeadoin 2023-03-21
* Fix for incorrect bindpoint x,y,z,headings ([#3141](https://github.com/EQEmu/Server/pull/3141)) @Aeadoin 2023-03-23
* Fix for transferring Raid Leader ([#3140](https://github.com/EQEmu/Server/pull/3140)) @Aeadoin 2023-03-23
* Fix issue with overflow on min/max hit dmg in npc scaling calculations ([#3052](https://github.com/EQEmu/Server/pull/3052)) @Aeadoin 2023-03-10
* Fix typo for bot_id raid_members column in db_update_manifest.txt ([#3132](https://github.com/EQEmu/Server/pull/3132)) @Kinglykrab 2023-03-20
* Fixes for corpses not properly saving some item instance data correctly. ([#3123](https://github.com/EQEmu/Server/pull/3123)) @KimLS 2023-03-23
### Illusions
* Fix bug where spells like Ignite Bones left NPC size incorrect. ([#3061](https://github.com/EQEmu/Server/pull/3061)) @noudess 2023-03-16
### Quest API
* Add SendIllusion overloads/parameters to Perl/Lua ([#3059](https://github.com/EQEmu/Server/pull/3059)) @Kinglykrab 2023-03-16
* Add Spell GetActX methods to Perl/Lua ([#3056](https://github.com/EQEmu/Server/pull/3056)) @Kinglykrab 2023-03-12
* Add Timer related methods to Mobs in Perl/Lua ([#3133](https://github.com/EQEmu/Server/pull/3133)) @Kinglykrab 2023-03-20
### Rules
* Add Multiplier for Heroic Stats. ([#3014](https://github.com/EQEmu/Server/pull/3014)) @Aeadoin 2023-03-04
* Add ResurrectionEffectsBlock ([#2990](https://github.com/EQEmu/Server/pull/2990)) @nytmyr 2023-03-04
* Add Rule to allow ExtraDmgSkill/SPA 220 to effect Spell Skills ([#3124](https://github.com/EQEmu/Server/pull/3124)) @Aeadoin 2023-03-19
* Add Task System Rule ExpRewardsIgnoreLevelBasedEXPMods ([#3112](https://github.com/EQEmu/Server/pull/3112)) @Aeadoin 2023-03-17
### Scaling
* Add support for pipe-separated zone IDs and versions ([#3015](https://github.com/EQEmu/Server/pull/3015)) @Kinglykrab 2023-03-04
### Strings
* Add exception handling to converters themselves ([#3029](https://github.com/EQEmu/Server/pull/3029)) @Akkadius 2023-03-05
* Add more number formatters ([#2873](https://github.com/EQEmu/Server/pull/2873)) @Kinglykrab 2023-03-04
## [22.4.5] - 03/03/2023
### Bots
* Add additional Heroic Sta/Wis/Int bonuses for Bots. ([#3013](https://github.com/EQEmu/Server/pull/3013)) @Aeadoin 2023-03-01
* Cleanup AI_IdleCastCheck Logic ([#3004](https://github.com/EQEmu/Server/pull/3004)) @Aeadoin 2023-02-26
### Code
* Delete unused zone/skills.h ([#3007](https://github.com/EQEmu/Server/pull/3007)) @Kinglykrab 2023-02-27
* Remove DumpPacketProfile() from client.h ([#3000](https://github.com/EQEmu/Server/pull/3000)) @Kinglykrab 2023-02-26
* Remove GetCombinedAC_TEST() from client.h ([#2999](https://github.com/EQEmu/Server/pull/2999)) @Kinglykrab 2023-02-26
* Remove GetDamageMultiplier() from client.h ([#3001](https://github.com/EQEmu/Server/pull/3001)) @Kinglykrab 2023-02-26
* Remove NumberOfAvailableTitles() from titles.h ([#3006](https://github.com/EQEmu/Server/pull/3006)) @Kinglykrab 2023-02-27
* Remove ReturnItemPacket from client.h/inventory.cpp ([#3002](https://github.com/EQEmu/Server/pull/3002)) @Kinglykrab 2023-02-26
* Remove class EGNode from mob.h ([#3003](https://github.com/EQEmu/Server/pull/3003)) @Kinglykrab 2023-02-26
* Remove unused ClientFactory in client.h ([#2998](https://github.com/EQEmu/Server/pull/2998)) @Kinglykrab 2023-02-26
* Remove unused iterator from LoadCharacterDisciplines ([#3012](https://github.com/EQEmu/Server/pull/3012)) @Aeadoin 2023-03-02
### Crash
* Fix crash in CheckTradeskillLoreConflict ([#3009](https://github.com/EQEmu/Server/pull/3009)) @Aeadoin 2023-02-28
### Fixes
* Account for bad data in Tradeskill Recipe Entries ([#2991](https://github.com/EQEmu/Server/pull/2991)) @Aeadoin 2023-02-25
* Fix DoAnim quest method default speed ([#3016](https://github.com/EQEmu/Server/pull/3016)) @Kinglykrab 2023-03-01
* Fix an issue where EVENT_TIMER timers would not be cleaned up after zone ([#3018](https://github.com/EQEmu/Server/pull/3018)) @noudess 2023-03-03
* Fix for Discipline Loading from Database causing issues with slot_ids ([#3008](https://github.com/EQEmu/Server/pull/3008)) @Aeadoin 2023-02-28
* Fix for Lore Components where component is returned. ([#3005](https://github.com/EQEmu/Server/pull/3005)) @Aeadoin 2023-02-27
* Fix issue where quest saylink responses would occur before the NPC's response ([#3010](https://github.com/EQEmu/Server/pull/3010)) @Akkadius 2023-03-01
* Fix log messages when players join channel ([#2992](https://github.com/EQEmu/Server/pull/2992)) @Valorith 2023-03-03
* Fix npcfeature and playerfeature ([#3017](https://github.com/EQEmu/Server/pull/3017)) @Kinglykrab 2023-03-02
### Quest API
* Add GetDefaultRaceSize() to Perl/Lua ([#2993](https://github.com/EQEmu/Server/pull/2993)) @Kinglykrab 2023-02-27
* Add HasSpecialAbilities() to Perl/Lua ([#2994](https://github.com/EQEmu/Server/pull/2994)) @Kinglykrab 2023-02-27
* Add IsBerserk() to Perl/Lua ([#2997](https://github.com/EQEmu/Server/pull/2997)) @Kinglykrab 2023-03-01
* Add IsFindable() and IsTrackable() to Perl/Lua ([#2996](https://github.com/EQEmu/Server/pull/2996)) @Kinglykrab 2023-03-01
* Add IsUnderwaterOnly() to Perl/Lua ([#2995](https://github.com/EQEmu/Server/pull/2995)) @Kinglykrab 2023-03-01
## [22.4.4] - 02/24/2023
### Bots
* Add Caster Range Command, and IsValidSpellRange Checks ([#2942](https://github.com/EQEmu/Server/pull/2942)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-23
* Cleanup BotDatabase::LoadBuffs ([#2981](https://github.com/EQEmu/Server/pull/2981)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
* Verify Bots Group Integrity on join ([#2980](https://github.com/EQEmu/Server/pull/2980)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-23
### Commands
* Cleanup #peekinv Command ([#2969](https://github.com/EQEmu/Server/pull/2969)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-23
### Doors
* Fix doors triggering invalid zone fetches of dest_zone of "none" ([#2985](https://github.com/EQEmu/Server/pull/2985)) ([Akkadius](https://github.com/Akkadius)) 2023-02-24
### Fixes
* Adjust database manifest to include .sql extension ([Akkadius](https://github.com/Akkadius)) 2023-02-25
* Correct Mend reuse time and add reduction support. ([#2972](https://github.com/EQEmu/Server/pull/2972)) ([nytmyr](https://github.com/nytmyr)) 2023-02-23
* Fix Beneficial Target of Target procs ([#2987](https://github.com/EQEmu/Server/pull/2987)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
* Fix for undefined MySQL library behavior. ([#2834](https://github.com/EQEmu/Server/pull/2834)) ([KimLS](https://github.com/KimLS)) 2023-02-25
### Pathing
* Improve roambox logic ([#2983](https://github.com/EQEmu/Server/pull/2983)) ([Akkadius](https://github.com/Akkadius)) 2023-02-24
* More z-clip improvements, Wurm and Spectral Iksar race adjustments ([#2988](https://github.com/EQEmu/Server/pull/2988)) ([Akkadius](https://github.com/Akkadius)) 2023-02-25
* Smoother pathing z-correction ([#2982](https://github.com/EQEmu/Server/pull/2982)) ([Akkadius](https://github.com/Akkadius)) 2023-02-24
### Player Events
* Add QS processing, mutex tweaks ([#2984](https://github.com/EQEmu/Server/pull/2984)) ([Akkadius](https://github.com/Akkadius)) 2023-02-25
### Quest API
* Add IsAutoAttackEnabled() to Perl/Lua ([#2979](https://github.com/EQEmu/Server/pull/2979)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-23
* Add IsAutoFireEnabled() to Perl/Lua ([#2978](https://github.com/EQEmu/Server/pull/2978)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-23
* Fix EVENT_TIMER crash when entity is no longer available ([#2986](https://github.com/EQEmu/Server/pull/2986)) ([Akkadius](https://github.com/Akkadius)) 2023-02-24
### Scaling
* Add support for zone ID and instance version to NPC Scaling ([#2968](https://github.com/EQEmu/Server/pull/2968)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-25
### Tradeskills
* Fix for Lore Conflict ([#2977](https://github.com/EQEmu/Server/pull/2977)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-24
## [22.4.3] - 02/21/2023
### Bots
* Change HasBotItem(item_id) to return slot_id instead of bool. ([#2966](https://github.com/EQEmu/Server/pull/2966)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-19
* Change SaveTimers to Replace instead of Insert. ([#2951](https://github.com/EQEmu/Server/pull/2951)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
* Fix output of ^spells while ^Enforcespellsettings is enabled ([#2959](https://github.com/EQEmu/Server/pull/2959)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
### Crash
* Fix crash with EVENT_UNEQUIP_ITEM_BOT ([#2973](https://github.com/EQEmu/Server/pull/2973)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-20
* Fix world crash in player event processing ([#2960](https://github.com/EQEmu/Server/pull/2960)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### Database
* Address deadlock in player events ([#2974](https://github.com/EQEmu/Server/pull/2974)) ([Akkadius](https://github.com/Akkadius)) 2023-02-21
### Fixes
* Fix MIR LDoN Theme Items on LDoN Merchants ([#2971](https://github.com/EQEmu/Server/pull/2971)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-20
* Fix OOCMute not functioning ([#2970](https://github.com/EQEmu/Server/pull/2970)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-20
### Pathing
* Improvements to z-clipping, z-recovery and z-calculations ([#2975](https://github.com/EQEmu/Server/pull/2975)) ([Akkadius](https://github.com/Akkadius)) 2023-02-21
### Pets
* Client Pet summoned by NPC should not change guard location. ([#2967](https://github.com/EQEmu/Server/pull/2967)) ([noudess](https://github.com/noudess)) 2023-02-19
### Player Events
* Create new event ITEM_CREATION ([#2944](https://github.com/EQEmu/Server/pull/2944)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### Quest API
* Add client->SignalClient() overload to Perl ([#2963](https://github.com/EQEmu/Server/pull/2963)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-19
* Fix Perl SetSimpleRoamBox Overloads ([#2961](https://github.com/EQEmu/Server/pull/2961)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-19
### Reload API
* Add world handlers for certain opcodes ([#2958](https://github.com/EQEmu/Server/pull/2958)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### SQL
* Add date to optional Drakkin Guktan Faction Update ([#2965](https://github.com/EQEmu/Server/pull/2965)) ([joligario](https://github.com/joligario)) 2023-02-19
## [22.4.2] - 02/18/2023
### Content
* Added optional SQL 2023_02_17_fix_sseru_mischief_doors.sql to fix sseru/mischief doors ([#2955](https://github.com/EQEmu/Server/pull/2955)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### Logging
* Remove noisy raid/group/forage errors ([#2952](https://github.com/EQEmu/Server/pull/2952)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### MySQL
* Add keepalives to UCS and Loginserver ([#2953](https://github.com/EQEmu/Server/pull/2953)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### Player Events
* Add logging category to hold processing batch logs ([#2954](https://github.com/EQEmu/Server/pull/2954)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
### Tradeskills
* Fix regression caused by #2932 ([#2956](https://github.com/EQEmu/Server/pull/2956)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
## [22.4.1] - 02/17/2023
### Bots
* Set Taunt to enabled for SK/Paladin Bots by Default. ([#2941](https://github.com/EQEmu/Server/pull/2941)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-17
### DevTools
* Fix NPC targetting dev tools display window ([#2943](https://github.com/EQEmu/Server/pull/2943)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
### Fixes
* Issue with AssignRaidToInstance that was using the groups repository instead of raid ([#2947](https://github.com/EQEmu/Server/pull/2947)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
* Missing comma in schema list breaking dumps ([Akkadius](https://github.com/Akkadius)) 2023-02-17
### Player Events
* Fix issue with item instances not being validated properly before accessing causing crashes on handin ([#2945](https://github.com/EQEmu/Server/pull/2945)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
* Fix rare out of bound issue when loading event types ([#2946](https://github.com/EQEmu/Server/pull/2946)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
* Turn off KILLED_NPC (trash) off by default ([#2948](https://github.com/EQEmu/Server/pull/2948)) ([Akkadius](https://github.com/Akkadius)) 2023-02-17
## [22.4.0] - 02/17/2023
### Bots
* Add Additional HeroicAgi/Dex Modifiers. ([#2838](https://github.com/EQEmu/Server/pull/2838)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
* Add Additional HeroicStr modifiers. ([#2837](https://github.com/EQEmu/Server/pull/2837)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
* Add IsBot() to methods in attack.cpp where applicable. ([#2840](https://github.com/EQEmu/Server/pull/2840)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
* Add Lore Check for Augments. ([#2874](https://github.com/EQEmu/Server/pull/2874)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-12
* Add Pet Power Support for Temp Pets. ([#2853](https://github.com/EQEmu/Server/pull/2853)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-11
* Add Support for TryTriggerOnCastFocusEffect ([#2864](https://github.com/EQEmu/Server/pull/2864)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
* Add TotalDominationBonus modifiers. ([#2852](https://github.com/EQEmu/Server/pull/2852)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
* ST_AreaClientOnly spells to land on Bots ([#2849](https://github.com/EQEmu/Server/pull/2849)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
* Update ResistSpell to use temp_level_diff client formula ([#2851](https://github.com/EQEmu/Server/pull/2851)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
### Bots & Mercenaries
* Add 100% Hit chance if sitting while attacked. ([#2839](https://github.com/EQEmu/Server/pull/2839)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
* Add Support for TrySympatheticProc ([#2866](https://github.com/EQEmu/Server/pull/2866)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
### CI
* Fix Windows stderr not bubbling properly ([#2925](https://github.com/EQEmu/Server/pull/2925)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
### Code
* Add IsOfClientBot() virtual method. ([#2845](https://github.com/EQEmu/Server/pull/2845)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
* Doors EVENT_CLICK_DOOR syntax adjustment ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Remove Unused Mod Hooks ([#2856](https://github.com/EQEmu/Server/pull/2856)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
### Crash
* Crash fix where invalid input to #heromodel would crash zone ([#2937](https://github.com/EQEmu/Server/pull/2937)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
* Fix Bot Crash in Bot::Bot Constructor. ([#2868](https://github.com/EQEmu/Server/pull/2868)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-12
* Fix Crash in FindType ([#2867](https://github.com/EQEmu/Server/pull/2867)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
* Fix crash in Mob::CommonDamage when attacker was null ([#2872](https://github.com/EQEmu/Server/pull/2872)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-13
* Fix crash issue with dropping items and order of operations ([#2939](https://github.com/EQEmu/Server/pull/2939)) ([joligario](https://github.com/joligario)) 2023-02-16
* Fix issue where long short names overflow file_name ([Akkadius](https://github.com/Akkadius)) 2023-02-09
* Fix potential crash in Mob::CommonDamage ([#2848](https://github.com/EQEmu/Server/pull/2848)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-09
### Doors
* Fix issue where NPC's wouldn't open doors because door param overflow ([#2934](https://github.com/EQEmu/Server/pull/2934)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
### Feature
* Add IsOfClientBotMerc() virtual method. ([#2843](https://github.com/EQEmu/Server/pull/2843)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-07
### Fixes
* Another doors fix ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Fix CheckNumHitsRemaining() with 1H Blunt ([#2846](https://github.com/EQEmu/Server/pull/2846)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-07
* Fix Door opening regression caused by #2880 ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Fix EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE regression caused by #2897 ([#2928](https://github.com/EQEmu/Server/pull/2928)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Fix HP_EVENT regression ([#2927](https://github.com/EQEmu/Server/pull/2927)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Fix crash in EVENT_DISCOVER_ITEM ([#2933](https://github.com/EQEmu/Server/pull/2933)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-15
* Fix crash where dropped items crash Lua logic ([#2936](https://github.com/EQEmu/Server/pull/2936)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
* Fix for interrupting item casts to no longer lock the client if cast time of item greater than 0 ([#2921](https://github.com/EQEmu/Server/pull/2921)) ([Natedog2012](https://github.com/Natedog2012)) 2023-02-13
* Fix issue where Lore groundspawn pickups will desync ROF2+ ([#2929](https://github.com/EQEmu/Server/pull/2929)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Fix issue with EVENT_HP firing regression from #2904 ([#2924](https://github.com/EQEmu/Server/pull/2924)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
* Replace uses of SPELL_UNKNOWN with IsValidSpell() ([#2938](https://github.com/EQEmu/Server/pull/2938)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-16
* Self Only Spells will no longer check target level or buff restrictions ([#2931](https://github.com/EQEmu/Server/pull/2931)) ([noudess](https://github.com/noudess)) 2023-02-15
### Groundspawns
* Fix issue where groundspawns appear floating high off the ground ([#2930](https://github.com/EQEmu/Server/pull/2930)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
### Logging
* Add raw opcode when emu translated opcode is not found (OP_Unknown) via (C->S) ([#2847](https://github.com/EQEmu/Server/pull/2847)) ([Akkadius](https://github.com/Akkadius)) 2023-02-08
* Implement Player Event Logging system ([#2833](https://github.com/EQEmu/Server/pull/2833)) ([Akkadius](https://github.com/Akkadius)) 2023-02-13
### Quest API
* (Performance) Check equip or scale item events exist before export and execute ([#2898](https://github.com/EQEmu/Server/pull/2898)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_AA_BUY or EVENT_AA_GAIN exist before export and execute ([#2892](https://github.com/EQEmu/Server/pull/2892)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_AGGRO, EVENT_ATTACK, or EVENT_COMBAT exist before export and execute ([#2901](https://github.com/EQEmu/Server/pull/2901)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_COMBINE, EVENT_COMBINE_SUCCESS, EVENT_COMBINE_FAILURE, or EVENT_COMBINE_VALIDATE exist before export and execute ([#2896](https://github.com/EQEmu/Server/pull/2896)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_DEATH, EVENT_DEATH_COMPLETE, or EVENT_DEATH_ZONE exist before export and execute ([#2909](https://github.com/EQEmu/Server/pull/2909)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_ENVIRONMENTAL_DAMAGE exists before export and execute ([#2899](https://github.com/EQEmu/Server/pull/2899)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_FEIGN_DEATH exists before export and execute ([#2916](https://github.com/EQEmu/Server/pull/2916)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_ITEM_TICK or EVENT_WEAPON_PROC exist before export and execute ([#2914](https://github.com/EQEmu/Server/pull/2914)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_LANGUAGE_SKILL_UP, EVENT_SKILL_UP, or EVENT_USE_SKILL exist before export and execute ([#2894](https://github.com/EQEmu/Server/pull/2894)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_PAYLOAD or EVENT_SIGNAL exist before export and execute ([#2902](https://github.com/EQEmu/Server/pull/2902)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_SLAY exists before export and execute ([#2910](https://github.com/EQEmu/Server/pull/2910)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event EVENT_WAYPOINT_ARRIVE or EVENT_WAYPOINT_DEPART exist before export and execute ([#2905](https://github.com/EQEmu/Server/pull/2905)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_AGGRO_SAY, EVENT_SAY, and EVENT_PROXIMITY_SAY ([#2882](https://github.com/EQEmu/Server/pull/2882)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_BOT_CREATE ([#2886](https://github.com/EQEmu/Server/pull/2886)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_CLICK_DOOR and EVENT_CLICK_OBJECT ([#2880](https://github.com/EQEmu/Server/pull/2880)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_DESPAWN and EVENT_DESPAWN_ZONE ([#2887](https://github.com/EQEmu/Server/pull/2887)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_DISCOVER_ITEM ([#2912](https://github.com/EQEmu/Server/pull/2912)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_DUEL_LOSE and EVENT_DUEL_WIN ([#2915](https://github.com/EQEmu/Server/pull/2915)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_ENTER_ZONE and EVENT_ZONE ([#2900](https://github.com/EQEmu/Server/pull/2900)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_GM_COMMAND ([#2890](https://github.com/EQEmu/Server/pull/2890)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_GROUP_CHANGE ([#2884](https://github.com/EQEmu/Server/pull/2884)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_HP ([#2904](https://github.com/EQEmu/Server/pull/2904)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_KILLED_MERIT ([#2911](https://github.com/EQEmu/Server/pull/2911)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_LEVEL_UP and EVENT_LEVEL_DOWN ([#2889](https://github.com/EQEmu/Server/pull/2889)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_POPUP_RESPONSE ([#2881](https://github.com/EQEmu/Server/pull/2881)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_RESPAWN ([#2917](https://github.com/EQEmu/Server/pull/2917)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_TICK ([#2919](https://github.com/EQEmu/Server/pull/2919)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_TIMER ([#2903](https://github.com/EQEmu/Server/pull/2903)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_TRADE ([#2906](https://github.com/EQEmu/Server/pull/2906)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_UNHANDLED_OPCODE ([#2918](https://github.com/EQEmu/Server/pull/2918)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_WARP ([#2907](https://github.com/EQEmu/Server/pull/2907)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute area events ([#2888](https://github.com/EQEmu/Server/pull/2888)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check merchant events exist before export and execute ([#2893](https://github.com/EQEmu/Server/pull/2893)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check spell or cast events exist before export and execute ([#2897](https://github.com/EQEmu/Server/pull/2897)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check task events exist before export and execute ([#2883](https://github.com/EQEmu/Server/pull/2883)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_CONNECT and EVENT_DISCONNECT ([#2913](https://github.com/EQEmu/Server/pull/2913)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* (Performance) Check event exists before export and execute EVENT_TEST_BUFF ([#2920](https://github.com/EQEmu/Server/pull/2920)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Add $target export to EVENT_INSPECT in Perl ([#2891](https://github.com/EQEmu/Server/pull/2891)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Add Additional XP Events EVENT_AA_EXP_GAIN, EVENT_EXP_GAIN ([#2865](https://github.com/EQEmu/Server/pull/2865)) ([Valorith](https://github.com/Valorith)) 2023-02-13
* Add EVENT_DESTROY_ITEM_CLIENT to Perl/Lua. ([#2871](https://github.com/EQEmu/Server/pull/2871)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Add EVENT_DROP_ITEM_CLIENT to Perl/Lua ([#2869](https://github.com/EQEmu/Server/pull/2869)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Add Recipe-based methods to Perl/Lua. ([#2844](https://github.com/EQEmu/Server/pull/2844)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-08
* Export $door to EVENT_CLICKDOOR in Perl ([#2861](https://github.com/EQEmu/Server/pull/2861)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
* Export $hate_entity to EVENT_HATE_LIST in Perl ([#2885](https://github.com/EQEmu/Server/pull/2885)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $item and $augment to augment events in Perl ([#2895](https://github.com/EQEmu/Server/pull/2895)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $item and $corpse to EVENT_LOOT and EVENT_LOOT_ZONE in Perl ([#2878](https://github.com/EQEmu/Server/pull/2878)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $item to Client/Bot Equip Events in Perl ([#2860](https://github.com/EQEmu/Server/pull/2860)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
* Export $item to EVENT_DISCOVER_ITEM in Perl ([#2863](https://github.com/EQEmu/Server/pull/2863)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
* Export $item to EVENT_PLAYER_PICKUP in Perl. ([#2875](https://github.com/EQEmu/Server/pull/2875)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $item to Fishing and Forage Events in Perl ([#2876](https://github.com/EQEmu/Server/pull/2876)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $killed_npc to EVENT_NPC_SLAY to Perl ([#2879](https://github.com/EQEmu/Server/pull/2879)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export $object to EVENT_CLICK_OBJECT in Perl ([#2862](https://github.com/EQEmu/Server/pull/2862)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-11
* Export $spawned to EVENT_SPAWN_ZONE in Perl ([#2877](https://github.com/EQEmu/Server/pull/2877)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export target to EVENT_TARGET_CHANGE in Perl/Lua. ([#2870](https://github.com/EQEmu/Server/pull/2870)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Export targets to EVENT_CONSIDER and EVENT_CONSIDER_CORPSE ([#2908](https://github.com/EQEmu/Server/pull/2908)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
* Fix SetSimpleRoamBox in Perl to have optional params again ([#2935](https://github.com/EQEmu/Server/pull/2935)) ([Akkadius](https://github.com/Akkadius)) 2023-02-15
### Rules
* Add Group/Raid Experience Rules ([#2850](https://github.com/EQEmu/Server/pull/2850)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-13
### Tradeskills
* Check if combine would result in lore conflict ([#2932](https://github.com/EQEmu/Server/pull/2932)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-16
### Windows
* Fix MSVC compilation bug via workaround ([#2926](https://github.com/EQEmu/Server/pull/2926)) ([Akkadius](https://github.com/Akkadius)) 2023-02-14
## [22.3.0] - 02/06/2023
### Bots
* Add GetAugmentIDsBySlotID & AddItem with table ref Methods. ([#2805](https://github.com/EQEmu/Server/pull/2805)) ([Aeadoin](https://github.com/Aeadoin)) 2023-01-29
### Commands
* #list now searches without case sensitivity ([#2825](https://github.com/EQEmu/Server/pull/2825)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
* Remove extraneous else from #weather ([#2819](https://github.com/EQEmu/Server/pull/2819)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-01
### Crash
* Fix IsUnderwaterOnly crash where npc data references can be stale ([#2830](https://github.com/EQEmu/Server/pull/2830)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
* Fix command crash with #npcedit weapon when second weapon not passed ni ([#2829](https://github.com/EQEmu/Server/pull/2829)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
* Fix crash in bot command botdyearmor ([#2832](https://github.com/EQEmu/Server/pull/2832)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### DB Updates
* Add Windows MySQL path auto detection for users where the path is not found ([#2836](https://github.com/EQEmu/Server/pull/2836)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### Doors
* Have NPCs trigger double doors ([#2821](https://github.com/EQEmu/Server/pull/2821)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
* Remove door dev tools spam on client controlled doors ([#2824](https://github.com/EQEmu/Server/pull/2824)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### Feature
* Add Min/Max Status to Merchants ([#2806](https://github.com/EQEmu/Server/pull/2806)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-29
### Fixes
* #reload aa will now refresh the AA table properly for every client when changes are made ([#2814](https://github.com/EQEmu/Server/pull/2814)) ([Natedog2012](https://github.com/Natedog2012)) 2023-01-31
* #reload static should now properly fill the entity_lists for… ([#2815](https://github.com/EQEmu/Server/pull/2815)) ([Natedog2012](https://github.com/Natedog2012)) 2023-01-31
* BuffLevelRestrictions were restricting group buffs if mob targeted ([#2809](https://github.com/EQEmu/Server/pull/2809)) ([noudess](https://github.com/noudess)) 2023-01-29
* Fix does_augment_fit_slot method. ([#2817](https://github.com/EQEmu/Server/pull/2817)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-01
* Fix NPC ghosting at safe coordinates ([#2823](https://github.com/EQEmu/Server/pull/2823)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
* Fixing % based mob see invis ([#2802](https://github.com/EQEmu/Server/pull/2802)) ([fryguy503](https://github.com/fryguy503)) 2023-01-29
* Resolve issue with max buff count being 25 in ROF2. ([#2800](https://github.com/EQEmu/Server/pull/2800)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-28
### Hotfix
* Post revert build fix for https://github.com/EQEmu/Server/commit/54050924d81d1f83268fe01f9c2b36fe10626601 ([Akkadius](https://github.com/Akkadius)) 2023-02-01
### Lua
* Resolve stoi Exception ([#2736](https://github.com/EQEmu/Server/pull/2736)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### Pathing
* Improvements to handling tight corridors pathing, clipping detection and recovery ([#2826](https://github.com/EQEmu/Server/pull/2826)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### Quest API
* Add Augment Slot support to does_augment_fit ([#2813](https://github.com/EQEmu/Server/pull/2813)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-31
* Add EVENT_DAMAGE_GIVEN and EVENT_DAMAGE_TAKEN to Perl/Lua. ([#2804](https://github.com/EQEmu/Server/pull/2804)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-29
* Add EVENT_ITEM_CLICK_CLIENT and EVENT_ITEM_CLICK_CAST_CLIENT to Perl/Lua. ([#2810](https://github.com/EQEmu/Server/pull/2810)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-30
* Add EVENT_TASKACCEPTED to Player scope ([#2822](https://github.com/EQEmu/Server/pull/2822)) ([Valorith](https://github.com/Valorith)) 2023-02-06
* Add GetItemCooldown to return the time remaining on items… ([#2811](https://github.com/EQEmu/Server/pull/2811)) ([Natedog2012](https://github.com/Natedog2012)) 2023-01-30
* Add LDoN Methods to Perl/Lua ([#2799](https://github.com/EQEmu/Server/pull/2799)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-01-29
* Add Override Parameters to ScaleNPC() in Perl/Lua. ([#2816](https://github.com/EQEmu/Server/pull/2816)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-01
* Add rule AlternateAugmentationSealer for using a different bagtype ([#2831](https://github.com/EQEmu/Server/pull/2831)) ([Natedog2012](https://github.com/Natedog2012)) 2023-02-06
* Default ScaleNPC to always scale. ([#2818](https://github.com/EQEmu/Server/pull/2818)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-06
### Readme
* Update build badges with Drone ([Akkadius](https://github.com/Akkadius)) 2023-01-29
### Rules
* Add rule to ignore name filter on chat channel creation. ([#2820](https://github.com/EQEmu/Server/pull/2820)) ([Valorith](https://github.com/Valorith)) 2023-02-06
* Added rule to bypass level based haste caps ([#2835](https://github.com/EQEmu/Server/pull/2835)) ([jcr4990](https://github.com/jcr4990)) 2023-02-06
* Fix rule updates that affected bot booting checks ([#2841](https://github.com/EQEmu/Server/pull/2841)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
### Tasks
* Implement alternate currency rewards ([#2827](https://github.com/EQEmu/Server/pull/2827)) ([Akkadius](https://github.com/Akkadius)) 2023-02-06
## [22.2.0] - 01/27/2023
### Bots
+3 -3
View File
@@ -1,7 +1,7 @@
# EQEmulator Core Server
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|:---:|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
| Drone (Linux x64) | Drone (Windows x64) |
|:---:|:---:|
|[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |
***
+3 -3
View File
@@ -86,7 +86,7 @@ int main(int argc, char **argv)
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -183,7 +183,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
}
auto row = results.begin();
if (row[0] && atoi(row[0]) > 0) {
if (row[0] && Strings::ToInt(row[0]) > 0) {
return true;
}
@@ -207,7 +207,7 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
}
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
void ExportSkillCaps(SharedDatabase *db)
+17 -17
View File
@@ -83,7 +83,7 @@ int main(int argc, char **argv) {
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -241,10 +241,10 @@ void ImportSkillCaps(SharedDatabase *db) {
}
int class_id, skill_id, level, cap;
class_id = atoi(split[0].c_str());
skill_id = atoi(split[1].c_str());
level = atoi(split[2].c_str());
cap = atoi(split[3].c_str());
class_id = Strings::ToInt(split[0].c_str());
skill_id = Strings::ToInt(split[1].c_str());
level = Strings::ToInt(split[2].c_str());
cap = Strings::ToInt(split[3].c_str());
std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
class_id, skill_id, level, cap);
@@ -280,16 +280,16 @@ void ImportBaseData(SharedDatabase *db) {
int level, class_id;
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
level = atoi(split[0].c_str());
class_id = atoi(split[1].c_str());
hp = atof(split[2].c_str());
mana = atof(split[3].c_str());
end = atof(split[4].c_str());
unk1 = atof(split[5].c_str());
unk2 = atof(split[6].c_str());
hp_fac = atof(split[7].c_str());
mana_fac = atof(split[8].c_str());
end_fac = atof(split[9].c_str());
level = Strings::ToInt(split[0].c_str());
class_id = Strings::ToInt(split[1].c_str());
hp = Strings::ToFloat(split[2].c_str());
mana = Strings::ToFloat(split[3].c_str());
end = Strings::ToFloat(split[4].c_str());
unk1 = Strings::ToFloat(split[5].c_str());
unk2 = Strings::ToFloat(split[6].c_str());
hp_fac = Strings::ToFloat(split[7].c_str());
mana_fac = Strings::ToFloat(split[8].c_str());
end_fac = Strings::ToFloat(split[9].c_str());
sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
@@ -339,8 +339,8 @@ void ImportDBStrings(SharedDatabase *db) {
int id, type;
std::string value;
id = atoi(split[0].c_str());
type = atoi(split[1].c_str());
id = Strings::ToInt(split[0].c_str());
type = Strings::ToInt(split[1].c_str());
if(split.size() >= 3) {
value = ::Strings::Escape(split[2]);
+13 -9
View File
@@ -33,9 +33,11 @@ SET(common_sources
eq_stream_proxy.cpp
eqtime.cpp
event_sub.cpp
events/player_event_logs.cpp
events/player_event_discord_formatter.cpp
expedition_lockout_timer.cpp
extprofile.cpp
discord_manager.cpp
discord/discord_manager.cpp
faction.cpp
file.cpp
guild_base.cpp
@@ -198,7 +200,6 @@ SET(repositories
repositories/base/base_dynamic_zones_repository.h
repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_dynamic_zone_templates_repository.h
repositories/base/base_eventlog_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_faction_association_repository.h
@@ -218,7 +219,6 @@ SET(repositories
repositories/base/base_guilds_repository.h
repositories/base/base_guild_ranks_repository.h
repositories/base/base_guild_relations_repository.h
repositories/base/base_hackers_repository.h
repositories/base/base_horses_repository.h
repositories/base/base_instance_list_repository.h
repositories/base/base_instance_list_player_repository.h
@@ -264,6 +264,8 @@ SET(repositories
repositories/base/base_pets_equipmentset_repository.h
repositories/base/base_pets_equipmentset_entries_repository.h
repositories/base/base_player_titlesets_repository.h
repositories/base/base_player_event_log_settings_repository.h
repositories/base/base_player_event_logs_repository.h
repositories/base/base_quest_globals_repository.h
repositories/base/base_raid_details_repository.h
repositories/base/base_raid_members_repository.h
@@ -376,7 +378,6 @@ SET(repositories
repositories/dynamic_zones_repository.h
repositories/dynamic_zone_members_repository.h
repositories/dynamic_zone_templates_repository.h
repositories/eventlog_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/faction_association_repository.h
@@ -396,7 +397,6 @@ SET(repositories
repositories/guilds_repository.h
repositories/guild_ranks_repository.h
repositories/guild_relations_repository.h
repositories/hackers_repository.h
repositories/horses_repository.h
repositories/instance_list_repository.h
repositories/instance_list_player_repository.h
@@ -442,6 +442,8 @@ SET(repositories
repositories/pets_equipmentset_repository.h
repositories/pets_equipmentset_entries_repository.h
repositories/player_titlesets_repository.h
repositories/player_event_log_settings_repository.h
repositories/player_event_logs_repository.h
repositories/quest_globals_repository.h
repositories/raid_details_repository.h
repositories/raid_members_repository.h
@@ -507,7 +509,7 @@ SET(common_headers
dbcore.h
deity.h
discord/discord.h
discord_manager.h
discord/discord_manager.h
dynamic_zone_base.h
emu_constants.h
emu_limits.h
@@ -530,6 +532,9 @@ SET(common_headers
eq_stream_locator.h
eq_stream_proxy.h
eqtime.h
events/player_event_logs.h
events/player_event_discord_formatter.h
events/player_events.h
errmsg.h
event_sub.h
expedition_lockout_timer.h
@@ -603,11 +608,11 @@ SET(common_headers
unix.h
useperl.h
version.h
zone_numbers.h
zone_store.h
event/event_loop.h
event/task.h
event/timer.h
json/json_archive_single_line.h
json/json.h
json/json-forwards.h
net/console_server.h
@@ -661,8 +666,7 @@ SET(common_headers
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
util/uuid.h
)
util/uuid.h)
SOURCE_GROUP(Event FILES
event/event_loop.h
+1 -1
View File
@@ -313,7 +313,7 @@ namespace cron
{
try
{
return static_cast<cron_int>(std::stoul(text.data()));
return static_cast<cron_int>(Strings::ToUnsignedInt(text.data()));
}
catch (std::exception const & ex)
{
+66 -104
View File
@@ -121,10 +121,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, const char *
auto row = results.begin();
auto id = std::stoul(row[0]);
auto id = Strings::ToUnsignedInt(row[0]);
if (oStatus) {
*oStatus = std::stoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
return id;
@@ -202,11 +202,11 @@ int16 Database::CheckStatus(uint32 account_id)
}
auto row = results.begin();
int16 status = std::stoi(row[0]);
int16 status = Strings::ToInt(row[0]);
int32 date_diff = 0;
if (row[1]) {
date_diff = std::stoi(row[1]);
date_diff = Strings::ToInt(row[1]);
}
if (date_diff > 0) {
@@ -345,7 +345,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
std::string query = StringFormat("SELECT `account_id`, `name` FROM `character_data` WHERE `name` = '%s'", name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
if (row[0] && atoi(row[0]) > 0){
if (row[0] && Strings::ToInt(row[0]) > 0){
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
return false;
}
@@ -387,7 +387,7 @@ bool Database::DeleteCharacter(char *character_name)
std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", character_name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
character_id = atoi(row[0]);
character_id = Strings::ToUnsignedInt(row[0]);
}
if (character_id <= 0) {
@@ -787,7 +787,7 @@ uint32 Database::GetCharacterID(const char *name) {
auto row = results.begin();
if (results.RowCount() == 1)
{
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
return 0;
}
@@ -812,10 +812,10 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
auto row = results.begin();
uint32 accountId = atoi(row[0]);
uint32 accountId = Strings::ToUnsignedInt(row[0]);
if (oCharID)
*oCharID = atoi(row[1]);
*oCharID = Strings::ToUnsignedInt(row[1]);
return accountId;
}
@@ -832,7 +832,7 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetAccountIDByName(std::string account_name, std::string loginserver, int16* status, uint32* lsid) {
@@ -852,14 +852,14 @@ uint32 Database::GetAccountIDByName(std::string account_name, std::string logins
}
auto row = results.begin();
auto account_id = std::stoul(row[0]);
auto account_id = Strings::ToUnsignedInt(row[0]);
if (status) {
*status = static_cast<int16>(std::stoi(row[1]));
*status = static_cast<int16>(Strings::ToInt(row[1]));
}
if (lsid) {
*lsid = row[2] ? std::stoul(row[2]) : 0;
*lsid = row[2] ? Strings::ToUnsignedInt(row[2]) : 0;
}
return account_id;
@@ -880,7 +880,7 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID
strcpy(name, row[0]);
if (row[1] && oLSAccountID) {
*oLSAccountID = atoi(row[1]);
*oLSAccountID = Strings::ToUnsignedInt(row[1]);
}
}
@@ -968,7 +968,7 @@ bool Database::LoadVariables() {
std::string key, value;
for (auto row = results.begin(); row != results.end(); ++row) {
varcache.last_update = atoi(row[2]); // ahh should we be comparing if this is newer?
varcache.last_update = Strings::ToUnsignedInt(row[2]); // ahh should we be comparing if this is newer?
key = row[0];
value = row[1];
std::transform(std::begin(key), std::end(key), std::begin(key), ::tolower); // keys are lower case, DB doesn't have to be
@@ -1052,15 +1052,15 @@ bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zon
auto row = results.begin();
if(graveyard_zoneid != nullptr)
*graveyard_zoneid = atoi(row[0]);
*graveyard_zoneid = Strings::ToUnsignedInt(row[0]);
if(graveyard_x != nullptr)
*graveyard_x = atof(row[1]);
*graveyard_x = Strings::ToFloat(row[1]);
if(graveyard_y != nullptr)
*graveyard_y = atof(row[2]);
*graveyard_y = Strings::ToFloat(row[2]);
if(graveyard_z != nullptr)
*graveyard_z = atof(row[3]);
*graveyard_z = Strings::ToFloat(row[3]);
if(graveyard_heading != nullptr)
*graveyard_heading = atof(row[4]);
*graveyard_heading = Strings::ToFloat(row[4]);
return true;
}
@@ -1168,13 +1168,13 @@ uint32 Database::GetAccountIDFromLSID(
}
for (auto row = results.begin(); row != results.end(); ++row) {
account_id = std::stoi(row[0]);
account_id = Strings::ToUnsignedInt(row[0]);
if (in_account_name) {
strcpy(in_account_name, row[1]);
}
if (in_status) {
*in_status = std::stoi(row[2]);
*in_status = Strings::ToInt(row[2]);
}
}
@@ -1198,7 +1198,7 @@ void Database::GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus) {
if (oAccountName)
strcpy(oAccountName, row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
void Database::ClearMerchantTemp(){
@@ -1244,7 +1244,7 @@ uint8 Database::GetServerType() {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
bool Database::MoveCharacterToZone(uint32 character_id, uint32 zone_id)
@@ -1281,44 +1281,6 @@ bool Database::MoveCharacterToZone(const char *charname, uint32 zone_id)
return results.RowsAffected() != 0;
}
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
std::string query = StringFormat("INSERT INTO `hackers` (account, name, hacked) values('%s','%s','%s')", accountname, charactername, hacked);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
std::string query = StringFormat("INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const std::string &hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
auto query = fmt::format("INSERT INTO hackers(account, name, hacked, zone) values('{}', '{}', '{}', '{}')",
accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
{
uint16 race_cap = 0;
@@ -1334,7 +1296,7 @@ uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level)
@@ -1350,12 +1312,12 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
if (results.Success() && results.RowsAffected() != 0)
{
auto row = results.begin();
skill_level = atoi(row[0]);
skill_formula = atoi(row[1]);
skill_cap = atoi(row[2]);
if (atoi(row[3]) > skill_cap)
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = atoi(row[4]);
skill_level = Strings::ToUnsignedInt(row[0]);
skill_formula = Strings::ToUnsignedInt(row[1]);
skill_cap = Strings::ToUnsignedInt(row[2]);
if (Strings::ToUnsignedInt(row[3]) > skill_cap)
skill_cap2 = (Strings::ToUnsignedInt(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = Strings::ToUnsignedInt(row[4]);
}
int race_skill = GetRaceSkill(skillid,in_race);
@@ -1400,10 +1362,10 @@ uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id
}
auto row = results.begin();
auto character_id = std::stoul(row[0]);
*account_id = std::stoul(row[1]);
*zone_id = std::stoul(row[2]);
*instance_id = std::stoul(row[3]);
auto character_id = Strings::ToUnsignedInt(row[0]);
*account_id = Strings::ToUnsignedInt(row[1]);
*zone_id = Strings::ToUnsignedInt(row[2]);
*instance_id = Strings::ToUnsignedInt(row[3]);
return character_id;
}
@@ -1526,7 +1488,7 @@ uint32 Database::GetGroupID(const char* name){
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
@@ -1540,7 +1502,7 @@ std::string Database::GetGroupLeaderForLogin(std::string character_name) {
if (results.Success() && results.RowCount()) {
auto row = results.begin();
group_id = std::stoul(row[0]);
group_id = Strings::ToUnsignedInt(row[0]);
}
if (!group_id) {
@@ -1629,7 +1591,7 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
strcpy(mentoree, row[5]);
if (mentor_percent)
*mentor_percent = atoi(row[6]);
*mentor_percent = Strings::ToInt(row[6]);
if(GLAA && results.LengthOfColumn(7) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[7], sizeof(GroupLeadershipAA_Struct));
@@ -1676,7 +1638,7 @@ uint8 Database::GetAgreementFlag(uint32 acctid) {
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
void Database::SetAgreementFlag(uint32 acctid) {
@@ -1762,7 +1724,7 @@ uint32 Database::GetRaidID(const char* name)
}
if (row[0]) // would it ever be possible to have a null here?
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
return 0;
}
@@ -1845,7 +1807,7 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank,
strcpy(mentoree, row[4]);
if (mentor_percent)
*mentor_percent = atoi(row[5]);
*mentor_percent = Strings::ToInt(row[5]);
if (GLAA && results.LengthOfColumn(6) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[6], sizeof(GroupLeadershipAA_Struct));
@@ -2018,16 +1980,16 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
auto row = results.begin();
as->success.guk = atoi(row[0]);
as->success.mir = atoi(row[1]);
as->success.mmc = atoi(row[2]);
as->success.ruj = atoi(row[3]);
as->success.tak = atoi(row[4]);
as->failure.guk = atoi(row[5]);
as->failure.mir = atoi(row[6]);
as->failure.mmc = atoi(row[7]);
as->failure.ruj = atoi(row[8]);
as->failure.tak = atoi(row[9]);
as->success.guk = Strings::ToUnsignedInt(row[0]);
as->success.mir = Strings::ToUnsignedInt(row[1]);
as->success.mmc = Strings::ToUnsignedInt(row[2]);
as->success.ruj = Strings::ToUnsignedInt(row[3]);
as->success.tak = Strings::ToUnsignedInt(row[4]);
as->failure.guk = Strings::ToUnsignedInt(row[5]);
as->failure.mir = Strings::ToUnsignedInt(row[6]);
as->failure.mmc = Strings::ToUnsignedInt(row[7]);
as->failure.ruj = Strings::ToUnsignedInt(row[8]);
as->failure.tak = Strings::ToUnsignedInt(row[9]);
as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak;
as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak;
@@ -2046,7 +2008,7 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetGroupIDByCharID(uint32 character_id)
@@ -2068,7 +2030,7 @@ uint32 Database::GetGroupIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
@@ -2082,7 +2044,7 @@ uint32 Database::GetRaidIDByCharID(uint32 character_id) {
);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
return atoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
return 0;
}
@@ -2096,7 +2058,7 @@ int Database::CountInvSnapshots() {
auto row = results.begin();
int64 count = atoll(row[0]);
int64 count = Strings::ToBigInt(row[0]);
if (count > 2147483647)
return -2;
if (count < 0)
@@ -2127,17 +2089,17 @@ struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
eqTime.day = 1;
eqTime.month = 1;
eqTime.year = 3100;
realtime = time(0);
realtime = time(nullptr);
}
else{
auto row = results.begin();
eqTime.minute = atoi(row[0]);
eqTime.hour = atoi(row[1]);
eqTime.day = atoi(row[2]);
eqTime.month = atoi(row[3]);
eqTime.year = atoi(row[4]);
realtime = atoi(row[5]);
eqTime.minute = Strings::ToUnsignedInt(row[0]);
eqTime.hour = Strings::ToUnsignedInt(row[1]);
eqTime.day = Strings::ToUnsignedInt(row[2]);
eqTime.month = Strings::ToUnsignedInt(row[3]);
eqTime.year = Strings::ToUnsignedInt(row[4]);
realtime = Strings::ToBigInt(row[5]);
}
return eqTime;
@@ -2164,7 +2126,7 @@ int Database::GetIPExemption(std::string account_ip) {
}
auto row = results.begin();
return std::stoi(row[0]);
return Strings::ToInt(row[0]);
}
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
@@ -2178,7 +2140,7 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
auto results = QueryDatabase(query);
if (results.Success() && results.RowCount()) {
auto row = results.begin();
exemption_id = std::stoul(row[0]);
exemption_id = Strings::ToUnsignedInt(row[0]);
}
query = fmt::format(
@@ -2204,7 +2166,7 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);;
return Strings::ToInt(row[0]);;
}
return 0;
@@ -2383,7 +2345,7 @@ void Database::SourceDatabaseTableFromUrl(std::string table_name, std::string ur
int sourced_queries = 0;
if (auto res = cli.Get(request_uri.get_path().c_str())) {
if (auto res = cli.Get(request_uri.get_path())) {
if (res->status == 200) {
for (auto &s: Strings::Split(res->body, ';')) {
if (!Strings::Trim(s).empty()) {
-5
View File
@@ -34,8 +34,6 @@
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class MySQLRequestResult;
class Client;
@@ -108,9 +106,6 @@ public:
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
bool ReserveName(uint32 account_id, char *name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
bool SetHackerFlag(const char *accountname, const char *charactername, const char *hacked);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const char *hacked, const char *zone);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
bool UpdateName(const char *oldname, const char *newname);
bool CopyCharacter(
const std::string& source_character_name,
+20 -19
View File
@@ -476,10 +476,11 @@ bool Database::CheckDatabaseConversions() {
CheckDatabaseConvertPPDeblob();
CheckDatabaseConvertCorpseDeblob();
RuleManager::Instance()->LoadRules(this, "default", false);
auto *r = RuleManager::Instance();
r->LoadRules(this, "default", false);
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
LogInfo("Bot tables found but rule not enabled, enabling");
RuleManager::Instance()->SetRule("Bots:Enabled", "true", this, true, true);
r->SetRule("Bots:Enabled", "true", this, true, true);
}
/* Run EQEmu Server script (Checks for database updates) */
@@ -498,7 +499,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
ExtendedProfile_Struct* e_pp;
uint32 pplen = 0;
uint32 i;
int character_id = 0;
uint32 character_id = 0;
int account_id = 0;
int number_of_characters = 0;
int printppdebug = 0; /* Prints Player Profile */
@@ -529,7 +530,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`");
results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) {
number_of_characters = atoi(row[0]);
number_of_characters = Strings::ToInt(row[0]);
printf("Number of Characters in Database: %i \n", number_of_characters);
}
@@ -928,19 +929,19 @@ bool Database::CheckDatabaseConvertPPDeblob(){
for (auto row = results.begin(); row != results.end(); ++row) {
char_iter_count++;
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", atoi(row[0]));
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", Strings::ToUnsignedInt(row[0]));
auto results2 = QueryDatabase(squery);
auto row2 = results2.begin();
pp = (Convert::PlayerProfile_Struct*)row2[1];
e_pp = (ExtendedProfile_Struct*)row2[11];
character_id = atoi(row[0]);
account_id = atoi(row2[4]);
character_id = Strings::ToUnsignedInt(row[0]);
account_id = Strings::ToInt(row2[4]);
/* Convert some data from the character_ table that is still relevant */
firstlogon = atoi(row2[5]);
lfg = atoi(row2[6]);
lfp = atoi(row2[7]);
firstlogon = Strings::ToUnsignedInt(row2[5]);
lfg = Strings::ToUnsignedInt(row2[6]);
lfp = Strings::ToUnsignedInt(row2[7]);
mailkey = row2[8];
xtargets = atoi(row2[9]);
xtargets = Strings::ToUnsignedInt(row2[9]);
inspectmessage = row2[10];
/* Verify PP Integrity */
@@ -1566,7 +1567,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
rquery = StringFormat("SELECT DISTINCT charid FROM character_corpses");
results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) {
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", atoi(row[0]));
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", Strings::ToUnsignedInt(row[0]));
auto results2 = QueryDatabase(squery);
for (auto row2 = results2.begin(); row2 != results2.end(); ++row2) {
in_datasize = results2.LengthOfColumn(2);
@@ -1598,7 +1599,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
c_type = "NULL";
continue;
}
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << atoi(row2[0]) << std::endl;
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << Strings::ToUnsignedInt(row2[0]) << std::endl;
if (is_sof){
scquery = StringFormat("UPDATE `character_corpses` SET \n"
@@ -1669,7 +1670,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc->item_tint[6].color,
dbpc->item_tint[7].color,
dbpc->item_tint[8].color,
atoi(row2[0])
Strings::ToUnsignedInt(row2[0])
);
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
@@ -1681,7 +1682,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToUnsignedInt(row2[0]),
dbpc->items[i].equipSlot,
dbpc->items[i].item_id,
dbpc->items[i].charges,
@@ -1697,7 +1698,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
}
else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToUnsignedInt(row2[0]),
dbpc->items[i].equipSlot,
dbpc->items[i].item_id,
dbpc->items[i].charges,
@@ -1777,7 +1778,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc_c->item_tint[6].color,
dbpc_c->item_tint[7].color,
dbpc_c->item_tint[8].color,
atoi(row2[0])
Strings::ToUnsignedInt(row2[0])
);
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
@@ -1790,7 +1791,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToUnsignedInt(row2[0]),
dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id,
dbpc_c->items[i].charges,
@@ -1806,7 +1807,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
}
else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToUnsignedInt(row2[0]),
dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id,
dbpc_c->items[i].charges,
+6 -6
View File
@@ -167,8 +167,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
auto row = results.begin();
if (atoi(row[0]) <= max) {
instance_id = atoi(row[0]);
if (Strings::ToInt(row[0]) <= max) {
instance_id = Strings::ToInt(row[0]);
return true;
}
@@ -194,7 +194,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
max_reserved_instance_id++;
for (auto row : results) {
if (max_reserved_instance_id < std::stoul(row[0])) {
if (max_reserved_instance_id < Strings::ToUnsignedInt(row[0])) {
instance_id = max_reserved_instance_id;
return true;
}
@@ -301,7 +301,7 @@ uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 versio
auto row = results.begin();
return static_cast<uint16>(std::stoul(row[0]));
return static_cast<uint16>(Strings::ToUnsignedInt(row[0]));
}
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id)
@@ -328,7 +328,7 @@ std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id
}
for (auto row : results) {
l.push_back(static_cast<uint16>(std::stoul(row[0])));
l.push_back(static_cast<uint16>(Strings::ToUnsignedInt(row[0])));
}
return l;
@@ -409,7 +409,7 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
auto l = GroupIdRepository::GetWhere(
auto l = RaidMembersRepository::GetWhere(
*this,
fmt::format(
"raidid = {}",
+2 -2
View File
@@ -321,13 +321,11 @@ namespace DatabaseSchema {
"discord_webhooks",
"dynamic_zone_members",
"dynamic_zones",
"eventlog",
"expedition_lockouts",
"expeditions",
"gm_ips",
"group_id",
"group_leaders",
"hackers",
"instance_list",
"ip_exemptions",
"item_tick",
@@ -343,6 +341,8 @@ namespace DatabaseSchema {
"respawn_times",
"saylink",
"server_scheduled_events",
"player_event_log_settings",
"player_event_logs",
"shared_task_activity_state",
"shared_task_dynamic_zones",
"shared_task_members",
+54 -48
View File
@@ -34,14 +34,16 @@
DBcore::DBcore()
{
mysql_init(&mysql);
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
mysql = mysql_init(nullptr);
mysqlOwner = true;
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
m_mutex = new Mutex;
}
DBcore::~DBcore()
@@ -51,16 +53,10 @@ DBcore::~DBcore()
* are re-using the default database connection pointer when we dont have an
* external configuration setup ex: (content_database)
*/
std::string mysql_connection_host;
if (mysql.host) {
mysql_connection_host = mysql.host;
if (mysqlOwner) {
mysql_close(mysql);
}
if (GetOriginHost() != mysql_connection_host) {
return;
}
mysql_close(&mysql);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -70,17 +66,18 @@ DBcore::~DBcore()
// Sends the MySQL server a keepalive
void DBcore::ping()
{
if (!MDatabase.trylock()) {
if (!m_mutex->trylock()) {
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return;
}
mysql_ping(&mysql);
MDatabase.unlock();
mysql_ping(mysql);
m_mutex->unlock();
}
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
{
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
return r;
}
bool DBcore::DoesTableExist(std::string table_name)
@@ -95,18 +92,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer;
timer.reset();
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
// Reconnect if we are not connected before hand.
if (pStatus != Connected) {
Open();
}
// request query. != 0 indicates some kind of error.
if (mysql_real_query(&mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(&mysql);
if (mysql_real_query(mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(mysql);
if (errorNumber == CR_SERVER_GONE_ERROR) {
pStatus = Error;
@@ -130,26 +125,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer);
}
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
/**
* Error logging
*/
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
if (mysql_errno(mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
}
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
}
// successful query. get results.
MYSQL_RES *res = mysql_store_result(&mysql);
MYSQL_RES *res = mysql_store_result(mysql);
uint32 rowCount = 0;
if (res != nullptr) {
@@ -158,10 +153,10 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
MySQLRequestResult requestResult(
res,
(uint32) mysql_affected_rows(&mysql),
(uint32) mysql_affected_rows(mysql),
rowCount,
(uint32) mysql_field_count(&mysql),
(uint32) mysql_insert_id(&mysql)
(uint32) mysql_field_count(mysql),
(uint32) mysql_insert_id(mysql)
);
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
@@ -207,7 +202,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
{
// No good reason to lock the DB, we only need it in the first place to check char encoding.
// LockMutex lock(&MDatabase);
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen);
}
bool DBcore::Open(
@@ -222,7 +217,7 @@ bool DBcore::Open(
bool iSSL
)
{
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -242,13 +237,13 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (errbuf) {
errbuf[0] = 0;
}
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
if (GetStatus() == Connected) {
return true;
}
if (GetStatus() == Error) {
mysql_close(&mysql);
mysql_init(&mysql); // Initialize structure again
mysql_close(mysql);
mysql_init(mysql); // Initialize structure again
}
if (!pHost) {
return false;
@@ -265,7 +260,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (pSSL) {
flags |= CLIENT_SSL;
}
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
pStatus = Connected;
std::string connected_origin_host = pHost;
@@ -275,21 +270,16 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
}
else {
if (errnum) {
*errnum = mysql_errno(&mysql);
*errnum = mysql_errno(mysql);
}
if (errbuf) {
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
}
pStatus = Error;
return false;
}
}
void DBcore::SetMysql(MYSQL *mysql)
{
DBcore::mysql = *mysql;
}
const std::string &DBcore::GetOriginHost() const
{
return origin_host;
@@ -299,3 +289,19 @@ void DBcore::SetOriginHost(const std::string &origin_host)
{
DBcore::origin_host = origin_host;
}
std::string DBcore::Escape(const std::string& s)
{
const std::size_t s_len = s.length();
std::vector<char> temp((s_len * 2) + 1, '\0');
mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len);
return temp.data();
}
void DBcore::SetMutex(Mutex *mutex)
{
safe_delete(m_mutex);
DBcore::m_mutex = mutex;
}
+14 -4
View File
@@ -12,6 +12,7 @@
#include <mysql.h>
#include <string.h>
#include <mutex>
class DBcore {
public:
@@ -27,16 +28,22 @@ public:
void TransactionBegin();
void TransactionCommit();
void TransactionRollback();
std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping();
MYSQL *getMySQL() { return &mysql; }
void SetMysql(MYSQL *mysql);
const std::string &GetOriginHost() const;
void SetOriginHost(const std::string &origin_host);
bool DoesTableExist(std::string table_name);
void SetMySQL(const DBcore &o)
{
mysql = o.mysql;
mysqlOwner = false;
}
void SetMutex(Mutex *mutex);
protected:
bool Open(
const char *iHost,
@@ -53,10 +60,13 @@ protected:
private:
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
MYSQL mysql;
Mutex MDatabase;
MYSQL* mysql;
bool mysqlOwner;
Mutex *m_mutex;
eStatus pStatus;
std::mutex m_query_lock{};
std::string origin_host;
char *pHost;
+93 -13
View File
@@ -1,22 +1,17 @@
#include <cereal/archives/json.hpp>
#include <cereal/archives/binary.hpp>
#include "discord.h"
#include "../http/httplib.h"
#include "../json/json.h"
#include "../strings.h"
#include "../eqemu_logsys.h"
#include "../events/player_event_logs.h"
constexpr int MAX_RETRIES = 10;
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return;
}
// validate
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
@@ -28,7 +23,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url.c_str());
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
@@ -46,9 +41,9 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
if (auto res = cli.Post(endpoint, payload.str(), "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
@@ -62,7 +57,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
@@ -81,6 +76,74 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
}
}
void Discord::SendPlayerEventMessage(
const PlayerEvent::PlayerEventContainer &e,
const std::string &webhook_url
)
{
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
auto s = Strings::Split(webhook_url, '/');
// url
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
std::string payload = PlayerEventLogs::GetDiscordPayloadFromEvent(e);
if (payload.empty()) {
return;
}
bool retry = true;
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint, payload, "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
std::stringstream ss(res->body);
Json::Value response;
try {
ss >> response;
}
catch (std::exception const &ex) {
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
}
if (res->status == 204) {
retry = false;
}
if (retries > MAX_RETRIES) {
LogDiscord("Retries exceeded for player event message");
retry = false;
}
retries++;
}
}
}
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
{
if (category_id == Logs::LogCategory::MySQLQuery) {
@@ -89,3 +152,20 @@ std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string
return message + "\n";
}
bool Discord::ValidateWebhookUrl(const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return false;
}
// validate
if (!Strings::Contains(webhook_url, "http://") && !Strings::Contains(webhook_url, "https://")) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
return false;
}
return true;
}
+5
View File
@@ -4,11 +4,16 @@
#include <string>
#include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class Discord {
public:
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
static void SendPlayerEventMessage(const PlayerEvent::PlayerEventContainer& e, const std::string &webhook_url);
static bool ValidateWebhookUrl(const std::string &webhook_url);
};
@@ -1,7 +1,6 @@
#include "discord_manager.h"
#include "../common/discord/discord.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
#include "../../common/discord/discord.h"
#include "../events/player_event_logs.h"
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
{
@@ -55,7 +54,6 @@ void DiscordManager::ProcessMessageQueue()
message = "";
}
}
// final flush
if (!message.empty()) {
Discord::SendWebhookMessage(
@@ -67,3 +65,11 @@ void DiscordManager::ProcessMessageQueue()
webhook_message_queue.clear();
webhook_queue_lock.unlock();
}
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w);
}
}
@@ -4,12 +4,15 @@
#include <mutex>
#include <map>
#include <vector>
#include "../common/types.h"
#include "../../common/types.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class DiscordManager {
public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
private:
std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
+25
View File
@@ -593,4 +593,29 @@ enum class ApplySpellType {
Raid
};
namespace HeroicBonusBucket
{
const std::string WisMaxMana = "HWIS-MaxMana";
const std::string WisManaRegen = "HWIS-ManaRegen";
const std::string WisHealAmt = "HWIS-HealAmt";
const std::string IntMaxMana = "HINT-MaxMana";
const std::string IntManaRegen = "HINT-ManaRegen";
const std::string IntSpellDmg = "HINT-SpellDmg";
const std::string StrMeleeDamage = "HSTR-MeleeDamage";
const std::string StrShieldAC = "HSTR-ShieldAC";
const std::string StrMaxEndurance = "HSTR-MaxEndurance";
const std::string StrEnduranceRegen = "HSTR-EnduranceRegen";
const std::string StaMaxHP = "HSTA-MaxHP";
const std::string StaHPRegen = "HSTA-HPRegen";
const std::string StaMaxEndurance = "HSTA-MaxEndurance";
const std::string StaEnduranceRegen = "HSTA-EnduranceRegen";
const std::string AgiAvoidance = "HAGI-Avoidance";
const std::string AgiMaxEndurance = "HAGI-MaxEndurance";
const std::string AgiEnduranceRegen = "HAGI-EnduranceRegen";
const std::string DexRangedDamage = "HDEX-RangedDamage";
const std::string DexMaxEndurance = "HDEX-MaxEndurance";
const std::string DexEnduranceRegen = "HDEX-EnduranceRegen";
}
#endif /*COMMON_EMU_CONSTANTS_H*/
+25 -8
View File
@@ -1017,15 +1017,32 @@ enum Anonymity : uint8
Roleplaying
};
enum ZoningMessage : int8
{
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
enum ZoningMessage : int8 {
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
ZoneNoExperience = -7
};
enum class RecipeCountType : uint8
{
Component,
Container,
Fail,
Salvage,
Success
};
#define ALT_CURRENCY_ID_RADIANT 4
#define ALT_CURRENCY_ID_EBON 5
enum ResurrectionActions
{
Decline,
Accept
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+17 -11
View File
@@ -29,7 +29,7 @@
#include "textures.h"
static const uint32 BUFF_COUNT = 25;
static const uint32 BUFF_COUNT = 42;
static const uint32 PET_BUFF_COUNT = 30;
static const uint32 MAX_MERC = 100;
static const uint32 MAX_MERC_GRADES = 10;
@@ -3632,17 +3632,19 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
};
struct MerchantList {
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint8 min_status;
uint8 max_status;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
std::string bucket_name;
std::string bucket_value;
uint8 bucket_comparison;
uint8 bucket_comparison;
};
struct TempMerchantList {
@@ -5520,7 +5522,11 @@ struct ServerLootItem_Struct {
uint32 aug_4; // uint32 aug_4;
uint32 aug_5; // uint32 aug_5;
uint32 aug_6; // uint32 aug_5;
uint8 attuned;
bool attuned;
std::string custom_data;
uint32 ornamenticon {};
uint32 ornamentidfile {};
uint32 ornament_hero_model {};
uint16 trivial_min_level;
uint16 trivial_max_level;
uint16 npc_min_level;
+19 -18
View File
@@ -19,6 +19,7 @@
#include "../common/global_define.h"
#include "eqemu_config.h"
#include "misc_functions.h"
#include "strings.h"
#include <iostream>
#include <sstream>
@@ -33,13 +34,13 @@ void EQEmuConfig::parse_config()
LongName = _root["server"]["world"].get("longname", "").asString();
WorldAddress = _root["server"]["world"].get("address", "").asString();
LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
MaxClients = Strings::ToInt(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
SharedKey = _root["server"]["world"].get("key", "").asString();
LoginCount = 0;
if (_root["server"]["world"]["loginserver"].isObject()) {
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginPort = Strings::ToUnsignedInt(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginLegacy = false;
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
@@ -62,7 +63,7 @@ void EQEmuConfig::parse_config()
auto loginconfig = new LoginConfig;
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginPort = Strings::ToUnsignedInt(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
@@ -85,15 +86,15 @@ void EQEmuConfig::parse_config()
Locked = false;
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetEnabled = false;
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; }
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPPort = Strings::ToUnsignedInt(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPEnabled = false;
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") {
@@ -108,9 +109,9 @@ void EQEmuConfig::parse_config()
* UCS
*/
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
ChatPort = Strings::ToUnsignedInt(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
MailPort = Strings::ToUnsignedInt(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
/**
* Database
@@ -118,7 +119,7 @@ void EQEmuConfig::parse_config()
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabasePort = Strings::ToUnsignedInt(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
/**
@@ -127,14 +128,14 @@ void EQEmuConfig::parse_config()
ContentDbUsername = _root["server"]["content_database"].get("username", "").asString();
ContentDbPassword = _root["server"]["content_database"].get("password", "").asString();
ContentDbHost = _root["server"]["content_database"].get("host", "").asString();
ContentDbPort = atoi(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbPort = Strings::ToUnsignedInt(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbName = _root["server"]["content_database"].get("db", "").asString();
/**
* QS
*/
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabasePort = Strings::ToUnsignedInt(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
@@ -142,9 +143,9 @@ void EQEmuConfig::parse_config()
/**
* Zones
*/
DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
DefaultStatus = Strings::ToUnsignedInt(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = Strings::ToUnsignedInt(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
/**
* Files
@@ -174,10 +175,10 @@ void EQEmuConfig::parse_config()
/**
* Launcher
*/
RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
RestartWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = Strings::ToInt(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
#ifdef WIN32
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
#else
+3 -1
View File
@@ -136,6 +136,7 @@ namespace Logs {
PacketServerToServer,
Bugs,
QuestErrors,
PlayerEvents,
MaxCategoryID /* Don't Remove this */
};
@@ -230,7 +231,8 @@ namespace Logs {
"Packet C->S",
"Packet S->S",
"Bugs",
"QuestErrors"
"QuestErrors",
"PlayerEvents",
};
}
+10
View File
@@ -784,6 +784,16 @@
OutF(LogSys, Logs::Detail, Logs::QuestErrors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEvents(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::PlayerEvents))\
OutF(LogSys, Logs::General, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEventsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PlayerEvents))\
OutF(LogSys, Logs::Detail, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,214 @@
#ifndef EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#define EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#include <string>
#include "player_events.h"
#include "../repositories/base/base_player_event_logs_repository.h"
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
struct DiscordField {
std::string name;
std::string value;
bool is_inline;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(value),
cereal::make_nvp("inline", is_inline)
);
}
};
struct DiscordAuthor {
std::string name;
std::string icon_url;
std::string url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(icon_url),
CEREAL_NVP(url)
);
}
};
struct DiscordEmbed {
std::vector<DiscordField> fields;
std::string title;
std::string description;
std::string timestamp;
DiscordAuthor author;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(fields),
CEREAL_NVP(title),
CEREAL_NVP(description),
CEREAL_NVP(timestamp),
CEREAL_NVP(author)
);
}
};
struct DiscordWebhook {
std::vector<DiscordEmbed> embeds;
std::string content;
std::string avatar_url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(embeds),
CEREAL_NVP(avatar_url),
CEREAL_NVP(content)
);
}
};
class PlayerEventDiscordFormatter {
public:
static std::string GetCurrentTimestamp();
static std::string FormatEventSay(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::SayEvent &e);
static std::string
FormatGMCommand(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::GMCommandEvent &e);
static void BuildDiscordField(
std::vector<DiscordField> *f,
const std::string &name,
const std::string &value,
bool is_inline = true
);
static void BuildBaseEmbed(
std::vector<DiscordEmbed> *e,
const std::vector<DiscordField> &f,
PlayerEvent::PlayerEventContainer c
);
static std::string FormatWithNodata(const PlayerEvent::PlayerEventContainer &c);
static std::string FormatAAGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAGainedEvent &e
);
static std::string FormatAAPurchasedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAPurchasedEvent &e
);
static std::string FormatDeathEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DeathEvent &e
);
static std::string FormatFishSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::FishSuccessEvent &e
);
static std::string FormatForageSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ForageSuccessEvent &e
);
static std::string FormatDestroyItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DestroyItemEvent &e
);
static std::string FormatDiscoverItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DiscoverItemEvent &e
);
static std::string FormatDroppedItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DroppedItemEvent &e
);
static std::string FormatLevelGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelGainedEvent &e
);
static std::string FormatLevelLostEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelLostEvent &e
);
static std::string FormatLootItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LootItemEvent &e
);
static std::string FormatGroundSpawnPickupEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::GroundSpawnPickupEvent &e
);
static std::string FormatMerchantPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantPurchaseEvent &e
);
static std::string FormatMerchantSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantSellEvent &e
);
static std::string FormatNPCHandinEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::HandinEvent &e
);
static std::string FormatSkillUpEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SkillUpEvent &e
);
static std::string FormatTaskAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskAcceptEvent &e
);
static std::string FormatTaskCompleteEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskCompleteEvent &e
);
static std::string FormatTaskUpdateEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskUpdateEvent &e
);
static std::string FormatTradeEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TradeEvent &e
);
static std::string FormatTraderPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderPurchaseEvent &e
);
static std::string FormatTraderSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderSellEvent &e
);
static std::string FormatResurrectAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ResurrectAcceptEvent &e
);
static std::string FormatSplitMoneyEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SplitMoneyEvent &e
);
static std::string FormatCombineEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::CombineEvent &e
);
static std::string FormatZoningEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ZoningEvent &e
);
static DiscordWebhook BuildDiscordWebhook(
const PlayerEvent::PlayerEventContainer &p,
std::vector<DiscordEmbed> &embeds
);
};
#endif //EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
+708
View File
@@ -0,0 +1,708 @@
#include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include "../platform.h"
#include "../rulesys.h"
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
// general initialization routine
void PlayerEventLogs::Init()
{
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
ValidateDatabaseConnection();
// initialize settings array
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].id = i;
m_settings[i].event_name = PlayerEvent::EventName[i];
m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0;
}
SetSettingsDefaults();
// initialize settings from database
auto s = PlayerEventLogSettingsRepository::All(*m_database);
std::vector<int> db{};
db.reserve(s.size());
for (auto &e: s) {
if (e.id >= PlayerEvent::MAX) {
continue;
}
m_settings[e.id] = e;
db.emplace_back(e.id);
}
// insert entries that don't exist in database
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
bool is_deprecated = Strings::Contains(PlayerEvent::EventName[i], "Deprecated");
bool is_implemented = !Strings::Contains(PlayerEvent::EventName[i], "Unimplemented");
// remove when deprecated
if (is_deprecated && is_in_database) {
LogInfo("[Deprecated] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
// remove when unimplemented if present
if (!is_implemented && is_in_database) {
LogInfo("[Unimplemented] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
if (is_missing_in_database && is_implemented && !is_deprecated) {
LogInfo(
"[New] PlayerEvent [{}] ({})",
PlayerEvent::EventName[i],
i
);
auto c = PlayerEventLogSettingsRepository::NewEntity();
c.id = i;
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
}
}
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
// on initial boot process truncation
if (processing_in_world || processing_in_qs) {
ProcessRetentionTruncation();
}
}
// set the database object, during initialization
PlayerEventLogs *PlayerEventLogs::SetDatabase(Database *db)
{
m_database = db;
return this;
}
// validates whether the connection is valid or not, used in initialization
bool PlayerEventLogs::ValidateDatabaseConnection()
{
if (!m_database) {
LogError("No database connection");
return false;
}
return true;
}
// determines if the passed in event is enabled or not
// this is used to gate logic or events from firing off
// this is used prior to building the events, we don't want to
// build the events, send them through the stack in a function call
// only to discard them immediately afterwards, very wasteful on resources
// the quest api currently does this
bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
{
return m_settings[event].event_enabled ? m_settings[event].event_enabled : false;
}
// this processes any current player events on the queue
void PlayerEventLogs::ProcessBatchQueue()
{
m_batch_queue_lock.lock();
if (m_record_batch_queue.empty()) {
m_batch_queue_lock.unlock();
return;
}
BenchTimer benchmark;
// flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
"Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(),
benchmark.elapsed()
);
// empty
m_record_batch_queue = {};
m_batch_queue_lock.unlock();
}
// adds a player event to the queue
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
{
m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log);
m_batch_queue_lock.unlock();
}
// fills common event data in the SendEvent function
void PlayerEventLogs::FillPlayerEvent(
const PlayerEvent::PlayerEvent &p,
PlayerEventLogsRepository::PlayerEventLogs &n
)
{
n.account_id = p.account_id;
n.character_id = p.character_id;
n.zone_id = p.zone_id;
n.instance_id = p.instance_id;
n.x = p.x;
n.y = p.y;
n.z = p.z;
n.heading = p.heading;
}
// builds the dynamic packet used to ship the player event over the wire
// supports serializing the struct so it can be rebuilt on the other end
std::unique_ptr<ServerPacket>
PlayerEventLogs::BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e)
{
EQ::Net::DynamicPacket dyn_pack;
dyn_pack.PutSerialize(0, e);
auto pack_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length();
auto pack = std::make_unique<ServerPacket>(ServerOP_PlayerEvent, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerSendPlayerEvent_Struct *>(pack->pBuffer);
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
return pack;
}
const PlayerEventLogSettingsRepository::PlayerEventLogSettings *PlayerEventLogs::GetSettings() const
{
return m_settings;
}
bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return false;
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return false;
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true;
}
return false;
}
std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return "";
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return "";
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
}
return "";
}
// GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter
// AA_PURCHASE | [x] Implemented Formatter
// FORAGE_SUCCESS | [x] Implemented Formatter
// FORAGE_FAILURE | [x] Implemented Formatter
// FISH_SUCCESS | [x] Implemented Formatter
// FISH_FAILURE | [x] Implemented Formatter
// ITEM_DESTROY | [x] Implemented Formatter
// WENT_ONLINE | [x] Implemented Formatter
// WENT_OFFLINE | [x] Implemented Formatter
// LEVEL_GAIN | [x] Implemented Formatter
// LEVEL_LOSS | [x] Implemented Formatter
// LOOT_ITEM | [x] Implemented Formatter
// MERCHANT_PURCHASE | [x] Implemented Formatter
// MERCHANT_SELL | [x] Implemented Formatter
// GROUP_JOIN | [] Implemented Formatter
// GROUP_LEAVE | [] Implemented Formatter
// RAID_JOIN | [] Implemented Formatter
// RAID_LEAVE | [] Implemented Formatter
// GROUNDSPAWN_PICKUP | [x] Implemented Formatter
// NPC_HANDIN | [x] Implemented Formatter
// SKILL_UP | [x] Implemented Formatter
// TASK_ACCEPT | [x] Implemented Formatter
// TASK_UPDATE | [x] Implemented Formatter
// TASK_COMPLETE | [x] Implemented Formatter
// TRADE | [] Implemented Formatter
// GIVE_ITEM | [] Implemented Formatter
// SAY | [x] Implemented Formatter
// REZ_ACCEPTED | [x] Implemented Formatter
// DEATH | [x] Implemented Formatter
// COMBINE_FAILURE | [x] Implemented Formatter
// COMBINE_SUCCESS | [x] Implemented Formatter
// DROPPED_ITEM | [x] Implemented Formatter
// SPLIT_MONEY | [x] Implemented Formatter
// DZ_JOIN | [] Implemented Formatter
// DZ_LEAVE | [] Implemented Formatter
// TRADER_PURCHASE | [x] Implemented Formatter
// TRADER_SELL | [x] Implemented Formatter
// BANDOLIER_CREATE | [] Implemented Formatter
// BANDOLIER_SWAP | [] Implemented Formatter
// DISCOVER_ITEM | [X] Implemented Formatter
std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e)
{
std::string payload;
switch (e.player_event_log.event_type_id) {
case PlayerEvent::AA_GAIN: {
PlayerEvent::AAGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAGainedEvent(e, n);
break;
}
case PlayerEvent::AA_PURCHASE: {
PlayerEvent::AAPurchasedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAPurchasedEvent(e, n);
break;
}
case PlayerEvent::COMBINE_FAILURE:
case PlayerEvent::COMBINE_SUCCESS: {
PlayerEvent::CombineEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatCombineEvent(e, n);
break;
}
case PlayerEvent::DEATH: {
PlayerEvent::DeathEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDeathEvent(e, n);
break;
}
case PlayerEvent::DISCOVER_ITEM: {
PlayerEvent::DiscoverItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDiscoverItemEvent(e, n);
break;
}
case PlayerEvent::DROPPED_ITEM: {
PlayerEvent::DroppedItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDroppedItemEvent(e, n);
break;
}
case PlayerEvent::FISH_FAILURE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FISH_SUCCESS: {
PlayerEvent::FishSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatFishSuccessEvent(e, n);
break;
}
case PlayerEvent::FORAGE_FAILURE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FORAGE_SUCCESS: {
PlayerEvent::ForageSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatForageSuccessEvent(e, n);
break;
}
case PlayerEvent::ITEM_DESTROY: {
PlayerEvent::DestroyItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDestroyItemEvent(e, n);
break;
}
case PlayerEvent::LEVEL_GAIN: {
PlayerEvent::LevelGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelGainedEvent(e, n);
break;
}
case PlayerEvent::LEVEL_LOSS: {
PlayerEvent::LevelLostEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelLostEvent(e, n);
break;
}
case PlayerEvent::LOOT_ITEM: {
PlayerEvent::LootItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLootItemEvent(e, n);
break;
}
case PlayerEvent::GROUNDSPAWN_PICKUP: {
PlayerEvent::GroundSpawnPickupEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGroundSpawnPickupEvent(e, n);
break;
}
case PlayerEvent::NPC_HANDIN: {
PlayerEvent::HandinEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatNPCHandinEvent(e, n);
break;
}
case PlayerEvent::SAY: {
PlayerEvent::SayEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatEventSay(e, n);
break;
}
case PlayerEvent::GM_COMMAND: {
PlayerEvent::GMCommandEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGMCommand(e, n);
break;
}
case PlayerEvent::SKILL_UP: {
PlayerEvent::SkillUpEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSkillUpEvent(e, n);
break;
}
case PlayerEvent::SPLIT_MONEY: {
PlayerEvent::SplitMoneyEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSplitMoneyEvent(e, n);
break;
}
case PlayerEvent::TASK_ACCEPT: {
PlayerEvent::TaskAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskAcceptEvent(e, n);
break;
}
case PlayerEvent::TASK_COMPLETE: {
PlayerEvent::TaskCompleteEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskCompleteEvent(e, n);
break;
}
case PlayerEvent::TASK_UPDATE: {
PlayerEvent::TaskUpdateEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskUpdateEvent(e, n);
break;
}
case PlayerEvent::TRADE: {
PlayerEvent::TradeEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTradeEvent(e, n);
break;
}
case PlayerEvent::TRADER_PURCHASE: {
PlayerEvent::TraderPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderPurchaseEvent(e, n);
break;
}
case PlayerEvent::TRADER_SELL: {
PlayerEvent::TraderSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderSellEvent(e, n);
break;
}
case PlayerEvent::REZ_ACCEPTED: {
PlayerEvent::ResurrectAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatResurrectAcceptEvent(e, n);
break;
}
case PlayerEvent::WENT_ONLINE:
case PlayerEvent::WENT_OFFLINE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::MERCHANT_PURCHASE: {
PlayerEvent::MerchantPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantPurchaseEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_SELL: {
PlayerEvent::MerchantSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantSellEvent(e, n);
break;
}
case PlayerEvent::ZONING: {
PlayerEvent::ZoningEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatZoningEvent(e, n);
break;
}
default: {
LogInfo(
"Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name,
e.player_event_log.event_type_id
);
}
}
return payload;
}
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process()
{
if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue();
}
if (m_process_retention_truncation_timer.Check()) {
ProcessRetentionTruncation();
}
}
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogInfo("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) {
int deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database,
fmt::format(
"event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
i,
m_settings[i].retention_days
)
);
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count,
PlayerEvent::EventName[i],
i,
m_settings[i].retention_days
);
}
}
}
}
void PlayerEventLogs::ReloadSettings()
{
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
m_settings[e.id] = e;
}
}
const int32_t RETENTION_DAYS_DEFAULT = 7;
void PlayerEventLogs::SetSettingsDefaults()
{
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
}
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef EQEMU_PLAYER_EVENT_LOGS_H
#define EQEMU_PLAYER_EVENT_LOGS_H
#include "../repositories/player_event_log_settings_repository.h"
#include "player_events.h"
#include "../servertalk.h"
#include "../repositories/player_event_logs_repository.h"
#include "../timer.h"
#include "../json/json_archive_single_line.h"
#include <cereal/archives/json.hpp>
#include <mutex>
class PlayerEventLogs {
public:
void Init();
void ReloadSettings();
PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event);
void Process();
// batch queue
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function
// can ingest any struct event types
template<typename T>
std::unique_ptr<ServerPacket> RecordEvent(
PlayerEvent::EventType t,
const PlayerEvent::PlayerEvent &p,
T e
)
{
auto n = PlayerEventLogsRepository::NewEntity();
FillPlayerEvent(p, n);
n.event_type_id = t;
std::stringstream ss;
{
cereal::JSONOutputArchiveSingleLine ar(ss);
e.serialize(ar);
}
n.event_type_name = PlayerEvent::EventName[t];
n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str();
n.created_at = std::time(nullptr);
auto c = PlayerEvent::PlayerEventContainer{
.player_event = p,
.player_event_log = n
};
return BuildPlayerEventPacket(c);
}
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
private:
Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
// batch queue is used to record events in batch
std::vector<PlayerEventLogsRepository::PlayerEventLogs> m_record_batch_queue{};
static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n);
static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
// timers
Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
// processing
std::mutex m_batch_queue_lock{};
void ProcessBatchQueue();
void ProcessRetentionTruncation();
void SetSettingsDefaults();
};
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H
+971
View File
@@ -0,0 +1,971 @@
#ifndef EQEMU_PLAYER_EVENTS_H
#define EQEMU_PLAYER_EVENTS_H
#include <string>
#include <cereal/cereal.hpp>
#include "../types.h"
#include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent {
enum EventType {
GM_COMMAND = 1,
ZONING,
AA_GAIN,
AA_PURCHASE,
FORAGE_SUCCESS,
FORAGE_FAILURE,
FISH_SUCCESS,
FISH_FAILURE,
ITEM_DESTROY,
WENT_ONLINE,
WENT_OFFLINE,
LEVEL_GAIN,
LEVEL_LOSS,
LOOT_ITEM,
MERCHANT_PURCHASE,
MERCHANT_SELL,
GROUP_JOIN, // unimplemented
GROUP_LEAVE, // unimplemented
RAID_JOIN, // unimplemented
RAID_LEAVE, // unimplemented
GROUNDSPAWN_PICKUP,
NPC_HANDIN,
SKILL_UP,
TASK_ACCEPT,
TASK_UPDATE,
TASK_COMPLETE,
TRADE,
GIVE_ITEM, // unimplemented
SAY,
REZ_ACCEPTED,
DEATH,
COMBINE_FAILURE,
COMBINE_SUCCESS,
DROPPED_ITEM,
SPLIT_MONEY,
DZ_JOIN, // unimplemented
DZ_LEAVE, // unimplemented
TRADER_PURCHASE,
TRADER_SELL,
BANDOLIER_CREATE, // unimplemented
BANDOLIER_SWAP, // unimplemented
DISCOVER_ITEM,
POSSIBLE_HACK,
KILLED_NPC,
KILLED_NAMED_NPC,
KILLED_RAID_NPC,
ITEM_CREATION,
MAX // dont remove
};
// Don't ever remove items, even if they are deprecated
// If event is deprecated just tag (Deprecated) in the name
// If event is unimplemented just tag (Unimplemented) in the name
// Events don't get saved to the database if unimplemented or deprecated
// Events tagged as deprecated will get automatically removed
static const char *EventName[PlayerEvent::MAX] = {
"None",
"GM Command",
"Zoning",
"AA Gain",
"AA Purchase",
"Forage Success",
"Forage Failure",
"Fish Success",
"Fish Failure",
"Item Destroy",
"Went Online",
"Went Offline",
"Level Gain",
"Level Loss",
"Loot Item",
"Merchant Purchase",
"Merchant Sell",
"Group Join (Unimplemented)",
"Group Leave (Unimplemented)",
"Raid Join (Unimplemented)",
"Raid Leave (Unimplemented)",
"Groundspawn Pickup",
"NPC Handin",
"Skill Up",
"Task Accept",
"Task Update",
"Task Complete",
"Trade",
"Given Item (Unimplemented)",
"Say",
"Rez Accepted",
"Death",
"Combine Failure",
"Combine Success",
"Dropped Item",
"Split Money",
"DZ Join (Unimplemented)",
"DZ Leave (Unimplemented)",
"Trader Purchase",
"Trader Sell",
"Bandolier Create (Unimplemented)",
"Bandolier Swap (Unimplemented)",
"Discover Item",
"Possible Hack",
"Killed NPC",
"Killed Named NPC",
"Killed Raid NPC",
"Item Creation"
};
// Generic struct used by all events
struct PlayerEvent {
int64 account_id;
std::string account_name;
int64 character_id;
std::string character_name;
int64 guild_id;
std::string guild_name;
int zone_id;
std::string zone_short_name;
std::string zone_long_name;
int instance_id;
float x;
float y;
float z;
float heading;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(account_id),
CEREAL_NVP(account_name),
CEREAL_NVP(character_id),
CEREAL_NVP(character_name),
CEREAL_NVP(guild_id),
CEREAL_NVP(guild_name),
CEREAL_NVP(zone_id),
CEREAL_NVP(zone_short_name),
CEREAL_NVP(zone_long_name),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading)
);
}
};
// contains metadata in use for things like log/discord formatters
// along with the actual event to be persisted
struct PlayerEventContainer {
PlayerEvent player_event;
PlayerEventLogsRepository::PlayerEventLogs player_event_log;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(player_event),
CEREAL_NVP(player_event_log)
);
}
};
// used in events with no extra data
struct EmptyEvent {
std::string noop; // noop, gets discard upstream
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(noop)
);
}
};
// used in Trade event
struct ItemCreationEvent {
int64 item_id;
std::string item_name;
uint16 to_slot;
int16 charges;
uint32 aug1;
uint32 aug2;
uint32 aug3;
uint32 aug4;
uint32 aug5;
uint32 aug6;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(to_slot),
CEREAL_NVP(charges),
CEREAL_NVP(aug1),
CEREAL_NVP(aug2),
CEREAL_NVP(aug3),
CEREAL_NVP(aug4),
CEREAL_NVP(aug5),
CEREAL_NVP(aug6),
CEREAL_NVP(attuned)
);
}
};
// used in Trade event
struct TradeItem {
int64 item_id;
std::string item_name;
int32 slot;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot)
);
}
};
// used in Trade event
class TradeItemEntry {
public:
uint16 slot;
uint32 item_id;
std::string item_name;
uint16 charges;
uint32 aug_1_item_id;
std::string aug_1_item_name;
uint32 aug_2_item_id;
std::string aug_2_item_name;
uint32 aug_3_item_id;
std::string aug_3_item_name;
uint32 aug_4_item_id;
std::string aug_4_item_name;
uint32 aug_5_item_id;
std::string aug_5_item_name;
uint32 aug_6_item_id;
std::string aug_6_item_name;
bool in_bag;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id),
CEREAL_NVP(charges),
CEREAL_NVP(aug_1_item_id),
CEREAL_NVP(aug_2_item_id),
CEREAL_NVP(aug_3_item_id),
CEREAL_NVP(aug_4_item_id),
CEREAL_NVP(aug_5_item_id),
CEREAL_NVP(in_bag)
);
}
};
/**
* Events
*/
struct Money {
int32 platinum;
int32 gold;
int32 silver;
int32 copper;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(platinum),
CEREAL_NVP(gold),
CEREAL_NVP(silver),
CEREAL_NVP(copper)
);
}
};
struct TradeEvent {
uint32 character_1_id;
std::string character_1_name;
uint32 character_2_id;
std::string character_2_name;
Money character_1_give_money;
Money character_2_give_money;
std::vector<TradeItemEntry> character_1_give_items;
std::vector<TradeItemEntry> character_2_give_items;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(character_1_id),
CEREAL_NVP(character_1_name),
CEREAL_NVP(character_2_id),
CEREAL_NVP(character_2_name),
CEREAL_NVP(character_1_give_money),
CEREAL_NVP(character_2_give_money),
CEREAL_NVP(character_1_give_items),
CEREAL_NVP(character_2_give_items)
);
}
};
struct GMCommandEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ZoningEvent {
std::string from_zone_long_name;
std::string from_zone_short_name;
int32 from_zone_id;
int32 from_instance_id;
int32 from_instance_version;
std::string to_zone_long_name;
std::string to_zone_short_name;
int32 to_zone_id;
int32 to_instance_id;
int32 to_instance_version;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_zone_long_name),
CEREAL_NVP(from_zone_short_name),
CEREAL_NVP(from_zone_id),
CEREAL_NVP(from_instance_id),
CEREAL_NVP(from_instance_version),
CEREAL_NVP(to_zone_long_name),
CEREAL_NVP(to_zone_short_name),
CEREAL_NVP(to_zone_id),
CEREAL_NVP(to_instance_id),
CEREAL_NVP(to_instance_version)
);
}
};
struct AAGainedEvent {
uint32 aa_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(CEREAL_NVP(aa_gained));
}
};
struct AAPurchasedEvent {
uint32 aa_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(aa_id),
CEREAL_NVP(aa_cost),
CEREAL_NVP(aa_previous_id),
CEREAL_NVP(aa_next_id)
);
}
};
struct ForageSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct FishSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct DestroyItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
std::string reason;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(reason),
CEREAL_NVP(charges)
);
}
};
struct LevelGainedEvent {
uint32 from_level;
uint8 to_level;
int levels_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_gained)
);
}
};
struct LevelLostEvent {
uint32 from_level;
uint8 to_level;
int levels_lost;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_lost)
);
}
};
struct LootItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 npc_id;
std::string corpse_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
}
};
struct MerchantPurchaseEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct MerchantSellEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct SkillUpEvent {
uint32 skill_id;
int value;
int16 max_skill;
std::string against_who;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(skill_id),
CEREAL_NVP(value),
CEREAL_NVP(max_skill),
CEREAL_NVP(against_who)
);
}
};
struct TaskAcceptEvent {
uint32 npc_id;
std::string npc_name;
uint32 task_id;
std::string task_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(task_id),
CEREAL_NVP(task_name)
);
}
};
struct TaskUpdateEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct TaskCompleteEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct GroundSpawnPickupEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct SayEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ResurrectAcceptEvent {
std::string resurrecter_name;
std::string spell_name;
uint32 spell_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(resurrecter_name),
CEREAL_NVP(spell_name),
CEREAL_NVP(spell_id)
);
}
};
struct CombineEvent {
uint32 recipe_id;
std::string recipe_name;
uint32 made_count;
uint32 tradeskill_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(recipe_id),
CEREAL_NVP(recipe_name),
CEREAL_NVP(made_count),
CEREAL_NVP(tradeskill_id)
);
}
};
struct DroppedItemEvent {
uint32 item_id;
std::string item_name;
int16 slot_id;
uint32 charges;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
);
}
};
struct DeathEvent {
uint32 killer_id;
std::string killer_name;
int64 damage;
uint32 spell_id;
std::string spell_name;
int skill_id;
std::string skill_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(killer_id),
CEREAL_NVP(killer_name),
CEREAL_NVP(damage),
CEREAL_NVP(spell_id),
CEREAL_NVP(spell_name),
CEREAL_NVP(skill_id),
CEREAL_NVP(skill_name)
);
}
};
struct SplitMoneyEvent {
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderPurchaseEvent {
uint32 item_id;
std::string item_name;
uint32 trader_id;
std::string trader_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderSellEvent {
uint32 item_id;
std::string item_name;
uint32 buyer_id;
std::string buyer_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct DiscoverItemEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
class HandinEntry {
public:
uint32 item_id;
std::string item_name;
uint16 charges;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(attuned)
);
}
};
class HandinMoney {
public:
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum)
);
}
};
struct HandinEvent {
uint32 npc_id;
std::string npc_name;
std::vector<HandinEntry> handin_items;
HandinMoney handin_money;
std::vector<HandinEntry> return_items;
HandinMoney return_money;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(handin_items),
CEREAL_NVP(handin_money),
CEREAL_NVP(return_items),
CEREAL_NVP(return_money)
);
}
};
struct PossibleHackEvent {
std::string message;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message)
);
}
};
struct KilledNPCEvent {
uint32 npc_id;
std::string npc_name;
uint32 combat_time_seconds;
uint64 total_damage_per_second_taken;
uint64 total_heal_per_second_taken;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(combat_time_seconds),
CEREAL_NVP(total_damage_per_second_taken),
CEREAL_NVP(total_heal_per_second_taken)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
#define RecordPlayerEventLog(event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
+1 -1
View File
@@ -132,7 +132,7 @@ enum { //reuse times
InstillDoubtReuseTime = 9,
FishingReuseTime = 11,
ForagingReuseTime = 50,
MendReuseTime = 290,
MendReuseTime = 360,
BashReuseTime = 5,
BackstabReuseTime = 9,
KickReuseTime = 5,
+17 -21
View File
@@ -61,7 +61,7 @@ bool BaseGuildManager::LoadGuilds() {
}
for (auto row=results.begin();row!=results.end();++row)
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
_CreateGuild(Strings::ToUnsignedInt(row[0]), row[1], Strings::ToUnsignedInt(row[2]), Strings::ToUnsignedInt(row[3]), row[4], row[5], row[6], row[7]);
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount())));
@@ -75,8 +75,8 @@ bool BaseGuildManager::LoadGuilds() {
for (auto row=results.begin();row!=results.end();++row)
{
uint32 guild_id = atoi(row[0]);
uint8 rankn = atoi(row[1]);
uint32 guild_id = Strings::ToUnsignedInt(row[0]);
uint8 rankn = Strings::ToUnsignedInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -131,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
auto row = results.begin();
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
info = _CreateGuild(guild_id, row[0], Strings::ToUnsignedInt(row[1]), Strings::ToUnsignedInt(row[2]), row[3], row[4], row[5], row[6]);
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
@@ -144,7 +144,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
for (auto row=results.begin();row!=results.end();++row)
{
uint8 rankn = atoi(row[1]);
uint8 rankn = Strings::ToUnsignedInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -787,9 +787,7 @@ bool BaseGuildManager::GetBankerFlag(uint32 CharID)
auto row = results.begin();
bool IsBanker = atoi(row[0]);
return IsBanker;
return Strings::ToBool(row[0]);
}
bool BaseGuildManager::DBSetAltFlag(uint32 charid, bool is_alt)
@@ -817,9 +815,7 @@ bool BaseGuildManager::GetAltFlag(uint32 CharID)
auto row = results.begin();
bool IsAlt = atoi(row[0]);
return IsAlt;
return Strings::ToBool(row[0]);
}
bool BaseGuildManager::DBSetTributeFlag(uint32 charid, bool enabled) {
@@ -873,19 +869,19 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
//fields from `characer_`
into.char_id = atoi(row[0]);
into.char_id = Strings::ToUnsignedInt(row[0]);
into.char_name = row[1];
into.class_ = atoi(row[2]);
into.level = atoi(row[3]);
into.time_last_on = atoul(row[4]);
into.zone_id = atoi(row[5]);
into.class_ = Strings::ToUnsignedInt(row[2]);
into.level = Strings::ToUnsignedInt(row[3]);
into.time_last_on = Strings::ToUnsignedInt(row[4]);
into.zone_id = Strings::ToUnsignedInt(row[5]);
//fields from `guild_members`, leave at defaults if missing
into.guild_id = row[6] ? atoi(row[6]) : GUILD_NONE;
into.rank = row[7] ? atoi(row[7]) : (GUILD_MAX_RANK+1);
into.guild_id = row[6] ? Strings::ToUnsignedInt(row[6]) : GUILD_NONE;
into.rank = row[7] ? Strings::ToUnsignedInt(row[7]) : (GUILD_MAX_RANK+1);
into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false;
into.total_tribute = row[9] ? atoi(row[9]) : 0;
into.last_tribute = row[10]? atoul(row[10]) : 0; //timestamp
into.total_tribute = row[9] ? Strings::ToUnsignedInt(row[9]) : 0;
into.last_tribute = row[10]? Strings::ToUnsignedInt(row[10]) : 0; //timestamp
into.banker = row[11]? (row[11][0] == '0'?false:true) : false;
into.public_note = row[12]? row[12] : "";
into.alt = row[13]? (row[13][0] == '0'?false:true) : false;
@@ -1258,7 +1254,7 @@ uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
}
auto row = results.begin();
auto guild_id = std::stoul(row[0]);
auto guild_id = Strings::ToUnsignedInt(row[0]);
return guild_id;
}
+8 -6
View File
@@ -272,6 +272,8 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
#include <brotli/encode.h>
#endif
#include "../strings.h"
/*
* Declaration
*/
@@ -3812,12 +3814,12 @@ inline bool brotli_decompressor::decompress(const char *data,
if (std::regex_match(b, e, cm, re_another_range)) {
ssize_t first = -1;
if (!cm.str(1).empty()) {
first = static_cast<ssize_t>(std::stoll(cm.str(1)));
first = static_cast<ssize_t>(Strings::ToBigInt(cm.str(1)));
}
ssize_t last = -1;
if (!cm.str(2).empty()) {
last = static_cast<ssize_t>(std::stoll(cm.str(2)));
last = static_cast<ssize_t>(Strings::ToBigInt(cm.str(2)));
}
if (first != -1 && last != -1 && first > last) {
@@ -6688,7 +6690,7 @@ static WSInit wsinit_;
if (params.empty()) { return Get(path, headers); }
std::string path_with_query = append_query_params(path, params);
return Get(path_with_query.c_str(), headers, progress);
return Get(path_with_query, headers, progress);
}
inline Result ClientImpl::Get(const std::string &path, const Params &params,
@@ -6708,7 +6710,7 @@ static WSInit wsinit_;
}
std::string path_with_query = append_query_params(path, params);
return Get(path_with_query.c_str(), headers, response_handler,
return Get(path_with_query, headers, response_handler,
content_receiver, progress);
}
@@ -6805,7 +6807,7 @@ static WSInit wsinit_;
std::string content_type;
const auto &body = detail::serialize_multipart_formdata(
items, detail::make_multipart_data_boundary(), content_type);
return Post(path, headers, body, content_type.c_str());
return Post(path, headers, body, content_type);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
@@ -6818,7 +6820,7 @@ static WSInit wsinit_;
std::string content_type;
const auto &body =
detail::serialize_multipart_formdata(items, boundary, content_type);
return Post(path, headers, body, content_type.c_str());
return Post(path, headers, body, content_type);
}
inline Result ClientImpl::Put(const std::string &path) {
+6 -6
View File
@@ -203,12 +203,12 @@ namespace EQ
void dumpBankItems();
void dumpSharedBankItems();
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, std::string value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, std::string identifier, bool value);
std::string GetCustomItemData(int16 slot_id, std::string identifier);
static const int GetItemStatValue(uint32 item_id, std::string identifier);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, const std::string& value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, int value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, float value);
void SetCustomItemData(uint32 character_id, int16 slot_id, const std::string &identifier, bool value);
std::string GetCustomItemData(int16 slot_id, const std::string& identifier);
static const int GetItemStatValue(uint32 item_id, const std::string& identifier);
protected:
///////////////////////////////
// Protected Methods
+3 -3
View File
@@ -131,7 +131,7 @@ namespace EQ
Mounts?
Ornamentations?
GuildBanners?
Collectible?
Collectible?
Placeable?
(others?)
*/
@@ -449,8 +449,8 @@ namespace EQ
int8 Shielding; // PoP: Shielding %
int8 StunResist; // PoP: Stun Resist %
int8 StrikeThrough; // PoP: Strike Through %
uint32 ExtraDmgSkill;
uint32 ExtraDmgAmt;
int32 ExtraDmgSkill;
int32 ExtraDmgAmt;
int8 SpellShield; // PoP: Spell Shield %
int8 Avoidance; // PoP: Avoidance +
int8 Accuracy; // PoP: Accuracy +
+37 -12
View File
@@ -358,15 +358,27 @@ int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
}
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
{
if (!m_item || !m_item->IsClassCommon())
return false;
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
if (
(
!GetItem(slot) &&
m_item->AugSlotVisible[slot]
) &&
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
)
) {
return true;
}
return false;
return false;
}
// Retrieve item inside container
@@ -598,7 +610,7 @@ bool EQ::ItemInstance::UpdateOrnamentationInfo() {
SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
if (strlen(ornamentItem->IDFile) > 2)
{
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
SetOrnamentationIDFile(Strings::ToUnsignedInt(&ornamentItem->IDFile[2]));
}
else
{
@@ -828,7 +840,20 @@ std::string EQ::ItemInstance::GetCustomDataString() const {
return ret_val;
}
std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
void EQ::ItemInstance::SetCustomDataString(const std::string& str)
{
auto components = Strings::Split(str, "^");
auto value_count = components.size() / 2;
for (auto i = 0; i < value_count; i++) {
auto identifier = components[i * 2];
auto value = components[(i * 2) + 1];
SetCustomData(identifier, value);
}
}
std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) {
return iter->second;
@@ -837,33 +862,33 @@ std::string EQ::ItemInstance::GetCustomData(std::string identifier) {
return "";
}
void EQ::ItemInstance::SetCustomData(std::string identifier, std::string value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, const std::string& value) {
DeleteCustomData(identifier);
m_custom_data[identifier] = value;
}
void EQ::ItemInstance::SetCustomData(std::string identifier, int value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, int value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::SetCustomData(std::string identifier, float value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, float value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::SetCustomData(std::string identifier, bool value) {
void EQ::ItemInstance::SetCustomData(const std::string& identifier, bool value) {
DeleteCustomData(identifier);
std::stringstream ss;
ss << value;
m_custom_data[identifier] = ss.str();
}
void EQ::ItemInstance::DeleteCustomData(std::string identifier) {
void EQ::ItemInstance::DeleteCustomData(const std::string& identifier) {
auto iter = m_custom_data.find(identifier);
if (iter != m_custom_data.end()) {
m_custom_data.erase(iter);
+9 -8
View File
@@ -101,8 +101,8 @@ namespace EQ
//
bool IsAugmentable() const;
bool AvailableWearSlot(uint32 aug_wear_slots) const;
int8 AvailableAugmentSlot(int32 augtype) const;
bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const;
int8 AvailableAugmentSlot(int32 augment_type) const;
bool IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const;
inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); }
inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); }
@@ -175,12 +175,13 @@ namespace EQ
void SetAttuned(bool flag) { m_attuned = flag; }
std::string GetCustomDataString() const;
std::string GetCustomData(std::string identifier);
void SetCustomData(std::string identifier, std::string value);
void SetCustomData(std::string identifier, int value);
void SetCustomData(std::string identifier, float value);
void SetCustomData(std::string identifier, bool value);
void DeleteCustomData(std::string identifier);
std::string GetCustomData(const std::string &identifier);
void SetCustomDataString(const std::string& str);
void SetCustomData(const std::string &identifier, const std::string& value);
void SetCustomData(const std::string &identifier, int value);
void SetCustomData(const std::string &identifier, float value);
void SetCustomData(const std::string &identifier, bool value);
void DeleteCustomData(const std::string& identifier);
// Allows treatment of this object as though it were a pointer to m_item
operator bool() const { return (m_item != nullptr); }
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -18,6 +18,7 @@
#include "misc.h"
#include "types.h"
#include <cstring>
#include "strings.h"
std::map<int,std::string> DBFieldNames;
@@ -150,7 +151,7 @@ static char *temp=nullptr;
return false;
}
ptr++;
uint32 id = atoi(field[id_pos].c_str());
uint32 id = Strings::ToUnsignedInt(field[id_pos]);
items[id]=field;
for(i=0;i<10;i++) {
+2 -1
View File
@@ -21,6 +21,7 @@
#include "misc_functions.h"
#include <string.h>
#include <time.h>
#include "strings.h"
#ifndef WIN32
#include <netinet/in.h>
@@ -130,7 +131,7 @@ bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf
if (*oIP == 0)
return false;
if (oPort)
*oPort = atoi(sep.arg[1]);
*oPort = Strings::ToUnsignedInt(sep.arg[1]);
return true;
}
return false;
+4 -4
View File
@@ -1050,7 +1050,7 @@ namespace RoF
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -1069,7 +1069,7 @@ namespace RoF
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -1099,7 +1099,7 @@ namespace RoF
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -1169,7 +1169,7 @@ namespace RoF
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
+4 -4
View File
@@ -1101,7 +1101,7 @@ namespace RoF2
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -1120,7 +1120,7 @@ namespace RoF2
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -1150,7 +1150,7 @@ namespace RoF2
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -1220,7 +1220,7 @@ namespace RoF2
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
+2 -2
View File
@@ -2590,7 +2590,7 @@ struct GroupUpdate_Struct_Live { // New for Live
struct GroupMembers_Struct { // New for Live
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2600,7 +2600,7 @@ struct GroupJoin_Struct_Live { // New for Live
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0
+2 -2
View File
@@ -2566,7 +2566,7 @@ struct GroupUpdate_Struct_Live { // New for Live
struct GroupMembers_Struct { // New for Live
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2576,7 +2576,7 @@ struct GroupJoin_Struct_Live { // New for Live
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0
+4 -4
View File
@@ -785,7 +785,7 @@ namespace SoD
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -804,7 +804,7 @@ namespace SoD
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -834,7 +834,7 @@ namespace SoD
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -902,7 +902,7 @@ namespace SoD
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
+2 -2
View File
@@ -2085,7 +2085,7 @@ struct GroupUpdate_Struct_SoD { // New for SoD
struct GroupMembers_Struct { // New for SoD
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2095,7 +2095,7 @@ struct GroupJoin_Struct_SoD { // New for SoD
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0
+3 -3
View File
@@ -2095,13 +2095,13 @@ namespace SoF
}
else
{
val = atoi(&emu->lastName[2]);
val = Strings::ToInt(&emu->lastName[2]);
}
}
else
{
sep[0] = nullptr;
ofs = atoi(&emu->lastName[2]);
ofs = Strings::ToInt(&emu->lastName[2]);
sep[0] = '=';
if ((sep[1] < '0') || (sep[1] > '9'))
{
@@ -2109,7 +2109,7 @@ namespace SoF
}
else
{
val = atoi(&sep[1]);
val = Strings::ToInt(&sep[1]);
}
}
+4 -4
View File
@@ -927,7 +927,7 @@ namespace UF
{
if ((gjs->action == groupActDisband) || !strcmp(gjs->yourname, gjs->membername))
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct));
@@ -947,7 +947,7 @@ namespace UF
return;
}
//if(gjs->action == groupActLeave)
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
// Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
auto outapp =
new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct));
@@ -977,7 +977,7 @@ namespace UF
for (int i = 0; i < 5; ++i)
{
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->membername[i]);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Membername[%i] is %s", i, gu2->member_name[i]);
if (gu2->membername[i][0] != '\0')
{
PacketLength += (22 + strlen(gu2->membername[i]) + 1);
@@ -1045,7 +1045,7 @@ namespace UF
delete in;
return;
}
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, membername = %s", gjs->yourname, gjs->membername);
//Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Generic GroupUpdate, yourname = %s, member_name = %s", gjs->yourname, gjs->member_name);
ENCODE_LENGTH_EXACT(GroupJoin_Struct);
SETUP_DIRECT_ENCODE(GroupJoin_Struct, structs::GroupJoin_Struct);
+2 -2
View File
@@ -2128,7 +2128,7 @@ struct GroupUpdate_Struct_Underfoot { // New for Underfoot
struct GroupMembers_Struct { // New for Underfoot
/*0000*/ uint32 membernumber; // Guess - number of member in the group (0 to 5?)
/*0000*/ //char membername[0]; // Member Name Null Terminated
/*0000*/ //char member_name[0]; // Member Name Null Terminated
/*0000*/ uint8 unknown001[3]; // Seen 0
/*0000*/ uint32 memberlevel; // Guess
/*0000*/ uint8 unknown002[11]; // Seen 0
@@ -2138,7 +2138,7 @@ struct GroupJoin_Struct_Underfoot { // New for Underfoot
/*0000*/ uint32 unknown0000; // Matches unknown0136 from GroupFollow_Struct
/*0004*/ uint32 action;
/*0008*/ uint8 unknown0008[5]; // Seen 0
/*0013*/ //char membername[0]; // Null Terminated?
/*0013*/ //char member_name[0]; // Null Terminated?
/*0000*/ uint8 unknown0013[3]; // Seen 0
/*0000*/ uint32 unknown0016; // Matches unknown0132 from GroupFollow_Struct
/*0000*/ uint8 unknown0020[11]; // Seen 0
+16 -11
View File
@@ -22,26 +22,31 @@
EQEmuExePlatform exe_platform = ExePlatformNone;
void RegisterExecutablePlatform(EQEmuExePlatform p) {
void RegisterExecutablePlatform(EQEmuExePlatform p)
{
exe_platform = p;
}
const EQEmuExePlatform& GetExecutablePlatform() {
const EQEmuExePlatform &GetExecutablePlatform()
{
return exe_platform;
}
/**
* @return
*/
int GetExecutablePlatformInt(){
int GetExecutablePlatformInt()
{
return exe_platform;
}
/**
* Returns platform name by string
*
* @return
*/
bool IsWorld()
{
return exe_platform == EQEmuExePlatform::ExePlatformWorld;
}
bool IsQueryServ()
{
return exe_platform == EQEmuExePlatform::ExePlatformQueryServ;
}
std::string GetPlatformName()
{
switch (GetExecutablePlatformInt()) {
+2
View File
@@ -44,5 +44,7 @@ void RegisterExecutablePlatform(EQEmuExePlatform p);
const EQEmuExePlatform& GetExecutablePlatform();
int GetExecutablePlatformInt();
std::string GetPlatformName();
bool IsWorld();
bool IsQueryServ();
#endif
+3 -3
View File
@@ -288,9 +288,9 @@ bool PTimerList::Load(Database *db) {
PersistentTimer *cur;
for (auto row = results.begin(); row != results.end(); ++row) {
type = atoi(row[0]);
start_time = strtoul(row[1], nullptr, 10);
timer_time = strtoul(row[2], nullptr, 10);
type = Strings::ToUnsignedInt(row[0]);
start_time = Strings::ToUnsignedInt(row[1]);
timer_time = Strings::ToUnsignedInt(row[2]);
enabled = (row[3][0] == '1');
//if it expired allready, dont bother.
@@ -69,6 +69,7 @@ public:
int32_t expansion_bitmask;
uint8_t enforce_spell_settings;
uint8_t archery_setting;
uint32_t caster_range;
};
static std::string PrimaryKey()
@@ -129,6 +130,7 @@ public:
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -185,6 +187,7 @@ public:
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -275,6 +278,7 @@ public:
e.expansion_bitmask = -1;
e.enforce_spell_settings = 0;
e.archery_setting = 0;
e.caster_range = 0;
return e;
}
@@ -361,6 +365,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
return e;
}
@@ -443,6 +448,7 @@ public:
v.push_back(columns[47] + " = " + std::to_string(e.expansion_bitmask));
v.push_back(columns[48] + " = " + std::to_string(e.enforce_spell_settings));
v.push_back(columns[49] + " = " + std::to_string(e.archery_setting));
v.push_back(columns[50] + " = " + std::to_string(e.caster_range));
auto results = db.QueryDatabase(
fmt::format(
@@ -514,6 +520,7 @@ public:
v.push_back(std::to_string(e.expansion_bitmask));
v.push_back(std::to_string(e.enforce_spell_settings));
v.push_back(std::to_string(e.archery_setting));
v.push_back(std::to_string(e.caster_range));
auto results = db.QueryDatabase(
fmt::format(
@@ -593,6 +600,7 @@ public:
v.push_back(std::to_string(e.expansion_bitmask));
v.push_back(std::to_string(e.enforce_spell_settings));
v.push_back(std::to_string(e.archery_setting));
v.push_back(std::to_string(e.caster_range));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -676,6 +684,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
all_entries.push_back(e);
}
@@ -750,6 +759,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
all_entries.push_back(e);
}
@@ -16,11 +16,12 @@
#include "../../strings.h"
#include <ctime>
class BaseDataBucketsRepository {
public:
struct DataBuckets {
uint64_t id;
std::string key;
std::string key_;
std::string value;
uint32_t expires;
};
@@ -34,7 +35,7 @@ public:
{
return {
"id",
"key",
"`key`",
"value",
"expires",
};
@@ -44,7 +45,7 @@ public:
{
return {
"id",
"key",
"`key`",
"value",
"expires",
};
@@ -88,7 +89,7 @@ public:
DataBuckets e{};
e.id = 0;
e.key = "";
e.key_ = "";
e.value = "";
e.expires = 0;
@@ -116,8 +117,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
data_buckets_id
)
);
@@ -127,7 +129,7 @@ public:
DataBuckets e{};
e.id = strtoull(row[0], nullptr, 10);
e.key = row[1] ? row[1] : "";
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
@@ -163,7 +165,7 @@ public:
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.key) + "'");
v.push_back(columns[1] + " = '" + Strings::Escape(e.key_) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.expires));
@@ -188,7 +190,7 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.key) + "'");
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
@@ -221,7 +223,7 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.key) + "'");
v.push_back("'" + Strings::Escape(e.key_) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back(std::to_string(e.expires));
@@ -258,7 +260,7 @@ public:
DataBuckets e{};
e.id = strtoull(row[0], nullptr, 10);
e.key = row[1] ? row[1] : "";
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
@@ -286,7 +288,7 @@ public:
DataBuckets e{};
e.id = strtoull(row[0], nullptr, 10);
e.key = row[1] ? row[1] : "";
e.key_ = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.expires = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
@@ -1,412 +0,0 @@
/**
* 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://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_EVENTLOG_REPOSITORY_H
#define EQEMU_BASE_EVENTLOG_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseEventlogRepository {
public:
struct Eventlog {
uint32_t id;
std::string accountname;
uint32_t accountid;
int32_t status;
std::string charname;
std::string target;
std::string time;
std::string descriptiontype;
std::string description;
int32_t event_nid;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"accountname",
"accountid",
"status",
"charname",
"target",
"time",
"descriptiontype",
"description",
"event_nid",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"accountname",
"accountid",
"status",
"charname",
"target",
"time",
"descriptiontype",
"description",
"event_nid",
};
}
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("eventlog");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Eventlog NewEntity()
{
Eventlog e{};
e.id = 0;
e.accountname = "";
e.accountid = 0;
e.status = 0;
e.charname = "";
e.target = "None";
e.time = std::time(nullptr);
e.descriptiontype = "";
e.description = "";
e.event_nid = 0;
return e;
}
static Eventlog GetEventlog(
const std::vector<Eventlog> &eventlogs,
int eventlog_id
)
{
for (auto &eventlog : eventlogs) {
if (eventlog.id == eventlog_id) {
return eventlog;
}
}
return NewEntity();
}
static Eventlog FindOne(
Database& db,
int eventlog_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
eventlog_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int eventlog_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
eventlog_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Eventlog &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.accountname) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.accountid));
v.push_back(columns[3] + " = " + std::to_string(e.status));
v.push_back(columns[4] + " = '" + Strings::Escape(e.charname) + "'");
v.push_back(columns[5] + " = '" + Strings::Escape(e.target) + "'");
v.push_back(columns[6] + " = '" + Strings::Escape(e.time) + "'");
v.push_back(columns[7] + " = '" + Strings::Escape(e.descriptiontype) + "'");
v.push_back(columns[8] + " = '" + Strings::Escape(e.description) + "'");
v.push_back(columns[9] + " = " + std::to_string(e.event_nid));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Eventlog InsertOne(
Database& db,
Eventlog e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.accountname) + "'");
v.push_back(std::to_string(e.accountid));
v.push_back(std::to_string(e.status));
v.push_back("'" + Strings::Escape(e.charname) + "'");
v.push_back("'" + Strings::Escape(e.target) + "'");
v.push_back("'" + Strings::Escape(e.time) + "'");
v.push_back("'" + Strings::Escape(e.descriptiontype) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.event_nid));
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<Eventlog> &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("'" + Strings::Escape(e.accountname) + "'");
v.push_back(std::to_string(e.accountid));
v.push_back(std::to_string(e.status));
v.push_back("'" + Strings::Escape(e.charname) + "'");
v.push_back("'" + Strings::Escape(e.target) + "'");
v.push_back("'" + Strings::Escape(e.time) + "'");
v.push_back("'" + Strings::Escape(e.descriptiontype) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.event_nid));
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<Eventlog> All(Database& db)
{
std::vector<Eventlog> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Eventlog> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Eventlog> 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) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
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);
}
};
#endif //EQEMU_BASE_EVENTLOG_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseMerchantlistRepository {
public:
struct Merchantlist {
@@ -24,6 +25,8 @@ public:
int32_t item;
int16_t faction_required;
uint8_t level_required;
uint8_t min_status;
uint8_t max_status;
uint16_t alt_currency_cost;
int32_t classes_required;
int32_t probability;
@@ -49,6 +52,8 @@ public:
"item",
"faction_required",
"level_required",
"min_status",
"max_status",
"alt_currency_cost",
"classes_required",
"probability",
@@ -70,6 +75,8 @@ public:
"item",
"faction_required",
"level_required",
"min_status",
"max_status",
"alt_currency_cost",
"classes_required",
"probability",
@@ -125,6 +132,8 @@ public:
e.item = 0;
e.faction_required = -100;
e.level_required = 0;
e.min_status = 0;
e.max_status = 255;
e.alt_currency_cost = 0;
e.classes_required = 65535;
e.probability = 100;
@@ -160,8 +169,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
merchantlist_id
)
);
@@ -175,16 +185,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
return e;
}
@@ -223,16 +235,18 @@ public:
v.push_back(columns[2] + " = " + std::to_string(e.item));
v.push_back(columns[3] + " = " + std::to_string(e.faction_required));
v.push_back(columns[4] + " = " + std::to_string(e.level_required));
v.push_back(columns[5] + " = " + std::to_string(e.alt_currency_cost));
v.push_back(columns[6] + " = " + std::to_string(e.classes_required));
v.push_back(columns[7] + " = " + std::to_string(e.probability));
v.push_back(columns[8] + " = '" + Strings::Escape(e.bucket_name) + "'");
v.push_back(columns[9] + " = '" + Strings::Escape(e.bucket_value) + "'");
v.push_back(columns[10] + " = " + std::to_string(e.bucket_comparison));
v.push_back(columns[11] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[12] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[13] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[14] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.min_status));
v.push_back(columns[6] + " = " + std::to_string(e.max_status));
v.push_back(columns[7] + " = " + std::to_string(e.alt_currency_cost));
v.push_back(columns[8] + " = " + std::to_string(e.classes_required));
v.push_back(columns[9] + " = " + std::to_string(e.probability));
v.push_back(columns[10] + " = '" + Strings::Escape(e.bucket_name) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.bucket_value) + "'");
v.push_back(columns[12] + " = " + std::to_string(e.bucket_comparison));
v.push_back(columns[13] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[14] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[16] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -259,6 +273,8 @@ public:
v.push_back(std::to_string(e.item));
v.push_back(std::to_string(e.faction_required));
v.push_back(std::to_string(e.level_required));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.max_status));
v.push_back(std::to_string(e.alt_currency_cost));
v.push_back(std::to_string(e.classes_required));
v.push_back(std::to_string(e.probability));
@@ -303,6 +319,8 @@ public:
v.push_back(std::to_string(e.item));
v.push_back(std::to_string(e.faction_required));
v.push_back(std::to_string(e.level_required));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.max_status));
v.push_back(std::to_string(e.alt_currency_cost));
v.push_back(std::to_string(e.classes_required));
v.push_back(std::to_string(e.probability));
@@ -351,16 +369,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -390,16 +410,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -16,13 +16,16 @@
#include "../../strings.h"
#include <ctime>
class BaseNpcScaleGlobalBaseRepository {
public:
struct NpcScaleGlobalBase {
int32_t type;
int32_t level;
std::string zone_id_list;
std::string instance_version_list;
int32_t ac;
int32_t hp;
int64_t hp;
int32_t accuracy;
int32_t slow_mitigation;
int32_t attack;
@@ -42,10 +45,13 @@ public:
int32_t physical_resist;
int32_t min_dmg;
int32_t max_dmg;
int32_t hp_regen_rate;
int64_t hp_regen_rate;
int64_t hp_regen_per_second;
int32_t attack_delay;
int32_t spell_scale;
int32_t heal_scale;
uint32_t avoidance;
int32_t heroic_strikethrough;
std::string special_abilities;
};
@@ -59,6 +65,8 @@ public:
return {
"type",
"level",
"zone_id_list",
"instance_version_list",
"ac",
"hp",
"accuracy",
@@ -81,9 +89,12 @@ public:
"min_dmg",
"max_dmg",
"hp_regen_rate",
"hp_regen_per_second",
"attack_delay",
"spell_scale",
"heal_scale",
"avoidance",
"heroic_strikethrough",
"special_abilities",
};
}
@@ -93,6 +104,8 @@ public:
return {
"type",
"level",
"zone_id_list",
"instance_version_list",
"ac",
"hp",
"accuracy",
@@ -115,9 +128,12 @@ public:
"min_dmg",
"max_dmg",
"hp_regen_rate",
"hp_regen_per_second",
"attack_delay",
"spell_scale",
"heal_scale",
"avoidance",
"heroic_strikethrough",
"special_abilities",
};
}
@@ -159,34 +175,39 @@ public:
{
NpcScaleGlobalBase e{};
e.type = 0;
e.level = 0;
e.ac = 0;
e.hp = 0;
e.accuracy = 0;
e.slow_mitigation = 0;
e.attack = 0;
e.strength = 0;
e.stamina = 0;
e.dexterity = 0;
e.agility = 0;
e.intelligence = 0;
e.wisdom = 0;
e.charisma = 0;
e.magic_resist = 0;
e.cold_resist = 0;
e.fire_resist = 0;
e.poison_resist = 0;
e.disease_resist = 0;
e.corruption_resist = 0;
e.physical_resist = 0;
e.min_dmg = 0;
e.max_dmg = 0;
e.hp_regen_rate = 0;
e.attack_delay = 0;
e.spell_scale = 100;
e.heal_scale = 100;
e.special_abilities = "";
e.type = 0;
e.level = 0;
e.zone_id_list = "";
e.instance_version_list = "";
e.ac = 0;
e.hp = 0;
e.accuracy = 0;
e.slow_mitigation = 0;
e.attack = 0;
e.strength = 0;
e.stamina = 0;
e.dexterity = 0;
e.agility = 0;
e.intelligence = 0;
e.wisdom = 0;
e.charisma = 0;
e.magic_resist = 0;
e.cold_resist = 0;
e.fire_resist = 0;
e.poison_resist = 0;
e.disease_resist = 0;
e.corruption_resist = 0;
e.physical_resist = 0;
e.min_dmg = 0;
e.max_dmg = 0;
e.hp_regen_rate = 0;
e.hp_regen_per_second = 0;
e.attack_delay = 0;
e.spell_scale = 100;
e.heal_scale = 100;
e.avoidance = 0;
e.heroic_strikethrough = 0;
e.special_abilities = "";
return e;
}
@@ -212,8 +233,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
npc_scale_global_base_id
)
);
@@ -222,34 +244,39 @@ public:
if (results.RowCount() == 1) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = strtoll(row[5], nullptr, 10);
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = strtoll(row[25], nullptr, 10);
e.hp_regen_per_second = strtoll(row[26], nullptr, 10);
e.attack_delay = static_cast<int32_t>(atoi(row[27]));
e.spell_scale = static_cast<int32_t>(atoi(row[28]));
e.heal_scale = static_cast<int32_t>(atoi(row[29]));
e.avoidance = static_cast<uint32_t>(strtoul(row[30], nullptr, 10));
e.heroic_strikethrough = static_cast<int32_t>(atoi(row[31]));
e.special_abilities = row[32] ? row[32] : "";
return e;
}
@@ -285,32 +312,37 @@ public:
v.push_back(columns[0] + " = " + std::to_string(e.type));
v.push_back(columns[1] + " = " + std::to_string(e.level));
v.push_back(columns[2] + " = " + std::to_string(e.ac));
v.push_back(columns[3] + " = " + std::to_string(e.hp));
v.push_back(columns[4] + " = " + std::to_string(e.accuracy));
v.push_back(columns[5] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[6] + " = " + std::to_string(e.attack));
v.push_back(columns[7] + " = " + std::to_string(e.strength));
v.push_back(columns[8] + " = " + std::to_string(e.stamina));
v.push_back(columns[9] + " = " + std::to_string(e.dexterity));
v.push_back(columns[10] + " = " + std::to_string(e.agility));
v.push_back(columns[11] + " = " + std::to_string(e.intelligence));
v.push_back(columns[12] + " = " + std::to_string(e.wisdom));
v.push_back(columns[13] + " = " + std::to_string(e.charisma));
v.push_back(columns[14] + " = " + std::to_string(e.magic_resist));
v.push_back(columns[15] + " = " + std::to_string(e.cold_resist));
v.push_back(columns[16] + " = " + std::to_string(e.fire_resist));
v.push_back(columns[17] + " = " + std::to_string(e.poison_resist));
v.push_back(columns[18] + " = " + std::to_string(e.disease_resist));
v.push_back(columns[19] + " = " + std::to_string(e.corruption_resist));
v.push_back(columns[20] + " = " + std::to_string(e.physical_resist));
v.push_back(columns[21] + " = " + std::to_string(e.min_dmg));
v.push_back(columns[22] + " = " + std::to_string(e.max_dmg));
v.push_back(columns[23] + " = " + std::to_string(e.hp_regen_rate));
v.push_back(columns[24] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[25] + " = " + std::to_string(e.spell_scale));
v.push_back(columns[26] + " = " + std::to_string(e.heal_scale));
v.push_back(columns[27] + " = '" + Strings::Escape(e.special_abilities) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.ac));
v.push_back(columns[5] + " = " + std::to_string(e.hp));
v.push_back(columns[6] + " = " + std::to_string(e.accuracy));
v.push_back(columns[7] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[8] + " = " + std::to_string(e.attack));
v.push_back(columns[9] + " = " + std::to_string(e.strength));
v.push_back(columns[10] + " = " + std::to_string(e.stamina));
v.push_back(columns[11] + " = " + std::to_string(e.dexterity));
v.push_back(columns[12] + " = " + std::to_string(e.agility));
v.push_back(columns[13] + " = " + std::to_string(e.intelligence));
v.push_back(columns[14] + " = " + std::to_string(e.wisdom));
v.push_back(columns[15] + " = " + std::to_string(e.charisma));
v.push_back(columns[16] + " = " + std::to_string(e.magic_resist));
v.push_back(columns[17] + " = " + std::to_string(e.cold_resist));
v.push_back(columns[18] + " = " + std::to_string(e.fire_resist));
v.push_back(columns[19] + " = " + std::to_string(e.poison_resist));
v.push_back(columns[20] + " = " + std::to_string(e.disease_resist));
v.push_back(columns[21] + " = " + std::to_string(e.corruption_resist));
v.push_back(columns[22] + " = " + std::to_string(e.physical_resist));
v.push_back(columns[23] + " = " + std::to_string(e.min_dmg));
v.push_back(columns[24] + " = " + std::to_string(e.max_dmg));
v.push_back(columns[25] + " = " + std::to_string(e.hp_regen_rate));
v.push_back(columns[26] + " = " + std::to_string(e.hp_regen_per_second));
v.push_back(columns[27] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[28] + " = " + std::to_string(e.spell_scale));
v.push_back(columns[29] + " = " + std::to_string(e.heal_scale));
v.push_back(columns[30] + " = " + std::to_string(e.avoidance));
v.push_back(columns[31] + " = " + std::to_string(e.heroic_strikethrough));
v.push_back(columns[32] + " = '" + Strings::Escape(e.special_abilities) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -334,6 +366,8 @@ public:
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.level));
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back("'" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(std::to_string(e.ac));
v.push_back(std::to_string(e.hp));
v.push_back(std::to_string(e.accuracy));
@@ -356,9 +390,12 @@ public:
v.push_back(std::to_string(e.min_dmg));
v.push_back(std::to_string(e.max_dmg));
v.push_back(std::to_string(e.hp_regen_rate));
v.push_back(std::to_string(e.hp_regen_per_second));
v.push_back(std::to_string(e.attack_delay));
v.push_back(std::to_string(e.spell_scale));
v.push_back(std::to_string(e.heal_scale));
v.push_back(std::to_string(e.avoidance));
v.push_back(std::to_string(e.heroic_strikethrough));
v.push_back("'" + Strings::Escape(e.special_abilities) + "'");
auto results = db.QueryDatabase(
@@ -391,6 +428,8 @@ public:
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.level));
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back("'" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(std::to_string(e.ac));
v.push_back(std::to_string(e.hp));
v.push_back(std::to_string(e.accuracy));
@@ -413,9 +452,12 @@ public:
v.push_back(std::to_string(e.min_dmg));
v.push_back(std::to_string(e.max_dmg));
v.push_back(std::to_string(e.hp_regen_rate));
v.push_back(std::to_string(e.hp_regen_per_second));
v.push_back(std::to_string(e.attack_delay));
v.push_back(std::to_string(e.spell_scale));
v.push_back(std::to_string(e.heal_scale));
v.push_back(std::to_string(e.avoidance));
v.push_back(std::to_string(e.heroic_strikethrough));
v.push_back("'" + Strings::Escape(e.special_abilities) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@@ -450,34 +492,39 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = strtoll(row[5], nullptr, 10);
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = strtoll(row[25], nullptr, 10);
e.hp_regen_per_second = strtoll(row[26], nullptr, 10);
e.attack_delay = static_cast<int32_t>(atoi(row[27]));
e.spell_scale = static_cast<int32_t>(atoi(row[28]));
e.heal_scale = static_cast<int32_t>(atoi(row[29]));
e.avoidance = static_cast<uint32_t>(strtoul(row[30], nullptr, 10));
e.heroic_strikethrough = static_cast<int32_t>(atoi(row[31]));
e.special_abilities = row[32] ? row[32] : "";
all_entries.push_back(e);
}
@@ -502,34 +549,39 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = strtoll(row[5], nullptr, 10);
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = strtoll(row[25], nullptr, 10);
e.hp_regen_per_second = strtoll(row[26], nullptr, 10);
e.attack_delay = static_cast<int32_t>(atoi(row[27]));
e.spell_scale = static_cast<int32_t>(atoi(row[28]));
e.heal_scale = static_cast<int32_t>(atoi(row[29]));
e.avoidance = static_cast<uint32_t>(strtoul(row[30], nullptr, 10));
e.heroic_strikethrough = static_cast<int32_t>(atoi(row[31]));
e.special_abilities = row[32] ? row[32] : "";
all_entries.push_back(e);
}
@@ -9,22 +9,21 @@
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_HACKERS_REPOSITORY_H
#define EQEMU_BASE_HACKERS_REPOSITORY_H
#ifndef EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseHackersRepository {
class BasePlayerEventLogSettingsRepository {
public:
struct Hackers {
int32_t id;
std::string account;
std::string name;
std::string hacked;
std::string zone;
std::string date;
struct PlayerEventLogSettings {
int64_t id;
std::string event_name;
int8_t event_enabled;
int32_t retention_days;
int32_t discord_webhook_id;
};
static std::string PrimaryKey()
@@ -36,11 +35,10 @@ public:
{
return {
"id",
"account",
"name",
"hacked",
"zone",
"date",
"event_name",
"event_enabled",
"retention_days",
"discord_webhook_id",
};
}
@@ -48,11 +46,10 @@ public:
{
return {
"id",
"account",
"name",
"hacked",
"zone",
"date",
"event_name",
"event_enabled",
"retention_days",
"discord_webhook_id",
};
}
@@ -68,7 +65,7 @@ public:
static std::string TableName()
{
return std::string("hackers");
return std::string("player_event_log_settings");
}
static std::string BaseSelect()
@@ -89,57 +86,56 @@ public:
);
}
static Hackers NewEntity()
static PlayerEventLogSettings NewEntity()
{
Hackers e{};
PlayerEventLogSettings e{};
e.id = 0;
e.account = "";
e.name = "";
e.hacked = "";
e.zone = "";
e.date = std::time(nullptr);
e.id = 0;
e.event_name = "";
e.event_enabled = 0;
e.retention_days = 0;
e.discord_webhook_id = 0;
return e;
}
static Hackers GetHackers(
const std::vector<Hackers> &hackerss,
int hackers_id
static PlayerEventLogSettings GetPlayerEventLogSettings(
const std::vector<PlayerEventLogSettings> &player_event_log_settingss,
int player_event_log_settings_id
)
{
for (auto &hackers : hackerss) {
if (hackers.id == hackers_id) {
return hackers;
for (auto &player_event_log_settings : player_event_log_settingss) {
if (player_event_log_settings.id == player_event_log_settings_id) {
return player_event_log_settings;
}
}
return NewEntity();
}
static Hackers FindOne(
static PlayerEventLogSettings FindOne(
Database& db,
int hackers_id
int player_event_log_settings_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
hackers_id
PrimaryKey(),
player_event_log_settings_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
return e;
}
@@ -149,7 +145,7 @@ public:
static int DeleteOne(
Database& db,
int hackers_id
int player_event_log_settings_id
)
{
auto results = db.QueryDatabase(
@@ -157,7 +153,7 @@ public:
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
hackers_id
player_event_log_settings_id
)
);
@@ -166,18 +162,18 @@ public:
static int UpdateOne(
Database& db,
const Hackers &e
const PlayerEventLogSettings &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.account) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.hacked) + "'");
v.push_back(columns[4] + " = '" + Strings::Escape(e.zone) + "'");
v.push_back(columns[5] + " = '" + Strings::Escape(e.date) + "'");
v.push_back(columns[0] + " = " + std::to_string(e.id));
v.push_back(columns[1] + " = '" + Strings::Escape(e.event_name) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.event_enabled));
v.push_back(columns[3] + " = " + std::to_string(e.retention_days));
v.push_back(columns[4] + " = " + std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -192,19 +188,18 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static Hackers InsertOne(
static PlayerEventLogSettings InsertOne(
Database& db,
Hackers e
PlayerEventLogSettings e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.account) + "'");
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back("'" + Strings::Escape(e.hacked) + "'");
v.push_back("'" + Strings::Escape(e.zone) + "'");
v.push_back("'" + Strings::Escape(e.date) + "'");
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -226,7 +221,7 @@ public:
static int InsertMany(
Database& db,
const std::vector<Hackers> &entries
const std::vector<PlayerEventLogSettings> &entries
)
{
std::vector<std::string> insert_chunks;
@@ -235,11 +230,10 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.account) + "'");
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back("'" + Strings::Escape(e.hacked) + "'");
v.push_back("'" + Strings::Escape(e.zone) + "'");
v.push_back("'" + Strings::Escape(e.date) + "'");
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -257,9 +251,9 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Hackers> All(Database& db)
static std::vector<PlayerEventLogSettings> All(Database& db)
{
std::vector<Hackers> all_entries;
std::vector<PlayerEventLogSettings> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -271,14 +265,13 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
all_entries.push_back(e);
}
@@ -286,9 +279,9 @@ public:
return all_entries;
}
static std::vector<Hackers> GetWhere(Database& db, const std::string &where_filter)
static std::vector<PlayerEventLogSettings> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Hackers> all_entries;
std::vector<PlayerEventLogSettings> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -301,14 +294,13 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
all_entries.push_back(e);
}
@@ -369,4 +361,4 @@ public:
};
#endif //EQEMU_BASE_HACKERS_REPOSITORY_H
#endif //EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -0,0 +1,465 @@
/**
* 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://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
#include <cereal/cereal.hpp>
class BasePlayerEventLogsRepository {
public:
struct PlayerEventLogs {
int64_t id;
int64_t account_id;
int64_t character_id;
int32_t zone_id;
int32_t instance_id;
float x;
float y;
float z;
float heading;
int32_t event_type_id;
std::string event_type_name;
std::string event_data;
time_t created_at;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(id),
CEREAL_NVP(account_id),
CEREAL_NVP(character_id),
CEREAL_NVP(zone_id),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading),
CEREAL_NVP(event_type_id),
CEREAL_NVP(event_type_name),
CEREAL_NVP(event_data),
CEREAL_NVP(created_at)
);
}
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"account_id",
"character_id",
"zone_id",
"instance_id",
"x",
"y",
"z",
"heading",
"event_type_id",
"event_type_name",
"event_data",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"account_id",
"character_id",
"zone_id",
"instance_id",
"x",
"y",
"z",
"heading",
"event_type_id",
"event_type_name",
"event_data",
"UNIX_TIMESTAMP(created_at)",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("player_event_logs");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventLogs NewEntity()
{
PlayerEventLogs e{};
e.id = 0;
e.account_id = 0;
e.character_id = 0;
e.zone_id = 0;
e.instance_id = 0;
e.x = 0;
e.y = 0;
e.z = 0;
e.heading = 0;
e.event_type_id = 0;
e.event_type_name = "";
e.event_data = "";
e.created_at = 0;
return e;
}
static PlayerEventLogs GetPlayerEventLogs(
const std::vector<PlayerEventLogs> &player_event_logss,
int player_event_logs_id
)
{
for (auto &player_event_logs : player_event_logss) {
if (player_event_logs.id == player_event_logs_id) {
return player_event_logs;
}
}
return NewEntity();
}
static PlayerEventLogs FindOne(
Database& db,
int player_event_logs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_logs_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_logs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_logs_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventLogs &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.account_id));
v.push_back(columns[2] + " = " + std::to_string(e.character_id));
v.push_back(columns[3] + " = " + std::to_string(e.zone_id));
v.push_back(columns[4] + " = " + std::to_string(e.instance_id));
v.push_back(columns[5] + " = " + std::to_string(e.x));
v.push_back(columns[6] + " = " + std::to_string(e.y));
v.push_back(columns[7] + " = " + std::to_string(e.z));
v.push_back(columns[8] + " = " + std::to_string(e.heading));
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static PlayerEventLogs InsertOne(
Database& db,
PlayerEventLogs e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<PlayerEventLogs> &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.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<PlayerEventLogs> All(Database& db)
{
std::vector<PlayerEventLogs> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventLogs> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventLogs> 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) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
@@ -16,11 +16,14 @@
#include "../../strings.h"
#include <ctime>
class BaseRaidMembersRepository {
public:
struct RaidMembers {
uint64_t id;
int32_t raidid;
int32_t charid;
int32_t bot_id;
uint32_t groupid;
int8_t _class;
int8_t level;
@@ -32,14 +35,16 @@ public:
static std::string PrimaryKey()
{
return std::string("charid");
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"raidid",
"charid",
"bot_id",
"groupid",
"_class",
"level",
@@ -53,8 +58,10 @@ public:
static std::vector<std::string> SelectColumns()
{
return {
"id",
"raidid",
"charid",
"bot_id",
"groupid",
"_class",
"level",
@@ -102,8 +109,10 @@ public:
{
RaidMembers e{};
e.id = 0;
e.raidid = 0;
e.charid = 0;
e.bot_id = 0;
e.groupid = 0;
e._class = 0;
e.level = 0;
@@ -121,7 +130,7 @@ public:
)
{
for (auto &raid_members : raid_memberss) {
if (raid_members.charid == raid_members_id) {
if (raid_members.id == raid_members_id) {
return raid_members;
}
}
@@ -136,8 +145,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
raid_members_id
)
);
@@ -146,15 +156,17 @@ public:
if (results.RowCount() == 1) {
RaidMembers e{};
e.raidid = static_cast<int32_t>(atoi(row[0]));
e.charid = static_cast<int32_t>(atoi(row[1]));
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[3]));
e.level = static_cast<int8_t>(atoi(row[4]));
e.name = row[5] ? row[5] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
e.israidleader = static_cast<int8_t>(atoi(row[7]));
e.islooter = static_cast<int8_t>(atoi(row[8]));
e.id = strtoull(row[0], nullptr, 10);
e.raidid = static_cast<int32_t>(atoi(row[1]));
e.charid = static_cast<int32_t>(atoi(row[2]));
e.bot_id = static_cast<int32_t>(atoi(row[3]));
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[5]));
e.level = static_cast<int8_t>(atoi(row[6]));
e.name = row[7] ? row[7] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
e.israidleader = static_cast<int8_t>(atoi(row[9]));
e.islooter = static_cast<int8_t>(atoi(row[10]));
return e;
}
@@ -188,15 +200,16 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.raidid));
v.push_back(columns[1] + " = " + std::to_string(e.charid));
v.push_back(columns[2] + " = " + std::to_string(e.groupid));
v.push_back(columns[3] + " = " + std::to_string(e._class));
v.push_back(columns[4] + " = " + std::to_string(e.level));
v.push_back(columns[5] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[6] + " = " + std::to_string(e.isgroupleader));
v.push_back(columns[7] + " = " + std::to_string(e.israidleader));
v.push_back(columns[8] + " = " + std::to_string(e.islooter));
v.push_back(columns[1] + " = " + std::to_string(e.raidid));
v.push_back(columns[2] + " = " + std::to_string(e.charid));
v.push_back(columns[3] + " = " + std::to_string(e.bot_id));
v.push_back(columns[4] + " = " + std::to_string(e.groupid));
v.push_back(columns[5] + " = " + std::to_string(e._class));
v.push_back(columns[6] + " = " + std::to_string(e.level));
v.push_back(columns[7] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[8] + " = " + std::to_string(e.isgroupleader));
v.push_back(columns[9] + " = " + std::to_string(e.israidleader));
v.push_back(columns[10] + " = " + std::to_string(e.islooter));
auto results = db.QueryDatabase(
fmt::format(
@@ -204,7 +217,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.charid
e.id
)
);
@@ -218,8 +231,10 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.raidid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e._class));
v.push_back(std::to_string(e.level));
@@ -237,7 +252,7 @@ public:
);
if (results.Success()) {
e.charid = results.LastInsertedID();
e.id = results.LastInsertedID();
return e;
}
@@ -256,8 +271,10 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.raidid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e._class));
v.push_back(std::to_string(e.level));
@@ -298,15 +315,17 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
RaidMembers e{};
e.raidid = static_cast<int32_t>(atoi(row[0]));
e.charid = static_cast<int32_t>(atoi(row[1]));
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[3]));
e.level = static_cast<int8_t>(atoi(row[4]));
e.name = row[5] ? row[5] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
e.israidleader = static_cast<int8_t>(atoi(row[7]));
e.islooter = static_cast<int8_t>(atoi(row[8]));
e.id = strtoull(row[0], nullptr, 10);
e.raidid = static_cast<int32_t>(atoi(row[1]));
e.charid = static_cast<int32_t>(atoi(row[2]));
e.bot_id = static_cast<int32_t>(atoi(row[3]));
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[5]));
e.level = static_cast<int8_t>(atoi(row[6]));
e.name = row[7] ? row[7] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
e.israidleader = static_cast<int8_t>(atoi(row[9]));
e.islooter = static_cast<int8_t>(atoi(row[10]));
all_entries.push_back(e);
}
@@ -331,15 +350,17 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
RaidMembers e{};
e.raidid = static_cast<int32_t>(atoi(row[0]));
e.charid = static_cast<int32_t>(atoi(row[1]));
e.groupid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[3]));
e.level = static_cast<int8_t>(atoi(row[4]));
e.name = row[5] ? row[5] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[6]));
e.israidleader = static_cast<int8_t>(atoi(row[7]));
e.islooter = static_cast<int8_t>(atoi(row[8]));
e.id = strtoull(row[0], nullptr, 10);
e.raidid = static_cast<int32_t>(atoi(row[1]));
e.charid = static_cast<int32_t>(atoi(row[2]));
e.bot_id = static_cast<int32_t>(atoi(row[3]));
e.groupid = static_cast<uint32_t>(strtoul(row[4], nullptr, 10));
e._class = static_cast<int8_t>(atoi(row[5]));
e.level = static_cast<int8_t>(atoi(row[6]));
e.name = row[7] ? row[7] : "";
e.isgroupleader = static_cast<int8_t>(atoi(row[8]));
e.israidleader = static_cast<int8_t>(atoi(row[9]));
e.islooter = static_cast<int8_t>(atoi(row[10]));
all_entries.push_back(e);
}
@@ -5,6 +5,8 @@
#include "../strings.h"
#include "base/base_character_data_repository.h"
class CharacterDataRepository: public BaseCharacterDataRepository {
public:
@@ -44,7 +46,6 @@ public:
*/
// Custom extended repository methods here
};
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
@@ -172,7 +172,7 @@ public:
DELETE FROM {}
WHERE dynamic_zone_id IN ({});
),
TableName(), fmt::join(dynamic_zone_ids, ",")
TableName(), Strings::Join(dynamic_zone_ids, ",")
));
}
}
@@ -75,7 +75,7 @@ public:
FROM expedition_lockouts
WHERE expedition_id IN ({})
),
fmt::join(expedition_ids, ",")
Strings::Join(expedition_ids, ",")
));
all_entries.reserve(results.RowCount());
+1 -1
View File
@@ -62,7 +62,7 @@ public:
std::vector<CharacterExpedition> entries;
auto joined_character_names = fmt::format("'{}'", fmt::join(character_names, "','"));
auto joined_character_names = fmt::format("'{}'", Strings::Join(character_names, "','"));
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
@@ -1,11 +1,11 @@
#ifndef EQEMU_EVENTLOG_REPOSITORY_H
#define EQEMU_EVENTLOG_REPOSITORY_H
#ifndef EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_eventlog_repository.h"
#include "base/base_player_event_log_settings_repository.h"
class EventlogRepository: public BaseEventlogRepository {
class PlayerEventLogSettingsRepository: public BasePlayerEventLogSettingsRepository {
public:
/**
@@ -32,10 +32,10 @@ public:
*
* Example custom methods in a repository
*
* EventlogRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* EventlogRepository::GetWhereNeverExpires()
* EventlogRepository::GetWhereXAndY()
* EventlogRepository::DeleteWhereXAndY()
* PlayerEventLogSettingsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* PlayerEventLogSettingsRepository::GetWhereNeverExpires()
* PlayerEventLogSettingsRepository::GetWhereXAndY()
* PlayerEventLogSettingsRepository::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
@@ -47,4 +47,4 @@ public:
};
#endif //EQEMU_EVENTLOG_REPOSITORY_H
#endif //EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -1,11 +1,11 @@
#ifndef EQEMU_HACKERS_REPOSITORY_H
#define EQEMU_HACKERS_REPOSITORY_H
#ifndef EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_hackers_repository.h"
#include "base/base_player_event_logs_repository.h"
class HackersRepository: public BaseHackersRepository {
class PlayerEventLogsRepository: public BasePlayerEventLogsRepository {
public:
/**
@@ -32,10 +32,10 @@ public:
*
* Example custom methods in a repository
*
* HackersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* HackersRepository::GetWhereNeverExpires()
* HackersRepository::GetWhereXAndY()
* HackersRepository::DeleteWhereXAndY()
* PlayerEventLogsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* PlayerEventLogsRepository::GetWhereNeverExpires()
* PlayerEventLogsRepository::GetWhereXAndY()
* PlayerEventLogsRepository::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
@@ -47,4 +47,4 @@ public:
};
#endif //EQEMU_HACKERS_REPOSITORY_H
#endif //EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
+12 -3
View File
@@ -141,11 +141,11 @@ bool RuleManager::SetRule(const std::string &rule_name, const std::string &rule_
switch (type) {
case IntRule:
m_RuleIntValues[index] = atoi(rule_value.c_str());
m_RuleIntValues[index] = Strings::ToInt(rule_value);
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleIntValues[index]);
break;
case RealRule:
m_RuleRealValues[index] = atof(rule_value.c_str());
m_RuleRealValues[index] = Strings::ToFloat(rule_value);
LogRules("Set rule [{}] to value [{:.2f}]", rule_name, m_RuleRealValues[index]);
break;
case BoolRule:
@@ -385,7 +385,16 @@ void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
e.rule_value = rule_value;
e.notes = rule_notes;
RuleValuesRepository::UpdateOne(*db, e);
db->QueryDatabase(
fmt::format(
"UPDATE rule_values SET rule_value = '{}', notes = '{}' WHERE ruleset_id = {} AND rule_name = '{}'",
rule_value,
Strings::Escape(rule_notes),
e.ruleset_id,
e.rule_name
)
);
return;
}
+26 -3
View File
@@ -93,6 +93,15 @@ RULE_INT(Character, ItemEnduranceRegenCap, 15, "Limit on endurance regeneration
RULE_INT(Character, ItemExtraDmgCap, 150, "Cap for bonuses to melee skills like Bash, Frenzy, etc.")
RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Character, Hastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_BOOL(Character, HeroicStatsUseDataBucketsToScale, false, "Allows scaling the benefits a character receives from Heroic Stats using Data Buckets. Stacks with other Heroic Stats Mulitplier Rules.")
RULE_REAL(Character, HeroicIntelligenceIncreaseSpellDmgMultiplier, 0.00, "Allows Heroic Intelligence to increase a Players Worn Spell Damage Stat from Equipment, for example, setting this rule to 1.00 will always grant 1 Spell Damage per 1 Heroic Intelligence")
RULE_REAL(Character, HeroicWisdomIncreaseHealAmtMultiplier, 0.00, "Allows Heroic Wisdom to increase a Players Worn Heal Amount Stat from Equipment, for example, setting this rule to 1.00 will always grant 1 Heal Amount per 1 Heroic Wisdom")
RULE_REAL(Character, HeroicStrengthMultiplier, 1.00, "Multplier scales benefits from Heroic Strength. Grants 25 Base Endurance, 0.05 Endurance Regen, 1 Melee Damage each Hit, and 1 Shield AC per 10 Heroic Strength.")
RULE_REAL(Character, HeroicStaminaMultiplier, 1.00, "Multplier scales benefits from Heroic Stamina. Grants 25 Base Endurance, 0.05 Endurance Regen, 100 Base HP, and 0.5 HP Regen per 10 Heroic Stamina.")
RULE_REAL(Character, HeroicAgilityMultiplier, 1.00, "Multplier scales benefits from Heroic Agility. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Avoidance AC per 10 Heroic Agility. (Rule does not change Dodge Chance)")
RULE_REAL(Character, HeroicDexterityMultiplier, 1.00, "Multplier scales benefits from Heroic Dexterity. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Archery/Throwing Damage each hit per 10 Heroic Dexterity. (Rule does not change Assassinate/Headshot/Block/Parry/Riposte Chances)")
RULE_REAL(Character, HeroicWisdomMultiplier, 1.00, "Multplier scales benefits from Heroic Wisdom. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Wisdom.")
RULE_REAL(Character, HeroicIntelligenceMultiplier, 1.00, "Multplier scales benefits from Heroic Intelligence. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Intelligence.")
RULE_INT(Character, SkillUpModifier, 100, "The probability for a skill-up is multiplied by value/100")
RULE_BOOL(Character, SharedBankPlat, false, "Shared bank platinum. Off by default to prevent duplication")
RULE_BOOL(Character, BindAnywhere, false, "Allows players to bind their soul anywhere in the world")
@@ -197,9 +206,15 @@ RULE_BOOL(Character, PetZoneWithOwner, true, "Should Pets Zone with Owner")
RULE_BOOL(Character, FullManaOnDeath, true, "On death set mana to full")
RULE_BOOL(Character, FullEndurOnDeath, true, "On death set endurance to full")
RULE_INT(Character, ExperiencePercentCapPerKill, -1, "Caps the percentage of experience that can be gained per kill. -1 disables the cap; 0 blocks all (non-aa) xp.")
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier based on number of players in group, default is true")
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier in group, default is true")
RULE_BOOL(Character, EnableGroupMemberEXPModifier, true, "Enable or disable the group member experience modifier based on number of players in group, default is true")
RULE_REAL(Character, GroupMemberEXPModifier, 0.2, "Sets the group experience modifier per members between 2 and 5, default is 0.2")
RULE_REAL(Character, FullGroupEXPModifier, 2.16, "Sets the group experience modifier for a full group, default is 2.16")
RULE_BOOL(Character, IgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid experience modifier, default is true")
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses")
RULE_BOOL(Character, ItemExtraSkillDamageCalcAsPercent, false, "If enabled, apply Item Extra Skill Damage as Percentage-based modifiers")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -259,7 +274,6 @@ RULE_BOOL(World, EnableTutorialButton, true, "Setting whether the Tutorial butto
RULE_BOOL(World, EnableReturnHomeButton, true, "Setting whether the Return Home button should be active")
RULE_INT(World, MaxLevelForTutorial, 10, "The highest level with which you can enter the tutorial")
RULE_INT(World, TutorialZoneID, 189, "Zone ID of the tutorial")
RULE_INT(World, GuildBankZoneID, 345, "Zone ID of the guild bank")
RULE_INT(World, MinOfflineTimeToReturnHome, 21600, "Minimum offline time to activate the Return Home button. 21600 seconds is 6 Hours")
RULE_INT(World, MaxClientsPerIP, -1, "Maximum number of clients allowed to connect per IP address if account status is < AddMaxClientsStatus. Default value: -1 (feature disabled)")
RULE_INT(World, ExemptMaxClientsStatus, -1, "Exempt accounts from the MaxClientsPerIP and AddMaxClientsStatus rules, if their status is >= this value. Default value: -1 (feature disabled)")
@@ -315,8 +329,8 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Map)
RULE_BOOL(Map, FixPathingZOnSendTo, false, "Try to repair Z coordinates in the SendTo routine as well")
RULE_BOOL(Map, FixZWhenPathing, true, "Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)")
RULE_REAL(Map, DistanceCanTravelBeforeAdjustment, 10.0, "Distance a mob can path before FixZ is called, depends on FixZWhenPathing")
RULE_BOOL(Map, MobZVisualDebug, false, "Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss)")
RULE_BOOL(Map, MobPathingVisualDebug, false, "Displays nodes in pathing points in realtime to help with visual debugging")
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20, "At runtime in SendTo: maximum change in Z to allow the BestZ code to apply")
RULE_INT(Map, FindBestZHeightAdjust, 1, "Adds this to the current Z before seeking the best Z position")
RULE_CATEGORY_END()
@@ -339,6 +353,7 @@ RULE_REAL(Watermap, FishingLineStepSize, 1, "Basic step size for fishing calc, t
RULE_CATEGORY_END()
RULE_CATEGORY(Spells)
RULE_BOOL(Spells, AllowExtraDmgSkill, false, "Allow ExtraDmgSkill from Items, Spells, and AAs to apply ExtraDmgAmt when the ExtraDmgSkill matches the casted Spells Skill Type.")
RULE_INT(Spells, BaseCritChance, 0, "Base percentage chance that everyone has to crit a spell")
RULE_INT(Spells, BaseCritRatio, 100, "Base percentage bonus to damage on a successful spell crit. 100=2xdamage")
RULE_INT(Spells, WizCritLevel, 12, "Level wizards first get spell crits")
@@ -430,6 +445,7 @@ RULE_BOOL(Spells, IllusionsAlwaysPersist, false, "Allows Illusions to persist be
RULE_BOOL(Spells, UseItemCastMessage, false, "Enable to use the \"item begins to glow\" messages when casting from an item.")
RULE_BOOL(Spells, TargetsTargetRequiresCombatRange, true, "Disable to remove combat range requirement from Target's Target Spell Target Type")
RULE_BOOL(Spells, NPCBuffLevelRestrictions, false, "Impose BuffLevelRestrictions on NPCs if true")
RULE_BOOL(Spells, ResurrectionEffectsBlock, true, "If enabled, resurrection effects cannot be overwritten.")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -566,6 +582,7 @@ RULE_BOOL(TaskSystem, RecordCompletedOptionalActivities, false, "Record complete
RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true, "Keep only one record per completed task")
RULE_BOOL(TaskSystem, EnableTaskProximity, true, "Enable task proximity system")
RULE_INT(TaskSystem, RequestCooldownTimerSeconds, 15, "Seconds between allowing characters to request tasks (live-like default: 15 seconds)")
RULE_BOOL(TaskSystem, ExpRewardsIgnoreLevelBasedEXPMods, false, "Rewarding Level Based Exp will ignore Rule LevelBasedEXPMods if true")
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_BOOL(TaskSystem, UpdateOneElementPerTask, true, "If true (live-like) task updates only increment the first matching activity. If false all matching elements will be incremented.")
@@ -583,6 +600,7 @@ RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are s
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, MobCloseScanDistance, 600, "Close scan distance")
RULE_INT(Range, MaxDistanceToClickDoors, 100, "Max distance that a client can click a door from (Client says 'You can't reach that' at roughly 25-50 for most doors)")
RULE_CATEGORY_END()
RULE_CATEGORY(Bots)
@@ -623,6 +641,7 @@ RULE_BOOL(Chat, EnableVoiceMacros, true, "Enable voice macros")
RULE_BOOL(Chat, EnableMailKeyIPVerification, true, "Setting whether the authenticity of the client should be verified via its IP address when accessing the InGame mailbox")
RULE_BOOL(Chat, EnableAntiSpam, true, "Enable anti-spam system for chat")
RULE_BOOL(Chat, SuppressCommandErrors, false, "Do not suppress command errors by default")
RULE_BOOL(Chat, ChannelsIgnoreNameFilter, false, "Ignore name filtering when creating new chat channels")
RULE_INT(Chat, MaxPermanentPlayerChannels, 0, "Maximum number of permanent chat channels a player can make. Default 0.")
RULE_INT(Chat, MinStatusToBypassAntiSpam, 100, "Minimum status to bypass the anti-spam system")
RULE_INT(Chat, MinimumMessagesPerInterval, 4, "Minimum number of chat messages allowed per interval. The karma value is added to this value")
@@ -744,6 +763,7 @@ RULE_BOOL(Inventory, DeleteTransformationMold, true, "False if you want mold to
RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any weapon transformation")
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_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
RULE_CATEGORY_END()
RULE_CATEGORY(Client)
@@ -773,6 +793,9 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Logging)
RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp::main:309] Loading variables...")
RULE_BOOL(Logging, WorldGMSayLogging, true, "Relay worldserver logging to zone processes via GM say output")
RULE_BOOL(Logging, PlayerEventsQSProcess, false, "Have query server process player events instead of world. Useful when wanting to use a dedicated server and database for processing player events on separate disk")
RULE_INT(Logging, BatchPlayerEventProcessIntervalSeconds, 5, "This is the interval in which player events are processed in world or qs")
RULE_INT(Logging, BatchPlayerEventProcessChunkSize, 10000, "This is the cap of events that can be inserted into the queue before a force flush. This is to keep from hitting MySQL max_allowed_packet and killing the connection")
RULE_CATEGORY_END()
RULE_CATEGORY(HotReload)
+2 -1
View File
@@ -99,8 +99,9 @@ public:
}
}
~Seperator() {
for (int i=0; i<=maxargnum; i++)
for (int i=0; i<=maxargnum; i++) {
safe_delete_array(arg[i]);
}
safe_delete_array(arg);
safe_delete_array(argplus);
safe_delete_array(msg);
+20 -12
View File
@@ -281,6 +281,9 @@
#define ServerOP_QSSendQuery 0x5006
#define ServerOP_QSPlayerDropItem 0x5007
// player events
#define ServerOP_PlayerEvent 0x5100
enum {
CZUpdateType_Character,
CZUpdateType_Group,
@@ -1308,10 +1311,10 @@ struct Server_Speech_Struct {
char message[0];
};
struct QSTradeItems_Struct {
uint32 from_id;
struct PlayerLogTradeItemsEntry_Struct {
uint32 from_character_id;
uint16 from_slot;
uint32 to_id;
uint32 to_character_id;
uint16 to_slot;
uint32 item_id;
uint16 charges;
@@ -1322,15 +1325,15 @@ struct QSTradeItems_Struct {
uint32 aug_5;
};
struct QSPlayerLogTrade_Struct {
uint32 char1_id;
MoneyUpdate_Struct char1_money;
uint16 char1_count;
uint32 char2_id;
MoneyUpdate_Struct char2_money;
uint16 char2_count;
uint16 _detail_count;
QSTradeItems_Struct items[0];
struct PlayerLogTrade_Struct {
uint32 character_1_id;
MoneyUpdate_Struct character_1_money;
uint16 character_1_item_count;
uint32 character_2_id;
MoneyUpdate_Struct character_2_money;
uint16 character_2_item_count;
uint16 _detail_count;
PlayerLogTradeItemsEntry_Struct item_entries[0];
};
struct QSDropItems_Struct {
@@ -1806,6 +1809,11 @@ struct ServerDzCreateSerialized_Struct {
char cereal_data[0];
};
struct ServerSendPlayerEvent_Struct {
uint32_t cereal_size;
char cereal_data[0];
};
struct ServerFlagUpdate_Struct {
uint32 account_id;
int16 admin;
+409 -455
View File
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -126,7 +126,11 @@ public:
uint32 aug4 = 0,
uint32 aug5 = 0,
uint32 aug6 = 0,
bool attuned = 0
bool attuned = false,
const std::string& custom_data = "",
uint32 ornamenticon = 0,
uint32 ornamentidfile = 0,
uint32 ornament_hero_model = 0
);
EQ::ItemInstance *CreateItem(
const EQ::ItemData *item,
@@ -137,7 +141,11 @@ public:
uint32 aug4 = 0,
uint32 aug5 = 0,
uint32 aug6 = 0,
bool attuned = 0
bool attuned = false,
const std::string &custom_data = "",
uint32 ornamenticon = 0,
uint32 ornamentidfile = 0,
uint32 ornament_hero_model = 0
);
EQ::ItemInstance *CreateBaseItem(const EQ::ItemData *item, int16 charges = 0);
+20 -2
View File
@@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
@@ -260,13 +260,31 @@ const std::map<EQ::skills::SkillType, std::string>& EQ::skills::GetSkillTypeMap(
return skill_type_map;
}
const std::vector<EQ::skills::SkillType>& EQ::skills::GetExtraDamageSkills()
{
static const std::vector<EQ::skills::SkillType> v = {
EQ::skills::SkillBackstab,
EQ::skills::SkillBash,
EQ::skills::SkillDragonPunch, // Same ID as Tail Rake
EQ::skills::SkillEagleStrike,
EQ::skills::SkillFlyingKick,
EQ::skills::SkillKick,
EQ::skills::SkillRoundKick,
EQ::skills::SkillRoundKick,
EQ::skills::SkillTigerClaw,
EQ::skills::SkillFrenzy
};
return v;
}
std::string EQ::skills::GetSkillName(SkillType skill)
{
if (skill >= Skill1HBlunt && skill <= Skill2HPiercing) {
auto skills = GetSkillTypeMap();
return skills[skill];
}
return std::string();
return {};
}
EQ::SkillProfile::SkillProfile()
+4 -2
View File
@@ -1,5 +1,5 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include <string>
#include <map>
#include <vector>
namespace EQ
@@ -170,6 +171,7 @@ namespace EQ
bool IsMeleeDmg(SkillType skill);
extern const std::map<SkillType, std::string>& GetSkillTypeMap();
extern const std::vector<SkillType>& GetExtraDamageSkills();
std::string GetSkillName(SkillType skill);
} /*skills*/
@@ -305,7 +307,7 @@ namespace EQ
uint32 operator[](int skill_id) const { return const_cast<SkillProfile*>(this)->GetSkill(skill_id); }
};
} /*EQEmu*/
#endif /*COMMON_SKILLS_H*/
+2 -2
View File
@@ -504,7 +504,7 @@ enum SpellRestriction
HAS_NO_ILLUSIONS_OF_GRANDEUR_BUFF = 12519, //
IS_HP_ABOVE_50_PCT = 16010, //
IS_HP_UNDER_50_PCT = 16031, //
IS_OFF_HAND_EQUIPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
IS_OFF_HAND_EQUIPPED = 27672, // You must be wielding a weapon or shield in your offhand to use this ability.
HAS_NO_PACT_OF_FATE_RECOURSE_BUFF = 29556, // This spell will not work while Pact of Fate Recourse is active. | caster restriction |
HAS_NO_SHROUD_OF_PRAYER_BUFF = 32339, // Your target cannot receive another Quiet Prayer this soon.
IS_MANA_BELOW_20_PCT = 38311, // This ability requires you to be at or below 20% of your maximum mana.
@@ -1211,7 +1211,7 @@ typedef enum {
#define SE_Double_Backstab_Front 473 // implemented - Chance to double backstab from front
#define SE_Pet_Crit_Melee_Damage_Pct_Owner 474 // implemenetd - Critical damage mod applied to pets from owner
#define SE_Trigger_Spell_Non_Item 475 // implemented - Trigger spell on cast only if not from item click.
#define SE_Weapon_Stance 476 // implemented, @Misc, Apply a specific spell buffs automatically depending 2Hander, Shield or Duel Wield is equiped, base: spellid, base: 0=2H 1=Shield 2=DW, max: none
#define SE_Weapon_Stance 476 // implemented, @Misc, Apply a specific spell buffs automatically depending 2Hander, Shield or Dual Wield is equipped, base: spellid, base: 0=2H 1=Shield 2=DW, max: none
#define SE_Hatelist_To_Top_Index 477 // Implemented - Chance to be set to top of rampage list
#define SE_Hatelist_To_Tail_Index 478 // Implemented - Chance to be set to bottom of rampage list
#define SE_Ff_Value_Min 479 // implemented, @Ff, Minimum base value of a spell that can be focused, base: spells to be focused base1 value
+121 -23
View File
@@ -115,7 +115,7 @@ Strings::SearchDelim(const std::string &haystack, const std::string &needle, con
}
std::string Strings::Implode(std::string glue, std::vector<std::string> src)
std::string Strings::Implode(const std::string& glue, std::vector<std::string> src)
{
if (src.empty()) {
return {};
@@ -191,24 +191,23 @@ std::string Strings::Escape(const std::string &s)
bool Strings::IsNumber(const std::string &s)
{
try {
auto r = stoi(s);
return true;
}
catch (std::exception &) {
return false;
for (char const &c: s) {
if (c == s[0] && s[0] == '-') {
continue;
}
if (std::isdigit(c) == 0) {
return false;
}
}
return true;
}
bool Strings::IsFloat(const std::string &s)
{
try {
auto r = stof(s);
return true;
}
catch (std::exception &) {
return false;
}
char* ptr;
strtof(s.c_str(), &ptr);
return (*ptr) == '\0';
}
std::string Strings::Join(const std::vector<std::string> &ar, const std::string &delim)
@@ -225,6 +224,20 @@ std::string Strings::Join(const std::vector<std::string> &ar, const std::string
return ret;
}
std::string Strings::Join(const std::vector<uint32_t> &ar, const std::string &delim)
{
std::string ret;
for (size_t i = 0; i < ar.size(); ++i) {
if (i != 0) {
ret += delim;
}
ret += std::to_string(ar[i]);
}
return ret;
}
void
Strings::FindReplace(std::string &string_subject, const std::string &search_string, const std::string &replace_string)
{
@@ -259,7 +272,7 @@ std::string Strings::Repeat(std::string s, int n)
return s;
}
bool Strings::Contains(std::vector<std::string> container, std::string element)
bool Strings::Contains(std::vector<std::string> container, const std::string& element)
{
return std::find(container.begin(), container.end(), element) != container.end();
}
@@ -303,7 +316,7 @@ const std::string Strings::ToUpper(std::string s)
);
return s;
}
const std::string Strings::UcFirst(std::string s)
const std::string Strings::UcFirst(const std::string& s)
{
std::string output = s;
if (!s.empty()) {
@@ -314,7 +327,7 @@ const std::string Strings::UcFirst(std::string s)
}
std::vector<std::string> Strings::Wrap(std::vector<std::string> &src, std::string character)
std::vector<std::string> Strings::Wrap(std::vector<std::string> &src, const std::string& character)
{
std::vector<std::string> new_vector;
new_vector.reserve(src.size());
@@ -646,7 +659,7 @@ std::string Strings::SecondsToTime(int duration, bool is_milliseconds)
return time_string;
}
std::string &Strings::LTrim(std::string &str, const std::string &chars)
std::string &Strings::LTrim(std::string &str, std::string_view chars)
{
str.erase(0, str.find_first_not_of(chars));
return str;
@@ -657,7 +670,7 @@ std::string Strings::MillisecondsToTime(int duration)
return SecondsToTime(duration, true);
}
std::string &Strings::RTrim(std::string &str, const std::string &chars)
std::string &Strings::RTrim(std::string &str, std::string_view chars)
{
str.erase(str.find_last_not_of(chars) + 1);
return str;
@@ -669,7 +682,7 @@ std::string &Strings::Trim(std::string &str, const std::string &chars)
}
// Function to convert single digit or two digit number into words
std::string Strings::ConvertToDigit(int n, std::string suffix)
std::string Strings::ConvertToDigit(int n, const std::string& suffix)
{
// if n is zero
if (n == 0) {
@@ -714,7 +727,7 @@ uint32 Strings::TimeToSeconds(std::string time_string)
time_unit.end()
);
auto unit = std::stoul(time_unit);
auto unit = Strings::ToUnsignedInt(time_unit);
uint32 duration = 0;
if (Strings::Contains(time_string, "s")) {
@@ -732,7 +745,7 @@ uint32 Strings::TimeToSeconds(std::string time_string)
return duration;
}
bool Strings::ToBool(std::string bool_string)
bool Strings::ToBool(const std::string& bool_string)
{
if (
Strings::Contains(bool_string, "true") ||
@@ -741,7 +754,7 @@ bool Strings::ToBool(std::string bool_string)
Strings::Contains(bool_string, "on") ||
Strings::Contains(bool_string, "enable") ||
Strings::Contains(bool_string, "enabled") ||
(Strings::IsNumber(bool_string) && std::stoi(bool_string))
(Strings::IsNumber(bool_string) && Strings::ToInt(bool_string))
) {
return true;
}
@@ -763,3 +776,88 @@ std::string Strings::Random(size_t length)
std::generate_n(str.begin(), length, randchar);
return str;
}
// a wrapper for stoi which will return a fallback if the string
// fails to cast to a number
int Strings::ToInt(const std::string &s, int fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoi(s);
}
catch (std::exception &) {
return fallback;
}
}
int64 Strings::ToBigInt(const std::string &s, int64 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoll(s);
}
catch (std::exception &) {
return fallback;
}
}
uint32 Strings::ToUnsignedInt(const std::string &s, uint32 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoul(s);
}
catch (std::exception &) {
return fallback;
}
}
uint64 Strings::ToUnsignedBigInt(const std::string &s, uint64 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoull(s);
}
catch (std::exception &) {
return fallback;
}
}
float Strings::ToFloat(const std::string &s, float fallback)
{
if (!Strings::IsFloat(s)) {
return fallback;
}
try {
return std::stof(s);
}
catch (std::exception &) {
return fallback;
}
}
std::string Strings::RemoveNumbers(std::string s)
{
int current = 0;
for (int i = 0; i < s.length(); i++) {
if (!isdigit(s[i])) {
s[current] = s[i];
current++;
}
}
return s.substr(0, current);
}
+15 -8
View File
@@ -84,15 +84,21 @@ namespace EQ {
class Strings {
public:
static bool Contains(std::vector<std::string> container, std::string element);
static bool Contains(std::vector<std::string> container, const std::string& element);
static bool Contains(const std::string& subject, const std::string& search);
static int ToInt(const std::string &s, int fallback = 0);
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
static uint64 ToUnsignedBigInt(const std::string &s, uint64 fallback = 0);
static float ToFloat(const std::string &s, float fallback = 0.0f);
static bool IsNumber(const std::string &s);
static std::string RemoveNumbers(std::string s);
static bool IsFloat(const std::string &s);
static const std::string ToLower(std::string s);
static const std::string ToUpper(std::string s);
static const std::string UcFirst(std::string s);
static std::string &LTrim(std::string &str, const std::string &chars = "\t\n\v\f\r ");
static std::string &RTrim(std::string &str, const std::string &chars = "\t\n\v\f\r ");
static const std::string UcFirst(const std::string& s);
static std::string &LTrim(std::string &str, std::string_view chars = "\t\n\v\f\r ");
static std::string &RTrim(std::string &str, std::string_view chars = "\t\n\v\f\r ");
static std::string &Trim(std::string &str, const std::string &chars = "\t\n\v\f\r ");
static std::string Commify(const std::string &number);
static std::string Commify(uint16 number) { return Strings::Commify(std::to_string(number)); };
@@ -101,11 +107,12 @@ public:
static std::string Commify(int16 number) { return Strings::Commify(std::to_string(number)); };
static std::string Commify(int32 number) { return Strings::Commify(std::to_string(number)); };
static std::string Commify(int64 number) { return Strings::Commify(std::to_string(number)); };
static std::string ConvertToDigit(int n, std::string suffix);
static std::string ConvertToDigit(int n, const std::string& suffix);
static std::string Escape(const std::string &s);
static std::string GetBetween(const std::string &s, std::string start_delim, std::string stop_delim);
static std::string Implode(std::string glue, std::vector<std::string> src);
static std::string Implode(const std::string& glue, std::vector<std::string> src);
static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
static std::string MillisecondsToTime(int duration);
static std::string Money(uint32 platinum, uint32 gold = 0, uint32 silver = 0, uint32 copper = 0);
static std::string NumberToWords(unsigned long long int n);
@@ -115,10 +122,10 @@ public:
static std::string::size_type SearchDelim(const std::string &haystack, const std::string &needle, const char deliminator = ',');
static std::vector<std::string> Split(const std::string &s, const char delim = ',');
static std::vector<std::string> Split(const std::string& s, const std::string& delimiter);
static std::vector<std::string> Wrap(std::vector<std::string> &src, std::string character);
static std::vector<std::string> Wrap(std::vector<std::string> &src, const std::string& character);
static void FindReplace(std::string &string_subject, const std::string &search_string, const std::string &replace_string);
static uint32 TimeToSeconds(std::string time_string);
static bool ToBool(std::string bool_string);
static bool ToBool(const std::string& bool_string);
static inline bool EqualFold(const std::string &string_one, const std::string &string_two) { return strcasecmp(string_one.c_str(), string_two.c_str()) == 0; }
static std::string Random(size_t length);
+1 -1
View File
@@ -192,7 +192,7 @@ bool atobool(const char *iBool)
if (!strcasecmp(iBool, "n")) {
return false;
}
if (atoi(iBool)) {
if (Strings::ToInt(iBool)) {
return true;
}
return false;
-8
View File
@@ -71,14 +71,6 @@ namespace StructStrategyFactory {
strategies[first_opcode] = structs;
}
const StructStrategy *FindPatch(EmuOpcode first_opcode) {
std::map<EmuOpcode, const StructStrategy *>::const_iterator res;
res = strategies.find(first_opcode);
if(res == strategies.end())
return(nullptr);
return(res->second);
}
};
-3
View File
@@ -43,9 +43,6 @@ protected:
//effectively a singleton, but I decided to do it this way for no apparent reason.
namespace StructStrategyFactory {
void RegisterPatch(EmuOpcode first_opcode, const StructStrategy *structs);
//does NOT return ownership of the strategy.
const StructStrategy *FindPatch(EmuOpcode first_opcode);
};
+6
View File
@@ -42,6 +42,8 @@
#include <cstring>
#include <iostream>
inline bool g_is_forced_tty = std::getenv("IS_TTY");
namespace rang {
/* For better compability with most of terminals do not use any style settings
@@ -220,6 +222,10 @@ inline bool isMsysPty(int fd) noexcept
inline bool isTerminal(const std::streambuf *osbuf) noexcept
{
if (g_is_forced_tty) {
return g_is_forced_tty;
}
using std::cerr;
using std::clog;
using std::cout;
-1
View File
@@ -16,7 +16,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Disgrace: for windows compile
#ifndef WIN32
#include <sys/time.h>
+4 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.2.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.9.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,8 +42,9 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9218
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9037
#define CURRENT_BINARY_DATABASE_VERSION 9227
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9039
#endif
-490
View File
@@ -1,490 +0,0 @@
#include "../common/types.h"
inline const char* StaticGetZoneName(uint32 zoneID) {
// @merth: I did the following query to retrieve these (following by a simple find/replace)
// select concat('case ', zoneidnumber), concat(short_name, '";') from zone order by zoneidnumber;
switch (zoneID) {
case 1: return "qeynos";
case 2: return "qeynos2";
case 3: return "qrg";
case 4: return "qeytoqrg";
case 5: return "highpass";
case 6: return "highkeep";
case 8: return "freportn";
case 9: return "freportw";
case 10: return "freporte";
case 11: return "runnyeye";
case 12: return "qey2hh1";
case 13: return "northkarana";
case 14: return "southkarana";
case 15: return "eastkarana";
case 16: return "beholder";
case 17: return "blackburrow";
case 18: return "paw";
case 19: return "rivervale";
case 20: return "kithicor";
case 21: return "commons";
case 22: return "ecommons";
case 23: return "erudnint";
case 24: return "erudnext";
case 25: return "nektulos";
case 26: return "cshome";
case 27: return "lavastorm";
case 28: return "nektropos";
case 29: return "halas";
case 30: return "everfrost";
case 31: return "soldunga";
case 32: return "soldungb";
case 33: return "misty";
case 34: return "nro";
case 35: return "sro";
case 36: return "befallen";
case 37: return "oasis";
case 38: return "tox";
case 39: return "hole";
case 40: return "neriaka";
case 41: return "neriakb";
case 42: return "neriakc";
case 43: return "neriakd";
case 44: return "najena";
case 45: return "qcat";
case 46: return "innothule";
case 47: return "feerrott";
case 48: return "cazicthule";
case 49: return "oggok";
case 50: return "rathemtn";
case 51: return "lakerathe";
case 52: return "grobb";
case 53: return "aviak";
case 54: return "gfaydark";
case 55: return "akanon";
case 56: return "steamfont";
case 57: return "lfaydark";
case 58: return "crushbone";
case 59: return "mistmoore";
case 60: return "kaladima";
case 61: return "felwithea";
case 62: return "felwitheb";
case 63: return "unrest";
case 64: return "kedge";
case 65: return "guktop";
case 66: return "gukbottom";
case 67: return "kaladimb";
case 68: return "butcher";
case 69: return "oot";
case 70: return "cauldron";
case 71: return "airplane";
case 72: return "fearplane";
case 73: return "permafrost";
case 74: return "kerraridge";
case 75: return "paineel";
case 76: return "hateplane";
case 77: return "arena";
case 78: return "fieldofbone";
case 79: return "warslikswood";
case 80: return "soltemple";
case 81: return "droga";
case 82: return "cabwest";
case 83: return "swampofnohope";
case 84: return "firiona";
case 85: return "lakeofillomen";
case 86: return "dreadlands";
case 87: return "burningwood";
case 88: return "kaesora";
case 89: return "sebilis";
case 90: return "citymist";
case 91: return "skyfire";
case 92: return "frontiermtns";
case 93: return "overthere";
case 94: return "emeraldjungle";
case 95: return "trakanon";
case 96: return "timorous";
case 97: return "kurn";
case 98: return "erudsxing";
case 100: return "stonebrunt";
case 101: return "warrens";
case 102: return "karnor";
case 103: return "chardok";
case 104: return "dalnir";
case 105: return "charasis";
case 106: return "cabeast";
case 107: return "nurga";
case 108: return "veeshan";
case 109: return "veksar";
case 110: return "iceclad";
case 111: return "frozenshadow";
case 112: return "velketor";
case 113: return "kael";
case 114: return "skyshrine";
case 115: return "thurgadina";
case 116: return "eastwastes";
case 117: return "cobaltscar";
case 118: return "greatdivide";
case 119: return "wakening";
case 120: return "westwastes";
case 121: return "crystal";
case 123: return "necropolis";
case 124: return "templeveeshan";
case 125: return "sirens";
case 126: return "mischiefplane";
case 127: return "growthplane";
case 128: return "sleeper";
case 129: return "thurgadinb";
case 130: return "erudsxing2";
case 150: return "shadowhaven";
case 151: return "bazaar";
case 152: return "nexus";
case 153: return "echo";
case 154: return "acrylia";
case 155: return "sharvahl";
case 156: return "paludal";
case 157: return "fungusgrove";
case 158: return "vexthal";
case 159: return "sseru";
case 160: return "katta";
case 161: return "netherbian";
case 162: return "ssratemple";
case 163: return "griegsend";
case 164: return "thedeep";
case 165: return "shadeweaver";
case 166: return "hollowshade";
case 167: return "grimling";
case 168: return "mseru";
case 169: return "letalis";
case 170: return "twilight";
case 171: return "thegrey";
case 172: return "tenebrous";
case 173: return "maiden";
case 174: return "dawnshroud";
case 175: return "scarlet";
case 176: return "umbral";
case 179: return "akheva";
case 180: return "arena2";
case 181: return "jaggedpine";
case 182: return "nedaria";
case 183: return "tutorial";
case 184: return "load";
case 185: return "load2";
case 186: return "hateplaneb";
case 187: return "shadowrest";
case 188: return "tutoriala";
case 189: return "tutorialb";
case 190: return "clz";
case 200: return "codecay";
case 201: return "pojustice";
case 202: return "poknowledge";
case 203: return "potranquility";
case 204: return "ponightmare";
case 205: return "podisease";
case 206: return "poinnovation";
case 207: return "potorment";
case 208: return "povalor";
case 209: return "bothunder";
case 210: return "postorms";
case 211: return "hohonora";
case 212: return "solrotower";
case 213: return "powar";
case 214: return "potactics";
case 215: return "poair";
case 216: return "powater";
case 217: return "pofire";
case 218: return "poeartha";
case 219: return "potimea";
case 220: return "hohonorb";
case 221: return "nightmareb";
case 222: return "poearthb";
case 223: return "potimeb";
case 224: return "gunthak";
case 225: return "dulak";
case 226: return "torgiran";
case 227: return "nadox";
case 228: return "hatesfury";
case 229: return "guka";
case 230: return "ruja";
case 231: return "taka";
case 232: return "mira";
case 233: return "mmca";
case 234: return "gukb";
case 235: return "rujb";
case 236: return "takb";
case 237: return "mirb";
case 238: return "mmcb";
case 239: return "gukc";
case 240: return "rujc";
case 241: return "takc";
case 242: return "mirc";
case 243: return "mmcc";
case 244: return "gukd";
case 245: return "rujd";
case 246: return "takd";
case 247: return "mird";
case 248: return "mmcd";
case 249: return "guke";
case 250: return "ruje";
case 251: return "take";
case 252: return "mire";
case 253: return "mmce";
case 254: return "gukf";
case 255: return "rujf";
case 256: return "takf";
case 257: return "mirf";
case 258: return "mmcf";
case 259: return "gukg";
case 260: return "rujg";
case 261: return "takg";
case 262: return "mirg";
case 263: return "mmcg";
case 264: return "gukh";
case 265: return "rujh";
case 266: return "takh";
case 267: return "mirh";
case 268: return "mmch";
case 269: return "ruji";
case 270: return "taki";
case 271: return "miri";
case 272: return "mmci";
case 273: return "rujj";
case 274: return "takj";
case 275: return "mirj";
case 276: return "mmcj";
case 277: return "chardokb";
case 278: return "soldungc";
case 279: return "abysmal";
case 280: return "natimbi";
case 281: return "qinimi";
case 282: return "riwwi";
case 283: return "barindu";
case 284: return "ferubi";
case 285: return "snpool";
case 286: return "snlair";
case 287: return "snplant";
case 288: return "sncrematory";
case 289: return "tipt";
case 290: return "vxed";
case 291: return "yxtta";
case 292: return "uqua";
case 293: return "kodtaz";
case 294: return "ikkinz";
case 295: return "qvic";
case 296: return "inktuta";
case 297: return "txevu";
case 298: return "tacvi";
case 299: return "qvicb";
case 300: return "wallofslaughter";
case 301: return "bloodfields";
case 302: return "draniksscar";
case 303: return "causeway";
case 304: return "chambersa";
case 305: return "chambersb";
case 306: return "chambersc";
case 307: return "chambersd";
case 308: return "chamberse";
case 309: return "chambersf";
case 316: return "provinggrounds";
case 317: return "anguish";
case 318: return "dranikhollowsa";
case 319: return "dranikhollowsb";
case 320: return "dranikhollowsc";
case 328: return "dranikcatacombsa";
case 329: return "dranikcatacombsb";
case 330: return "dranikcatacombsc";
case 331: return "draniksewersa";
case 332: return "draniksewersb";
case 333: return "draniksewersc";
case 334: return "riftseekers";
case 335: return "harbingers";
case 336: return "dranik";
case 337: return "broodlands";
case 338: return "stillmoona";
case 339: return "stillmoonb";
case 340: return "thundercrest";
case 341: return "delvea";
case 342: return "delveb";
case 343: return "thenest";
case 344: return "guildlobby";
case 345: return "guildhall";
case 346: return "barter";
case 347: return "illsalin";
case 348: return "illsalina";
case 349: return "illsalinb";
case 350: return "illsalinc";
case 351: return "dreadspire";
case 354: return "drachnidhive";
case 355: return "drachnidhivea";
case 356: return "drachnidhiveb";
case 357: return "drachnidhivec";
case 358: return "westkorlach";
case 359: return "westkorlacha";
case 360: return "westkorlachb";
case 361: return "westkorlachc";
case 362: return "eastkorlach";
case 363: return "eastkorlacha";
case 364: return "shadowspine";
case 365: return "corathus";
case 366: return "corathusa";
case 367: return "corathusb";
case 368: return "nektulosa";
case 369: return "arcstone";
case 370: return "relic";
case 371: return "skylance";
case 372: return "devastation";
case 373: return "devastationa";
case 374: return "rage";
case 375: return "ragea";
case 376: return "takishruins";
case 377: return "takishruinsa";
case 378: return "elddar";
case 379: return "elddara";
case 380: return "theater";
case 381: return "theatera";
case 382: return "freeporteast";
case 383: return "freeportwest";
case 384: return "freeportsewers";
case 385: return "freeportacademy";
case 386: return "freeporttemple";
case 387: return "freeportmilitia";
case 388: return "freeportarena";
case 389: return "freeportcityhall";
case 390: return "freeporttheater";
case 391: return "freeporthall";
case 392: return "northro";
case 393: return "southro";
case 394: return "crescent";
case 395: return "moors";
case 396: return "stonehive";
case 397: return "mesa";
case 398: return "roost";
case 399: return "steppes";
case 400: return "icefall";
case 401: return "valdeholm";
case 402: return "frostcrypt";
case 403: return "sunderock";
case 404: return "vergalid";
case 405: return "direwind";
case 406: return "ashengate";
case 407: return "highpasshold";
case 408: return "commonlands";
case 409: return "oceanoftears";
case 410: return "kithforest";
case 411: return "befallenb";
case 412: return "highpasskeep";
case 413: return "innothuleb";
case 414: return "toxxulia";
case 415: return "mistythicket";
case 416: return "kattacastrum";
case 417: return "thalassius";
case 418: return "atiiki";
case 419: return "zhisza";
case 420: return "silyssar";
case 421: return "solteris";
case 422: return "barren";
case 423: return "buriedsea";
case 424: return "jardelshook";
case 425: return "monkeyrock";
case 426: return "suncrest";
case 427: return "deadbone";
case 428: return "blacksail";
case 429: return "maidensgrave";
case 430: return "redfeather";
case 431: return "shipmvp";
case 432: return "shipmvu";
case 433: return "shippvu";
case 434: return "shipuvu";
case 435: return "shipmvm";
case 436: return "mechanotus";
case 437: return "mansion";
case 438: return "steamfactory";
case 439: return "shipworkshop";
case 440: return "gyrospireb";
case 441: return "gyrospirez";
case 442: return "dragonscale";
case 443: return "lopingplains";
case 444: return "hillsofshade";
case 445: return "bloodmoon";
case 446: return "crystallos";
case 447: return "guardian";
case 448: return "steamfontmts";
case 449: return "cryptofshade";
case 451: return "dragonscaleb";
case 452: return "oldfieldofbone";
case 453: return "oldkaesoraa";
case 454: return "oldkaesorab";
case 455: return "oldkurn";
case 456: return "oldkithicor";
case 457: return "oldcommons";
case 458: return "oldhighpass";
case 459: return "thevoida";
case 460: return "thevoidb";
case 461: return "thevoidc";
case 462: return "thevoidd";
case 463: return "thevoide";
case 464: return "thevoidf";
case 465: return "thevoidg";
case 466: return "oceangreenhills";
case 467: return "oceangreenvillage";
case 468: return "oldblackburrow";
case 469: return "bertoxtemple";
case 470: return "discord";
case 471: return "discordtower";
case 472: return "oldbloodfield";
case 473: return "precipiceofwar";
case 474: return "olddranik";
case 475: return "toskirakk";
case 476: return "korascian";
case 477: return "rathechamber";
case 480: return "brellsrest";
case 481: return "fungalforest";
case 482: return "underquarry";
case 483: return "coolingchamber";
case 484: return "shiningcity";
case 485: return "arthicrex";
case 486: return "foundation";
case 487: return "lichencreep";
case 488: return "pellucid";
case 489: return "stonesnake";
case 490: return "brellstemple";
case 491: return "convorteum";
case 492: return "brellsarena";
case 493: return "weddingchapel";
case 494: return "weddingchapeldark";
case 495: return "dragoncrypt";
case 700: return "feerrott2";
case 701: return "thulehouse1";
case 702: return "thulehouse2";
case 703: return "housegarden";
case 704: return "thulelibrary";
case 705: return "well";
case 706: return "fallen";
case 707: return "morellcastle";
case 708: return "somnium";
case 709: return "alkabormare";
case 710: return "miragulmare";
case 711: return "thuledream";
case 712: return "neighborhood";
case 724: return "argath";
case 725: return "arelis";
case 726: return "sarithcity";
case 727: return "rubak";
case 728: return "beastdomain";
case 729: return "resplendent";
case 730: return "pillarsalra";
case 731: return "windsong";
case 732: return "cityofbronze";
case 733: return "sepulcher";
case 734: return "eastsepulcher";
case 735: return "westsepulcher";
case 752: return "shardslanding";
case 753: return "xorbb";
case 754: return "kaelshard";
case 755: return "eastwastesshard";
case 756: return "crystalshard";
case 757: return "breedinggrounds";
case 758: return "eviltree";
case 759: return "grelleth";
case 760: return "chapterhouse";
case 996: return "arttest";
case 998: return "fhalls";
case 999: return "apprentice";
}
return "UNKNWN";
}
-5
View File
@@ -28,11 +28,6 @@
int ZoneLaunch::s_running = 0; //the number of zones running under this launcher
Timer ZoneLaunch::s_startTimer(1); //I do not trust this things state after static initialization
void ZoneLaunch::InitStartTimer() {
s_startTimer.Start(1);
s_startTimer.Trigger();
}
ZoneLaunch::ZoneLaunch(WorldServer *world, const char *launcher_name,
const char *zone_name, uint16 port, const EQEmuConfig *config)
: m_state(StateStartPending),
-4
View File
@@ -39,10 +39,6 @@ public:
void SendStatus() const;
const char *GetZone() const { return(m_zone.c_str()); }
uint32 GetStartCount() const { return(m_startCount); }
//should only be called during process init to setup the start timer.
static void InitStartTimer();
protected:
bool IsRunning() const { return(m_state == StateStarted || m_state == StateStopPending || m_state == StateRestartPending); }
+1 -22
View File
@@ -260,27 +260,6 @@ bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
return updated_account;
}
/**
* @param in_account_id
* @param in_account_password_hash
*/
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordById(
uint32 in_account_id,
const std::string &in_account_password_hash
)
{
bool updated_account = server.db->UpdateLoginWorldAdminAccountPassword(in_account_id, in_account_password_hash);
LogInfo(
"[{}] account_name [{}] status [{}]",
__func__,
in_account_id,
(updated_account ? "success" : "failed")
);
return updated_account;
}
constexpr int REQUEST_TIMEOUT_MS = 1500;
/**
@@ -381,7 +360,7 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
auto s = Strings::Split(server.options.GetEQEmuLoginServerAddress(), ':');
if (s.size() == 2) {
auto address = s[0];
auto port = std::stoi(s[1]);
auto port = Strings::ToInt(s[1]);
EQ::Net::DNSLookup(
address, port, false, [&](const std::string &addr) {
-10
View File
@@ -80,16 +80,6 @@ public:
const std::string &in_account_password
);
/**
* @param in_account_id
* @param in_account_password_hash
* @return
*/
static bool UpdateLoginserverWorldAdminAccountPasswordById(
uint32 in_account_id,
const std::string &in_account_password_hash
);
static uint32 HealthCheckUserLogin();
};
+2 -141
View File
@@ -26,10 +26,11 @@ bool Client::Process()
{
EQApplicationPacket *app = m_connection->PopPacket();
while (app) {
auto o = m_connection->GetOpcodeManager();
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
m_connection->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
o->EmuToEQ(app->GetOpcode()) == 0 ? app->GetProtocolOpcode() : o->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
@@ -657,146 +658,6 @@ void Client::CreateEQEmuAccount(
}
}
/**
* @param connection
*/
void Client::LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection)
{
m_login_connection = connection;
}
/**
* @param conn
* @param from
* @param to
*/
void Client::LoginOnStatusChange(
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
)
{
if (to == EQ::Net::StatusConnected) {
LogDebug("EQ::Net::StatusConnected");
LoginSendSessionReady();
}
if (to == EQ::Net::StatusDisconnecting || to == EQ::Net::StatusDisconnected) {
LogDebug("EQ::Net::StatusDisconnecting || EQ::Net::StatusDisconnected");
DoFailedLogin();
}
}
/**
* @param conn
* @param from
* @param to
*/
void Client::LoginOnStatusChangeIgnored(
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
)
{
}
/**
* @param conn
* @param p
*/
void Client::LoginOnPacketRecv(std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p)
{
auto opcode = p.GetUInt16(0);
switch (opcode) {
case 0x0017: //OP_ChatMessage
LoginSendLogin();
break;
case 0x0018:
LoginProcessLoginResponse(p);
break;
}
}
void Client::LoginSendSessionReady()
{
EQ::Net::DynamicPacket p;
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
m_login_connection->QueuePacket(p);
}
void Client::LoginSendLogin()
{
size_t buffer_len = m_stored_user.length() + m_stored_pass.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], m_stored_user.c_str());
strcpy(&buffer[m_stored_user.length() + 1], m_stored_pass.c_str());
size_t encrypted_len = buffer_len;
if (encrypted_len % 8 > 0) {
encrypted_len = ((encrypted_len / 8) + 1) * 8;
}
EQ::Net::DynamicPacket p;
p.Resize(12 + encrypted_len);
p.PutUInt16(0, 2); //OP_Login
p.PutUInt32(2, 3);
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
m_login_connection->QueuePacket(p);
}
/**
* @param p
*/
void Client::LoginProcessLoginResponse(const EQ::Net::Packet &p)
{
auto encrypt_size = p.Length() - 12;
if (encrypt_size % 8 > 0) {
encrypt_size = (encrypt_size / 8) * 8;
}
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
eqcrypt_block((char *) p.Data() + 12, encrypt_size, &decrypted[0], false);
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
auto response_error = sp.GetUInt16(1);
m_login_connection_manager->OnConnectionStateChange(
std::bind(
&Client::LoginOnStatusChangeIgnored,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3
)
);
if (response_error > 101) {
LogDebug("response [{0}] failed login", response_error);
DoFailedLogin();
m_login_connection->Close();
}
else {
LogDebug(
"response [{0}] login succeeded user [{1}]",
response_error,
m_stored_user
);
auto m_dbid = sp.GetUInt32(8);
CreateEQEmuAccount(m_stored_user, m_stored_pass, m_dbid);
m_login_connection->Close();
}
}
bool Client::ProcessHealthCheck(std::string username)
{
if (username == "healthcheckuser") {
-15
View File
@@ -198,21 +198,6 @@ private:
std::string m_stored_user;
std::string m_stored_pass;
void LoginOnNewConnection(std::shared_ptr<EQ::Net::DaybreakConnection> connection);
void LoginOnStatusChange(
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
);
void LoginOnStatusChangeIgnored(
std::shared_ptr<EQ::Net::DaybreakConnection> conn,
EQ::Net::DbProtocolStatus from,
EQ::Net::DbProtocolStatus to
);
void LoginOnPacketRecv(std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p);
void LoginSendSessionReady();
void LoginSendLogin();
void LoginProcessLoginResponse(const EQ::Net::Packet &p);
static bool ProcessHealthCheck(std::string username);
};
+11 -11
View File
@@ -32,7 +32,7 @@ Database::Database(
user.c_str(),
pass.c_str(),
name.c_str(),
std::stoi(port),
Strings::ToUnsignedInt(port),
&errnum,
errbuf
)
@@ -93,7 +93,7 @@ bool Database::GetLoginDataFromAccountInfo(
auto row = results.begin();
id = atoi(row[0]);
id = Strings::ToUnsignedInt(row[0]);
password = row[1];
LogDebug(
@@ -145,7 +145,7 @@ bool Database::GetLoginTokenDataFromToken(
}
if (strcmp(row[2], "login_server_id") == 0) {
db_account_id = atoi(row[3]);
db_account_id = Strings::ToUnsignedInt(row[3]);
found_login_id = true;
continue;
}
@@ -178,7 +178,7 @@ unsigned int Database::GetFreeID(const std::string &loginserver)
auto row = results.begin();
return std::stoi(row[0]);
return Strings::ToUnsignedInt(row[0]);
}
/**
@@ -368,12 +368,12 @@ Database::DbWorldRegistration Database::GetWorldRegistration(
auto row = results.begin();
r.loaded = true;
r.server_id = std::stoi(row[0]);
r.server_id = Strings::ToInt(row[0]);
r.server_description = row[1];
r.server_list_type = std::stoi(row[3]);
r.is_server_trusted = std::stoi(row[2]) > 0;
r.server_list_type = Strings::ToInt(row[3]);
r.is_server_trusted = Strings::ToInt(row[2]) > 0;
r.server_list_description = row[4];
r.server_admin_id = std::stoi(row[5]);
r.server_admin_id = Strings::ToUnsignedInt(row[5]);
if (r.server_admin_id <= 0) {
return r;
@@ -513,7 +513,7 @@ bool Database::CreateWorldRegistration(
auto row = results.begin();
id = std::stoi(row[0]);
id = Strings::ToUnsignedInt(row[0]);
auto insert_query = fmt::format(
"INSERT INTO login_world_servers SET id = {0}, long_name = '{1}', short_name = '{2}', last_ip_address = '{3}', \n"
"login_server_list_type_id = 3, login_server_admin_id = {4}, is_server_trusted = 0, tag_description = ''",
@@ -647,7 +647,7 @@ Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &ac
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = std::stoi(row[0]);
r.id = Strings::ToUnsignedInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.first_name = row[3];
@@ -683,7 +683,7 @@ Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = std::stoi(row[0]);
r.id = Strings::ToUnsignedInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.account_email = row[3];
-1
View File
@@ -29,7 +29,6 @@ public:
* Destructor, frees our database if needed.
*/
~Database();
bool IsConnected() { return (m_database != nullptr); }
/**
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
-7
View File
@@ -23,13 +23,6 @@ struct LoginHandShakeReply_Struct {
char unknown[1]; // variable length string
};
// for reference, login buffer is variable (minimum size 8 due to encryption)
struct PlayerLogin_Struct {
LoginBaseMessage_Struct base_header;
char username[1];
char password[1];
};
// variable length, can use directly if not serializing strings
struct PlayerLoginReply_Struct {
// base header excluded to make struct data easier to encrypt
+2 -2
View File
@@ -480,8 +480,8 @@ namespace LoginserverWebserver {
for (auto row = results.begin(); row != results.end(); ++row) {
LoginserverWebserver::TokenManager::token_data token_data;
token_data.token = row[0];
token_data.can_write = std::stoi(row[1]) > 0;
token_data.can_read = std::stoi(row[2]) > 0;
token_data.can_write = Strings::ToInt(row[1]) > 0;
token_data.can_read = Strings::ToInt(row[2]) > 0;
LogDebug(
"Inserting api token to internal list [{0}] write {1} read {2}",
+7
View File
@@ -288,9 +288,16 @@ int main(int argc, char **argv)
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
LogInfo("[Config] [Security] IsUpdatingInsecurePasswords [{0}]", server.options.IsUpdatingInsecurePasswords());
Timer keepalive(INTERSERVER_TIMER); // does auto-reconnect
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
if (keepalive.Check()) {
keepalive.Start();
server.db->ping();
}
if (!run_server) {
EQ::EventLoop::Get().Shutdown();
return;
-19
View File
@@ -73,25 +73,6 @@ ServerManager::ServerManager()
ServerManager::~ServerManager() = default;
/**
* @param ip_address
* @param port
* @return
*/
WorldServer *ServerManager::GetServerByAddress(const std::string &ip_address, int port)
{
auto iter = m_world_servers.begin();
while (iter != m_world_servers.end()) {
if ((*iter)->GetConnection()->Handle()->RemoteIP() == ip_address &&
(*iter)->GetConnection()->Handle()->RemotePort()) {
return (*iter).get();
}
++iter;
}
return nullptr;
}
/**
* @param client
* @param sequence
-11
View File
@@ -72,17 +72,6 @@ public:
const std::list<std::unique_ptr<WorldServer>> &getWorldServers() const;
private:
/**
* Retrieves a server(if exists) by ip address
* Useful utility for the reconnect process
*
* @param ip_address
* @param port
* @return
*/
WorldServer *GetServerByAddress(const std::string &ip_address, int port);
std::unique_ptr<EQ::Net::ServertalkServer> m_server_connection;
std::list<std::unique_ptr<WorldServer>> m_world_servers;
-1
View File
@@ -31,7 +31,6 @@ public:
* Accesses connection, it is intentional that this is not const (trust me).
*/
std::shared_ptr<EQ::Net::ServertalkServerConnection> GetConnection() { return m_connection; }
void SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> c) { m_connection = c; }
/**
* @return
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.2.0",
"version": "22.9.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+9 -10
View File
@@ -50,7 +50,6 @@
#include "../common/strings.h"
#include "../common/servertalk.h"
void QSDatabase::AddSpeech(
const char *from,
const char *to,
@@ -125,7 +124,7 @@ void QSDatabase::LogPlayerDropItem(QSPlayerDropItem_Struct *QS)
}
}
void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
void QSDatabase::LogPlayerTrade(PlayerLogTrade_Struct *QS, uint32 detailCount)
{
std::string query = StringFormat(
@@ -134,10 +133,10 @@ void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
"`char1_sp` = '%i', `char1_cp` = '%i', `char1_items` = '%i', "
"`char2_id` = '%i', `char2_pp` = '%i', `char2_gp` = '%i', "
"`char2_sp` = '%i', `char2_cp` = '%i', `char2_items` = '%i'",
QS->char1_id, QS->char1_money.platinum, QS->char1_money.gold,
QS->char1_money.silver, QS->char1_money.copper, QS->char1_count,
QS->char2_id, QS->char2_money.platinum, QS->char2_money.gold,
QS->char2_money.silver, QS->char2_money.copper, QS->char2_count
QS->character_1_id, QS->character_1_money.platinum, QS->character_1_money.gold,
QS->character_1_money.silver, QS->character_1_money.copper, QS->character_1_item_count,
QS->character_2_id, QS->character_2_money.platinum, QS->character_2_money.gold,
QS->character_2_money.silver, QS->character_2_money.copper, QS->character_2_item_count
);
auto results = QueryDatabase(query);
if (!results.Success()) {
@@ -157,10 +156,10 @@ void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
"`from_id` = '%i', `from_slot` = '%i', `to_id` = '%i', `to_slot` = '%i', "
"`item_id` = '%i', `charges` = '%i', `aug_1` = '%i', `aug_2` = '%i', "
"`aug_3` = '%i', `aug_4` = '%i', `aug_5` = '%i'",
lastIndex, QS->items[i].from_id, QS->items[i].from_slot,
QS->items[i].to_id, QS->items[i].to_slot, QS->items[i].item_id,
QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2,
QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5
lastIndex, QS->item_entries[i].from_character_id, QS->item_entries[i].from_slot,
QS->item_entries[i].to_character_id, QS->item_entries[i].to_slot, QS->item_entries[i].item_id,
QS->item_entries[i].charges, QS->item_entries[i].aug_1, QS->item_entries[i].aug_2,
QS->item_entries[i].aug_3, QS->item_entries[i].aug_4, QS->item_entries[i].aug_5
);
results = QueryDatabase(query);
if (!results.Success()) {
+1 -9
View File
@@ -33,13 +33,11 @@
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class QSDatabase : public Database {
public:
void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type);
void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount);
void LogPlayerTrade(PlayerLogTrade_Struct* QS, uint32 DetailCount);
void LogPlayerDropItem(QSPlayerDropItem_Struct* QS);
void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount);
void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members);
@@ -47,12 +45,6 @@ public:
void LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 Items);
void LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 Items);
void GeneralQueryReceive(ServerPacket *pack);
protected:
void HandleMysqlError(uint32 errnum);
private:
void DBInitVars();
};
#endif
+3 -3
View File
@@ -44,15 +44,15 @@ bool LFGuildManager::LoadDatabase()
}
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 type = atoul(row[0]);
uint32 type = Strings::ToUnsignedInt(row[0]);
if(type == 0)
{
PlayerLookingForGuild p(row[1], row[2], atoul(row[3]), atoul(row[5]), atoul(row[6]), atoul(row[7]), atoul(row[8]));
PlayerLookingForGuild p(row[1], row[2], Strings::ToUnsignedInt(row[3]), Strings::ToUnsignedInt(row[5]), Strings::ToUnsignedInt(row[6]), Strings::ToUnsignedInt(row[7]), Strings::ToUnsignedInt(row[8]));
Players.push_back(p);
continue;
}
GuildLookingForPlayers g(row[1], row[2], atoul(row[3]), atoul(row[4]), atoul(row[5]), atoul(row[6]), atoul(row[7]), atoul(row[8]));
GuildLookingForPlayers g(row[1], row[2], Strings::ToUnsignedInt(row[3]), Strings::ToUnsignedInt(row[4]), Strings::ToUnsignedInt(row[5]), Strings::ToUnsignedInt(row[6]), Strings::ToUnsignedInt(row[7]), Strings::ToUnsignedInt(row[8]));
Guilds.push_back(g);
}

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