Compare commits

..

49 Commits

Author SHA1 Message Date
KimLS e25ff70de9 Gonna start looking at implementing patch stuff 2025-02-16 14:14:29 -08:00
KimLS 3c02b3e60f Initial commit from laurion branch 2025-02-16 13:49:38 -08:00
Mitch Freeman dfb089b0c1 [Fix] Change logging level for no items found in a bazaar search to reduce spam logs. (#4675) 2025-02-13 12:21:15 -05:00
nytmyr d9d2d5d47c [Commands] [Hotfix] Fix Illusion Block (#4666)
* [Commands] [Hotfix] Fix Illusion Block

This wasn't properly being set or saved if bots were not enabled, moved to extended character profile for players.

* Move out of EPP

* ValueWithin

* I learned a new word today - idempotent

I'm dumb. Will forget it tomorrow.

* Move saving to ZoneDatabase, inline SetIllusionBlock
2025-02-12 00:18:34 -06:00
Chris Miles ac4ffefa09 [Crash] Fix raid/group crash regression (#4671) 2025-02-12 00:25:29 -05:00
Alex King c228604255 [Bug Fix] Fix Beastlord Warder Size Modifier (#4665)
* [Bug Fix] Fix Beastlord Warder Size Modifier

* Push

* Update repository-generator.pl

---------

Co-authored-by: Chris Miles <akkadius1@gmail.com>
2025-02-11 21:27:59 -06:00
Chris Miles 59292b15f6 [Loginserver] Fix iterator crash (#4670) 2025-02-11 21:22:56 -06:00
Chris Miles 843f6531a7 [Fix] Always spawn zone controller first (#4669) 2025-02-11 22:19:15 -05:00
nytmyr 432452c5c7 [Hotfix] [Spells] Fix ST_GroupNoPets and ST_GroupClientAndPet (#4667) 2025-02-10 01:44:25 -05:00
Alex King f3a2f97155 [Bug Fix] Fix Item Discovery (#4663)
* [Bug Fix] Fix Item Discovery for Pickups, Evolving, Fishing, and Forage

* Push

* Caching

* Update tradeskills.cpp

* Update task_client_state.cpp
2025-02-09 22:25:43 -05:00
Alex King 9e07d90664 [Quest API] Add Zone Support to Perl and Lua (#4662)
* [Quest API] Add Zone Support to Perl and Lua

* Final
2025-02-08 23:21:15 -06:00
Alex King 4fe229c475 [Bug Fix] Fix Tradeskill Queries (#4661) 2025-02-08 20:35:18 -06:00
nytmyr 4658e7f60d [Bots] Fix spell priority commands (#4660)
- Fix priority value check in spellpriority commands
- Fix list option
- Remove unnecessary temp vector on list grab

- Will move getter to cache in future PR
2025-02-08 02:18:36 -05:00
nytmyr 95559b2e17 [Bots] Fix typo in positioning (#4659) 2025-02-08 01:12:03 -05:00
Alex King 7ad63575c7 [Bug Fix] Fix SendStatsWindow Mod2 Value Display (#4658) 2025-02-07 16:23:24 -06:00
nytmyr bc6b21f601 [Bots] Correct helper message for forced casts (#4656)
* Fixed helper message for forced casts

* Update bot.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2025-02-07 14:32:32 -05:00
nytmyr 05c7e6409d [Bots] Fix a couple potential crashes with GetNumberNeedingHealedInGroup (#4652) 2025-02-07 14:06:59 -05:00
nytmyr 60ba76b39c [Cleanup] Bot RaidGroupSay (#4653) 2025-02-07 14:06:31 -05:00
nytmyr 41009aa19b [Bots] Add IsInRaidOrGroup checks to ^attack and ^pull (#4654) 2025-02-07 14:05:55 -05:00
nytmyr ed7023f336 [Bots] Move BotGetSpellsByType to cache (#4655) 2025-02-07 14:05:36 -05:00
Chris Miles e0d95b4302 [NPC Handins] Fix MultiQuest Handins (#4651)
* [NPC Handins] Fix multi-quest handins

* Update linux-build.sh
2025-02-07 03:28:02 -06:00
Alex King 537b585791 [Cleanup] Use Repositories for Titles (#4608)
* [Cleanup] Use Repositories for Titles

* Update titles.h

* Further use repositories

* Revert "Further use repositories"

This reverts commit 80d5f750f0157657af05497eeade8b45e15dc12a.

* Push

* Update titles.cpp

* Push

* Merge branch 'cleanup/titles_repositories' of https://github.com/EQEmu/Server into cleanup/titles_repositories

* Final push
2025-02-06 23:25:36 -06:00
Chris Miles 1a48add20e [Loginserver] Modernize codebase (#4647)
* Beginning of cleanup

* More cleanup

* More cleanup

* Enc cleanup

* client manager cleanup

* client cleanup

* More cleanup

* More cleanup

* Cleanup

* More cleanup, account  context, account management

* Remove positional fmt bindings

* Use LoginAccountContext

* Update loginserver_webserver.cpp

* Remove comments

* Port CreateLoginServerAccount to repositories

* More cleanup

* More cleanup

* More cleanup

* More cleanup

* Remove a ton of functions

* More cleanup

* More cleanup

* More cleanup

* Cleanup SendClientAuthToWorld

* Consolidate world server logic

* Update login_accounts_repository.h

* Update login_accounts_repository.h

* Move api tokens to repositories

* Cleanup options

* Move everything else to repositories

* Update account_management.cpp

* uint64 account

* Update login_schema.sql

* Fix

* Update world_server.cpp

* auto
2025-02-06 12:47:02 -06:00
nytmyr 1650efa787 [Bots] Correct camp count on ^camp (#4650)
* Correct camp count on ^camp

* Update bot.cpp

---------

Co-authored-by: Alex King <89047260+Kinglykrab@users.noreply.github.com>
2025-02-06 04:40:09 -05:00
nytmyr 0dde51f518 [Bots] Fix crash related to GetTempSpellType() (#4649)
_tempSpellType was not getting defined during bot spawn process which could lead to a potential crash in RaidGroupSay.

Auto archery toggle was what triggered the crash as it announces their status on spawn.

Also moved this toggle for Rangers further down the proccess line.
2025-02-06 04:14:25 -05:00
Alex King 5cebc42f89 [Feature] Add Support for Tradeskill Recipe Inspect (#4648)
* [Feature] Add Support for Tradeskill Recipe Inspect

* Push

* Update client_packet.cpp
2025-02-05 23:10:16 -06:00
Fryguy 7021602bf4 [Bug] Item Purchase Offset when multiple buyers are buying at the same time. (#4628)
* [Bug] Item Purchase Offset when multiple buyers are buying at the same time.

- Much of the code lifted from TAKP/P2002 and adapted
- Needs Testing
- This should help prevent situations where multiple people are purchasing items from a merchant and both attempt to purchase the same temp merchant or limited item, it should result in the later person recieving a notice that the item no longer exists and refreshes the merchant table.
- Updated strings

* fix formatting

* Push

* Update client.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update client.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-02-05 20:56:57 -06:00
Chris Miles 752ac78c56 [CI] Fix database race condition (#4646)
* [CI] Fix race condition

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh
2025-02-05 19:29:16 -06:00
Fryguy e9678da311 [Fix] Big Bag additional fixes (#4644)
* [Fix] Big Bag additional fixes

* More inventory updates
2025-02-05 17:20:36 -05:00
catapultam-habeo 51f25ed779 [Feature] Add rule to allow /changepetname to function without being enabled by scripts. 2025-02-05 15:20:24 -05:00
Mitch Freeman 8f4f8368df [Player Event Logs] Migrate and Deprecate QS Legacy Logging (#4542)
* First pass of player_event_loot_items

* Second pass of player_event_loot_items

* Third pass of player_event_loot_items

* Example without RecordDetailEvent template

* Cleanup the removal of the template

* Fourth Pass

Add retention for etl tables
Rename tables/fields to etl nomenclature
Combine database work to one atomic load

* Reposition to reduce db tasks

* Refactor etl processing for easier additions

* Add merchant purchase event
testing passed though appears that the event itself has a few bugs.  Will fix them in another commit

* Fix PlayerEventMerchantPurchase in client_packet.cpp

* WIP - Handin

* Handin Event added

* Cleanup

* All a rentention period of 0 days which deletes all current records.

* Updates

Cleanup and refactor a few items.

* Cleanup and Formatting

Cleanup and Formatting

* Add etl for
Playerevent::Trade
PlayerEvent::Speech (new event to mirror functionality of qs_speech

* Add etl for
Playerevent::KilledNPC, KilledNamedNPC and KilledRaidNPC

* Add etl for Playerevent::AA_purchase

Add etl for Playerevent::AA_purchase

* Cleanup before PR

* Review comment updates.

* Add world cli etl:settings to output a json on all player event details.

* Add reserve for all etl_queues
Correct a failed test case for improper next id for etl tables when table is first created.

* Potential solution for a dedicated database connection for player events.

* Simple thread for player_events.  Likely there is a better way to do this.

* Add zone to qs communications for recordplayerevents

First pass of enabling zone to qs direct transport to allow for PlayerEvents to bypass world.

* Cleanup a linux compile issue

* Add augments to LOOT ITEM and DESTROY ITEM

* Add augments to ITEMCREATION, FORAGESUCCESS, FISHSUCCESS, DESTROYITEM, LOOTITEM, DROPPEDITEM, TRADERPURCHASE, TRADERSELL, GUILDTRIBUTEDONATE and cleaned up the naming convention of augments

* Formatting fixes

* Swap out GetNextTableId

* Statically load counter

* Add counter.clear() since the counter is static

* Upload optional QS conversion scripts

* Remove all qs_tables and code referencing them

* Update database.cpp

* Simplify ProcessBatchQueue

* Simplify PorcessBatchQueue

* Simplify event truncation

* Build event truncation to bulk query by retention groups

* Post rebase

* Update player_events.h

* Fix build

* Update npc.cpp

* First pass of direct zone to qs sending for player events

* Remove keepalive logic

* Fix event ordering

* Cleanup

* Update player_event_logs.cpp

* Wipe event data after ETL processed

* Split up database connections, hot reload logs for QS

* Load rules from database vs qs_database

* Update player_event_logs.cpp

* Hot toggle queryserv connect

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-02-05 02:02:16 -06:00
Fryguy 21d27a1122 [Fix] Big Bag Cleanup (#4643)
* [Bug] Big Bag Cleanup

- Fixed the Database Updates to properly check for the missing column
- Added the cursor slot overflow migration and drop - Only the first 200 overflow slots are migrated due to the destination buffer size shrinking from 1000 to 200. Anything over 200 is dropped (Generally just summoned food).
- Fixed a direct DB call in corpses to the inventory table with incorrect column names
- Fixed the Inventory Snapshot bidirectional queries to account for updated inventory table names.

* Accidently nuked a line.
2025-02-04 22:29:58 -06:00
nytmyr 6519fb40c7 [Bots] Sanity checks for spell type updates (#4641)
This isn't really necessary, but just in case anyone rolls back version or an error/crash happens during an update, it doesn't rerun these checks by returning false positives for the condition checks. Also validates most data from spells_new incase modifications were made..
2025-02-04 19:20:28 -06:00
nytmyr ff2763785c [Cleanup] Cleanup logic in cursor bag check (#4642)
* [Cleanup] Cleanup logic in cursor bag check

* oops
2025-02-04 17:16:34 -05:00
nytmyr f1852e16b7 [Inventory] Fix cursor bag saving to invalid slot_ids (#4640) 2025-02-04 01:36:07 -05:00
Alex King 49917bfb13 [Quest API] Add Potion Belt Methods (#4634)
* [Quest API] Add Potion Belt Methods

* Update client.h

* Cleanup

* Update client.h

* Constrain properly

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-02-03 19:37:46 -05:00
catapultam-habeo ff86cc3b8a [Crash] Fix zone crash caused by NPC::MoveTo (#4639) 2025-02-03 17:29:39 -06:00
Akkadius 91a0e14509 [Hotfix] Fix CI since hand-ins are merged 2025-02-03 16:57:46 -06:00
Chris Miles 6fb919a16f [Items] Overhaul Item Hand-in System (#4593)
* [Items] Overhaul Item Hand-in System

* Edge case lua fix

* Merge fix

* I'm going to be amazed if this works first try

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Update linux-build.sh

* Add protections against scripts that hand back items themselves

* Remove EVENT_ITEM_ScriptStopReturn

* test

* Update npc_handins.cpp

* Add Items:AlwaysReturnHandins

* Update spdat.cpp

* Bypass update prompt on CI
2025-02-03 16:51:09 -06:00
Alex King d1d6db3a09 [Feature] Implement Big Bags (#4606)
* [Feature] Implement "Big Bags"

* Update worlddb.cpp

* Update shareddb.cpp

* Cleanup

* Cleanup

* Add slot ID conversions

* Update shareddb.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update ruletypes.h

* Update database_update_manifest.cpp

* Inventory load fix

* Wrap Handle_OP_MoveItem in a transaction, taking 200+ queries from 200ms+ to 5-20ms

* Speed up lazy loading

* [Performance] Significantly Improve Client Network Resends

* Improve resend algorithm to be exact about when to resend

* Manifest merge

* Update database_update_manifest.cpp

* Post merge

* Add forced interactive update

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-02-03 16:14:41 -06:00
nytmyr e3ab90695f [Bots] Fix Bards not casting (#4638) 2025-02-03 15:40:04 -05:00
nytmyr aa423e398a [Hotfix] [Bots] Fix error in update manifest (#4637) 2025-02-03 14:00:51 -05:00
Alex King 1cf7709c9d [Quest API] Add Bandolier Methods (#4635) 2025-02-03 04:03:27 -06:00
nytmyr f466964db8 [Bots] Bot Overhaul (#4580)
* Implement spell AI pulling, fix throw stone

* more pull tweaks

* holding check at start of ai process

* fully implement ^pull logic to always return, can still be overidden by ^attack

* Rewrite ^pull logic and handling. **MORE**

Add ^setassistee command to set who your bots will assist. Bots will always assist you first before anyone else.

If the rule Bots, AllowCrossGroupRaidAssist is enabled bots will assist the group or raid main assists.

Rewrites logic in handling of pull and returning to ensure bots make it back to their location.

* Move HateLine to a better ID

* cleanup ST_Self logic in CastChecks

* Removed unused BotSpellTypeRequiresLoS

* Move fizzle message to define

* add timer checks to Idle/Engaged/Pursue CastCheck to early terminate

* Add back !IsBotNonSpellFighter() check to the different CastCheck

* Correct IsValidSpellRange

* Implement AAs and harmtouch/layonhands to ^cast --- fix IsValidSpellRange

* Add PetDamageShields and PetResistBuffs to IsPetBotSpellType()

* Add priorities to HateLine inserts for db update

* Remove SpellTypeRequiresCastChecks

* Add bot check to DetermineSpellTargets for IsIllusionSpell

* merge with previous

* Correct bot checks for ST_GroupClientAndPet

* Remove misc target_type checks

* Add lull/aelull to ^cast

* Add more checks for CommandedSubTypes::AETarget

* remove unneeded checks on IsValidSpellTypeBySpellID

* add to aelull

* rewrite GetCorrectSpellType

* Add IsBlockedBuff to CastChecks

* Add spellid option to ^cast to allow casting of a specific spell by ID

* ^cast adjustments for spellid casts

* Add missing alert round for ranged attacks

* More castcheck improvements

* CanUseBotSpell for ^cast

* remove ht/loh from attack ai

* remove SetCombatRoundForAlerts that triggered every engagement

* Add RangedAttackImmunity checks before trying to ranged attack

* move bot backstab to mob

* fix MinStatusToBypassCreateLimit

* more backstab to mob cleanup

* add bot checks to tryheadshot / tryassassinate

* adjust version number for bots

* add back m_mob_check_moving_timer, necessary?

* add sanity checks for classattacks

* Get rid of Bots:BotGroupXP and change logic to support Bots:SameRaidGroupForXP

Bots won't do anything if not in the same group so this should more accurately control only when in the same raid group.

* add "confirm" check to ^delete

* Update bot.cpp

* Remove `id` from bot_settings, correct types

* Implement blocked_buffs and blocked_pet_buffs

* more blocked buff tweaks

* add beneficial check to ^blockedbuffs

* command grammar

* missing )

* Move getnames for categories and settings to mob, rename hptomed/manatomed

* add GetBotSpellCategoryIDByShortName and CopyBotBlockedPetBuffs, update ^defaultsettings command

* cls cleanup

* Allow bots to clear HasProjectIllusion flag

* Add PercentChanceToCastGroupCure

* Implmenet PetCures, add some missing types for defaults/chance to cast

* Change GetRaidByBotName to GetRaidByBot

* Typo on PetBuffs implement

* Change GetSpellListSpellType to GetParentSpellType

* missing from GetChanceToCastBySpellType

* Fix performance in IsValidSpellRange by flipping HasProjectIllusion

* merge with prev

* merge with cls cleanup

* Reorder IsTargetAlreadyReceivingSpell/CheckSpellLevelRestriction/IsBlockedBuff

* Combine GatherGroupSpellTargets and GatherSpellTargets

* Cleanup IsTargetAlreadyReceivingSpell

* Fix ^petsettype to account for usable levels of spells and remove hardcoded level limits.

* Remove Bot_AICheckCloseBeneficialSpells and use AttemptCloseBeneficialSpells for better performance

* remove default hold for resist buffa

* move IsValidSpellRange further down castchecks

* raid optimizations

* correct name checking to match players

* more name checks and add proper soft deletes to bots

* organize some checks in IsImmuneToBotSpell

* Fix GetRaidByBotName and GetRaidByBot checks to not loop unnecessarily

* Move GatherSpellTargets to mob

* Change GetPrioritizedBotSpellsBySpellType to vector

Some slipped through in "organize some checks in IsImmuneToBotSpell"

* Move GatherSpellTargets and Raid to stored variables.

Missing some in "organize some checks in IsImmuneToBotSpell"

* comment out precheck, delays, thresholds, etc logging

missed some in "organize some checks in IsImmuneToBotSpell"

* Missing IsInGroupOrRaid cleanup

* Implement AIBot_spells_by_type to reduce looping when searching for spells

* Add _tempSpellType as placeholder for any future passthru

* todo

* Move bot_list from std::list to std::unordered_map like other entities

* Fix missing raid assignment for GetStoredRaid in IsInGroupOrRaid

* TempPet owned by bots that get the kill will now give exp like a client would

* Remove unnecessary checks in bot process (closescanmoving timer, verify raid, send hp/mana/end packet

* Fix client spell commands from saving the wrong setting

* Cleanup ^copysettings command and add new commands

* Add pet option to ^taunt

No longer has toggle, required on/off option and an optional "pet" option to control pets' taunting state

* Allow pet types to ^cast, prevent failure spam, add cure check

* more raid optimizations, should be final.

10 clients, 710 bots, 10 raids, ~250 pets sits around 3.5% CPU idle

* Move spell range check to proper location

* Implement ^discipline

* remove ^aggressive/^defensive

* remove this for a separate PR

* cleanup

* Add BotGroupSay method

* todo list

* Add missing bot_blocked_buffs to schema

* Remove plural on ^spelltypeidsand ^spelltypenames

* Move spelltype names, spell subtypes, category names and setting names to maps.

* move los checks to mob.cpp

* Bot CampAll fix

* Bots special_attacks.cpp fix

* Add zero check for bot spawn limits

If the spawn limit rule is set to 0 and spawn limit is set by bucket, if no class buckets are set, it defaults to the rule of 0 and renders the player unable to spawn bots.

This adds a check where if the rule and class bucket are 0, it will check for the spawn limit bucket

* Add HasSkill checks to bot special abilities (kick/bash/etc)

* code cleanup 1

* code cleanup 2

* code cleanup 3

* code cleanup 4

* fix ^cast wirh commanded types

* Remove bcspells, fix helper_send_usage_required_bots

* linux build fix

* remove completed todo

* Allow inventory give to specific ID slots

* Update TODO

* Correct slot ranges for inventorygive

* Add zone specific spawn limits and zone specific forced spawn limits

* remove bd. from update queries where it doesn't exist

* Rename _spellSettings to m_bot_spell_settings

* Add IsPetOwnerOfClientBot(), add Lua and Perl methods

* Make botOwnerCharacterID snakecase

* Throw bot_camp_timer behind Bots:Enabled rule

* Move various Bot<>Checks logging to BotSpellChecks

* Remove from LogCategoryName

* Consolidate IsInGroupOrRaid

* Consolidate GatherSpellTargets

* Add missing Bot Spell Type Checks to log

* Add GetParentSpellType when checking spelltypes for idle, engaged, pursue CastChecks.

* Consolidate AttemptForcedCastSpell

* Consolidate SetBotBlockedBuff/SetBotBlockedPetBuff

* Add list option to ^spellpriority commands.

* Move client functions to client_bot

* Move mob functions to mob_bot

* Move bot spdat functions to spdat_bot

* Move SendCommandHelpWindow to SendBotCommandHelpWindow and simplify

* Change char_id to character_id for bot_settings

* update todo

* Fix typo on merge conflict

* Cleanup command format changes, remove hardcoded class IDs in examples.

* Set #illusionblock for players to guide access

* Move client commands for bot spells from gm commands to existing bot commands

* Fix alignment issues

* More alignment fixes

* More cleanup 1

* More cleanup 2

* Fix BotMeditate to med at proper percentages

* Correct GetStopMeleeLevel checks for some buff checks

* Add back hpmanaend update to bot raid, force timer update to prevent spamming

* Remove log

* Cleanup ranged and ammo calculations - Adds throwing check for match

* Add check in distance calculations to stay at range if set even if no ammo or ranged

* Move melee distance calculations to better function

* Add GetBuffTargets helper

* Missing p_item, s_item in CombatRangeInput

* Linux test?

* Reduce GetCorrectBotSpellType branching slightly

This is still an ugly ass function but my brain is melted

* Line fixes

* Make bot pets only do half damage in pvp

* Add bot pet pvp damage to tune

* Add bot pet check for AIYellForHelp

* Add bots to UseSpellImpliedTargeting

* Move toggleranged, togglehelm and illusionblock to new help window. Add actionable support

* Add bot and bot pet checks to various spells, auras and targeting checks that were missing.

* update todo

* New lines

* Correct DoLosChecks

* Remove Log TestDebug

* Remove _Struct from struct declarations

* Add bot check to IsAttackAllowed for GetUltimateOwner to skip entity list where possible

* Wrap SaveBotSettings in Bots Enabled check

* Remove comment

* Wrap bot setting loading for clients in bots enabled rule

* Cleanup BlockedBuffs logic in SpellOnTarget

* Rename BotSpells_Struct/BotSpells_Struct_wIndex

* Rename spawn/create status bypass rules, fix return for spawn limit

* Remove unnecessary return in CanBuffStack, cleanup

* Enable recastdelay support for clients

* Remove unused variables

* Rename _assistee to bot_assistee

* hardcode BotCommandHelpWindow colors

* todo

* Fix ^cast summoncorpse

* todo

* Reimplement secondary colors to BotSendCommandHelpWindow

* Give ^copysettings/^defaultsettings more options, cleanup.

* Cleanup some commands

* Add comment to CheckLosCheat/CheckLosCheatExempt

* Make struct BotSpellSettings snake case

* Allow duplicate casts of same spell on target for heals and cures

* Add default delay to cures

* Remove unused methods

* Implement missing ^spellresistlimits/^resistlimits command

* Move functions out of mob.h and cleanup

* Return for GetRawBotList

This checks offline bots too

* Rename BotGroupSay to RaidGroupSay

* Prevent bots from forming their own group if a bot that is a group leader is removed from the raid

* Linux fix?

* IsPetOwner fixes

* Add remove option to list for ^blockedbuffs / ^blockedpetbuffs

* Implement ^spellannouncecasts to toggle announcing casts of spell types

* Remove rule Bots:BardsAnnounceCasts

* Update bot.h

* Remove unused no_pets option from GatherSpellTargets

* Move ^attack response back to normal chat window (other)

* Set lower limit of spell delays to 100 rather than 1

* Correct pet checks on GetUltimateSpell functions

* Add rules (Bots, AICastSpellTypeDelay, Bots, AICastSpellTypeHeldDelay) to prevent spamming of failed spell type AI casts

* Correct pet buff type logic to catch DS/Resists with other spell effects in them

* Fix defaults for clients

* Add more logic for necros/shaman for default heal thresholds due to lich and canni

* Rename SpellHold, SpellDelay, SpellMinThreshold, SpellMaxThreshold, SpellRecastDelay to fit SpellType style naming

* Use GetTempSpellType() for announce check in RaidGroupSay

* Make all spell shortnames plural where applicable

* Update bot.cpp

* Bots:BotsUseLiveBlockedMessage filter to spell failure

* Move GetSpellTargetList to only get called when necessary to reduce overhead

* formatting

* Formatting

* Simplify case SE_Illusion and SE_IllusionCopy for GetIllusionBlock

* Clean up InterruptSpell

* Cleanup IsBot() checks for DetermineSpellTargets->ST_GroupClientAndPet

* Cleanup range/aoe_range check in SpellFinished

* Cleanup DetermineSpellTargets->ST_GroupNoPets

* Cleanup DetermineSpellTargets->ST_Self for bot summon corpse

* Cleanup DetermineSpellTargets->ST_Pet

* Cleanup bot logic in TryBackstab

* Cleanup IsAttackAllowed checks for bots and their pets

* Cleanup StopMoving for bots

* Cleanup CanThisClassTripleAttack

* Fix casting for GetIllusionBlock checks

* Formatting

* Fix DetermineSpellTargets for group spells (this also wasn't properly checking the rule Character:EnableTGB in master)

* Cleanup spelltarget grabbing logic, consolidate group heals in to GetNumberNeedingHealedInGroup

* Throw added client los pet checks behind LoS cheat rule for bots

* CLeanup give_exp on npc death logic and ensure client pets always pass.

* Undo unintended rename from previous refactor

* Remove pointless Bots, SameRaidGroupForXP rule

* Revision to 0690783a9d

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2025-02-03 04:02:42 -06:00
Chris Miles 4fda3c045e [Release] 22.62.2 (#4633) 2025-02-01 16:25:53 -06:00
Mitch Freeman 0a20100d12 [Fix] Add price change check to the Bazaar Search Window purchase mechanics (#4632) 2025-02-01 14:30:07 -06:00
Mitch Freeman 29701d0ea7 [Fix] Update the shard bazaar search feature (#4630) 2025-02-01 13:36:26 -06:00
Mitch Freeman 4a38fd8829 [Fix] NewBazaar Search Consumables (#4631) 2025-02-01 13:35:08 -06:00
Chris Miles 08c8e0d81f [Performance] Significantly Improve Client Network Resends (#4629)
* [Performance] Significantly Improve Client Network Resends

* Update daybreak_connection.cpp

* Improve resend algorithm to be exact about when to resend
2025-01-31 22:23:08 -06:00
328 changed files with 41020 additions and 16707 deletions
+16
View File
@@ -1,3 +1,19 @@
## [22.62.2] 2/1/2025
### Fixes
* Add price change check to the Bazaar Search Window purchase mechanics ([#4632](https://github.com/EQEmu/Server/pull/4632)) @neckkola 2025-02-01
* NewBazaar Search Consumables ([#4631](https://github.com/EQEmu/Server/pull/4631)) @neckkola 2025-02-01
* Update the shard bazaar search feature ([#4630](https://github.com/EQEmu/Server/pull/4630)) @neckkola 2025-02-01
### Memory Leak
* Revert " Change raw pointer to unique_ptr to avoid potential leak in dbg stream " ([#4616](https://github.com/EQEmu/Server/pull/4616)) @Akkadius 2025-01-27
### Performance
* Significantly Improve Client Network Resends ([#4629](https://github.com/EQEmu/Server/pull/4629)) @Akkadius 2025-02-01
## [22.62.1] 1/27/2025
### Memory Leak
+25
View File
@@ -89,6 +89,7 @@ SET(common_sources
skills.cpp
skill_caps.cpp
spdat.cpp
spdat_bot.cpp
strings.cpp
struct_strategy.cpp
textures.cpp
@@ -281,8 +282,20 @@ 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_aa_purchase_repository.h
repositories/base/base_player_event_killed_npc_repository.h
repositories/base/base_player_event_killed_named_npc_repository.h
repositories/base/base_player_event_killed_raid_npc_repository.h
repositories/base/base_player_event_log_settings_repository.h
repositories/base/base_player_event_logs_repository.h
repositories/base/base_player_event_loot_items_repository.h
repositories/base/base_player_event_merchant_purchase_repository.h
repositories/base/base_player_event_merchant_sell_repository.h
repositories/base/base_player_event_npc_handin_repository.h
repositories/base/base_player_event_npc_handin_entries_repository.h
repositories/base/base_player_event_speech_repository.h
repositories/base/base_player_event_trade_repository.h
repositories/base/base_player_event_trade_entries_repository.h
repositories/base/base_quest_globals_repository.h
repositories/base/base_raid_details_repository.h
repositories/base/base_raid_members_repository.h
@@ -466,8 +479,20 @@ SET(repositories
repositories/pets_equipmentset_repository.h
repositories/pets_equipmentset_entries_repository.h
repositories/player_titlesets_repository.h
repositories/player_event_aa_purchase_repository.h
repositories/player_event_killed_npc_repository.h
repositories/player_event_killed_named_npc_repository.h
repositories/player_event_killed_raid_npc_repository.h
repositories/player_event_log_settings_repository.h
repositories/player_event_logs_repository.h
repositories/player_event_loot_items_repository.h
repositories/player_event_merchant_purchase_repository.h
repositories/player_event_merchant_sell_repository.h
repositories/player_event_npc_handin_repository.h
repositories/player_event_npc_handin_entries_repository.h
repositories/player_event_speech_repository.h
repositories/player_event_trade_repository.h
repositories/player_event_trade_entries_repository.h
repositories/quest_globals_repository.h
repositories/raid_details_repository.h
repositories/raid_members_repository.h
+7 -4
View File
@@ -283,7 +283,7 @@ Bazaar::GetSearchResults(
);
if (item_results.empty()) {
LogError("Bazaar - No items found in bazaar search.");
LogTradingDetail("Bazaar - No items found in bazaar search.");
return all_entries;
}
@@ -300,7 +300,7 @@ Bazaar::GetSearchResults(
r.serial_number = t.trader.item_sn;
r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id;
r.sum_charges = t.trader.item_charges;
r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable;
r.icon_id = item_results.at(t.trader.item_id).icon;
r.trader_zone_id = t.trader.char_zone_id;
@@ -312,9 +312,12 @@ Bazaar::GetSearchResults(
r.item_stat = item_results.at(t.trader.item_id).stats;
if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (convert || (r.trader_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)) {
if (convert ||
char_zone_id != Zones::BAZAAR ||
(char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
) {
r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
}
}
}
all_entries.push_back(r);
+2
View File
@@ -131,6 +131,8 @@ static std::map<uint8, std::string> class_names = {
#define ARMOR_TYPE_LAST ARMOR_TYPE_PLATE
#define ARMOR_TYPE_COUNT 5
#define BOT_CLASS_BASE_ID_PREFIX 3000
const char* GetClassIDName(uint8 class_id, uint8 level = 0);
+29 -12
View File
@@ -2155,18 +2155,18 @@ void Database::PurgeCharacterParcels()
pel.event_type_name = PlayerEvent::EventName[pel.event_type_id];
std::stringstream ss;
for (auto const &r: results) {
pd.from_name = r.from_name;
pd.item_id = r.item_id;
pd.aug_slot_1 = r.aug_slot_1;
pd.aug_slot_2 = r.aug_slot_2;
pd.aug_slot_3 = r.aug_slot_3;
pd.aug_slot_4 = r.aug_slot_4;
pd.aug_slot_5 = r.aug_slot_5;
pd.aug_slot_6 = r.aug_slot_6;
pd.note = r.note;
pd.quantity = r.quantity;
pd.sent_date = r.sent_date;
pd.char_id = r.char_id;
pd.from_name = r.from_name;
pd.item_id = r.item_id;
pd.augment_1_id = r.aug_slot_1;
pd.augment_2_id = r.aug_slot_2;
pd.augment_3_id = r.aug_slot_3;
pd.augment_4_id = r.aug_slot_4;
pd.augment_5_id = r.aug_slot_5;
pd.augment_6_id = r.aug_slot_6;
pd.note = r.note;
pd.quantity = r.quantity;
pd.sent_date = r.sent_date;
pd.char_id = r.char_id;
{
cereal::JSONOutputArchiveSingleLine ar(ss);
pd.serialize(ar);
@@ -2202,3 +2202,20 @@ void Database::ClearBuyerDetails()
{
BuyerRepository::DeleteBuyer(*this, 0);
}
uint64_t Database::GetNextTableId(const std::string &table_name)
{
auto results = QueryDatabase(fmt::format("SHOW TABLE STATUS LIKE '{}'", table_name));
for (auto row: results) {
for (int row_index = 0; row_index < results.ColumnCount(); row_index++) {
std::string field_name = Strings::ToLower(results.FieldName(row_index));
if (field_name == "auto_increment") {
std::string value = row[row_index] ? row[row_index] : "null";
return Strings::ToUnsignedBigInt(value, 1);
}
}
}
return 1;
}
+2
View File
@@ -274,6 +274,8 @@ public:
void Encode(std::string &in);
void Decode(std::string &in);
uint64_t GetNextTableId(const std::string& table_name);
private:
Mutex Mvarcache;
VarCache_Struct varcache;
-21
View File
@@ -136,11 +136,6 @@ std::string DatabaseDumpService::GetLoginTableList()
return Strings::Join(DatabaseSchema::GetLoginTables(), " ");
}
std::string DatabaseDumpService::GetQueryServTables()
{
return Strings::Join(DatabaseSchema::GetQueryServerTables(), " ");
}
std::string DatabaseDumpService::GetSystemTablesList()
{
auto system_tables = DatabaseSchema::GetServerTables();
@@ -272,11 +267,6 @@ void DatabaseDumpService::DatabaseDump()
tables_to_dump += GetLoginTableList() + " ";
dump_descriptor += "-login";
}
if (IsDumpQueryServerTables()) {
tables_to_dump += GetQueryServTables();
dump_descriptor += "-queryserv";
}
}
if (IsDumpStaticInstanceData()) {
@@ -401,7 +391,6 @@ void DatabaseDumpService::DatabaseDump()
// LogDebug("[{}] dump-to-console", IsDumpOutputToConsole());
// LogDebug("[{}] dump-path", GetSetDumpPath());
// LogDebug("[{}] compression", (IsDumpWithCompression() ? "true" : "false"));
// LogDebug("[{}] query-serv", (IsDumpQueryServerTables() ? "true" : "false"));
// LogDebug("[{}] has-compression-binary", (HasCompressionBinary() ? "true" : "false"));
// LogDebug("[{}] content", (IsDumpContentTables() ? "true" : "false"));
// LogDebug("[{}] no-data", (IsDumpWithNoData() ? "true" : "false"));
@@ -511,16 +500,6 @@ const std::string &DatabaseDumpService::GetDumpFileName() const
return dump_file_name;
}
bool DatabaseDumpService::IsDumpQueryServerTables() const
{
return dump_query_server_tables;
}
void DatabaseDumpService::SetDumpQueryServerTables(bool dump_query_server_tables)
{
DatabaseDumpService::dump_query_server_tables = dump_query_server_tables;
}
bool DatabaseDumpService::IsDumpOutputToConsole() const
{
return dump_output_to_console;
-3
View File
@@ -45,8 +45,6 @@ public:
void SetDumpPath(const std::string &dump_path);
const std::string &GetDumpFileName() const;
void SetDumpFileName(const std::string &dump_file_name);
bool IsDumpQueryServerTables() const;
void SetDumpQueryServerTables(bool dump_query_server_tables);
bool IsDumpOutputToConsole() const;
void SetDumpOutputToConsole(bool dump_output_to_console);
bool IsDumpDropTableSyntaxOnly() const;
@@ -96,7 +94,6 @@ private:
bool HasCompressionBinary();
std::string GetDumpFileNameWithPath();
std::string GetSetDumpPath();
std::string GetQueryServTables();
void RemoveSqlBackup();
void BuildCredentialsFile();
void RemoveCredentialsFile();
+41
View File
@@ -142,6 +142,7 @@ bool DatabaseUpdate::UpdateManifest(
if (version_low != version_high) {
LogSys.DisableMySQLErrorLogs();
bool force_interactive = false;
for (int version = version_low + 1; version <= version_high; ++version) {
for (auto &e: entries) {
if (e.version == version) {
@@ -163,6 +164,10 @@ bool DatabaseUpdate::UpdateManifest(
prefix,
e.description
);
if (!has_migration && e.force_interactive) {
force_interactive = true;
}
}
}
}
@@ -187,6 +192,42 @@ bool DatabaseUpdate::UpdateManifest(
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
}
if (force_interactive && !std::getenv("FORCE_INTERACTIVE")) {
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
LogInfo("Some migrations require user input. Running interactively");
LogInfo("This is usually due to a major change that could cause data loss");
LogInfo("Your server is automatically backed up before these updates are applied");
LogInfo("but you should also make sure you take a backup prior to running this update");
LogInfo("Would you like to run this update? [y/n] (Timeout 60s)");
LogInfo("{}", Strings::Repeat("-", BREAK_LENGTH));
// user input
std::string input;
bool gave_input = false;
time_t start_time = time(nullptr);
time_t wait_time_seconds = 60;
// spawn a concurrent thread that waits for input from std::cin
std::thread t1(
[&]() {
std::cin >> input;
gave_input = true;
}
);
t1.detach();
// check the inputReceived flag once every 50ms for 10 seconds
while (time(nullptr) < start_time + wait_time_seconds && !gave_input) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
// prompt for user skip
if (Strings::Trim(input) != "y") {
LogInfo("Exiting due to user input");
std::exit(1);
}
}
for (auto &m: missing_migrations) {
for (auto &e: entries) {
if (e.version == m) {
+1
View File
@@ -11,6 +11,7 @@ struct ManifestEntry {
std::string match{}; // match field that is not always used, but works in conjunction with "condition" values [missing|match|contains]
std::string sql{}; // the SQL DDL that gets ran when the condition is true
bool content_schema_update{}; // if true, this migration is a content schema update and should be ran against the content database
bool force_interactive; // if true, this migration will always be run interactively
};
struct DatabaseVersion {
+302 -7
View File
@@ -6380,8 +6380,21 @@ CREATE INDEX idx_trader_active_transaction ON trader (active_transaction);
},
ManifestEntry{
.version = 9296,
.description = "2025_02_01_trader_table_listing_date.sql",
.check = "SHOW CREATE TABLE `trader`",
.condition = "missing",
.match = "listing_date",
.sql = R"(
ALTER TABLE `trader`
ADD COLUMN `listing_date` DATETIME NULL DEFAULT NULL AFTER `active_transaction`,
ADD INDEX `idx_trader_listing_date` (`listing_date`);
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9297,
.description = "2024_01_22_sharedbank_guid_primary_key.sql",
.check = "SHOW COLUMN FROM `sharedbank` LIKE 'guid'",
.check = "SHOW COLUMNS FROM `sharedbank` LIKE 'guid'",
.condition = "empty",
.match = "",
.sql = R"(
@@ -6402,12 +6415,14 @@ ADD COLUMN `ornament_idfile` int(11) UNSIGNED NOT NULL AFTER `ornament_icon`,
ADD COLUMN `ornament_hero_model` int(11) NOT NULL AFTER `ornament_idfile`,
ADD COLUMN `guid` bigint(20) UNSIGNED NOT NULL DEFAULT 0 AFTER `ornament_hero_model`,
ADD PRIMARY KEY (`account_id`, `slot_id`);
)"
)",
.content_schema_update = false,
.force_interactive = true
},
ManifestEntry{
.version = 9297,
.version = 9298,
.description = "2024_10_24_inventory_changes.sql",
.check = "SHOW COLUMN FROM `inventory` LIKE 'charid'",
.check = "SHOW COLUMNS FROM `inventory` LIKE 'character_id'",
.condition = "empty",
.match = "",
.sql = R"(
@@ -6435,6 +6450,8 @@ UPDATE `inventory` SET `slot_id` = ((`slot_id` - 311) + 5210) WHERE `slot_id` BE
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 321) + 5410) WHERE `slot_id` BETWEEN 321 AND 330; -- Bag 8
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 331) + 5610) WHERE `slot_id` BETWEEN 331 AND 340; -- Bag 9
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 341) + 5810) WHERE `slot_id` BETWEEN 341 AND 350; -- Bag 10
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 8000) + 6010) WHERE `slot_id` BETWEEN 8000 AND 8199; -- Cursor Overflow
DELETE FROM `inventory` WHERE `slot_id` BETWEEN 8200 AND 8999; -- Extreme Cursor Overflow
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 351) + 6010) WHERE `slot_id` BETWEEN 351 AND 360; -- Cursor Bag
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2031) + 6210) WHERE `slot_id` BETWEEN 2031 AND 2040; -- Bank Bag 1
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2041) + 6410) WHERE `slot_id` BETWEEN 2041 AND 2050; -- Bank Bag 2
@@ -6462,10 +6479,12 @@ UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2251) + 10610) WHERE `slot_id`
UPDATE `inventory` SET `slot_id` = ((`slot_id` - 2261) + 10810) WHERE `slot_id` BETWEEN 2261 AND 2270; -- Bank Bag 24
UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2531) + 11010) WHERE `slot_id` BETWEEN 2531 AND 2540; -- Shared Bank Bag 1
UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2541) + 11210) WHERE `slot_id` BETWEEN 2541 AND 2550; -- Shared Bank Bag 2
)"
)",
.content_schema_update = false,
.force_interactive = true
},
ManifestEntry{
.version = 9298,
.version = 9299,
.description = "2024_10_24_merchantlist_temp_uncap.sql",
.check = "SHOW CREATE TABLE `merchantlist_temp`",
.condition = "contains",
@@ -6473,9 +6492,285 @@ UPDATE `sharedbank` SET `slot_id` = ((`slot_id` - 2541) + 11210) WHERE `slot_id`
.sql = R"(
ALTER TABLE `merchantlist_temp`
MODIFY COLUMN `slot` int UNSIGNED NOT NULL DEFAULT 0 AFTER `npcid`;
)",
.content_schema_update = false
},
ManifestEntry{
.version = 9300,
.description = "2024_10_15_npc_types_multiquest_enabled.sql",
.check = "SHOW COLUMNS FROM `npc_types` LIKE 'multiquest_enabled'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_types`
ADD COLUMN `multiquest_enabled` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_parcel_merchant`;
)",
.content_schema_update = true
},
ManifestEntry{
.version = 9301,
.description = "2024_10_08_add_detail_player_event_logging.sql",
.check = "SHOW COLUMNS FROM `player_event_log_settings` LIKE 'etl_enabled'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `player_event_log_settings`
ADD COLUMN `etl_enabled` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `discord_webhook_id`;
ALTER TABLE `player_event_logs`
ADD COLUMN `etl_table_id` BIGINT(20) NOT NULL DEFAULT '0' AFTER `event_data`;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 14;
CREATE TABLE `player_event_loot_items` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`item_id` INT(10) UNSIGNED NULL DEFAULT NULL,
`item_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`charges` INT(11) NULL DEFAULT NULL,
`augment_1_id` INT UNSIGNED NULL DEFAULT '0',
`augment_2_id` INT UNSIGNED NULL DEFAULT '0',
`augment_3_id` INT UNSIGNED NULL DEFAULT '0',
`augment_4_id` INT UNSIGNED NULL DEFAULT '0',
`augment_5_id` INT UNSIGNED NULL DEFAULT '0',
`augment_6_id` INT UNSIGNED NULL DEFAULT '0',
`npc_id` INT(10) UNSIGNED NULL DEFAULT NULL,
`corpse_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `item_id_npc_id` (`item_id`, `npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 16;
CREATE TABLE `player_event_merchant_sell` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`merchant_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`merchant_type` INT(10) UNSIGNED NULL DEFAULT '0',
`item_id` INT(10) UNSIGNED NULL DEFAULT '0',
`item_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`charges` INT(11) NULL DEFAULT '0',
`cost` INT(10) UNSIGNED NULL DEFAULT '0',
`alternate_currency_id` INT(10) UNSIGNED NULL DEFAULT '0',
`player_money_balance` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`player_currency_balance` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `item_id_npc_id` (`item_id`, `npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 15;
CREATE TABLE `player_event_merchant_purchase` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`merchant_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`merchant_type` INT(10) UNSIGNED NULL DEFAULT '0',
`item_id` INT(10) UNSIGNED NULL DEFAULT '0',
`item_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`charges` INT(11) NULL DEFAULT '0',
`cost` INT(10) UNSIGNED NULL DEFAULT '0',
`alternate_currency_id` INT(10) UNSIGNED NULL DEFAULT '0',
`player_money_balance` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`player_currency_balance` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `item_id_npc_id` (`item_id`, `npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 22;
CREATE TABLE `player_event_npc_handin` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`npc_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`handin_copper` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`handin_silver` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`handin_gold` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`handin_platinum` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`return_copper` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`return_silver` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`return_gold` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`return_platinum` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`is_quest_handin` TINYINT(3) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `npc_id_is_quest_handin` (`npc_id`, `is_quest_handin`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
CREATE TABLE `player_event_npc_handin_entries` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`player_event_npc_handin_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`type` INT(10) UNSIGNED NULL DEFAULT NULL,
`item_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`charges` INT(11) NOT NULL DEFAULT '0',
`evolve_level` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`evolve_amount` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`augment_1_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`augment_2_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`augment_3_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`augment_4_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`augment_5_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`augment_6_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `type_item_id` (`type`, `item_id`) USING BTREE,
INDEX `player_event_npc_handin_id` (`player_event_npc_handin_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 27;
CREATE TABLE `player_event_trade` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`char1_id` INT(10) UNSIGNED NULL DEFAULT '0',
`char2_id` INT(10) UNSIGNED NULL DEFAULT '0',
`char1_copper` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char1_silver` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char1_gold` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char1_platinum` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char2_copper` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char2_silver` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char2_gold` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char2_platinum` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `char1_id_char2_id` (`char1_id`, `char2_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
CREATE TABLE `player_event_trade_entries` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`player_event_trade_id` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`char_id` INT(10) UNSIGNED NULL DEFAULT '0',
`slot` SMALLINT(6) NULL DEFAULT '0',
`item_id` INT(10) UNSIGNED NULL DEFAULT '0',
`charges` SMALLINT(6) NULL DEFAULT '0',
`augment_1_id` INT(10) UNSIGNED NULL DEFAULT '0',
`augment_2_id` INT(10) UNSIGNED NULL DEFAULT '0',
`augment_3_id` INT(10) UNSIGNED NULL DEFAULT '0',
`augment_4_id` INT(10) UNSIGNED NULL DEFAULT '0',
`augment_5_id` INT(10) UNSIGNED NULL DEFAULT '0',
`augment_6_id` INT(10) UNSIGNED NULL DEFAULT '0',
`in_bag` TINYINT(4) NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `player_event_trade_id` (`player_event_trade_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 0 WHERE `id` = 54;
CREATE TABLE `player_event_speech` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`to_char_id` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`from_char_id` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`guild_id` INT(10) UNSIGNED NULL DEFAULT '0',
`type` INT(10) UNSIGNED NULL DEFAULT '0',
`min_status` INT(10) UNSIGNED NULL DEFAULT '0',
`message` LONGTEXT NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `to_char_id_from_char_id` (`to_char_id`, `from_char_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 44;
CREATE TABLE `player_event_killed_npc` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`npc_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`combat_time_seconds` INT(10) UNSIGNED NULL DEFAULT '0',
`total_damage_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`total_heal_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `npc_id` (`npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 45;
CREATE TABLE `player_event_killed_named_npc` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`npc_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`combat_time_seconds` INT(10) UNSIGNED NULL DEFAULT '0',
`total_damage_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`total_heal_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `npc_id` (`npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 46;
CREATE TABLE `player_event_killed_raid_npc` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_id` INT(10) UNSIGNED NULL DEFAULT '0',
`npc_name` VARCHAR(64) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
`combat_time_seconds` INT(10) UNSIGNED NULL DEFAULT '0',
`total_damage_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`total_heal_per_second_taken` BIGINT(20) UNSIGNED NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `npc_id` (`npc_id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
UPDATE `player_event_log_settings` SET `etl_enabled` = 1 WHERE `id` = 4;
CREATE TABLE `player_event_aa_purchase` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`aa_ability_id` INT(11) NULL DEFAULT '0',
`cost` INT(11) NULL DEFAULT '0',
`previous_id` INT(11) NULL DEFAULT '0',
`next_id` INT(11) NULL DEFAULT '0',
`created_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `created_at` (`created_at`) USING BTREE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;
)"
}
},
ManifestEntry{
.version = 9302,
.description = "2025_02_09_illusion_block.sql",
.check = "SHOW COLUMNS FROM `character_data` LIKE 'illusion_block'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `character_data`
ADD COLUMN `illusion_block` TINYINT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `deleted_at`;
UPDATE `command_settings`
SET `aliases` =
CASE
WHEN LENGTH(`aliases`) > 0 AND `aliases` NOT LIKE '%|ib%'
THEN CONCAT(`aliases`, '|ib')
WHEN LENGTH(`aliases`) = 0
THEN 'ib'
ELSE `aliases`
END
WHERE `command` = 'illusionblock'
AND `aliases` NOT LIKE '%ib%';
)",
}
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
// .version = 9228,
File diff suppressed because it is too large Load Diff
+14 -26
View File
@@ -291,32 +291,6 @@ namespace DatabaseSchema {
};
}
/**
* Gets QueryServer tables
*
* @return
*/
static std::vector<std::string> GetQueryServerTables()
{
return {
"qs_merchant_transaction_record",
"qs_merchant_transaction_record_entries",
"qs_player_aa_rate_hourly",
"qs_player_delete_record",
"qs_player_delete_record_entries",
"qs_player_events",
"qs_player_handin_record",
"qs_player_handin_record_entries",
"qs_player_move_record",
"qs_player_move_record_entries",
"qs_player_npc_kill_record",
"qs_player_npc_kill_record_entries",
"qs_player_speech",
"qs_player_trade_record",
"qs_player_trade_record_entries",
};
}
/**
* Gets state tables
* Tables that keep track of server state
@@ -359,8 +333,20 @@ namespace DatabaseSchema {
"saylink",
"server_scheduled_events",
"spawn2_disabled",
"player_event_aa_purchase",
"player_event_killed_npc",
"player_event_killed_named_npc",
"player_event_killed_raid_npc",
"player_event_log_settings",
"player_event_logs",
"player_event_loot_items",
"player_event_merchant_purchase",
"player_event_merchant_sell",
"player_event_npc_handin",
"player_event_npc_handin_entries",
"player_event_speech",
"player_event_trade",
"player_event_trade_entries",
"shared_task_activity_state",
"shared_task_dynamic_zones",
"shared_task_members",
@@ -406,6 +392,7 @@ namespace DatabaseSchema {
static std::vector<std::string> GetBotTables()
{
return {
"bot_blocked_buffs",
"bot_buffs",
"bot_command_settings",
"bot_create_combinations",
@@ -419,6 +406,7 @@ namespace DatabaseSchema {
"bot_pet_buffs",
"bot_pet_inventories",
"bot_pets",
"bot_settings",
"bot_spell_casting_chances",
"bot_spell_settings",
"bot_spells_entries",
+1
View File
@@ -574,6 +574,7 @@ N(OP_TradeRequestAck),
N(OP_TraderItemUpdate),
N(OP_TraderShop),
N(OP_TradeSkillCombine),
N(OP_TradeSkillRecipeInspect),
N(OP_Translocate),
N(OP_TributeInfo),
N(OP_TributeItem),
+4
View File
@@ -4283,6 +4283,10 @@ struct NewCombine_Struct {
/*04*/
};
struct TradeSkillRecipeInspect_Struct {
uint32 recipe_id;
uint32 padding[17]; // unknown
};
//client requesting favorite recipies
struct TradeskillFavorites_Struct {
+2
View File
@@ -147,6 +147,8 @@ void EQEmuConfig::parse_config()
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
QSHost = _root["server"]["queryserver"].get("host", "localhost").asString();
QSPort = Strings::ToUnsignedInt(_root["server"]["queryserver"].get("port", "9500").asString());
/**
* Zones
+3 -1
View File
@@ -81,7 +81,9 @@ class EQEmuConfig
std::string QSDatabaseUsername;
std::string QSDatabasePassword;
std::string QSDatabaseDB;
uint16 QSDatabasePort;
uint16 QSDatabasePort;
std::string QSHost;
int QSPort;
// From <files/>
std::string SpellsFile;
+4
View File
@@ -105,6 +105,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::QuestErrors].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::EqTime].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NpcHandin].log_to_gmsay = static_cast<uint8>(Logs::General);
/**
* RFC 5424
@@ -599,6 +601,8 @@ void EQEmuLogSys::SilenceConsoleLogging()
log_settings[log_index].is_category_enabled = 0;
}
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::MySQLError);
log_settings[Logs::Error].log_to_console = static_cast<uint8>(Logs::Error);
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
}
+9 -1
View File
@@ -145,6 +145,10 @@ namespace Logs {
EvolveItem,
PositionUpdate,
KSM,
BotSettings,
BotSpellChecks,
BotSpellTypeChecks,
NpcHandin,
MaxCategoryID /* Don't Remove this */
};
@@ -248,7 +252,11 @@ namespace Logs {
"XTargets",
"EvolveItem",
"PositionUpdate",
"KSM" // Kernel Samepage Merging
"KSM", // Kernel Samepage Merging
"Bot Settings",
"Bot Spell Checks",
"Bot Spell Type Checks",
"NpcHandin"
};
}
+40
View File
@@ -874,6 +874,46 @@
OutF(LogSys, Logs::Detail, Logs::KSM, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSettings(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::BotSettings))\
OutF(LogSys, Logs::General, Logs::BotSettings, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSettingsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::BotSettings))\
OutF(LogSys, Logs::Detail, Logs::BotSettings, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSpellChecks(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::BotSpellChecks))\
OutF(LogSys, Logs::General, Logs::BotSpellChecks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSpellChecksDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::BotSpellChecks))\
OutF(LogSys, Logs::Detail, Logs::BotSpellChecks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSpellTypeChecks(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::BotSpellTypeChecks))\
OutF(LogSys, Logs::General, Logs::BotSpellTypeChecks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBotSpellTypeChecksDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::BotSpellTypeChecks))\
OutF(LogSys, Logs::Detail, Logs::BotSpellTypeChecks, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogNpcHandin(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::NpcHandin))\
OutF(LogSys, Logs::General, Logs::NpcHandin, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogNpcHandinDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::NpcHandin))\
OutF(LogSys, Logs::Detail, Logs::NpcHandin, __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__);\
@@ -714,6 +714,18 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
h.charges > 1 ? fmt::format(" Charges: {}", h.charges) : "",
h.attuned ? " (Attuned)" : ""
);
for (int i = 0; i < h.augment_ids.size(); i++) {
if (!Strings::EqualFold(h.augment_names[i], "None")) {
const uint8 slot_id = (i + 1);
handin_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
h.augment_names[i],
h.augment_ids[i]
);
}
}
}
}
@@ -727,6 +739,18 @@ std::string PlayerEventDiscordFormatter::FormatNPCHandinEvent(
r.charges > 1 ? fmt::format(" Charges: {}", r.charges) : "",
r.attuned ? " (Attuned)" : ""
);
for (int i = 0; i < r.augment_ids.size(); i++) {
if (!Strings::EqualFold(r.augment_names[i], "None")) {
const uint8 slot_id = (i + 1);
return_items_info += fmt::format(
"Augment {}: {} ({})\n",
slot_id,
r.augment_names[i],
r.augment_ids[i]
);
}
}
}
}
@@ -1057,51 +1081,51 @@ std::string PlayerEventDiscordFormatter::FormatTradeEvent(
if (!e.character_1_give_items.empty()) {
for (const auto &i: e.character_1_give_items) {
std::string augment_info;
if (i.aug_1_item_id > 0) {
if (i.augment_1_id > 0) {
augment_info += fmt::format(
"Augment 1: {} ({})",
i.aug_1_item_name,
i.aug_1_item_id
i.augment_1_name,
i.augment_1_id
);
}
if (i.aug_2_item_id > 0) {
if (i.augment_2_id > 0) {
augment_info += fmt::format(
"Augment 2: {} ({})",
i.aug_2_item_name,
i.aug_2_item_id
i.augment_2_name,
i.augment_2_id
);
}
if (i.aug_3_item_id > 0) {
if (i.augment_3_id > 0) {
augment_info += fmt::format(
"Augment 3: {} ({})",
i.aug_3_item_name,
i.aug_3_item_id
i.augment_3_name,
i.augment_3_id
);
}
if (i.aug_4_item_id > 0) {
if (i.augment_4_id > 0) {
augment_info += fmt::format(
"Augment 4: {} ({})\n",
i.aug_4_item_name,
i.aug_4_item_id
i.augment_4_name,
i.augment_4_id
);
}
if (i.aug_5_item_id > 0) {
if (i.augment_5_id > 0) {
augment_info += fmt::format(
"Augment 5: {} ({})\n",
i.aug_5_item_name,
i.aug_5_item_id
i.augment_5_name,
i.augment_5_id
);
}
if (i.aug_6_item_id > 0) {
if (i.augment_6_id > 0) {
augment_info += fmt::format(
"Augment 6: {} ({})",
i.aug_6_item_name,
i.aug_6_item_id
i.augment_6_name,
i.augment_6_id
);
}
@@ -1122,51 +1146,51 @@ std::string PlayerEventDiscordFormatter::FormatTradeEvent(
if (!e.character_2_give_items.empty()) {
for (const auto &i: e.character_2_give_items) {
std::string augment_info;
if (i.aug_1_item_id > 0) {
if (i.augment_1_id > 0) {
augment_info += fmt::format(
"Augment 1: {} ({})",
i.aug_1_item_name,
i.aug_1_item_id
i.augment_1_name,
i.augment_1_id
);
}
if (i.aug_2_item_id > 0) {
if (i.augment_2_id > 0) {
augment_info += fmt::format(
"Augment 2: {} ({})",
i.aug_2_item_name,
i.aug_2_item_id
i.augment_2_name,
i.augment_2_id
);
}
if (i.aug_3_item_id > 0) {
if (i.augment_3_id > 0) {
augment_info += fmt::format(
"Augment 3: {} ({})",
i.aug_3_item_name,
i.aug_3_item_id
i.augment_3_name,
i.augment_3_id
);
}
if (i.aug_4_item_id > 0) {
if (i.augment_4_id > 0) {
augment_info += fmt::format(
"Augment 4: {} ({})\n",
i.aug_4_item_name,
i.aug_4_item_id
i.augment_4_name,
i.augment_4_id
);
}
if (i.aug_5_item_id > 0) {
if (i.augment_5_id > 0) {
augment_info += fmt::format(
"Augment 5: {} ({})\n",
i.aug_5_item_name,
i.aug_5_item_id
i.augment_5_name,
i.augment_5_id
);
}
if (i.aug_6_item_id > 0) {
if (i.augment_6_id > 0) {
augment_info += fmt::format(
"Augment 6: {} ({})",
i.aug_6_item_name,
i.aug_6_item_id
i.augment_6_name,
i.augment_6_id
);
}
+554 -25
View File
@@ -1,14 +1,21 @@
#include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include <cereal/archives/json.hpp>
#include "../platform.h"
#include "../rulesys.h"
#include "player_event_discord_formatter.h"
#include "../repositories/player_event_loot_items_repository.h"
#include "../repositories/player_event_merchant_sell_repository.h"
#include "../repositories/player_event_merchant_purchase_repository.h"
#include "../repositories/player_event_npc_handin_repository.h"
#include "../repositories/player_event_npc_handin_entries_repository.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);
@@ -21,6 +28,7 @@ void PlayerEventLogs::Init()
m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0;
m_settings[i].etl_enabled = false;
}
SetSettingsDefaults();
@@ -65,6 +73,7 @@ void PlayerEventLogs::Init()
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
c.etl_enabled = false;
settings_to_insert.emplace_back(c);
}
}
@@ -73,6 +82,8 @@ void PlayerEventLogs::Init()
PlayerEventLogSettingsRepository::ReplaceMany(*m_database, settings_to_insert);
}
LoadEtlIds();
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
@@ -121,23 +132,319 @@ void PlayerEventLogs::ProcessBatchQueue()
return;
}
static std::map<uint32, uint32> counter{};
counter.clear();
for (auto const &e: m_record_batch_queue) {
counter[e.event_type_id]++;
}
BenchTimer benchmark;
EtlQueues etl_queues{};
for (const auto &[type, count]: counter) {
if (count > 0) {
switch (type) {
case PlayerEvent::TRADE:
etl_queues.trade.reserve(count);
break;
case PlayerEvent::SPEECH:
etl_queues.speech.reserve(count);
break;
case PlayerEvent::LOOT_ITEM:
etl_queues.loot_items.reserve(count);
break;
case PlayerEvent::KILLED_NPC:
etl_queues.killed_npc.reserve(count);
break;
case PlayerEvent::NPC_HANDIN:
etl_queues.npc_handin.reserve(count);
break;
case PlayerEvent::AA_PURCHASE:
etl_queues.aa_purchase.reserve(count);
break;
case PlayerEvent::MERCHANT_SELL:
etl_queues.merchant_sell.reserve(count);
break;
case PlayerEvent::KILLED_RAID_NPC:
etl_queues.killed_raid_npc.reserve(count);
break;
case PlayerEvent::KILLED_NAMED_NPC:
etl_queues.killed_named_npc.reserve(count);
break;
case PlayerEvent::MERCHANT_PURCHASE:
etl_queues.merchant_purchase.reserve(count);
break;
default:
break;
}
}
}
// Helper to deserialize event data
auto Deserialize = [](const std::string &data, auto &out) {
std::stringstream ss(data);
cereal::JSONInputArchive ar(ss);
out.serialize(ar);
};
// Helper to assign ETL table ID
auto AssignEtlId = [&](
PlayerEventLogsRepository::PlayerEventLogs &r,
PlayerEvent::EventType type
) {
if (m_etl_settings.contains(type)) {
r.etl_table_id = m_etl_settings.at(type).next_id++;
}
};
// Define event processors
std::unordered_map<PlayerEvent::EventType, std::function<void(PlayerEventLogsRepository::PlayerEventLogs &)>> event_processors = {
{
PlayerEvent::EventType::LOOT_ITEM, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::LootItemEvent in{};
PlayerEventLootItemsRepository::PlayerEventLootItems out{};
Deserialize(r.event_data, in);
out.charges = in.charges;
out.corpse_name = in.corpse_name;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.augment_1_id = in.augment_1_id;
out.augment_2_id = in.augment_2_id;
out.augment_3_id = in.augment_3_id;
out.augment_4_id = in.augment_4_id;
out.augment_5_id = in.augment_5_id;
out.augment_6_id = in.augment_6_id;
out.npc_id = in.npc_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::LOOT_ITEM);
etl_queues.loot_items.push_back(out);
}
},
{
PlayerEvent::EventType::MERCHANT_SELL, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::MerchantSellEvent in{};
PlayerEventMerchantSellRepository::PlayerEventMerchantSell out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.merchant_name = in.merchant_name;
out.merchant_type = in.merchant_type;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.charges = in.charges;
out.cost = in.cost;
out.alternate_currency_id = in.alternate_currency_id;
out.player_money_balance = in.player_money_balance;
out.player_currency_balance = in.player_currency_balance;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::MERCHANT_SELL);
etl_queues.merchant_sell.push_back(out);
}},
{
PlayerEvent::EventType::MERCHANT_PURCHASE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::MerchantPurchaseEvent in{};
PlayerEventMerchantPurchaseRepository::PlayerEventMerchantPurchase out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.merchant_name = in.merchant_name;
out.merchant_type = in.merchant_type;
out.item_id = in.item_id;
out.item_name = in.item_name;
out.charges = in.charges;
out.cost = in.cost;
out.alternate_currency_id = in.alternate_currency_id;
out.player_money_balance = in.player_money_balance;
out.player_currency_balance = in.player_currency_balance;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::MERCHANT_PURCHASE);
etl_queues.merchant_purchase.push_back(out);
}},
{
PlayerEvent::EventType::NPC_HANDIN, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::HandinEvent in{};
PlayerEventNpcHandinRepository::PlayerEventNpcHandin out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.npc_name = in.npc_name;
out.handin_copper = in.handin_money.copper;
out.handin_silver = in.handin_money.silver;
out.handin_gold = in.handin_money.gold;
out.handin_platinum = in.handin_money.platinum;
out.return_copper = in.return_money.copper;
out.return_silver = in.return_money.silver;
out.return_gold = in.return_money.gold;
out.return_platinum = in.return_money.platinum;
out.is_quest_handin = in.is_quest_handin;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::NPC_HANDIN);
etl_queues.npc_handin.push_back(out);
for (const auto &i: in.handin_items) {
PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries entry{};
entry.player_event_npc_handin_id = r.etl_table_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.type = 1;
etl_queues.npc_handin_entries.push_back(entry);
}
for (const auto &i: in.return_items) {
PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries entry{};
entry.player_event_npc_handin_id = r.etl_table_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.type = 2;
etl_queues.npc_handin_entries.push_back(entry);
}
}},
{
PlayerEvent::EventType::TRADE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::TradeEvent in{};
PlayerEventTradeRepository::PlayerEventTrade out{};
Deserialize(r.event_data, in);
out.char1_id = in.character_1_id;
out.char2_id = in.character_2_id;
out.char1_copper = in.character_1_give_money.copper;
out.char1_silver = in.character_1_give_money.silver;
out.char1_gold = in.character_1_give_money.gold;
out.char1_platinum = in.character_1_give_money.platinum;
out.char2_copper = in.character_2_give_money.copper;
out.char2_silver = in.character_2_give_money.silver;
out.char2_gold = in.character_2_give_money.gold;
out.char2_platinum = in.character_2_give_money.platinum;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::TRADE);
etl_queues.trade.push_back(out);
for (const auto &i: in.character_1_give_items) {
PlayerEventTradeEntriesRepository::PlayerEventTradeEntries entry{};
entry.player_event_trade_id = r.etl_table_id;
entry.char_id = in.character_1_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.slot = i.slot;
etl_queues.trade_entries.push_back(entry);
}
for (const auto &i: in.character_2_give_items) {
PlayerEventTradeEntriesRepository::PlayerEventTradeEntries entry{};
entry.player_event_trade_id = r.etl_table_id;
entry.char_id = in.character_2_id;
entry.item_id = i.item_id;
entry.charges = i.charges;
entry.slot = i.slot;
etl_queues.trade_entries.push_back(entry);
}
}},
{
PlayerEvent::EventType::SPEECH, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::PlayerSpeech in{};
PlayerEventSpeechRepository::PlayerEventSpeech out{};
Deserialize(r.event_data, in);
out.from_char_id = in.from;
out.to_char_id = in.to;
out.type = in.type;
out.min_status = in.min_status;
out.message = in.message;
out.guild_id = in.guild_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::SPEECH);
etl_queues.speech.push_back(out);
}},
{
PlayerEvent::EventType::KILLED_NPC, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::KilledNPCEvent in{};
PlayerEventKilledNpcRepository::PlayerEventKilledNpc out{};
Deserialize(r.event_data, in);
out.npc_id = in.npc_id;
out.npc_name = in.npc_name;
out.combat_time_seconds = in.combat_time_seconds;
out.total_damage_per_second_taken = in.total_damage_per_second_taken;
out.total_heal_per_second_taken = in.total_heal_per_second_taken;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::KILLED_NPC);
etl_queues.killed_npc.push_back(out);
}},
{
PlayerEvent::EventType::AA_PURCHASE, [&](PlayerEventLogsRepository::PlayerEventLogs &r) {
PlayerEvent::AAPurchasedEvent in{};
PlayerEventAaPurchaseRepository::PlayerEventAaPurchase out{};
Deserialize(r.event_data, in);
out.aa_ability_id = in.aa_id;
out.cost = in.aa_cost;
out.previous_id = in.aa_previous_id;
out.next_id = in.aa_next_id;
out.created_at = r.created_at;
AssignEtlId(r, PlayerEvent::EventType::AA_PURCHASE);
etl_queues.aa_purchase.push_back(out);
}},
};
// Process the batch queue
for (auto &r: m_record_batch_queue) {
if (m_settings[r.event_type_id].etl_enabled) {
auto it = event_processors.find(static_cast<PlayerEvent::EventType>(r.event_type_id));
if (it != event_processors.end()) {
it->second(r); // Call the appropriate lambda
r.event_data = "{}"; // Clear event data
}
else {
LogError("Non-Implemented ETL routing [{}]", r.event_type_id);
}
}
}
// Helper to flush and clear queues
auto flush_queue = [&](auto insert_many, auto &queue) {
if (!queue.empty()) {
insert_many(*m_database, queue);
queue.clear();
}
};
// flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
// flush etl queues
flush_queue(PlayerEventLootItemsRepository::InsertMany, etl_queues.loot_items);
flush_queue(PlayerEventMerchantSellRepository::InsertMany, etl_queues.merchant_sell);
flush_queue(PlayerEventMerchantPurchaseRepository::InsertMany, etl_queues.merchant_purchase);
flush_queue(PlayerEventNpcHandinRepository::InsertMany, etl_queues.npc_handin);
flush_queue(PlayerEventNpcHandinEntriesRepository::InsertMany, etl_queues.npc_handin_entries);
flush_queue(PlayerEventTradeRepository::InsertMany, etl_queues.trade);
flush_queue(PlayerEventTradeEntriesRepository::InsertMany, etl_queues.trade_entries);
flush_queue(PlayerEventSpeechRepository::InsertMany, etl_queues.speech);
flush_queue(PlayerEventKilledNpcRepository::InsertMany, etl_queues.killed_npc);
flush_queue(PlayerEventKilledNamedNpcRepository::InsertMany, etl_queues.killed_named_npc);
flush_queue(PlayerEventKilledRaidNpcRepository::InsertMany, etl_queues.killed_raid_npc);
flush_queue(PlayerEventAaPurchaseRepository::InsertMany, etl_queues.aa_purchase);
LogPlayerEvents(
"Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(),
benchmark.elapsed()
);
// empty
m_record_batch_queue = {};
m_record_batch_queue.clear();
m_batch_queue_lock.unlock();
}
// adds a player event to the queue
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
void PlayerEventLogs::AddToQueue(PlayerEventLogsRepository::PlayerEventLogs &log)
{
m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log);
@@ -588,7 +895,7 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
break;
}
default: {
LogInfo(
LogPlayerEventsDetail(
"Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name,
e.player_event_log.event_type_id
@@ -602,7 +909,8 @@ std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::Playe
// 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)) {
if (m_process_batch_events_timer.Check() ||
m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue();
}
@@ -613,29 +921,115 @@ void PlayerEventLogs::Process()
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogPlayerEvents("Running truncation");
LogPlayerEventsDetail("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
// Map of repository-specific deletion functions
std::unordered_map<PlayerEvent::EventType, std::function<uint32(const std::string &)>> repository_deleters = {
{
PlayerEvent::LOOT_ITEM, [&](const std::string &condition) {
return PlayerEventLootItemsRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::MERCHANT_SELL, [&](const std::string &condition) {
return PlayerEventMerchantSellRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::MERCHANT_PURCHASE, [&](const std::string &condition) {
return PlayerEventMerchantPurchaseRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::NPC_HANDIN, [&](const std::string &condition) {
uint32 deleted_count = PlayerEventNpcHandinRepository::DeleteWhere(*m_database, condition);
deleted_count += PlayerEventNpcHandinEntriesRepository::DeleteWhere(*m_database, condition);
return deleted_count;
}},
{
PlayerEvent::TRADE, [&](const std::string &condition) {
uint32 deleted_count = PlayerEventTradeRepository::DeleteWhere(*m_database, condition);
deleted_count += PlayerEventTradeEntriesRepository::DeleteWhere(*m_database, condition);
return deleted_count;
}},
{
PlayerEvent::SPEECH, [&](const std::string &condition) {
return PlayerEventSpeechRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_NPC, [&](const std::string &condition) {
return PlayerEventKilledNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_NAMED_NPC, [&](const std::string &condition) {
return PlayerEventKilledNamedNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::KILLED_RAID_NPC, [&](const std::string &condition) {
return PlayerEventKilledRaidNpcRepository::DeleteWhere(*m_database, condition);
}},
{
PlayerEvent::AA_PURCHASE, [&](const std::string &condition) {
return PlayerEventAaPurchaseRepository::DeleteWhere(*m_database, condition);
}}
};
// Group event types by retention interval
std::unordered_map<int, std::vector<int>> retention_groups;
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
)
);
retention_groups[m_settings[i].retention_days].push_back(i);
}
}
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count,
PlayerEvent::EventName[i],
i,
m_settings[i].retention_days
);
for (const auto &[retention_days, event_types]: retention_groups) {
std::string condition = fmt::format(
"created_at < (NOW() - INTERVAL {} DAY)",
retention_days
);
// Handle ETL deletions for each event type in the group
uint32 total_deleted_count = 0;
for (int event_type_id: event_types) {
if (m_settings[event_type_id].etl_enabled) {
auto it = repository_deleters.find(static_cast<PlayerEvent::EventType>(m_settings[event_type_id].id));
if (it != repository_deleters.end()) {
total_deleted_count += it->second(condition);
}
else {
LogError("Non-Implemented ETL Event Type [{}]", static_cast<uint32>(m_settings[event_type_id].id));
}
}
}
if (total_deleted_count > 0) {
LogInfo(
"Truncated [{}] ETL events older than [{}] days",
total_deleted_count,
retention_days
);
}
// Batch deletion for player_event_logs
std::string event_type_ids = fmt::format(
"({})",
fmt::join(event_types, ", ")
);
uint32 deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database,
fmt::format(
"event_type_id IN {} AND {}",
event_type_ids,
condition
)
);
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of types [{}] older than [{}] days",
deleted_count,
event_type_ids,
retention_days
);
}
}
}
@@ -708,8 +1102,143 @@ void PlayerEventLogs::SetSettingsDefaults()
m_settings[PlayerEvent::PARCEL_DELETE].event_enabled = 1;
m_settings[PlayerEvent::BARTER_TRANSACTION].event_enabled = 1;
m_settings[PlayerEvent::EVOLVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPEECH].event_enabled = 0;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
}
}
void PlayerEventLogs::LoadEtlIds()
{
auto e = [&](auto p) -> bool {
for (PlayerEventLogSettingsRepository::PlayerEventLogSettings const &c: m_settings) {
if (c.id == p) {
return c.etl_enabled ? true : false;
}
}
return false;
};
m_etl_settings.clear();
m_etl_settings = {
{
PlayerEvent::LOOT_ITEM,
{
.enabled = e(PlayerEvent::LOOT_ITEM),
.table_name = "player_event_loot_items",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventLootItemsRepository::TableName()))
}
},
{
PlayerEvent::MERCHANT_SELL,
{
.enabled = e(PlayerEvent::MERCHANT_SELL),
.table_name = "player_event_merchant_sell",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventMerchantSellRepository::TableName()))
}
},
{
PlayerEvent::MERCHANT_PURCHASE,
{
.enabled = e(PlayerEvent::MERCHANT_PURCHASE),
.table_name = "player_event_merchant_purchase",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventMerchantPurchaseRepository::TableName()))
}
},
{
PlayerEvent::NPC_HANDIN,
{
.enabled = e(PlayerEvent::NPC_HANDIN),
.table_name = "player_event_npc_handin",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventNpcHandinRepository::TableName()))
}
},
{
PlayerEvent::TRADE,
{
.enabled = e(PlayerEvent::TRADE),
.table_name = "player_event_trade",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventTradeRepository::TableName()))
}
},
{
PlayerEvent::SPEECH,
{
.enabled = e(PlayerEvent::SPEECH),
.table_name = "player_event_speech",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventSpeechRepository::TableName()))
}
},
{
PlayerEvent::KILLED_NPC,
{
.enabled = e(PlayerEvent::KILLED_NPC),
.table_name = "player_event_killed_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledNpcRepository::TableName()))
}
},
{
PlayerEvent::KILLED_NAMED_NPC,
{
.enabled = e(PlayerEvent::KILLED_NAMED_NPC),
.table_name = "player_event_killed_named_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledNamedNpcRepository::TableName()))
}
},
{
PlayerEvent::KILLED_RAID_NPC,
{
.enabled = e(PlayerEvent::KILLED_RAID_NPC),
.table_name = "player_event_killed_raid_npc",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventKilledRaidNpcRepository::TableName()))
}
},
{
PlayerEvent::AA_PURCHASE,
{
.enabled = e(PlayerEvent::AA_PURCHASE),
.table_name = "player_event_aa_purchase",
.next_id = static_cast<int64>(m_database->GetNextTableId(PlayerEventAaPurchaseRepository::TableName()))
}
}
};
for (auto &e: m_etl_settings) {
LogPlayerEventsDetail(
"ETL Settings [{}] Enabled [{}] Table [{}] NextId [{}]",
PlayerEvent::EventName[e.first],
e.second.enabled,
e.second.table_name,
e.second.next_id
);
}
}
bool PlayerEventLogs::LoadDatabaseConnection()
{
const auto c = EQEmuConfig::get();
LogInfo(
"Connecting to MySQL for PlayerEvents [{}]@[{}]:[{}]",
c->DatabaseUsername.c_str(),
c->DatabaseHost.c_str(),
c->DatabasePort
);
if (!player_event_database.Connect(
c->DatabaseHost.c_str(),
c->DatabaseUsername.c_str(),
c->DatabasePassword.c_str(),
c->DatabaseDB.c_str(),
c->DatabasePort
)) {
LogError("Cannot continue without a database connection for player events.");
return false;
}
SetDatabase(&player_event_database);
return true;
}
+53 -7
View File
@@ -1,19 +1,38 @@
#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>
#include "../json/json_archive_single_line.h"
#include "../servertalk.h"
#include "../timer.h"
#include "../eqemu_config.h"
#include "../repositories/player_event_log_settings_repository.h"
#include "../repositories/player_event_logs_repository.h"
#include "../repositories/player_event_loot_items_repository.h"
#include "../repositories/player_event_merchant_purchase_repository.h"
#include "../repositories/player_event_merchant_sell_repository.h"
#include "../repositories/player_event_npc_handin_repository.h"
#include "../repositories/player_event_npc_handin_entries_repository.h"
#include "../repositories/player_event_trade_repository.h"
#include "../repositories/player_event_trade_entries_repository.h"
#include "../repositories/player_event_speech_repository.h"
#include "../repositories/player_event_killed_npc_repository.h"
#include "../repositories/player_event_killed_named_npc_repository.h"
#include "../repositories/player_event_killed_raid_npc_repository.h"
#include "../repositories/player_event_aa_purchase_repository.h"
class PlayerEventLogs {
public:
Database player_event_database{};
void Init();
bool LoadDatabaseConnection();
void ReloadSettings();
void LoadEtlIds();
PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event);
@@ -21,7 +40,7 @@ public:
void Process();
// batch queue
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
void AddToQueue(PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function
// can ingest any struct event types
@@ -59,7 +78,29 @@ public:
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
struct EtlQueues {
std::vector<PlayerEventLootItemsRepository::PlayerEventLootItems> loot_items;
std::vector<PlayerEventMerchantPurchaseRepository::PlayerEventMerchantPurchase> merchant_purchase;
std::vector<PlayerEventMerchantSellRepository::PlayerEventMerchantSell> merchant_sell;
std::vector<PlayerEventNpcHandinRepository::PlayerEventNpcHandin> npc_handin;
std::vector<PlayerEventNpcHandinEntriesRepository::PlayerEventNpcHandinEntries> npc_handin_entries;
std::vector<PlayerEventTradeRepository::PlayerEventTrade> trade;
std::vector<PlayerEventTradeEntriesRepository::PlayerEventTradeEntries> trade_entries;
std::vector<PlayerEventSpeechRepository::PlayerEventSpeech> speech;
std::vector<PlayerEventKilledNpcRepository::PlayerEventKilledNpc> killed_npc;
std::vector<PlayerEventKilledNamedNpcRepository::PlayerEventKilledNamedNpc> killed_named_npc;
std::vector<PlayerEventKilledRaidNpcRepository::PlayerEventKilledRaidNpc> killed_raid_npc;
std::vector<PlayerEventAaPurchaseRepository::PlayerEventAaPurchase> aa_purchase;
};
private:
struct EtlSettings {
bool enabled;
std::string table_name;
int64 next_id;
};
Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
@@ -69,6 +110,8 @@ private:
static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
std::map<PlayerEvent::EventType, EtlSettings> m_etl_settings{};
// timers
Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
@@ -78,6 +121,9 @@ private:
void ProcessBatchQueue();
void ProcessRetentionTruncation();
void SetSettingsDefaults();
public:
std::map<PlayerEvent::EventType, EtlSettings> &GetEtlSettings() { return m_etl_settings;}
};
extern PlayerEventLogs player_event_logs;
+267 -111
View File
@@ -4,6 +4,7 @@
#include <string>
#include <cereal/cereal.hpp>
#include "../types.h"
#include "../rulesys.h"
#include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent {
@@ -62,6 +63,7 @@ namespace PlayerEvent {
PARCEL_RETRIEVE,
PARCEL_DELETE,
BARTER_TRANSACTION,
SPEECH,
EVOLVE_ITEM,
MAX // dont remove
};
@@ -126,6 +128,7 @@ namespace PlayerEvent {
"Parcel Item Retrieved",
"Parcel Prune Routine",
"Barter Transaction",
"Player Speech",
"Evolve Item Update"
};
@@ -206,12 +209,12 @@ namespace PlayerEvent {
std::string item_name;
uint16 to_slot;
int16 charges;
uint32 aug1;
uint32 aug2;
uint32 aug3;
uint32 aug4;
uint32 aug5;
uint32 aug6;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
bool attuned;
// cereal
@@ -223,56 +226,57 @@ namespace PlayerEvent {
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(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
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)
);
}
};
// 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;
uint32 augment_1_id;
std::string augment_1_name;
uint32 augment_2_id;
std::string augment_2_name;
uint32 augment_3_id;
std::string augment_3_name;
uint32 augment_4_id;
std::string augment_4_name;
uint32 augment_5_id;
std::string augment_5_name;
uint32 augment_6_id;
std::string augment_6_name;
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)
@@ -280,12 +284,20 @@ namespace PlayerEvent {
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_1_name),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_2_name),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_1_name),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_4_name),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_5_name),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(augment_6_name),
CEREAL_NVP(item_name),
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)
);
}
@@ -399,9 +411,9 @@ namespace PlayerEvent {
struct AAPurchasedEvent {
uint32 aa_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
// cereal
template<class Archive>
@@ -418,6 +430,12 @@ namespace PlayerEvent {
struct ForageSuccessEvent {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
std::string item_name;
// cereal
@@ -426,6 +444,12 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(item_name)
);
}
@@ -433,6 +457,12 @@ namespace PlayerEvent {
struct FishSuccessEvent {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
std::string item_name;
// cereal
@@ -441,6 +471,12 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(item_name)
);
}
@@ -450,6 +486,13 @@ namespace PlayerEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
bool attuned;
std::string reason;
// cereal
@@ -459,8 +502,15 @@ namespace PlayerEvent {
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(reason),
CEREAL_NVP(charges)
CEREAL_NVP(charges),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(attuned),
CEREAL_NVP(reason)
);
}
};
@@ -503,6 +553,12 @@ namespace PlayerEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
uint32 npc_id;
std::string corpse_name;
@@ -514,6 +570,12 @@ namespace PlayerEvent {
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
@@ -726,6 +788,12 @@ namespace PlayerEvent {
struct DroppedItemEvent {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
std::string item_name;
int16 slot_id;
uint32 charges;
@@ -736,6 +804,12 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
@@ -791,6 +865,12 @@ namespace PlayerEvent {
struct TraderPurchaseEvent {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
std::string item_name;
uint32 trader_id;
std::string trader_name;
@@ -806,6 +886,12 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
@@ -819,6 +905,12 @@ namespace PlayerEvent {
struct TraderSellEvent {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
std::string item_name;
uint32 buyer_id;
std::string buyer_name;
@@ -834,6 +926,12 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
@@ -964,8 +1062,16 @@ namespace PlayerEvent {
};
struct GuildTributeDonateItem {
uint32 item_id;
uint32 guild_favor;
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
int16 charges;
bool attuned;
uint32 guild_favor;
// cereal
template<class Archive>
@@ -973,14 +1079,20 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(guild_favor)
);
}
};
struct GuildTributeDonatePlat {
uint32 plat;
uint32 guild_favor;
uint32 plat;
uint32 guild_favor;
// cereal
template<class Archive>
@@ -995,15 +1107,15 @@ namespace PlayerEvent {
struct ParcelRetrieve {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
uint32 quantity;
std::string from_player_name;
uint32 sent_date;
uint32 aug_slot_1;
uint32 aug_slot_2;
uint32 aug_slot_3;
uint32 aug_slot_4;
uint32 aug_slot_5;
uint32 aug_slot_6;
// cereal
template<class Archive>
@@ -1011,31 +1123,31 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(quantity),
CEREAL_NVP(from_player_name),
CEREAL_NVP(sent_date),
CEREAL_NVP(aug_slot_1),
CEREAL_NVP(aug_slot_2),
CEREAL_NVP(aug_slot_3),
CEREAL_NVP(aug_slot_4),
CEREAL_NVP(aug_slot_5),
CEREAL_NVP(aug_slot_6)
CEREAL_NVP(sent_date)
);
}
};
struct ParcelSend {
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
uint32 quantity;
std::string from_player_name;
std::string to_player_name;
uint32 sent_date;
uint32 aug_slot_1;
uint32 aug_slot_2;
uint32 aug_slot_3;
uint32 aug_slot_4;
uint32 aug_slot_5;
uint32 aug_slot_6;
// cereal
template<class Archive>
@@ -1043,33 +1155,33 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(quantity),
CEREAL_NVP(from_player_name),
CEREAL_NVP(to_player_name),
CEREAL_NVP(sent_date),
CEREAL_NVP(aug_slot_1),
CEREAL_NVP(aug_slot_2),
CEREAL_NVP(aug_slot_3),
CEREAL_NVP(aug_slot_4),
CEREAL_NVP(aug_slot_5),
CEREAL_NVP(aug_slot_6)
CEREAL_NVP(sent_date)
);
}
};
struct ParcelDelete {
uint32 item_id;
uint32 quantity;
uint32 char_id;
uint32 item_id;
uint32 augment_1_id;
uint32 augment_2_id;
uint32 augment_3_id;
uint32 augment_4_id;
uint32 augment_5_id;
uint32 augment_6_id;
uint32 quantity;
uint32 sent_date;
std::string from_name;
std::string note;
uint32 sent_date;
uint32 aug_slot_1;
uint32 aug_slot_2;
uint32 aug_slot_3;
uint32 aug_slot_4;
uint32 aug_slot_5;
uint32 aug_slot_6;
// cereal
template<class Archive>
@@ -1077,18 +1189,18 @@ namespace PlayerEvent {
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(augment_1_id),
CEREAL_NVP(augment_2_id),
CEREAL_NVP(augment_3_id),
CEREAL_NVP(augment_4_id),
CEREAL_NVP(augment_5_id),
CEREAL_NVP(augment_6_id),
CEREAL_NVP(quantity),
CEREAL_NVP(char_id),
CEREAL_NVP(from_name),
CEREAL_NVP(note),
CEREAL_NVP(sent_date),
CEREAL_NVP(aug_slot_1),
CEREAL_NVP(aug_slot_2),
CEREAL_NVP(aug_slot_3),
CEREAL_NVP(aug_slot_4),
CEREAL_NVP(aug_slot_5),
CEREAL_NVP(aug_slot_6)
);
CEREAL_NVP(sent_date)
);
}
};
@@ -1140,30 +1252,74 @@ namespace PlayerEvent {
);
}
};
struct PlayerSpeech {
std::string to;
std::string from;
uint32 guild_id;
int16 min_status;
uint32 type;
std::string message;
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(to),
CEREAL_NVP(from),
CEREAL_NVP(guild_id),
CEREAL_NVP(min_status),
CEREAL_NVP(type),
CEREAL_NVP(message)
);
}
};
}
#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()\
);\
if (RuleB(Logging, PlayerEventsQSProcess)) {\
QServ->SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
GetPlayerEvent(),\
event_data\
).get()\
);\
} \
else { \
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()\
);\
if (RuleB(Logging, PlayerEventsQSProcess)) {\
QServ->SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
else {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
}\
} while (0)
+28
View File
@@ -220,6 +220,34 @@ bool EQ::ItemData::IsType1HWeapon() const
return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing) || (ItemType == item::ItemTypeMartial));
}
bool EQ::ItemData::IsPetUsable() const
{
if (ItemClass == item::ItemClassBag) {
return true;
}
// if it's a misc item and has slots, it's wearable
// this item type is conflated with many other item types
if (ItemClass == item::ItemTypeMisc && Slots != 0) {
return true;
}
switch (ItemType) {
case item::ItemType1HBlunt:
case item::ItemType1HSlash:
case item::ItemType1HPiercing:
case item::ItemType2HBlunt:
case item::ItemType2HSlash:
case item::ItemTypeMartial:
case item::ItemTypeShield:
case item::ItemTypeArmor:
case item::ItemTypeJewelry:
return true;
default:
return false;
}
}
bool EQ::ItemData::IsType2HWeapon() const
{
return ((ItemType == item::ItemType2HBlunt) || (ItemType == item::ItemType2HSlash) || (ItemType == item::ItemType2HPiercing));
+1
View File
@@ -550,6 +550,7 @@ namespace EQ
bool IsType1HWeapon() const;
bool IsType2HWeapon() const;
bool IsTypeShield() const;
bool IsPetUsable() const;
bool IsQuestItem() const;
static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item);
+12
View File
@@ -1785,6 +1785,18 @@ std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
return augments;
}
std::vector<std::string> EQ::ItemInstance::GetAugmentNames() const
{
std::vector<std::string> augment_names;
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
const auto augment = GetAugment(slot_id);
augment_names.push_back(augment ? augment->GetItem()->Name : "None");
}
return augment_names;
}
int EQ::ItemInstance::GetItemRegen(bool augments) const
{
int stat = 0;
+1
View File
@@ -305,6 +305,7 @@ namespace EQ
int GetItemSkillsStat(EQ::skills::SkillType skill, bool augments = false) const;
uint32 GetItemGuildFavor() const;
std::vector<uint32> GetAugmentIDs() const;
std::vector<std::string> GetAugmentNames() const;
static void AddGUIDToMap(uint64 existing_serial_number);
static void ClearGUIDMap();
+6 -112
View File
@@ -8,110 +8,6 @@
#include <fmt/format.h>
#include <sstream>
#include <cstring> // For memcpy
#include <thread>
#define INITIAL_RING_BUFFER_CAPACITY 8192 // Initial number of buffers
#define BUFFER_SIZE 512 // Fixed buffer size
class StaticRingBuffer {
private:
char (*m_data)[BUFFER_SIZE]; // Pointer to dynamically allocated buffer array
bool* m_in_use; // Tracks if a buffer is currently allocated
size_t m_capacity; // Current capacity of the ring buffer
volatile size_t m_write_index = 0; // Next available buffer
volatile size_t m_read_index = 0; // Next buffer to be freed
std::atomic<size_t> m_used_space = 0; // Track used buffers
public:
StaticRingBuffer()
: m_capacity(INITIAL_RING_BUFFER_CAPACITY) {
m_data = new char[m_capacity][BUFFER_SIZE]; // Allocate initial buffer pool
m_in_use = new bool[m_capacity]{false}; // Track buffer usage (initialized to false)
}
~StaticRingBuffer() {
delete[] m_data; // Free memory
delete[] m_in_use; // Free tracking array
}
// Acquire a fixed-size buffer (doubles capacity if full)
char* Acquire() {
for (size_t i = 0; i < m_capacity; ++i) {
size_t index = (m_write_index + i) % m_capacity;
if (!m_in_use[index]) {
m_in_use[index] = true;
m_write_index = (index + 1) % m_capacity;
std::cout << "Acquired buffer " << index << std::endl;
return m_data[index];
}
}
DoubleCapacity();
return Acquire(); // Retry after resizing
}
// Release a buffer back to the pool
void Release(char* buffer) {
size_t index = (buffer - m_data[0]) / BUFFER_SIZE; // Divide by BUFFER_SIZE, not m_capacity
// Prevent invalid releases (e.g., if the buffer isn't from m_data[])
if (index >= m_capacity || m_data[index] != buffer) {
// std::cerr << "Invalid Release: Buffer not in m_data or incorrect index!\n";
return;
}
// std::cout << "Released buffer " << index << std::endl;
m_in_use[index] = false; // Mark buffer as available
}
private:
// Doubles the ring buffer capacity while preserving existing data
// TODO: Add a lock to prevent concurrent issues during resizing
void DoubleCapacity() {
size_t new_capacity = m_capacity * 2;
char (*new_data)[BUFFER_SIZE] = new char[new_capacity][BUFFER_SIZE];
bool* new_in_use = new bool[new_capacity]{false};
size_t current_size = (m_write_index >= m_read_index)
? (m_write_index - m_read_index)
: (m_capacity - m_read_index + m_write_index);
std::cout << "[INFO] Resizing buffer from " << m_capacity << " to " << new_capacity << std::endl;
// Copy data in FIFO order
for (size_t i = 0; i < current_size; ++i) {
size_t old_index = (m_read_index + i) % m_capacity;
memcpy(new_data[i], m_data[old_index], BUFFER_SIZE);
new_in_use[i] = m_in_use[old_index];
}
// Store old buffer reference
char (*old_data_ref)[BUFFER_SIZE] = m_data;
bool* old_in_use_ref = m_in_use;
size_t old_capacity = m_capacity;
// Assign new memory
m_data = new_data;
m_in_use = new_in_use;
m_capacity = new_capacity;
m_read_index = 0;
m_write_index = current_size;
// Delay deletion of old data to avoid access issues
std::thread([old_data_ref, old_in_use_ref, old_capacity]() {
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // Ensure old packets are sent
delete[] old_data_ref;
delete[] old_in_use_ref;
std::cout << "[INFO] Old buffer safely deallocated (Capacity: " << old_capacity << ")\n";
}).detach();
}
};
EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager()
{
m_attached = nullptr;
@@ -1437,8 +1333,6 @@ void EQ::Net::DaybreakConnection::SendKeepAlive()
InternalSend(p);
}
StaticRingBuffer m_ring_buffer;
void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
{
if (m_owner->m_options.outgoing_data_rate > 0.0) {
@@ -1455,10 +1349,8 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
m_last_send = Clock::now();
auto send_func = [](uv_udp_send_t* req, int status) {
if (req->data) {
m_ring_buffer.Release((char*)req->data); // Return buffer to pool
}
delete req; // Return send request to pool
delete[](char*)req->data;
delete req;
};
if (PacketCanBeEncoded(p)) {
@@ -1495,7 +1387,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
char* data = m_ring_buffer.Acquire();
char *data = new char[out.Length()];
memcpy(data, out.Data(), out.Length());
send_buffers[0] = uv_buf_init(data, out.Length());
send_req->data = send_buffers[0].base;
@@ -1503,6 +1395,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
m_stats.sent_bytes += out.Length();
m_stats.sent_packets++;
if (m_owner->m_options.simulated_out_packet_loss && m_owner->m_options.simulated_out_packet_loss >= m_owner->m_rand.Int(0, 100)) {
delete[](char*)send_req->data;
delete send_req;
return;
}
@@ -1518,7 +1411,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
uv_ip4_addr(m_endpoint.c_str(), m_port, &send_addr);
uv_buf_t send_buffers[1];
char* data = m_ring_buffer.Acquire();
char *data = new char[p.Length()];
memcpy(data, p.Data(), p.Length());
send_buffers[0] = uv_buf_init(data, p.Length());
send_req->data = send_buffers[0].base;
@@ -1527,6 +1420,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p)
m_stats.sent_packets++;
if (m_owner->m_options.simulated_out_packet_loss && m_owner->m_options.simulated_out_packet_loss >= m_owner->m_rand.Int(0, 100)) {
delete[](char*)send_req->data;
delete send_req;
return;
}
@@ -23,6 +23,9 @@ namespace EQ
bool Connected() const { return m_connecting != true; }
std::shared_ptr<EQ::Net::TCPConnection> Handle() { return m_connection; }
const std::unique_ptr<EQ::Timer> &GetTimer() const { return m_timer; }
private:
void Connect();
void ProcessData(EQ::Net::TCPConnection *c, const unsigned char *data, size_t length);
+2 -2
View File
@@ -123,7 +123,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
{
size_t current = 0;
size_t total = m_buffer.size();
constexpr size_t ls_info_size = sizeof(ServerNewLSInfo_Struct);
constexpr size_t ls_info_size = sizeof(LoginserverNewWorldRequest);
while (current < total) {
auto left = total - current;
@@ -138,7 +138,7 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer()
//this creates a small edge case where the exact size of a
//packet from the modern protocol can't be "43061256"
//so in send we pad it one byte if that's the case
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(ServerNewLSInfo_Struct)) {
if (leg_opcode == ServerOP_NewLSInfo && leg_size == sizeof(LoginserverNewWorldRequest)) {
m_legacy_mode = true;
m_identifier = "World";
m_parent->ConnectionIdentified(this);
+1
View File
@@ -197,6 +197,7 @@ IN(OP_RecipeDetails, uint32);
//there is also a complicated OP_RecipeDetails reply struct OUT
IN(OP_RecipeAutoCombine, RecipeAutoCombine_Struct);
IN(OP_TradeSkillCombine, NewCombine_Struct);
IN(OP_TradeSkillRecipeInspect, TradeSkillRecipeInspect_Struct);
IN(OP_ItemName, ItemNamePacket_Struct);
IN(OP_AugmentItem, AugmentItem_Struct);
IN(OP_ClickDoor, ClickDoor_Struct);
+6 -1
View File
@@ -3935,6 +3935,11 @@ struct NewCombine_Struct
/*24*/
};
struct TradeSkillRecipeInspect_Struct {
uint32 recipe_id;
uint32 padding[17];
};
//client requesting favorite recipies
struct TradeskillFavorites_Struct {
@@ -4736,7 +4741,7 @@ struct ItemSerializationHeader
/*036*/ uint32 merchant_slot; // 1 if not a merchant item
/*040*/ uint32 scaled_value; // 0
/*044*/ uint32 instance_id; // unique instance id if not merchant item, else is merchant slot
/*048*/ uint32 parcel_item_id;
/*048*/ uint32 parcel_item_id;
/*052*/ uint32 last_cast_time; // Unix Time from PP of last cast for this recast type if recast delay > 0
/*056*/ uint32 charges; // Total Charges an item has (-1 for unlimited)
/*060*/ uint32 inst_nodrop; // 1 if the item is no drop (attuned items)
@@ -0,0 +1,416 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_BOT_BLOCKED_BUFFS_REPOSITORY_H
#define EQEMU_BASE_BOT_BLOCKED_BUFFS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseBotBlockedBuffsRepository {
public:
struct BotBlockedBuffs {
uint32_t bot_id;
uint32_t spell_id;
uint8_t blocked;
uint8_t blocked_pet;
};
static std::string PrimaryKey()
{
return std::string("bot_id");
}
static std::vector<std::string> Columns()
{
return {
"bot_id",
"spell_id",
"blocked",
"blocked_pet",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"bot_id",
"spell_id",
"blocked",
"blocked_pet",
};
}
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("bot_blocked_buffs");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static BotBlockedBuffs NewEntity()
{
BotBlockedBuffs e{};
e.bot_id = 0;
e.spell_id = 0;
e.blocked = 0;
e.blocked_pet = 0;
return e;
}
static BotBlockedBuffs GetBotBlockedBuffs(
const std::vector<BotBlockedBuffs> &bot_blocked_buffss,
int bot_blocked_buffs_id
)
{
for (auto &bot_blocked_buffs : bot_blocked_buffss) {
if (bot_blocked_buffs.bot_id == bot_blocked_buffs_id) {
return bot_blocked_buffs;
}
}
return NewEntity();
}
static BotBlockedBuffs FindOne(
Database& db,
int bot_blocked_buffs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
bot_blocked_buffs_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
BotBlockedBuffs e{};
e.bot_id = row[0] ? static_cast<uint32_t>(atoi(row[0])) : 0;
e.spell_id = row[1] ? static_cast<uint32_t>(atoi(row[1])) : 0;
e.blocked = row[2] ? static_cast<uint8_t>(atoi(row[2])) : 0;
e.blocked_pet = row[3] ? static_cast<uint8_t>(atoi(row[3])) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int bot_blocked_buffs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
bot_blocked_buffs_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const BotBlockedBuffs &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
v.push_back(columns[1] + " = " + std::to_string(e.spell_id));
v.push_back(columns[2] + " = " + std::to_string(e.blocked));
v.push_back(columns[3] + " = " + std::to_string(e.blocked_pet));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.bot_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static BotBlockedBuffs InsertOne(
Database& db,
BotBlockedBuffs e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.blocked));
v.push_back(std::to_string(e.blocked_pet));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.bot_id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<BotBlockedBuffs> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.blocked));
v.push_back(std::to_string(e.blocked_pet));
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<BotBlockedBuffs> All(Database& db)
{
std::vector<BotBlockedBuffs> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BotBlockedBuffs e{};
e.bot_id = row[0] ? static_cast<uint32_t>(atoi(row[0])) : 0;
e.spell_id = row[1] ? static_cast<uint32_t>(atoi(row[1])) : 0;
e.blocked = row[2] ? static_cast<uint8_t>(atoi(row[2])) : 0;
e.blocked_pet = row[3] ? static_cast<uint8_t>(atoi(row[3])) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<BotBlockedBuffs> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<BotBlockedBuffs> 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) {
BotBlockedBuffs e{};
e.bot_id = row[0] ? static_cast<uint32_t>(atoi(row[0])) : 0;
e.spell_id = row[1] ? static_cast<uint32_t>(atoi(row[1])) : 0;
e.blocked = row[2] ? static_cast<uint8_t>(atoi(row[2])) : 0;
e.blocked_pet = row[3] ? static_cast<uint8_t>(atoi(row[3])) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const BotBlockedBuffs &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.blocked));
v.push_back(std::to_string(e.blocked_pet));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<BotBlockedBuffs> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.blocked));
v.push_back(std::to_string(e.blocked_pet));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_BOT_BLOCKED_BUFFS_REPOSITORY_H
@@ -64,13 +64,6 @@ public:
int16_t poison;
int16_t disease;
int16_t corruption;
uint32_t show_helm;
uint32_t follow_distance;
uint8_t stop_melee_level;
int32_t expansion_bitmask;
uint8_t enforce_spell_settings;
uint8_t archery_setting;
uint32_t caster_range;
};
static std::string PrimaryKey()
@@ -126,13 +119,6 @@ public:
"poison",
"disease",
"corruption",
"show_helm",
"follow_distance",
"stop_melee_level",
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -184,13 +170,6 @@ public:
"poison",
"disease",
"corruption",
"show_helm",
"follow_distance",
"stop_melee_level",
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -276,13 +255,7 @@ public:
e.poison = 0;
e.disease = 0;
e.corruption = 0;
e.show_helm = 0;
e.follow_distance = 200;
e.stop_melee_level = 255;
e.expansion_bitmask = -1;
e.enforce_spell_settings = 0;
e.archery_setting = 0;
e.caster_range = 300;
return e;
}
@@ -364,13 +337,6 @@ public:
e.poison = row[42] ? static_cast<int16_t>(atoi(row[42])) : 0;
e.disease = row[43] ? static_cast<int16_t>(atoi(row[43])) : 0;
e.corruption = row[44] ? static_cast<int16_t>(atoi(row[44])) : 0;
e.show_helm = row[45] ? static_cast<uint32_t>(strtoul(row[45], nullptr, 10)) : 0;
e.follow_distance = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 200;
e.stop_melee_level = row[47] ? static_cast<uint8_t>(strtoul(row[47], nullptr, 10)) : 255;
e.expansion_bitmask = row[48] ? static_cast<int32_t>(atoi(row[48])) : -1;
e.enforce_spell_settings = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 0;
e.archery_setting = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.caster_range = row[51] ? static_cast<uint32_t>(strtoul(row[51], nullptr, 10)) : 300;
return e;
}
@@ -383,14 +349,25 @@ public:
int bot_data_id
)
{
auto results = db.QueryDatabase(
fmt::format(
std::string query;
if (RuleB(Bots, BotSoftDeletes)) {
query = fmt::format(
"UPDATE {} SET name = SUBSTRING(CONCAT(name, '-deleted-', UNIX_TIMESTAMP()), 1, 64) WHERE {} = {}",
TableName(),
PrimaryKey(),
bot_data_id
);
}
else {
query = fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
bot_data_id
)
);
);
}
auto results = db.QueryDatabase(query);
return (results.Success() ? results.RowsAffected() : 0);
}
@@ -448,13 +425,6 @@ public:
v.push_back(columns[42] + " = " + std::to_string(e.poison));
v.push_back(columns[43] + " = " + std::to_string(e.disease));
v.push_back(columns[44] + " = " + std::to_string(e.corruption));
v.push_back(columns[45] + " = " + std::to_string(e.show_helm));
v.push_back(columns[46] + " = " + std::to_string(e.follow_distance));
v.push_back(columns[47] + " = " + std::to_string(e.stop_melee_level));
v.push_back(columns[48] + " = " + std::to_string(e.expansion_bitmask));
v.push_back(columns[49] + " = " + std::to_string(e.enforce_spell_settings));
v.push_back(columns[50] + " = " + std::to_string(e.archery_setting));
v.push_back(columns[51] + " = " + std::to_string(e.caster_range));
auto results = db.QueryDatabase(
fmt::format(
@@ -521,13 +491,6 @@ public:
v.push_back(std::to_string(e.poison));
v.push_back(std::to_string(e.disease));
v.push_back(std::to_string(e.corruption));
v.push_back(std::to_string(e.show_helm));
v.push_back(std::to_string(e.follow_distance));
v.push_back(std::to_string(e.stop_melee_level));
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(
@@ -602,13 +565,6 @@ public:
v.push_back(std::to_string(e.poison));
v.push_back(std::to_string(e.disease));
v.push_back(std::to_string(e.corruption));
v.push_back(std::to_string(e.show_helm));
v.push_back(std::to_string(e.follow_distance));
v.push_back(std::to_string(e.stop_melee_level));
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) + ")");
}
@@ -687,13 +643,6 @@ public:
e.poison = row[42] ? static_cast<int16_t>(atoi(row[42])) : 0;
e.disease = row[43] ? static_cast<int16_t>(atoi(row[43])) : 0;
e.corruption = row[44] ? static_cast<int16_t>(atoi(row[44])) : 0;
e.show_helm = row[45] ? static_cast<uint32_t>(strtoul(row[45], nullptr, 10)) : 0;
e.follow_distance = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 200;
e.stop_melee_level = row[47] ? static_cast<uint8_t>(strtoul(row[47], nullptr, 10)) : 255;
e.expansion_bitmask = row[48] ? static_cast<int32_t>(atoi(row[48])) : -1;
e.enforce_spell_settings = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 0;
e.archery_setting = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.caster_range = row[51] ? static_cast<uint32_t>(strtoul(row[51], nullptr, 10)) : 300;
all_entries.push_back(e);
}
@@ -763,13 +712,6 @@ public:
e.poison = row[42] ? static_cast<int16_t>(atoi(row[42])) : 0;
e.disease = row[43] ? static_cast<int16_t>(atoi(row[43])) : 0;
e.corruption = row[44] ? static_cast<int16_t>(atoi(row[44])) : 0;
e.show_helm = row[45] ? static_cast<uint32_t>(strtoul(row[45], nullptr, 10)) : 0;
e.follow_distance = row[46] ? static_cast<uint32_t>(strtoul(row[46], nullptr, 10)) : 200;
e.stop_melee_level = row[47] ? static_cast<uint8_t>(strtoul(row[47], nullptr, 10)) : 255;
e.expansion_bitmask = row[48] ? static_cast<int32_t>(atoi(row[48])) : -1;
e.enforce_spell_settings = row[49] ? static_cast<uint8_t>(strtoul(row[49], nullptr, 10)) : 0;
e.archery_setting = row[50] ? static_cast<uint8_t>(strtoul(row[50], nullptr, 10)) : 0;
e.caster_range = row[51] ? static_cast<uint32_t>(strtoul(row[51], nullptr, 10)) : 300;
all_entries.push_back(e);
}
@@ -889,13 +831,6 @@ public:
v.push_back(std::to_string(e.poison));
v.push_back(std::to_string(e.disease));
v.push_back(std::to_string(e.corruption));
v.push_back(std::to_string(e.show_helm));
v.push_back(std::to_string(e.follow_distance));
v.push_back(std::to_string(e.stop_melee_level));
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(
@@ -963,13 +898,6 @@ public:
v.push_back(std::to_string(e.poison));
v.push_back(std::to_string(e.disease));
v.push_back(std::to_string(e.corruption));
v.push_back(std::to_string(e.show_helm));
v.push_back(std::to_string(e.follow_distance));
v.push_back(std::to_string(e.stop_melee_level));
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) + ")");
}
@@ -0,0 +1,464 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_BOT_SETTINGS_REPOSITORY_H
#define EQEMU_BASE_BOT_SETTINGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseBotSettingsRepository {
public:
struct BotSettings {
uint32_t character_id;
uint32_t bot_id;
uint8_t stance;
uint16_t setting_id;
uint8_t setting_type;
int32_t value;
std::string category_name;
std::string setting_name;
};
static std::string PrimaryKey()
{
return std::string("character_id");
}
static std::vector<std::string> Columns()
{
return {
"character_id",
"bot_id",
"stance",
"setting_id",
"setting_type",
"value",
"category_name",
"setting_name",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"character_id",
"bot_id",
"stance",
"setting_id",
"setting_type",
"value",
"category_name",
"setting_name",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("bot_settings");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static BotSettings NewEntity()
{
BotSettings e{};
e.character_id = 0;
e.bot_id = 0;
e.stance = 0;
e.setting_id = 0;
e.setting_type = 0;
e.value = 0;
e.category_name = "";
e.setting_name = "";
return e;
}
static BotSettings GetBotSettings(
const std::vector<BotSettings> &bot_settingss,
int bot_settings_id
)
{
for (auto &bot_settings : bot_settingss) {
if (bot_settings.character_id == bot_settings_id) {
return bot_settings;
}
}
return NewEntity();
}
static BotSettings FindOne(
Database& db,
int bot_settings_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
bot_settings_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
BotSettings e{};
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.stance = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.setting_id = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.setting_type = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.value = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.category_name = row[6] ? row[6] : "";
e.setting_name = row[7] ? row[7] : "";
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int bot_settings_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
bot_settings_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const BotSettings &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.character_id));
v.push_back(columns[1] + " = " + std::to_string(e.bot_id));
v.push_back(columns[2] + " = " + std::to_string(e.stance));
v.push_back(columns[3] + " = " + std::to_string(e.setting_id));
v.push_back(columns[4] + " = " + std::to_string(e.setting_type));
v.push_back(columns[5] + " = " + std::to_string(e.value));
v.push_back(columns[6] + " = '" + Strings::Escape(e.category_name) + "'");
v.push_back(columns[7] + " = '" + Strings::Escape(e.setting_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.character_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static BotSettings InsertOne(
Database& db,
BotSettings e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.stance));
v.push_back(std::to_string(e.setting_id));
v.push_back(std::to_string(e.setting_type));
v.push_back(std::to_string(e.value));
v.push_back("'" + Strings::Escape(e.category_name) + "'");
v.push_back("'" + Strings::Escape(e.setting_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.character_id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<BotSettings> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.stance));
v.push_back(std::to_string(e.setting_id));
v.push_back(std::to_string(e.setting_type));
v.push_back(std::to_string(e.value));
v.push_back("'" + Strings::Escape(e.category_name) + "'");
v.push_back("'" + Strings::Escape(e.setting_name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<BotSettings> All(Database& db)
{
std::vector<BotSettings> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
BotSettings e{};
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.stance = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.setting_id = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.setting_type = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.value = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.category_name = row[6] ? row[6] : "";
e.setting_name = row[7] ? row[7] : "";
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<BotSettings> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<BotSettings> 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) {
BotSettings e{};
e.character_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.bot_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.stance = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.setting_id = row[3] ? static_cast<uint16_t>(strtoul(row[3], nullptr, 10)) : 0;
e.setting_type = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.value = row[5] ? static_cast<int32_t>(atoi(row[5])) : 0;
e.category_name = row[6] ? row[6] : "";
e.setting_name = row[7] ? row[7] : "";
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const BotSettings &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.stance));
v.push_back(std::to_string(e.setting_id));
v.push_back(std::to_string(e.setting_type));
v.push_back(std::to_string(e.value));
v.push_back("'" + Strings::Escape(e.category_name) + "'");
v.push_back("'" + Strings::Escape(e.setting_name) + "'");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<BotSettings> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.stance));
v.push_back(std::to_string(e.setting_id));
v.push_back(std::to_string(e.setting_type));
v.push_back(std::to_string(e.value));
v.push_back("'" + Strings::Escape(e.category_name) + "'");
v.push_back("'" + Strings::Escape(e.setting_name) + "'");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_BOT_SETTINGS_REPOSITORY_H
@@ -123,6 +123,7 @@ public:
uint32_t aa_points_old;
uint32_t e_last_invsnapshot;
time_t deleted_at;
uint8_t illusion_block;
};
static std::string PrimaryKey()
@@ -237,6 +238,7 @@ public:
"aa_points_old",
"e_last_invsnapshot",
"deleted_at",
"illusion_block",
};
}
@@ -347,6 +349,7 @@ public:
"aa_points_old",
"e_last_invsnapshot",
"UNIX_TIMESTAMP(deleted_at)",
"illusion_block",
};
}
@@ -491,6 +494,7 @@ public:
e.aa_points_old = 0;
e.e_last_invsnapshot = 0;
e.deleted_at = 0;
e.illusion_block = 0;
return e;
}
@@ -631,6 +635,7 @@ public:
e.aa_points_old = row[101] ? static_cast<uint32_t>(strtoul(row[101], nullptr, 10)) : 0;
e.e_last_invsnapshot = row[102] ? static_cast<uint32_t>(strtoul(row[102], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[103] ? row[103] : "-1", nullptr, 10);
e.illusion_block = row[104] ? static_cast<uint8_t>(strtoul(row[104], nullptr, 10)) : 0;
return e;
}
@@ -767,6 +772,7 @@ public:
v.push_back(columns[101] + " = " + std::to_string(e.aa_points_old));
v.push_back(columns[102] + " = " + std::to_string(e.e_last_invsnapshot));
v.push_back(columns[103] + " = FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
v.push_back(columns[104] + " = " + std::to_string(e.illusion_block));
auto results = db.QueryDatabase(
fmt::format(
@@ -892,6 +898,7 @@ public:
v.push_back(std::to_string(e.aa_points_old));
v.push_back(std::to_string(e.e_last_invsnapshot));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
v.push_back(std::to_string(e.illusion_block));
auto results = db.QueryDatabase(
fmt::format(
@@ -1025,6 +1032,7 @@ public:
v.push_back(std::to_string(e.aa_points_old));
v.push_back(std::to_string(e.e_last_invsnapshot));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
v.push_back(std::to_string(e.illusion_block));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -1162,6 +1170,7 @@ public:
e.aa_points_old = row[101] ? static_cast<uint32_t>(strtoul(row[101], nullptr, 10)) : 0;
e.e_last_invsnapshot = row[102] ? static_cast<uint32_t>(strtoul(row[102], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[103] ? row[103] : "-1", nullptr, 10);
e.illusion_block = row[104] ? static_cast<uint8_t>(strtoul(row[104], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1290,6 +1299,7 @@ public:
e.aa_points_old = row[101] ? static_cast<uint32_t>(strtoul(row[101], nullptr, 10)) : 0;
e.e_last_invsnapshot = row[102] ? static_cast<uint32_t>(strtoul(row[102], nullptr, 10)) : 0;
e.deleted_at = strtoll(row[103] ? row[103] : "-1", nullptr, 10);
e.illusion_block = row[104] ? static_cast<uint8_t>(strtoul(row[104], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1468,6 +1478,7 @@ public:
v.push_back(std::to_string(e.aa_points_old));
v.push_back(std::to_string(e.e_last_invsnapshot));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
v.push_back(std::to_string(e.illusion_block));
auto results = db.QueryDatabase(
fmt::format(
@@ -1594,6 +1605,7 @@ public:
v.push_back(std::to_string(e.aa_points_old));
v.push_back(std::to_string(e.e_last_invsnapshot));
v.push_back("FROM_UNIXTIME(" + (e.deleted_at > 0 ? std::to_string(e.deleted_at) : "null") + ")");
v.push_back(std::to_string(e.illusion_block));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -123,7 +123,7 @@ public:
int8_t legtexture;
int8_t feettexture;
int8_t light;
int8_t walkspeed;
float walkspeed;
int32_t peqid;
int8_t unique_;
int8_t fixed;
@@ -148,6 +148,7 @@ public:
int32_t faction_amount;
uint8_t keeps_sold_items;
uint8_t is_parcel_merchant;
uint8_t multiquest_enabled;
};
static std::string PrimaryKey()
@@ -287,6 +288,7 @@ public:
"faction_amount",
"keeps_sold_items",
"is_parcel_merchant",
"multiquest_enabled",
};
}
@@ -422,6 +424,7 @@ public:
"faction_amount",
"keeps_sold_items",
"is_parcel_merchant",
"multiquest_enabled",
};
}
@@ -591,6 +594,7 @@ public:
e.faction_amount = 0;
e.keeps_sold_items = 1;
e.is_parcel_merchant = 0;
e.multiquest_enabled = 0;
return e;
}
@@ -731,7 +735,7 @@ public:
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.walkspeed = row[104] ? strtof(row[104], nullptr) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
@@ -756,6 +760,7 @@ public:
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;
return e;
}
@@ -917,6 +922,7 @@ public:
v.push_back(columns[126] + " = " + std::to_string(e.faction_amount));
v.push_back(columns[127] + " = " + std::to_string(e.keeps_sold_items));
v.push_back(columns[128] + " = " + std::to_string(e.is_parcel_merchant));
v.push_back(columns[129] + " = " + std::to_string(e.multiquest_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -1067,6 +1073,7 @@ public:
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -1225,6 +1232,7 @@ public:
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -1362,7 +1370,7 @@ public:
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.walkspeed = row[104] ? strtof(row[104], nullptr) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
@@ -1387,6 +1395,7 @@ public:
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1515,7 +1524,7 @@ public:
e.legtexture = row[101] ? static_cast<int8_t>(atoi(row[101])) : 0;
e.feettexture = row[102] ? static_cast<int8_t>(atoi(row[102])) : 0;
e.light = row[103] ? static_cast<int8_t>(atoi(row[103])) : 0;
e.walkspeed = row[104] ? static_cast<int8_t>(atoi(row[104])) : 0;
e.walkspeed = row[104] ? strtof(row[104], nullptr) : 0;
e.peqid = row[105] ? static_cast<int32_t>(atoi(row[105])) : 0;
e.unique_ = row[106] ? static_cast<int8_t>(atoi(row[106])) : 0;
e.fixed = row[107] ? static_cast<int8_t>(atoi(row[107])) : 0;
@@ -1540,6 +1549,7 @@ public:
e.faction_amount = row[126] ? static_cast<int32_t>(atoi(row[126])) : 0;
e.keeps_sold_items = row[127] ? static_cast<uint8_t>(strtoul(row[127], nullptr, 10)) : 1;
e.is_parcel_merchant = row[128] ? static_cast<uint8_t>(strtoul(row[128], nullptr, 10)) : 0;
e.multiquest_enabled = row[129] ? static_cast<uint8_t>(strtoul(row[129], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -1743,6 +1753,7 @@ public:
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -1894,6 +1905,7 @@ public:
v.push_back(std::to_string(e.faction_amount));
v.push_back(std::to_string(e.keeps_sold_items));
v.push_back(std::to_string(e.is_parcel_merchant));
v.push_back(std::to_string(e.multiquest_enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -144,6 +144,7 @@ public:
e.texture = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.helm_texture = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.gender = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 2;
e.size_modifier = row[5] ? (strtof(row[5], nullptr) > 0.0f ? strtof(row[5], nullptr) : 1) : 1;
e.face = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 0;
return e;
@@ -287,6 +288,7 @@ public:
e.texture = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.helm_texture = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.gender = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 2;
e.size_modifier = row[5] ? (strtof(row[5], nullptr) > 0.0f ? strtof(row[5], nullptr) : 1) : 1;
e.face = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 0;
all_entries.push_back(e);
@@ -317,6 +319,7 @@ public:
e.texture = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.helm_texture = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.gender = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 2;
e.size_modifier = row[5] ? (strtof(row[5], nullptr) > 0.0f ? strtof(row[5], nullptr) : 1) : 1;
e.face = row[6] ? static_cast<uint8_t>(strtoul(row[6], nullptr, 10)) : 0;
all_entries.push_back(e);
@@ -0,0 +1,439 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventAaPurchaseRepository {
public:
struct PlayerEventAaPurchase {
uint64_t id;
int32_t aa_ability_id;
int32_t cost;
int32_t previous_id;
int32_t next_id;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"aa_ability_id",
"cost",
"previous_id",
"next_id",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"aa_ability_id",
"cost",
"previous_id",
"next_id",
"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_aa_purchase");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventAaPurchase NewEntity()
{
PlayerEventAaPurchase e{};
e.id = 0;
e.aa_ability_id = 0;
e.cost = 0;
e.previous_id = 0;
e.next_id = 0;
e.created_at = 0;
return e;
}
static PlayerEventAaPurchase GetPlayerEventAaPurchase(
const std::vector<PlayerEventAaPurchase> &player_event_aa_purchases,
int player_event_aa_purchase_id
)
{
for (auto &player_event_aa_purchase : player_event_aa_purchases) {
if (player_event_aa_purchase.id == player_event_aa_purchase_id) {
return player_event_aa_purchase;
}
}
return NewEntity();
}
static PlayerEventAaPurchase FindOne(
Database& db,
int player_event_aa_purchase_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_aa_purchase_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventAaPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.aa_ability_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.cost = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.previous_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.next_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.created_at = strtoll(row[5] ? row[5] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_aa_purchase_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_aa_purchase_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventAaPurchase &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.aa_ability_id));
v.push_back(columns[2] + " = " + std::to_string(e.cost));
v.push_back(columns[3] + " = " + std::to_string(e.previous_id));
v.push_back(columns[4] + " = " + std::to_string(e.next_id));
v.push_back(columns[5] + " = 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 PlayerEventAaPurchase InsertOne(
Database& db,
PlayerEventAaPurchase e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.aa_ability_id));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.previous_id));
v.push_back(std::to_string(e.next_id));
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<PlayerEventAaPurchase> &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.aa_ability_id));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.previous_id));
v.push_back(std::to_string(e.next_id));
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<PlayerEventAaPurchase> All(Database& db)
{
std::vector<PlayerEventAaPurchase> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventAaPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.aa_ability_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.cost = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.previous_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.next_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.created_at = strtoll(row[5] ? row[5] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventAaPurchase> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventAaPurchase> 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) {
PlayerEventAaPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.aa_ability_id = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.cost = row[2] ? static_cast<int32_t>(atoi(row[2])) : 0;
e.previous_id = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.next_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.created_at = strtoll(row[5] ? row[5] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventAaPurchase &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.aa_ability_id));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.previous_id));
v.push_back(std::to_string(e.next_id));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventAaPurchase> &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.aa_ability_id));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.previous_id));
v.push_back(std::to_string(e.next_id));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
@@ -0,0 +1,451 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventKilledNamedNpcRepository {
public:
struct PlayerEventKilledNamedNpc {
uint64_t id;
uint32_t npc_id;
std::string npc_name;
uint32_t combat_time_seconds;
uint64_t total_damage_per_second_taken;
uint64_t total_heal_per_second_taken;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"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_killed_named_npc");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventKilledNamedNpc NewEntity()
{
PlayerEventKilledNamedNpc e{};
e.id = 0;
e.npc_id = 0;
e.npc_name = "";
e.combat_time_seconds = 0;
e.total_damage_per_second_taken = 0;
e.total_heal_per_second_taken = 0;
e.created_at = 0;
return e;
}
static PlayerEventKilledNamedNpc GetPlayerEventKilledNamedNpc(
const std::vector<PlayerEventKilledNamedNpc> &player_event_killed_named_npcs,
int player_event_killed_named_npc_id
)
{
for (auto &player_event_killed_named_npc : player_event_killed_named_npcs) {
if (player_event_killed_named_npc.id == player_event_killed_named_npc_id) {
return player_event_killed_named_npc;
}
}
return NewEntity();
}
static PlayerEventKilledNamedNpc FindOne(
Database& db,
int player_event_killed_named_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_killed_named_npc_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventKilledNamedNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_killed_named_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_killed_named_npc_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventKilledNamedNpc &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.npc_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.combat_time_seconds));
v.push_back(columns[4] + " = " + std::to_string(e.total_damage_per_second_taken));
v.push_back(columns[5] + " = " + std::to_string(e.total_heal_per_second_taken));
v.push_back(columns[6] + " = 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 PlayerEventKilledNamedNpc InsertOne(
Database& db,
PlayerEventKilledNamedNpc e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledNamedNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledNamedNpc> All(Database& db)
{
std::vector<PlayerEventKilledNamedNpc> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventKilledNamedNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventKilledNamedNpc> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventKilledNamedNpc> 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) {
PlayerEventKilledNamedNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventKilledNamedNpc &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventKilledNamedNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
@@ -0,0 +1,451 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventKilledNpcRepository {
public:
struct PlayerEventKilledNpc {
uint64_t id;
uint32_t npc_id;
std::string npc_name;
uint32_t combat_time_seconds;
uint64_t total_damage_per_second_taken;
uint64_t total_heal_per_second_taken;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"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_killed_npc");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventKilledNpc NewEntity()
{
PlayerEventKilledNpc e{};
e.id = 0;
e.npc_id = 0;
e.npc_name = "";
e.combat_time_seconds = 0;
e.total_damage_per_second_taken = 0;
e.total_heal_per_second_taken = 0;
e.created_at = 0;
return e;
}
static PlayerEventKilledNpc GetPlayerEventKilledNpc(
const std::vector<PlayerEventKilledNpc> &player_event_killed_npcs,
int player_event_killed_npc_id
)
{
for (auto &player_event_killed_npc : player_event_killed_npcs) {
if (player_event_killed_npc.id == player_event_killed_npc_id) {
return player_event_killed_npc;
}
}
return NewEntity();
}
static PlayerEventKilledNpc FindOne(
Database& db,
int player_event_killed_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_killed_npc_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventKilledNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_killed_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_killed_npc_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventKilledNpc &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.npc_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.combat_time_seconds));
v.push_back(columns[4] + " = " + std::to_string(e.total_damage_per_second_taken));
v.push_back(columns[5] + " = " + std::to_string(e.total_heal_per_second_taken));
v.push_back(columns[6] + " = 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 PlayerEventKilledNpc InsertOne(
Database& db,
PlayerEventKilledNpc e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledNpc> All(Database& db)
{
std::vector<PlayerEventKilledNpc> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventKilledNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventKilledNpc> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventKilledNpc> 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) {
PlayerEventKilledNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventKilledNpc &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventKilledNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
@@ -0,0 +1,451 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventKilledRaidNpcRepository {
public:
struct PlayerEventKilledRaidNpc {
uint64_t id;
uint32_t npc_id;
std::string npc_name;
uint32_t combat_time_seconds;
uint64_t total_damage_per_second_taken;
uint64_t total_heal_per_second_taken;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"npc_name",
"combat_time_seconds",
"total_damage_per_second_taken",
"total_heal_per_second_taken",
"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_killed_raid_npc");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventKilledRaidNpc NewEntity()
{
PlayerEventKilledRaidNpc e{};
e.id = 0;
e.npc_id = 0;
e.npc_name = "";
e.combat_time_seconds = 0;
e.total_damage_per_second_taken = 0;
e.total_heal_per_second_taken = 0;
e.created_at = 0;
return e;
}
static PlayerEventKilledRaidNpc GetPlayerEventKilledRaidNpc(
const std::vector<PlayerEventKilledRaidNpc> &player_event_killed_raid_npcs,
int player_event_killed_raid_npc_id
)
{
for (auto &player_event_killed_raid_npc : player_event_killed_raid_npcs) {
if (player_event_killed_raid_npc.id == player_event_killed_raid_npc_id) {
return player_event_killed_raid_npc;
}
}
return NewEntity();
}
static PlayerEventKilledRaidNpc FindOne(
Database& db,
int player_event_killed_raid_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_killed_raid_npc_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventKilledRaidNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_killed_raid_npc_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_killed_raid_npc_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventKilledRaidNpc &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.npc_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.combat_time_seconds));
v.push_back(columns[4] + " = " + std::to_string(e.total_damage_per_second_taken));
v.push_back(columns[5] + " = " + std::to_string(e.total_heal_per_second_taken));
v.push_back(columns[6] + " = 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 PlayerEventKilledRaidNpc InsertOne(
Database& db,
PlayerEventKilledRaidNpc e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledRaidNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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<PlayerEventKilledRaidNpc> All(Database& db)
{
std::vector<PlayerEventKilledRaidNpc> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventKilledRaidNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventKilledRaidNpc> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventKilledRaidNpc> 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) {
PlayerEventKilledRaidNpc e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.combat_time_seconds = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.total_damage_per_second_taken = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.total_heal_per_second_taken = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.created_at = strtoll(row[6] ? row[6] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventKilledRaidNpc &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventKilledRaidNpc> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.combat_time_seconds));
v.push_back(std::to_string(e.total_damage_per_second_taken));
v.push_back(std::to_string(e.total_heal_per_second_taken));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
@@ -24,6 +24,7 @@ public:
int8_t event_enabled;
int32_t retention_days;
int32_t discord_webhook_id;
uint8_t etl_enabled;
};
static std::string PrimaryKey()
@@ -39,6 +40,7 @@ public:
"event_enabled",
"retention_days",
"discord_webhook_id",
"etl_enabled",
};
}
@@ -50,6 +52,7 @@ public:
"event_enabled",
"retention_days",
"discord_webhook_id",
"etl_enabled",
};
}
@@ -95,6 +98,7 @@ public:
e.event_enabled = 0;
e.retention_days = 0;
e.discord_webhook_id = 0;
e.etl_enabled = 0;
return e;
}
@@ -136,6 +140,7 @@ public:
e.event_enabled = row[2] ? static_cast<int8_t>(atoi(row[2])) : 0;
e.retention_days = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.discord_webhook_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.etl_enabled = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
return e;
}
@@ -174,6 +179,7 @@ public:
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));
v.push_back(columns[5] + " = " + std::to_string(e.etl_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -200,6 +206,7 @@ public:
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));
v.push_back(std::to_string(e.etl_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -234,6 +241,7 @@ public:
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));
v.push_back(std::to_string(e.etl_enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -272,6 +280,7 @@ public:
e.event_enabled = row[2] ? static_cast<int8_t>(atoi(row[2])) : 0;
e.retention_days = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.discord_webhook_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.etl_enabled = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -301,6 +310,7 @@ public:
e.event_enabled = row[2] ? static_cast<int8_t>(atoi(row[2])) : 0;
e.retention_days = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.discord_webhook_id = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.etl_enabled = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -380,6 +390,7 @@ public:
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));
v.push_back(std::to_string(e.etl_enabled));
auto results = db.QueryDatabase(
fmt::format(
@@ -407,6 +418,7 @@ public:
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));
v.push_back(std::to_string(e.etl_enabled));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -31,6 +31,7 @@ public:
int32_t event_type_id;
std::string event_type_name;
std::string event_data;
int64_t etl_table_id;
time_t created_at;
// cereal
@@ -50,6 +51,7 @@ public:
CEREAL_NVP(event_type_id),
CEREAL_NVP(event_type_name),
CEREAL_NVP(event_data),
CEREAL_NVP(etl_table_id),
CEREAL_NVP(created_at)
);
}
@@ -75,6 +77,7 @@ public:
"event_type_id",
"event_type_name",
"event_data",
"etl_table_id",
"created_at",
};
}
@@ -94,6 +97,7 @@ public:
"event_type_id",
"event_type_name",
"event_data",
"etl_table_id",
"UNIX_TIMESTAMP(created_at)",
};
}
@@ -147,6 +151,7 @@ public:
e.event_type_id = 0;
e.event_type_name = "";
e.event_data = "";
e.etl_table_id = 0;
e.created_at = 0;
return e;
@@ -196,7 +201,8 @@ public:
e.event_type_id = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
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);
e.etl_table_id = row[12] ? strtoll(row[12], nullptr, 10) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
return e;
}
@@ -241,7 +247,8 @@ public:
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
v.push_back(columns[10] + " = '" + Strings::Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.event_data) + "'");
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
v.push_back(columns[12] + " = " + std::to_string(e.etl_table_id));
v.push_back(columns[13] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -275,6 +282,7 @@ public:
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back(std::to_string(e.etl_table_id));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
@@ -317,6 +325,7 @@ public:
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back(std::to_string(e.etl_table_id));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@@ -363,7 +372,8 @@ public:
e.event_type_id = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
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);
e.etl_table_id = row[12] ? strtoll(row[12], nullptr, 10) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -400,7 +410,8 @@ public:
e.event_type_id = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
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);
e.etl_table_id = row[12] ? strtoll(row[12], nullptr, 10) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -487,6 +498,7 @@ public:
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back(std::to_string(e.etl_table_id));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
@@ -522,6 +534,7 @@ public:
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
v.push_back("'" + Strings::Escape(e.event_data) + "'");
v.push_back(std::to_string(e.etl_table_id));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@@ -0,0 +1,523 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventLootItemsRepository {
public:
struct PlayerEventLootItems {
uint64_t id;
uint32_t item_id;
std::string item_name;
int32_t charges;
uint32_t augment_1_id;
uint32_t augment_2_id;
uint32_t augment_3_id;
uint32_t augment_4_id;
uint32_t augment_5_id;
uint32_t augment_6_id;
uint32_t npc_id;
std::string corpse_name;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"item_id",
"item_name",
"charges",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
"npc_id",
"corpse_name",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"item_id",
"item_name",
"charges",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
"npc_id",
"corpse_name",
"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_loot_items");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventLootItems NewEntity()
{
PlayerEventLootItems e{};
e.id = 0;
e.item_id = 0;
e.item_name = "";
e.charges = 0;
e.augment_1_id = 0;
e.augment_2_id = 0;
e.augment_3_id = 0;
e.augment_4_id = 0;
e.augment_5_id = 0;
e.augment_6_id = 0;
e.npc_id = 0;
e.corpse_name = "";
e.created_at = 0;
return e;
}
static PlayerEventLootItems GetPlayerEventLootItems(
const std::vector<PlayerEventLootItems> &player_event_loot_itemss,
int player_event_loot_items_id
)
{
for (auto &player_event_loot_items : player_event_loot_itemss) {
if (player_event_loot_items.id == player_event_loot_items_id) {
return player_event_loot_items;
}
}
return NewEntity();
}
static PlayerEventLootItems FindOne(
Database& db,
int player_event_loot_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_loot_items_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventLootItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_name = row[2] ? row[2] : "";
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.augment_1_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_2_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_3_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_4_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_5_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_6_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.npc_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.corpse_name = 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_loot_items_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_loot_items_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventLootItems &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.item_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.item_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.charges));
v.push_back(columns[4] + " = " + std::to_string(e.augment_1_id));
v.push_back(columns[5] + " = " + std::to_string(e.augment_2_id));
v.push_back(columns[6] + " = " + std::to_string(e.augment_3_id));
v.push_back(columns[7] + " = " + std::to_string(e.augment_4_id));
v.push_back(columns[8] + " = " + std::to_string(e.augment_5_id));
v.push_back(columns[9] + " = " + std::to_string(e.augment_6_id));
v.push_back(columns[10] + " = " + std::to_string(e.npc_id));
v.push_back(columns[11] + " = '" + Strings::Escape(e.corpse_name) + "'");
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 PlayerEventLootItems InsertOne(
Database& db,
PlayerEventLootItems e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.corpse_name) + "'");
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<PlayerEventLootItems> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.corpse_name) + "'");
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<PlayerEventLootItems> All(Database& db)
{
std::vector<PlayerEventLootItems> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventLootItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_name = row[2] ? row[2] : "";
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.augment_1_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_2_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_3_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_4_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_5_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_6_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.npc_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.corpse_name = 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<PlayerEventLootItems> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventLootItems> 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) {
PlayerEventLootItems e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.item_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_name = row[2] ? row[2] : "";
e.charges = row[3] ? static_cast<int32_t>(atoi(row[3])) : 0;
e.augment_1_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.augment_2_id = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.augment_3_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_4_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_5_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_6_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.npc_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.corpse_name = 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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventLootItems &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.corpse_name) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventLootItems> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.corpse_name) + "'");
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
@@ -0,0 +1,511 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventMerchantPurchaseRepository {
public:
struct PlayerEventMerchantPurchase {
uint64_t id;
uint32_t npc_id;
std::string merchant_name;
uint32_t merchant_type;
uint32_t item_id;
std::string item_name;
int32_t charges;
uint32_t cost;
uint32_t alternate_currency_id;
uint64_t player_money_balance;
uint64_t player_currency_balance;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"merchant_name",
"merchant_type",
"item_id",
"item_name",
"charges",
"cost",
"alternate_currency_id",
"player_money_balance",
"player_currency_balance",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"merchant_name",
"merchant_type",
"item_id",
"item_name",
"charges",
"cost",
"alternate_currency_id",
"player_money_balance",
"player_currency_balance",
"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_merchant_purchase");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventMerchantPurchase NewEntity()
{
PlayerEventMerchantPurchase e{};
e.id = 0;
e.npc_id = 0;
e.merchant_name = "";
e.merchant_type = 0;
e.item_id = 0;
e.item_name = "";
e.charges = 0;
e.cost = 0;
e.alternate_currency_id = 0;
e.player_money_balance = 0;
e.player_currency_balance = 0;
e.created_at = 0;
return e;
}
static PlayerEventMerchantPurchase GetPlayerEventMerchantPurchase(
const std::vector<PlayerEventMerchantPurchase> &player_event_merchant_purchases,
int player_event_merchant_purchase_id
)
{
for (auto &player_event_merchant_purchase : player_event_merchant_purchases) {
if (player_event_merchant_purchase.id == player_event_merchant_purchase_id) {
return player_event_merchant_purchase;
}
}
return NewEntity();
}
static PlayerEventMerchantPurchase FindOne(
Database& db,
int player_event_merchant_purchase_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_merchant_purchase_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventMerchantPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_merchant_purchase_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_merchant_purchase_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventMerchantPurchase &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.merchant_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.merchant_type));
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
v.push_back(columns[5] + " = '" + Strings::Escape(e.item_name) + "'");
v.push_back(columns[6] + " = " + std::to_string(e.charges));
v.push_back(columns[7] + " = " + std::to_string(e.cost));
v.push_back(columns[8] + " = " + std::to_string(e.alternate_currency_id));
v.push_back(columns[9] + " = " + std::to_string(e.player_money_balance));
v.push_back(columns[10] + " = " + std::to_string(e.player_currency_balance));
v.push_back(columns[11] + " = 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 PlayerEventMerchantPurchase InsertOne(
Database& db,
PlayerEventMerchantPurchase e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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<PlayerEventMerchantPurchase> &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.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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<PlayerEventMerchantPurchase> All(Database& db)
{
std::vector<PlayerEventMerchantPurchase> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventMerchantPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventMerchantPurchase> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventMerchantPurchase> 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) {
PlayerEventMerchantPurchase e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventMerchantPurchase &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventMerchantPurchase> &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.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
@@ -0,0 +1,511 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventMerchantSellRepository {
public:
struct PlayerEventMerchantSell {
uint64_t id;
uint32_t npc_id;
std::string merchant_name;
uint32_t merchant_type;
uint32_t item_id;
std::string item_name;
int32_t charges;
uint32_t cost;
uint32_t alternate_currency_id;
uint64_t player_money_balance;
uint64_t player_currency_balance;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"merchant_name",
"merchant_type",
"item_id",
"item_name",
"charges",
"cost",
"alternate_currency_id",
"player_money_balance",
"player_currency_balance",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"merchant_name",
"merchant_type",
"item_id",
"item_name",
"charges",
"cost",
"alternate_currency_id",
"player_money_balance",
"player_currency_balance",
"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_merchant_sell");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventMerchantSell NewEntity()
{
PlayerEventMerchantSell e{};
e.id = 0;
e.npc_id = 0;
e.merchant_name = "";
e.merchant_type = 0;
e.item_id = 0;
e.item_name = "";
e.charges = 0;
e.cost = 0;
e.alternate_currency_id = 0;
e.player_money_balance = 0;
e.player_currency_balance = 0;
e.created_at = 0;
return e;
}
static PlayerEventMerchantSell GetPlayerEventMerchantSell(
const std::vector<PlayerEventMerchantSell> &player_event_merchant_sells,
int player_event_merchant_sell_id
)
{
for (auto &player_event_merchant_sell : player_event_merchant_sells) {
if (player_event_merchant_sell.id == player_event_merchant_sell_id) {
return player_event_merchant_sell;
}
}
return NewEntity();
}
static PlayerEventMerchantSell FindOne(
Database& db,
int player_event_merchant_sell_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_merchant_sell_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventMerchantSell e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_merchant_sell_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_merchant_sell_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventMerchantSell &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.merchant_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.merchant_type));
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
v.push_back(columns[5] + " = '" + Strings::Escape(e.item_name) + "'");
v.push_back(columns[6] + " = " + std::to_string(e.charges));
v.push_back(columns[7] + " = " + std::to_string(e.cost));
v.push_back(columns[8] + " = " + std::to_string(e.alternate_currency_id));
v.push_back(columns[9] + " = " + std::to_string(e.player_money_balance));
v.push_back(columns[10] + " = " + std::to_string(e.player_currency_balance));
v.push_back(columns[11] + " = 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 PlayerEventMerchantSell InsertOne(
Database& db,
PlayerEventMerchantSell e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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<PlayerEventMerchantSell> &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.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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<PlayerEventMerchantSell> All(Database& db)
{
std::vector<PlayerEventMerchantSell> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventMerchantSell e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventMerchantSell> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventMerchantSell> 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) {
PlayerEventMerchantSell e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.merchant_name = row[2] ? row[2] : "";
e.merchant_type = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.item_name = row[5] ? row[5] : "";
e.charges = row[6] ? static_cast<int32_t>(atoi(row[6])) : 0;
e.cost = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.alternate_currency_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.player_money_balance = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.player_currency_balance = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventMerchantSell &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventMerchantSell> &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.npc_id));
v.push_back("'" + Strings::Escape(e.merchant_name) + "'");
v.push_back(std::to_string(e.merchant_type));
v.push_back(std::to_string(e.item_id));
v.push_back("'" + Strings::Escape(e.item_name) + "'");
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.cost));
v.push_back(std::to_string(e.alternate_currency_id));
v.push_back(std::to_string(e.player_money_balance));
v.push_back(std::to_string(e.player_currency_balance));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
@@ -0,0 +1,523 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventNpcHandinEntriesRepository {
public:
struct PlayerEventNpcHandinEntries {
uint64_t id;
uint64_t player_event_npc_handin_id;
uint32_t type;
uint32_t item_id;
int32_t charges;
uint32_t evolve_level;
uint64_t evolve_amount;
uint32_t augment_1_id;
uint32_t augment_2_id;
uint32_t augment_3_id;
uint32_t augment_4_id;
uint32_t augment_5_id;
uint32_t augment_6_id;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"player_event_npc_handin_id",
"type",
"item_id",
"charges",
"evolve_level",
"evolve_amount",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"player_event_npc_handin_id",
"type",
"item_id",
"charges",
"evolve_level",
"evolve_amount",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
};
}
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_npc_handin_entries");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventNpcHandinEntries NewEntity()
{
PlayerEventNpcHandinEntries e{};
e.id = 0;
e.player_event_npc_handin_id = 0;
e.type = 0;
e.item_id = 0;
e.charges = 0;
e.evolve_level = 0;
e.evolve_amount = 0;
e.augment_1_id = 0;
e.augment_2_id = 0;
e.augment_3_id = 0;
e.augment_4_id = 0;
e.augment_5_id = 0;
e.augment_6_id = 0;
return e;
}
static PlayerEventNpcHandinEntries GetPlayerEventNpcHandinEntries(
const std::vector<PlayerEventNpcHandinEntries> &player_event_npc_handin_entriess,
int player_event_npc_handin_entries_id
)
{
for (auto &player_event_npc_handin_entries : player_event_npc_handin_entriess) {
if (player_event_npc_handin_entries.id == player_event_npc_handin_entries_id) {
return player_event_npc_handin_entries;
}
}
return NewEntity();
}
static PlayerEventNpcHandinEntries FindOne(
Database& db,
int player_event_npc_handin_entries_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_npc_handin_entries_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventNpcHandinEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_npc_handin_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.evolve_level = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.evolve_amount = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.augment_1_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_2_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_3_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_4_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_5_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_6_id = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_npc_handin_entries_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_npc_handin_entries_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventNpcHandinEntries &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.player_event_npc_handin_id));
v.push_back(columns[2] + " = " + std::to_string(e.type));
v.push_back(columns[3] + " = " + std::to_string(e.item_id));
v.push_back(columns[4] + " = " + std::to_string(e.charges));
v.push_back(columns[5] + " = " + std::to_string(e.evolve_level));
v.push_back(columns[6] + " = " + std::to_string(e.evolve_amount));
v.push_back(columns[7] + " = " + std::to_string(e.augment_1_id));
v.push_back(columns[8] + " = " + std::to_string(e.augment_2_id));
v.push_back(columns[9] + " = " + std::to_string(e.augment_3_id));
v.push_back(columns[10] + " = " + std::to_string(e.augment_4_id));
v.push_back(columns[11] + " = " + std::to_string(e.augment_5_id));
v.push_back(columns[12] + " = " + std::to_string(e.augment_6_id));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static PlayerEventNpcHandinEntries InsertOne(
Database& db,
PlayerEventNpcHandinEntries e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.player_event_npc_handin_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.evolve_level));
v.push_back(std::to_string(e.evolve_amount));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
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<PlayerEventNpcHandinEntries> &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.player_event_npc_handin_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.evolve_level));
v.push_back(std::to_string(e.evolve_amount));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
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<PlayerEventNpcHandinEntries> All(Database& db)
{
std::vector<PlayerEventNpcHandinEntries> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventNpcHandinEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_npc_handin_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.evolve_level = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.evolve_amount = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.augment_1_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_2_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_3_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_4_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_5_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_6_id = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventNpcHandinEntries> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventNpcHandinEntries> 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) {
PlayerEventNpcHandinEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_npc_handin_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.type = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.item_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.charges = row[4] ? static_cast<int32_t>(atoi(row[4])) : 0;
e.evolve_level = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.evolve_amount = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.augment_1_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_2_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_3_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_4_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_5_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.augment_6_id = row[12] ? static_cast<uint32_t>(strtoul(row[12], nullptr, 10)) : 0;
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventNpcHandinEntries &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.player_event_npc_handin_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.evolve_level));
v.push_back(std::to_string(e.evolve_amount));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventNpcHandinEntries> &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.player_event_npc_handin_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.evolve_level));
v.push_back(std::to_string(e.evolve_amount));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
@@ -0,0 +1,523 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventNpcHandinRepository {
public:
struct PlayerEventNpcHandin {
uint64_t id;
uint32_t npc_id;
std::string npc_name;
uint64_t handin_copper;
uint64_t handin_silver;
uint64_t handin_gold;
uint64_t handin_platinum;
uint64_t return_copper;
uint64_t return_silver;
uint64_t return_gold;
uint64_t return_platinum;
uint8_t is_quest_handin;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"npc_id",
"npc_name",
"handin_copper",
"handin_silver",
"handin_gold",
"handin_platinum",
"return_copper",
"return_silver",
"return_gold",
"return_platinum",
"is_quest_handin",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"npc_id",
"npc_name",
"handin_copper",
"handin_silver",
"handin_gold",
"handin_platinum",
"return_copper",
"return_silver",
"return_gold",
"return_platinum",
"is_quest_handin",
"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_npc_handin");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventNpcHandin NewEntity()
{
PlayerEventNpcHandin e{};
e.id = 0;
e.npc_id = 0;
e.npc_name = "";
e.handin_copper = 0;
e.handin_silver = 0;
e.handin_gold = 0;
e.handin_platinum = 0;
e.return_copper = 0;
e.return_silver = 0;
e.return_gold = 0;
e.return_platinum = 0;
e.is_quest_handin = 0;
e.created_at = 0;
return e;
}
static PlayerEventNpcHandin GetPlayerEventNpcHandin(
const std::vector<PlayerEventNpcHandin> &player_event_npc_handins,
int player_event_npc_handin_id
)
{
for (auto &player_event_npc_handin : player_event_npc_handins) {
if (player_event_npc_handin.id == player_event_npc_handin_id) {
return player_event_npc_handin;
}
}
return NewEntity();
}
static PlayerEventNpcHandin FindOne(
Database& db,
int player_event_npc_handin_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_npc_handin_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventNpcHandin e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.handin_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.handin_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.handin_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.handin_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.return_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.return_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.return_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.return_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.is_quest_handin = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_npc_handin_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_npc_handin_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventNpcHandin &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.npc_id));
v.push_back(columns[2] + " = '" + Strings::Escape(e.npc_name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.handin_copper));
v.push_back(columns[4] + " = " + std::to_string(e.handin_silver));
v.push_back(columns[5] + " = " + std::to_string(e.handin_gold));
v.push_back(columns[6] + " = " + std::to_string(e.handin_platinum));
v.push_back(columns[7] + " = " + std::to_string(e.return_copper));
v.push_back(columns[8] + " = " + std::to_string(e.return_silver));
v.push_back(columns[9] + " = " + std::to_string(e.return_gold));
v.push_back(columns[10] + " = " + std::to_string(e.return_platinum));
v.push_back(columns[11] + " = " + std::to_string(e.is_quest_handin));
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 PlayerEventNpcHandin InsertOne(
Database& db,
PlayerEventNpcHandin e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.handin_copper));
v.push_back(std::to_string(e.handin_silver));
v.push_back(std::to_string(e.handin_gold));
v.push_back(std::to_string(e.handin_platinum));
v.push_back(std::to_string(e.return_copper));
v.push_back(std::to_string(e.return_silver));
v.push_back(std::to_string(e.return_gold));
v.push_back(std::to_string(e.return_platinum));
v.push_back(std::to_string(e.is_quest_handin));
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<PlayerEventNpcHandin> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.handin_copper));
v.push_back(std::to_string(e.handin_silver));
v.push_back(std::to_string(e.handin_gold));
v.push_back(std::to_string(e.handin_platinum));
v.push_back(std::to_string(e.return_copper));
v.push_back(std::to_string(e.return_silver));
v.push_back(std::to_string(e.return_gold));
v.push_back(std::to_string(e.return_platinum));
v.push_back(std::to_string(e.is_quest_handin));
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<PlayerEventNpcHandin> All(Database& db)
{
std::vector<PlayerEventNpcHandin> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventNpcHandin e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.handin_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.handin_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.handin_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.handin_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.return_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.return_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.return_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.return_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.is_quest_handin = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventNpcHandin> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventNpcHandin> 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) {
PlayerEventNpcHandin e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.npc_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.npc_name = row[2] ? row[2] : "";
e.handin_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.handin_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.handin_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.handin_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.return_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.return_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.return_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.return_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.is_quest_handin = row[11] ? static_cast<uint8_t>(strtoul(row[11], nullptr, 10)) : 0;
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);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventNpcHandin &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.handin_copper));
v.push_back(std::to_string(e.handin_silver));
v.push_back(std::to_string(e.handin_gold));
v.push_back(std::to_string(e.handin_platinum));
v.push_back(std::to_string(e.return_copper));
v.push_back(std::to_string(e.return_silver));
v.push_back(std::to_string(e.return_gold));
v.push_back(std::to_string(e.return_platinum));
v.push_back(std::to_string(e.is_quest_handin));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventNpcHandin> &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.npc_id));
v.push_back("'" + Strings::Escape(e.npc_name) + "'");
v.push_back(std::to_string(e.handin_copper));
v.push_back(std::to_string(e.handin_silver));
v.push_back(std::to_string(e.handin_gold));
v.push_back(std::to_string(e.handin_platinum));
v.push_back(std::to_string(e.return_copper));
v.push_back(std::to_string(e.return_silver));
v.push_back(std::to_string(e.return_gold));
v.push_back(std::to_string(e.return_platinum));
v.push_back(std::to_string(e.is_quest_handin));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
@@ -0,0 +1,463 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_SPEECH_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_SPEECH_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventSpeechRepository {
public:
struct PlayerEventSpeech {
uint64_t id;
std::string to_char_id;
std::string from_char_id;
uint32_t guild_id;
uint32_t type;
uint32_t min_status;
std::string message;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"to_char_id",
"from_char_id",
"guild_id",
"type",
"min_status",
"message",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"to_char_id",
"from_char_id",
"guild_id",
"type",
"min_status",
"message",
"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_speech");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventSpeech NewEntity()
{
PlayerEventSpeech e{};
e.id = 0;
e.to_char_id = "";
e.from_char_id = "";
e.guild_id = 0;
e.type = 0;
e.min_status = 0;
e.message = "";
e.created_at = 0;
return e;
}
static PlayerEventSpeech GetPlayerEventSpeech(
const std::vector<PlayerEventSpeech> &player_event_speechs,
int player_event_speech_id
)
{
for (auto &player_event_speech : player_event_speechs) {
if (player_event_speech.id == player_event_speech_id) {
return player_event_speech;
}
}
return NewEntity();
}
static PlayerEventSpeech FindOne(
Database& db,
int player_event_speech_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_speech_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventSpeech e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.to_char_id = row[1] ? row[1] : "";
e.from_char_id = row[2] ? row[2] : "";
e.guild_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.min_status = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.message = row[6] ? row[6] : "";
e.created_at = strtoll(row[7] ? row[7] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_speech_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_speech_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventSpeech &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.to_char_id) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.from_char_id) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.guild_id));
v.push_back(columns[4] + " = " + std::to_string(e.type));
v.push_back(columns[5] + " = " + std::to_string(e.min_status));
v.push_back(columns[6] + " = '" + Strings::Escape(e.message) + "'");
v.push_back(columns[7] + " = 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 PlayerEventSpeech InsertOne(
Database& db,
PlayerEventSpeech e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.to_char_id) + "'");
v.push_back("'" + Strings::Escape(e.from_char_id) + "'");
v.push_back(std::to_string(e.guild_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.min_status));
v.push_back("'" + Strings::Escape(e.message) + "'");
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<PlayerEventSpeech> &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.to_char_id) + "'");
v.push_back("'" + Strings::Escape(e.from_char_id) + "'");
v.push_back(std::to_string(e.guild_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.min_status));
v.push_back("'" + Strings::Escape(e.message) + "'");
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<PlayerEventSpeech> All(Database& db)
{
std::vector<PlayerEventSpeech> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventSpeech e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.to_char_id = row[1] ? row[1] : "";
e.from_char_id = row[2] ? row[2] : "";
e.guild_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.min_status = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.message = row[6] ? row[6] : "";
e.created_at = strtoll(row[7] ? row[7] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventSpeech> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventSpeech> 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) {
PlayerEventSpeech e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.to_char_id = row[1] ? row[1] : "";
e.from_char_id = row[2] ? row[2] : "";
e.guild_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.type = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.min_status = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.message = row[6] ? row[6] : "";
e.created_at = strtoll(row[7] ? row[7] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventSpeech &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.to_char_id) + "'");
v.push_back("'" + Strings::Escape(e.from_char_id) + "'");
v.push_back(std::to_string(e.guild_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.min_status));
v.push_back("'" + Strings::Escape(e.message) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventSpeech> &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.to_char_id) + "'");
v.push_back("'" + Strings::Escape(e.from_char_id) + "'");
v.push_back(std::to_string(e.guild_id));
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.min_status));
v.push_back("'" + Strings::Escape(e.message) + "'");
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_SPEECH_REPOSITORY_H
@@ -0,0 +1,535 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventTradeEntriesRepository {
public:
struct PlayerEventTradeEntries {
uint64_t id;
uint64_t player_event_trade_id;
uint32_t char_id;
int16_t slot;
uint32_t item_id;
int16_t charges;
uint32_t augment_1_id;
uint32_t augment_2_id;
uint32_t augment_3_id;
uint32_t augment_4_id;
uint32_t augment_5_id;
uint32_t augment_6_id;
int8_t in_bag;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"player_event_trade_id",
"char_id",
"slot",
"item_id",
"charges",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
"in_bag",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"player_event_trade_id",
"char_id",
"slot",
"item_id",
"charges",
"augment_1_id",
"augment_2_id",
"augment_3_id",
"augment_4_id",
"augment_5_id",
"augment_6_id",
"in_bag",
"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_trade_entries");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventTradeEntries NewEntity()
{
PlayerEventTradeEntries e{};
e.id = 0;
e.player_event_trade_id = 0;
e.char_id = 0;
e.slot = 0;
e.item_id = 0;
e.charges = 0;
e.augment_1_id = 0;
e.augment_2_id = 0;
e.augment_3_id = 0;
e.augment_4_id = 0;
e.augment_5_id = 0;
e.augment_6_id = 0;
e.in_bag = 0;
e.created_at = 0;
return e;
}
static PlayerEventTradeEntries GetPlayerEventTradeEntries(
const std::vector<PlayerEventTradeEntries> &player_event_trade_entriess,
int player_event_trade_entries_id
)
{
for (auto &player_event_trade_entries : player_event_trade_entriess) {
if (player_event_trade_entries.id == player_event_trade_entries_id) {
return player_event_trade_entries;
}
}
return NewEntity();
}
static PlayerEventTradeEntries FindOne(
Database& db,
int player_event_trade_entries_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_trade_entries_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventTradeEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_trade_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.slot = row[3] ? static_cast<int16_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.charges = row[5] ? static_cast<int16_t>(atoi(row[5])) : 0;
e.augment_1_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_2_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_3_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_4_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_5_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_6_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.in_bag = row[12] ? static_cast<int8_t>(atoi(row[12])) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_trade_entries_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_trade_entries_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventTradeEntries &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.player_event_trade_id));
v.push_back(columns[2] + " = " + std::to_string(e.char_id));
v.push_back(columns[3] + " = " + std::to_string(e.slot));
v.push_back(columns[4] + " = " + std::to_string(e.item_id));
v.push_back(columns[5] + " = " + std::to_string(e.charges));
v.push_back(columns[6] + " = " + std::to_string(e.augment_1_id));
v.push_back(columns[7] + " = " + std::to_string(e.augment_2_id));
v.push_back(columns[8] + " = " + std::to_string(e.augment_3_id));
v.push_back(columns[9] + " = " + std::to_string(e.augment_4_id));
v.push_back(columns[10] + " = " + std::to_string(e.augment_5_id));
v.push_back(columns[11] + " = " + std::to_string(e.augment_6_id));
v.push_back(columns[12] + " = " + std::to_string(e.in_bag));
v.push_back(columns[13] + " = 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 PlayerEventTradeEntries InsertOne(
Database& db,
PlayerEventTradeEntries e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.player_event_trade_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.in_bag));
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<PlayerEventTradeEntries> &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.player_event_trade_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.in_bag));
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<PlayerEventTradeEntries> All(Database& db)
{
std::vector<PlayerEventTradeEntries> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventTradeEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_trade_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.slot = row[3] ? static_cast<int16_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.charges = row[5] ? static_cast<int16_t>(atoi(row[5])) : 0;
e.augment_1_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_2_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_3_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_4_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_5_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_6_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.in_bag = row[12] ? static_cast<int8_t>(atoi(row[12])) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventTradeEntries> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventTradeEntries> 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) {
PlayerEventTradeEntries e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.player_event_trade_id = row[1] ? strtoull(row[1], nullptr, 10) : 0;
e.char_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.slot = row[3] ? static_cast<int16_t>(atoi(row[3])) : 0;
e.item_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.charges = row[5] ? static_cast<int16_t>(atoi(row[5])) : 0;
e.augment_1_id = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.augment_2_id = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.augment_3_id = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.augment_4_id = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.augment_5_id = row[10] ? static_cast<uint32_t>(strtoul(row[10], nullptr, 10)) : 0;
e.augment_6_id = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.in_bag = row[12] ? static_cast<int8_t>(atoi(row[12])) : 0;
e.created_at = strtoll(row[13] ? row[13] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventTradeEntries &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.player_event_trade_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.in_bag));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventTradeEntries> &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.player_event_trade_id));
v.push_back(std::to_string(e.char_id));
v.push_back(std::to_string(e.slot));
v.push_back(std::to_string(e.item_id));
v.push_back(std::to_string(e.charges));
v.push_back(std::to_string(e.augment_1_id));
v.push_back(std::to_string(e.augment_2_id));
v.push_back(std::to_string(e.augment_3_id));
v.push_back(std::to_string(e.augment_4_id));
v.push_back(std::to_string(e.augment_5_id));
v.push_back(std::to_string(e.augment_6_id));
v.push_back(std::to_string(e.in_bag));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
@@ -0,0 +1,511 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_TRADE_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_TRADE_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BasePlayerEventTradeRepository {
public:
struct PlayerEventTrade {
uint32_t id;
uint32_t char1_id;
uint32_t char2_id;
uint64_t char1_copper;
uint64_t char1_silver;
uint64_t char1_gold;
uint64_t char1_platinum;
uint64_t char2_copper;
uint64_t char2_silver;
uint64_t char2_gold;
uint64_t char2_platinum;
time_t created_at;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"char1_id",
"char2_id",
"char1_copper",
"char1_silver",
"char1_gold",
"char1_platinum",
"char2_copper",
"char2_silver",
"char2_gold",
"char2_platinum",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"char1_id",
"char2_id",
"char1_copper",
"char1_silver",
"char1_gold",
"char1_platinum",
"char2_copper",
"char2_silver",
"char2_gold",
"char2_platinum",
"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_trade");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventTrade NewEntity()
{
PlayerEventTrade e{};
e.id = 0;
e.char1_id = 0;
e.char2_id = 0;
e.char1_copper = 0;
e.char1_silver = 0;
e.char1_gold = 0;
e.char1_platinum = 0;
e.char2_copper = 0;
e.char2_silver = 0;
e.char2_gold = 0;
e.char2_platinum = 0;
e.created_at = 0;
return e;
}
static PlayerEventTrade GetPlayerEventTrade(
const std::vector<PlayerEventTrade> &player_event_trades,
int player_event_trade_id
)
{
for (auto &player_event_trade : player_event_trades) {
if (player_event_trade.id == player_event_trade_id) {
return player_event_trade;
}
}
return NewEntity();
}
static PlayerEventTrade FindOne(
Database& db,
int player_event_trade_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_trade_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventTrade e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char1_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char2_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char1_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.char1_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.char1_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.char1_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.char2_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.char2_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.char2_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.char2_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_trade_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_trade_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventTrade &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.char1_id));
v.push_back(columns[2] + " = " + std::to_string(e.char2_id));
v.push_back(columns[3] + " = " + std::to_string(e.char1_copper));
v.push_back(columns[4] + " = " + std::to_string(e.char1_silver));
v.push_back(columns[5] + " = " + std::to_string(e.char1_gold));
v.push_back(columns[6] + " = " + std::to_string(e.char1_platinum));
v.push_back(columns[7] + " = " + std::to_string(e.char2_copper));
v.push_back(columns[8] + " = " + std::to_string(e.char2_silver));
v.push_back(columns[9] + " = " + std::to_string(e.char2_gold));
v.push_back(columns[10] + " = " + std::to_string(e.char2_platinum));
v.push_back(columns[11] + " = 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 PlayerEventTrade InsertOne(
Database& db,
PlayerEventTrade e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char1_id));
v.push_back(std::to_string(e.char2_id));
v.push_back(std::to_string(e.char1_copper));
v.push_back(std::to_string(e.char1_silver));
v.push_back(std::to_string(e.char1_gold));
v.push_back(std::to_string(e.char1_platinum));
v.push_back(std::to_string(e.char2_copper));
v.push_back(std::to_string(e.char2_silver));
v.push_back(std::to_string(e.char2_gold));
v.push_back(std::to_string(e.char2_platinum));
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<PlayerEventTrade> &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.char1_id));
v.push_back(std::to_string(e.char2_id));
v.push_back(std::to_string(e.char1_copper));
v.push_back(std::to_string(e.char1_silver));
v.push_back(std::to_string(e.char1_gold));
v.push_back(std::to_string(e.char1_platinum));
v.push_back(std::to_string(e.char2_copper));
v.push_back(std::to_string(e.char2_silver));
v.push_back(std::to_string(e.char2_gold));
v.push_back(std::to_string(e.char2_platinum));
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<PlayerEventTrade> All(Database& db)
{
std::vector<PlayerEventTrade> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventTrade e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char1_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char2_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char1_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.char1_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.char1_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.char1_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.char2_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.char2_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.char2_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.char2_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventTrade> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventTrade> 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) {
PlayerEventTrade e{};
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.char1_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.char2_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.char1_copper = row[3] ? strtoull(row[3], nullptr, 10) : 0;
e.char1_silver = row[4] ? strtoull(row[4], nullptr, 10) : 0;
e.char1_gold = row[5] ? strtoull(row[5], nullptr, 10) : 0;
e.char1_platinum = row[6] ? strtoull(row[6], nullptr, 10) : 0;
e.char2_copper = row[7] ? strtoull(row[7], nullptr, 10) : 0;
e.char2_silver = row[8] ? strtoull(row[8], nullptr, 10) : 0;
e.char2_gold = row[9] ? strtoull(row[9], nullptr, 10) : 0;
e.char2_platinum = row[10] ? strtoull(row[10], nullptr, 10) : 0;
e.created_at = strtoll(row[11] ? row[11] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const PlayerEventTrade &e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.char1_id));
v.push_back(std::to_string(e.char2_id));
v.push_back(std::to_string(e.char1_copper));
v.push_back(std::to_string(e.char1_silver));
v.push_back(std::to_string(e.char1_gold));
v.push_back(std::to_string(e.char1_platinum));
v.push_back(std::to_string(e.char2_copper));
v.push_back(std::to_string(e.char2_silver));
v.push_back(std::to_string(e.char2_gold));
v.push_back(std::to_string(e.char2_platinum));
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<PlayerEventTrade> &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.char1_id));
v.push_back(std::to_string(e.char2_id));
v.push_back(std::to_string(e.char1_copper));
v.push_back(std::to_string(e.char1_silver));
v.push_back(std::to_string(e.char1_gold));
v.push_back(std::to_string(e.char1_platinum));
v.push_back(std::to_string(e.char2_copper));
v.push_back(std::to_string(e.char2_silver));
v.push_back(std::to_string(e.char2_gold));
v.push_back(std::to_string(e.char2_platinum));
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 {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_TRADE_REPOSITORY_H
@@ -36,6 +36,7 @@ public:
uint32_t char_zone_id;
int32_t char_zone_instance_id;
uint8_t active_transaction;
time_t listing_date;
};
static std::string PrimaryKey()
@@ -63,6 +64,7 @@ public:
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
"listing_date",
};
}
@@ -86,6 +88,7 @@ public:
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
"UNIX_TIMESTAMP(listing_date)",
};
}
@@ -143,6 +146,7 @@ public:
e.char_zone_id = 0;
e.char_zone_instance_id = 0;
e.active_transaction = 0;
e.listing_date = 0;
return e;
}
@@ -196,6 +200,7 @@ public:
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
return e;
}
@@ -245,6 +250,7 @@ public:
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
v.push_back(columns[15] + " = " + std::to_string(e.char_zone_instance_id));
v.push_back(columns[16] + " = " + std::to_string(e.active_transaction));
v.push_back(columns[17] + " = FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -283,6 +289,7 @@ public:
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -329,6 +336,7 @@ public:
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -379,6 +387,7 @@ public:
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -420,6 +429,7 @@ public:
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.listing_date = strtoll(row[17] ? row[17] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -511,6 +521,7 @@ public:
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -550,6 +561,7 @@ public:
v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
v.push_back("FROM_UNIXTIME(" + (e.listing_date > 0 ? std::to_string(e.listing_date) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -0,0 +1,50 @@
#ifndef EQEMU_BOT_BLOCKED_BUFFS_REPOSITORY_H
#define EQEMU_BOT_BLOCKED_BUFFS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_bot_blocked_buffs_repository.h"
class BotBlockedBuffsRepository: public BaseBotBlockedBuffsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* BotBlockedBuffsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* BotBlockedBuffsRepository::GetWhereNeverExpires()
* BotBlockedBuffsRepository::GetWhereXAndY()
* BotBlockedBuffsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_BOT_BLOCKED_BUFFS_REPOSITORY_H
-40
View File
@@ -44,46 +44,6 @@ public:
*/
// Custom extended repository methods here
static bool SaveAllHelmAppearances(Database& db, const uint32 owner_id, const bool show_flag)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `show_helm` = {} WHERE `owner_id` = {}",
TableName(),
show_flag ? 1 : 0,
owner_id
)
);
return results.Success();
}
static bool ToggleAllHelmAppearances(Database& db, const uint32 owner_id)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `show_helm` = (`show_helm` XOR '1') WHERE `owner_id` = {}",
TableName(),
owner_id
)
);
return results.Success();
}
static bool SaveAllFollowDistances(Database& db, const uint32 owner_id, const uint32 follow_distance)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `follow_distance` = {} WHERE `owner_id` = {}",
TableName(),
follow_distance,
owner_id
)
);
return results.Success();
}
};
#endif //EQEMU_BOT_DATA_REPOSITORY_H
@@ -0,0 +1,50 @@
#ifndef EQEMU_BOT_SETTINGS_REPOSITORY_H
#define EQEMU_BOT_SETTINGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_bot_settings_repository.h"
class BotSettingsRepository: public BaseBotSettingsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* BotSettingsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* BotSettingsRepository::GetWhereNeverExpires()
* BotSettingsRepository::GetWhereXAndY()
* BotSettingsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_BOT_SETTINGS_REPOSITORY_H
+83 -36
View File
@@ -4,47 +4,94 @@
#include "../database.h"
#include "../strings.h"
#include "base/base_login_accounts_repository.h"
#include "../../loginserver/encryption.h"
#include "../../loginserver/login_types.h"
class LoginAccountsRepository: public BaseLoginAccountsRepository {
class LoginAccountsRepository : public BaseLoginAccountsRepository {
public:
static int64 GetFreeID(Database &db, const std::string &loginserver)
{
auto query = fmt::format(
"SELECT IFNULL(MAX(id), 0) + 1 FROM login_accounts WHERE source_loginserver = '{}'",
Strings::Escape(loginserver)
);
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* LoginAccountsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* LoginAccountsRepository::GetWhereNeverExpires()
* LoginAccountsRepository::GetWhereXAndY()
* LoginAccountsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
auto results = db.QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) {
return 0;
}
// Custom extended repository methods here
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
static LoginAccountsRepository::LoginAccounts CreateAccountFromContext(
Database &db,
LoginAccountContext c
)
{
auto a = LoginAccountsRepository::NewEntity();
if (!c.password_is_encrypted) {
auto e = EncryptPasswordFromContext(c);
a.account_password = e.password;
}
a.id = c.login_account_id > 0 ? c.login_account_id : GetFreeID(db, c.source_loginserver);
a.account_name = c.username;
a.account_email = !c.email.empty() ? c.email : "local_creation";
a.source_loginserver = c.source_loginserver;
a.last_ip_address = "127.0.0.1";
a.last_login_date = std::time(nullptr);
a.created_at = std::time(nullptr);
LoginAccountsRepository::InsertOne(db, a);
return GetAccountFromContext(db, c).id > 0 ? a : NewEntity();
}
static LoginAccountsRepository::LoginAccounts GetAccountFromContext(
Database &db,
LoginAccountContext c
)
{
std::string where = fmt::format(
"account_name = '{}' AND source_loginserver = '{}'",
Strings::Escape(c.username),
Strings::Escape(c.source_loginserver)
);
if (!c.email.empty()) {
where += fmt::format(" AND account_email = '{}'", Strings::Escape(c.email));
}
if (c.login_account_id > 0) {
where += fmt::format(" AND id = {}", c.login_account_id);
}
where += " LIMIT 1";
auto results = LoginAccountsRepository::GetWhere(db, where);
auto e = LoginAccountsRepository::NewEntity();
if (results.size() == 1) {
e = results.front();
}
return e;
}
static LoginAccounts UpdateAccountPassword(Database &db, LoginAccounts a, std::string password)
{
LoginAccountContext c;
c.username = a.account_name;
c.password = password;
auto e = EncryptPasswordFromContext(c);
a.account_password = e.password;
int success = LoginAccountsRepository::UpdateOne(db, a);
return success ? a : NewEntity();
}
};
#endif //EQEMU_LOGIN_ACCOUNTS_REPOSITORY_H
@@ -5,46 +5,24 @@
#include "../strings.h"
#include "base/base_login_server_admins_repository.h"
class LoginServerAdminsRepository: public BaseLoginServerAdminsRepository {
class LoginServerAdminsRepository : public BaseLoginServerAdminsRepository {
public:
static LoginServerAdmins GetByName(Database &db, std::string account_name)
{
auto admins = GetWhere(
db,
fmt::format(
"account_name = '{}' LIMIT 1",
Strings::Escape(account_name)
)
);
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* LoginServerAdminsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* LoginServerAdminsRepository::GetWhereNeverExpires()
* LoginServerAdminsRepository::GetWhereXAndY()
* LoginServerAdminsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
if (admins.size() == 1) {
return admins.front();
}
return NewEntity();
}
};
#endif //EQEMU_LOGIN_SERVER_ADMINS_REPOSITORY_H
@@ -7,44 +7,27 @@
class LoginWorldServersRepository: public BaseLoginWorldServersRepository {
public:
static LoginWorldServers GetFromWorldContext(Database &db, LoginWorldContext c) {
std::string where = fmt::format(
"short_name = '{}' AND long_name = '{}'",
Strings::Escape(c.short_name),
Strings::Escape(c.long_name)
);
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* LoginWorldServersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* LoginWorldServersRepository::GetWhereNeverExpires()
* LoginWorldServersRepository::GetWhereXAndY()
* LoginWorldServersRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
if (c.admin_id > 0) {
where += fmt::format(" AND login_server_admin_id = {}", c.admin_id);
}
// Custom extended repository methods here
where += " LIMIT 1";
auto results = GetWhere(db, where);
auto e = NewEntity();
if (results.size() == 1) {
e = results.front();
}
return e;
}
};
#endif //EQEMU_LOGIN_WORLD_SERVERS_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_aa_purchase_repository.h"
class PlayerEventAaPurchaseRepository: public BasePlayerEventAaPurchaseRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_AA_PURCHASE_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_killed_named_npc_repository.h"
class PlayerEventKilledNamedNpcRepository: public BasePlayerEventKilledNamedNpcRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_KILLED_NAMED_NPC_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_killed_npc_repository.h"
class PlayerEventKilledNpcRepository: public BasePlayerEventKilledNpcRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_KILLED_NPC_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_killed_raid_npc_repository.h"
class PlayerEventKilledRaidNpcRepository: public BasePlayerEventKilledRaidNpcRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_KILLED_RAID_NPC_REPOSITORY_H
@@ -2,49 +2,13 @@
#define EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#include "../database.h"
#include "../events/player_events.h"
#include "../strings.h"
#include "base/base_player_event_log_settings_repository.h"
#include "base/base_player_event_loot_items_repository.h"
class PlayerEventLogSettingsRepository: public BasePlayerEventLogSettingsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* 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
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -7,44 +7,7 @@
class PlayerEventLogsRepository: public BasePlayerEventLogsRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* 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
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_loot_items_repository.h"
class PlayerEventLootItemsRepository: public BasePlayerEventLootItemsRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_LOOT_ITEMS_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_merchant_purchase_repository.h"
class PlayerEventMerchantPurchaseRepository: public BasePlayerEventMerchantPurchaseRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_MERCHANT_PURCHASE_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_merchant_sell_repository.h"
class PlayerEventMerchantSellRepository: public BasePlayerEventMerchantSellRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_MERCHANT_SELL_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_npc_handin_entries_repository.h"
class PlayerEventNpcHandinEntriesRepository: public BasePlayerEventNpcHandinEntriesRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_NPC_HANDIN_ENTRIES_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_npc_handin_repository.h"
class PlayerEventNpcHandinRepository: public BasePlayerEventNpcHandinRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_NPC_HANDIN_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_SPEECH_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_SPEECH_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_speech_repository.h"
class PlayerEventSpeechRepository: public BasePlayerEventSpeechRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_SPEECH_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_trade_entries_repository.h"
class PlayerEventTradeEntriesRepository: public BasePlayerEventTradeEntriesRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_TRADE_ENTRIES_REPOSITORY_H
@@ -0,0 +1,13 @@
#ifndef EQEMU_PLAYER_EVENT_TRADE_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_TRADE_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_player_event_trade_repository.h"
class PlayerEventTradeRepository: public BasePlayerEventTradeRepository {
public:
// Custom extended repository methods here
};
#endif //EQEMU_PLAYER_EVENT_TRADE_REPOSITORY_H
+4 -1
View File
@@ -130,7 +130,8 @@ public:
}
for (auto &i: items) {
i.item_cost = new_price;
i.item_cost = new_price;
i.listing_date = time(nullptr);
}
return ReplaceMany(db, items);
@@ -178,6 +179,7 @@ public:
auto m = trader_item[0];
m.item_charges = quantity;
m.listing_date = time(nullptr);
return UpdateOne(db, m);
}
@@ -221,6 +223,7 @@ public:
}
e.active_transaction = status == true ? 1 : 0;
e.listing_date = time(nullptr);
return UpdateOne(db, e);
}
+121 -5
View File
@@ -283,11 +283,11 @@ RULE_CATEGORY(Pets)
RULE_REAL(Pets, AttackCommandRange, 150, "Range at which a pet will respond to attack commands")
RULE_BOOL(Pets, UnTargetableSwarmPet, false, "Setting whether swarm pets should be targetable")
RULE_REAL(Pets, PetPowerLevelCap, 10, "Maximum number of levels a player pet can go up with pet power")
RULE_BOOL(Pets, CanTakeNoDrop, false, "Setting whether anyone can give no-drop items to pets")
RULE_BOOL(Pets, CanTakeQuestItems, true, "Setting whether anyone can give quest items to pets")
RULE_BOOL(Pets, LivelikeBreakCharmOnInvis, true, "Default: true will break charm on any type of invis (hide/ivu/iva/etc) false will only break if the pet can not see you (ex. you have an undead pet and cast IVU")
RULE_BOOL(Pets, ClientPetsUseOwnerNameInLastName, true, "Disable this to keep client pet's last names from being owner_name's pet")
RULE_BOOL(Pets, CanTakeNoDrop, false, "Setting whether anyone can give no-drop items to pets")
RULE_INT(Pets, PetTauntRange, 150, "Range at which a pet will taunt targets.")
RULE_BOOL(Pets, AlwaysAllowPetRename, false, "Enable this option to allow /changepetname to work without enabling a pet name change via scripts.")
RULE_CATEGORY_END()
RULE_CATEGORY(GM)
@@ -382,6 +382,9 @@ RULE_BOOL(Map, MobZVisualDebug, false, "Displays spell effects determining wheth
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_BOOL(Map, CheckForLoSCheat, false, "Runs predefined zone checks to check for LoS cheating through doors and such.")
RULE_BOOL(Map, EnableLoSCheatExemptions, false, "Enables exemptions for the LoS Cheat check.")
RULE_REAL(Map, RangeCheckForLoSCheat, 20.0, "Default 20.0. Range to check if one is within range of a door.")
RULE_CATEGORY_END()
RULE_CATEGORY(Pathing)
@@ -663,8 +666,6 @@ RULE_BOOL(NPC, EnableNPCQuestJournal, false, "Setting whether the NPC Quest Jour
RULE_INT(NPC, LastFightingDelayMovingMin, 10000, "Minimum time before mob goes home after all aggro loss (milliseconds)")
RULE_INT(NPC, LastFightingDelayMovingMax, 20000, "Maximum time before mob goes home after all aggro loss (milliseconds)")
RULE_BOOL(NPC, SmartLastFightingDelayMoving, true, "When true, mobs that started going home previously will do so again immediately if still on FD hate list")
RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false, "Returns NO DROP items on NPC that don't have an EVENT_TRADE sub in their script")
RULE_BOOL(NPC, ReturnQuestItemsFromNonQuestNPCs, false, "Returns Quest items traded to NPCs that are not flagged as a Quest NPC")
RULE_INT(NPC, StartEnrageValue, 9, " Percentage HP that an NPC will begin to enrage")
RULE_BOOL(NPC, LiveLikeEnrage, false, "If set to true then only player controlled pets will enrage")
RULE_BOOL(NPC, EnableMeritBasedFaction, false, "If set to true, faction will be given in the same way as experience (solo/group/raid)")
@@ -754,13 +755,13 @@ RULE_INT(Bots, CommandSpellRank, 1, "Filters bot command spells by rank. 1, 2 an
RULE_INT(Bots, CreationLimit, 150, "Number of bots that each account can create")
RULE_BOOL(Bots, FinishBuffing, false, "Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat")
RULE_BOOL(Bots, GroupBuffing, false, "Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB")
RULE_BOOL(Bots, RaidBuffing, false, "Bots will cast single target buffs as raid buffs, default is false for single. Does not make single target buffs work for MGB")
RULE_INT(Bots, HealRotationMaxMembers, 24, "Maximum number of heal rotation members")
RULE_INT(Bots, HealRotationMaxTargets, 12, "Maximum number of heal rotation targets")
RULE_REAL(Bots, ManaRegen, 2.0, "Adjust mana regen. Acts as a final multiplier, stacks with Rule Character:ManaRegenMultiplier.")
RULE_BOOL(Bots, PreferNoManaCommandSpells, true, "Give sorting priority to newer no-mana spells (i.e., 'Bind Affinity')")
RULE_BOOL(Bots, QuestableSpawnLimit, false, "Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl")
RULE_INT(Bots, SpawnLimit, 71, "Number of bots a character can have spawned at one time, You + 71 bots is a 12 group pseudo-raid")
RULE_BOOL(Bots, BotGroupXP, false, "Determines whether client gets experience for bots outside their group")
RULE_BOOL(Bots, BotLevelsWithOwner, false, "Auto-updates spawned bots as owner levels/de-levels (false is original behavior)")
RULE_INT(Bots, BotCharacterLevel, 0, "If level is greater that value player can spawn bots if BotCharacterLevelEnabled is true")
RULE_INT(Bots, CasterStopMeleeLevel, 13, "Level at which caster bots stop melee attacks")
@@ -783,6 +784,119 @@ RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to cl
RULE_BOOL(Bots, BotsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(Bots, BotsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Bots, BotsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_BOOL(Bots, CrossRaidBuffingAndHealing, true, "If True, bots will be able to cast on all raid members rather than just their raid group members. Default true.")
RULE_BOOL(Bots, CanCastIllusionsOnPets, false, "If True, bots will be able to cast spells that have an illusion effect on pets. Default false.")
RULE_BOOL(Bots, CanCastPetOnlyOnOthersPets, false, "If True, bots will be able to cast pet only spells on other's pets. Default false.")
RULE_BOOL(Bots, RequirePetAffinity, true, "If True, bots will be need to have the Pet Affinity AA to allow their pets to be hit with group spells.")
RULE_INT(Bots, SpellResistLimit, 150, "150 Default. This is the resist cap where bots will refuse to cast spells on enemies due to a high resist chance.")
RULE_INT(Bots, StunCastChanceIfCasting, 50, "50 Default. Chance for non-Paladins to cast a stun spell if the target is casting.")
RULE_INT(Bots, StunCastChanceNormal, 15, "15 Default. Chance for non-Paladins to cast a stun spell on the target.")
RULE_INT(Bots, StunCastChancePaladins, 75, "75 Default. Chance for Paladins to cast a stun spell if the target is casting.")
RULE_INT(Bots, PercentChanceToCastAEs, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastNuke, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastGroupHeal, 90, "The chance for a bot to attempt to cast the given spell type in combat. Default 90%.")
RULE_INT(Bots, PercentChanceToCastHeal, 90, "The chance for a bot to attempt to cast the given spell type in combat. Default 90%.")
RULE_INT(Bots, PercentChanceToCastRoot, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastBuff, 90, "The chance for a bot to attempt to cast the given spell type in combat. Default 90%.")
RULE_INT(Bots, PercentChanceToCastEscape, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastLifetap, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastSnare, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastDOT, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastDispel, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastInCombatBuff, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastHateLine, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastMez, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastSlow, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastDebuff, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastCure, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastGroupCure, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastHateRedux, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastFear, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.")
RULE_INT(Bots, PercentChanceToCastOtherType, 90, "The chance for a bot to attempt to cast the remaining spell types in combat. Default 0-%.")
RULE_INT(Bots, MinDelayBetweenInCombatCastAttempts, 500, "The minimum delay in milliseconds between cast attempts while in-combat. This is rolled between the min and max. Default 500ms.")
RULE_INT(Bots, MaxDelayBetweenInCombatCastAttempts, 2000, "The maximum delay in milliseconds between cast attempts while in-combat. This is rolled between the min and max. Default 2500ms.")
RULE_INT(Bots, MinDelayBetweenOutCombatCastAttempts, 1000, "The minimum delay in milliseconds between cast attempts while out-of-combat. This is rolled between the min and max. Default 1000ms.")
RULE_INT(Bots, MaxDelayBetweenOutCombatCastAttempts, 2500, "The maximum delay in milliseconds between cast attempts while out-of-combat. This is rolled between the min and max. Default 2500ms.")
RULE_INT(Bots, MezChance, 35, "35 Default. Chance for a bot to attempt to Mez a target after validating it is eligible.")
RULE_INT(Bots, AEMezChance, 35, "35 Default. Chance for a bot to attempt to AE Mez targets after validating they are eligible.")
RULE_INT(Bots, MezSuccessDelay, 3500, "3500 (3.5 sec) Default. Delay between successful Mez attempts.")
RULE_INT(Bots, AEMezSuccessDelay, 5000, "5000 (5 sec) Default. Delay between successful AEMez attempts.")
RULE_INT(Bots, MezFailDelay, 2000, "2000 (2 sec) Default. Delay between failed Mez attempts.")
RULE_INT(Bots, MezAEFailDelay, 4000, "4000 (4 sec) Default. Delay between failed AEMez attempts.")
RULE_INT(Bots, MinGroupHealTargets, 3, "Minimum number of targets in valid range that are required for a group heal to cast. Default 3.")
RULE_INT(Bots, MinGroupCureTargets, 3, "Minimum number of targets in valid range that are required for a cure heal to cast. Default 3.")
RULE_INT(Bots, MinTargetsForAESpell, 3, "Minimum number of targets in valid range that are required for an AE spell to cast. Default 3.")
RULE_INT(Bots, MinTargetsForGroupSpell, 3, "Minimum number of targets in valid range that are required for an group spell to cast. Default 3.")
RULE_BOOL(Bots, AllowBuffingHealingFamiliars, false, "Determines if bots are allowed to buff and heal familiars. Default false.")
RULE_BOOL(Bots, RunSpellTypeChecksOnSpawn, false, "This will run a serious of checks on spell types and output errors to LogBotSpellTypeChecks")
RULE_BOOL(Bots, UseParentSpellTypeForChecks, true, "This will check only the parent instead of AE/Group/Pet types (ex: AENukes/AERains/PBAENukes fall under Nukes or PetBuffs fall under buffs) when RunSpellTypeChecksOnSpawn fires")
RULE_BOOL(Bots, AllowForcedCastsBySpellID, true, "If enabled, players can use ^cast spellid # to cast a specific spell by ID that is in their spell list")
RULE_BOOL(Bots, AllowCastAAs, true, "If enabled, players can use ^cast aa to cast a clickable AA")
RULE_BOOL(Bots, AllowMagicianEpicPet, false, "If enabled, magician bots can summon their epic pets following the rules AllowMagicianEpicPetLevel")
RULE_INT(Bots, AllowMagicianEpicPetLevel, 50, "If AllowMagicianEpicPet is enabled, bots can start using their epic pets at this level")
RULE_INT(Bots, RequiredMagicianEpicPetItemID, 28034, "If AllowMagicianEpicPet is enabled and this is set, bots will be required to have this item ID equipped to cast their epic. Takes in to account AllowMagicianEpicPetLevel as well. Set to 0 to disable requirement")
RULE_STRING(Bots, EpicPetSpellName, "", "'teleport_zone' in the spell to be cast for epic pets. This must be in their spell list to cast.")
RULE_INT(Bots, ReclaimEnergySpellID, 331, "Spell ID for reclaim energy when using ^petsettype. Default 331")
RULE_BOOL(Bots, UseSpellPulling, true, "If enabled bots will use a spell to pull when within range. Uses PullSpellID.")
RULE_INT(Bots, PullSpellID, 5225, "Default 5225 - Throw Stone. Spell that will be cast to pull by bots")
RULE_BOOL(Bots, AllowRangedPulling, true, "If enabled bots will pull with their ranged items if set to ranged.")
RULE_BOOL(Bots, AllowAISpellPulling, true, "If enabled bots will rely on their detrimental AI to pull when within range.")
RULE_BOOL(Bots, AllowBotEquipAnyClassGear, false, "Allows Bots to wear Equipment even if their class is not valid")
RULE_BOOL(Bots, BotArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption")
RULE_BOOL(Bots, BotThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption")
RULE_INT(Bots, StackSizeMin, 20, "20 Default. -1 to disable and use default max stack size. Minimum stack size to give a bot (Arrows/Throwing).")
RULE_INT(Bots, HasOrMayGetAggroThreshold, 90, "90 Default. Percent threshold of total hate where bots will stop casting spells that generate hate if they are set to try to not pull aggro via spells.")
RULE_BOOL(Bots, UseFlatNormalMeleeRange, false, "False Default. If true, bots melee distance will be a flat distance set by Bots:NormalMeleeRangeDistance.")
RULE_REAL(Bots, NormalMeleeRangeDistance, 0.75, "If UseFlatNormalMeleeRange is enabled, multiplier of the max melee range at which a bot will stand in melee combat. 0.75 Recommended, max melee for all abilities to land.")
RULE_REAL(Bots, PercentMinMeleeDistance, 0.75, "Multiplier of the their melee range - Minimum distance from target a bot will stand while in melee combat before trying to adjust. 0.60 Recommended.")
RULE_REAL(Bots, MaxDistanceForMelee, 20, "Maximum distance bots will stand for melee. Default 20 to allow all special attacks to land.")
RULE_REAL(Bots, TauntNormalMeleeRangeDistance, 0.50, "Multiplier of the max melee range at which a taunting bot will stand in melee combat. 0.50 Recommended, closer than others .")
RULE_REAL(Bots, PercentTauntMinMeleeDistance, 0.40, "Multiplier of their melee range - Minimum distance from target a taunting bot will stand while in melee combat before trying to adjust. 0.25 Recommended.")
RULE_REAL(Bots, PercentMaxMeleeRangeDistance, 0.95, "Multiplier of the max melee range at which a bot will stand in melee combat. 0.95 Recommended, max melee while disabling special attacks/taunt.")
RULE_REAL(Bots, PercentMinMaxMeleeRangeDistance, 0.75, "Multiplier of the closest max melee range at which a bot will stand in melee combat before trying to adjust. 0.75 Recommended, max melee while disabling special attacks/taunt.")
RULE_BOOL(Bots, TauntingBotsFollowTopHate, true, "True Default. If true, bots that are taunting will attempt to stick with whoever currently is top hate.")
RULE_INT(Bots, DistanceTauntingBotsStickMainHate, 10, "If TauntingBotsFollowTopHate is enabled, this is the distance bots will try to stick to whoever currently is Top Hate.")
RULE_BOOL(Bots, DisableSpecialAbilitiesAtMaxMelee, true, "True Default. If true, when bots are at max melee distance, special abilities including taunt will be disabled.")
RULE_INT(Bots, MinJitterTimer, 500, "Minimum ms between bot movement jitter checks.")
RULE_INT(Bots, MaxJitterTimer, 2500, "Maximum ms between bot movement jitter checks. Set to 0 to disable timer checks.")
RULE_BOOL(Bots, PreventBotCampOnFD, true, "True Default. If true, players will not be able to camp bots while feign death.")
RULE_BOOL(Bots, PreventBotSpawnOnFD, true, "True Default. If true, players will not be able to spawn bots while feign death.")
RULE_BOOL(Bots, PreventBotSpawnOnEngaged, true, "True Default. If true, players will not be able to spawn bots while you, your group or raid are engaged.")
RULE_BOOL(Bots, PreventBotCampOnEngaged, true, "True Default. If true, players will not be able to camp bots while you, your group or raid are engaged.")
RULE_BOOL(Bots, CopySettingsOwnBotsOnly, true, "Determines whether a bot you are copying settings from must be a bot you own or not, default true.")
RULE_BOOL(Bots, AllowCopySettingsAnon, false, "If player's are allowed to copy settings of bots owned by anonymous players.")
RULE_BOOL(Bots, AllowCharmedPetBuffs, true, "Whether or not bots are allowed to cast buff charmed pets, default true.")
RULE_BOOL(Bots, AllowCharmedPetHeals, true, "Whether or not bots are allowed to cast heal charmed pets, default true.")
RULE_BOOL(Bots, AllowCharmedPetCures, true, "Whether or not bots are allowed to cast cure charmed pets, default true.")
RULE_BOOL(Bots, ShowResistMessagesToOwner, true, "Default True. If enabled, when a bot's spell is resisted it will send a spell failure to their owner.")
RULE_BOOL(Bots, BotBuffLevelRestrictions, true, "Buffs will not land on low level bots like live players")
RULE_BOOL(Bots, BotsUseLiveBlockedMessage, true, "Setting whether detailed spell block messages should be used for bots as players do on the live servers")
RULE_BOOL(Bots, BotSoftDeletes, true, "When bots are deleted, they are only soft deleted")
RULE_INT(Bots, MinStatusToBypassSpawnLimit, 100, "Minimum status to bypass spawn limit. Default 100.")
RULE_INT(Bots, MinStatusBypassSpawnLimit, 120, "Spawn limit with status bypass. Default 120.")
RULE_INT(Bots, MinStatusToBypassCreateLimit, 100, "Minimum status to bypass create limit. Default 100.")
RULE_INT(Bots, MinStatusBypassCreateLimit, 120, "Create limit with status bypass. Default 120.")
RULE_BOOL(Bots, EnableBotTGB, true, "If enabled bots will cast group buffs as TGB.")
RULE_BOOL(Bots, DoResponseAnimations, true, "If enabled bots will do animations to certain responses or commands.")
RULE_INT(Bots, DefaultFollowDistance, 20, "Default 20. Distance a bot will follow behind.")
RULE_INT(Bots, MaxFollowDistance, 300, "Default 300. Max distance a bot can be set to follow behind.")
RULE_INT(Bots, MaxDistanceRanged, 300, "Default 300. Max distance a bot can be set to ranged.")
RULE_BOOL(Bots, AllowAIMez, true, "If enabled bots will automatically mez/AE mez eligible targets.")
RULE_BOOL(Bots, AllowCommandedCharm, true, "If enabled bots can be commanded to charm NPCs.")
RULE_BOOL(Bots, AllowCommandedMez, true, "If enabled bots can be commanded to mez NPCs.")
RULE_BOOL(Bots, AllowCommandedResurrect, true, "If enabled bots can be commanded to resurrect players.")
RULE_BOOL(Bots, AllowCommandedSummonCorpse, true, "If enabled bots can be commanded to summon other's corpses.")
RULE_BOOL(Bots, AllowCommandedLull, true, "If enabled bots can be commanded to lull targets.")
RULE_INT(Bots, CampTimer, 25, "Number of seconds after /camp has begun before bots camp out.")
RULE_BOOL(Bots, SendClassRaceOnHelp, true, "If enabled a reminder of how to check class/race IDs will be sent when using compatible commands.")
RULE_BOOL(Bots, AllowCrossGroupRaidAssist, true, "If enabled bots will autodefend group or raid members set as main assist.")
RULE_BOOL(Bots, AllowBotBlockedBuffs, true, "If enabled, you can create blocked buffs for each bot and for their pets.")
RULE_STRING(Bots, ZonesWithSpawnLimits, "", "Comma-delimited list of zones where different bot spawn limits apply. This is the max a zone allows.")
RULE_STRING(Bots, ZoneSpawnLimits, "", "Comma-delimited list of spawn limits for zones.")
RULE_STRING(Bots, ZonesWithForcedSpawnLimits, "", "Comma-delimited list of zones where bot spawn limits are forced. This will take priority over any other type of spawn limits.")
RULE_STRING(Bots, ZoneForcedSpawnLimits, "", "Comma-delimited list of forced spawn limits for zones.")
RULE_INT(Bots, AICastSpellTypeDelay, 100, "Delay in milliseconds between AI cast attempts for each spell type. Default 100ms")
RULE_INT(Bots, AICastSpellTypeHeldDelay, 2500, "Delay in milliseconds between AI cast attempts for each spell type that is held or disabled. Default 2500ms (2.5s)")
RULE_CATEGORY_END()
RULE_CATEGORY(Chat)
@@ -1009,6 +1123,7 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Command)
RULE_BOOL(Command, DyeCommandRequiresDyes, false, "Enable this to require a Prismatic Dye (32557) each time someone uses #dye.")
RULE_BOOL(Command, HideMeCommandDisablesTells, true, "Disable this to allow tells to be received when using #hideme.")
RULE_INT(Command, MaxHelpLineLength, 53, "Maximum length of a line before splitting it in to new lines for DiaWind. Default 53.")
RULE_CATEGORY_END()
RULE_CATEGORY(Doors)
@@ -1027,6 +1142,7 @@ RULE_BOOL(Items, DisablePotionBelt, false, "Enable this to disable Potion Belt I
RULE_BOOL(Items, DisableSpellFocusEffects, false, "Enable this to disable Spell Focus Effects on Items")
RULE_BOOL(Items, SummonItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots of items in Client::SummonItem")
RULE_BOOL(Items, AugmentItemAllowInvisibleAugments, false, "Enable this to allow augments to be put in invisible augment slots by players")
RULE_BOOL(Items, AlwaysReturnHandins, true, "Enable this to always return handins to the player")
RULE_CATEGORY_END()
RULE_CATEGORY(Parcel)
+11 -183
View File
@@ -304,19 +304,8 @@
#define ServerOP_WWSpell 0x4757
#define ServerOP_WWTaskUpdate 0x4758
/**
* QueryServer
*/
#define ServerOP_QSPlayerLogTrades 0x5000
#define ServerOP_QSPlayerLogHandins 0x5001
#define ServerOP_QSPlayerLogNPCKills 0x5002
#define ServerOP_QSPlayerLogDeletes 0x5003
#define ServerOP_QSPlayerLogMoves 0x5004
#define ServerOP_QSPlayerLogMerchantTransactions 0x5005
#define ServerOP_QSSendQuery 0x5006
#define ServerOP_QSPlayerDropItem 0x5007
// player events
#define ServerOP_QSSendQuery 0x5000
#define ServerOP_PlayerEvent 0x5100
enum {
@@ -400,7 +389,6 @@ enum { QSG_LFGuild = 0 };
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
QSG_LFGuild_RequestGuildInfo };
#define ServerOP_Speech 0x5500
enum {
UserToWorldStatusWorldUnavail = 0,
@@ -658,7 +646,7 @@ struct ServerLSInfo_Struct {
uint8 servertype; // 0=world, 1=chat, 2=login, 3=MeshLogin
};
struct ServerNewLSInfo_Struct {
struct LoginserverNewWorldRequest {
char server_long_name[201]; // name the worldserver wants
char server_short_name[50]; // shortname the worldserver wants
char remote_ip_address[125]; // DNS address of the server
@@ -670,21 +658,21 @@ struct ServerNewLSInfo_Struct {
uint8 server_process_type; // 0=world, 1=chat, 2=login, 3=MeshLogin
};
struct ServerLSAccountUpdate_Struct { // for updating info on login server
char worldaccount[31]; // account name for the worldserver
char worldpassword[31]; // password for the name
uint32 useraccountid; // player account ID
char useraccount[31]; // player account name
char userpassword[51]; // player account password
char user_email[101]; // player account email address
struct LoginserverAccountUpdate { // for updating info on login server
char world_account[31]; // account name for the worldserver
char world_password[31]; // password for the name
uint32 user_account_id; // player account ID
char user_account_name[31]; // player account name
char user_account_password[51]; // player account password
char user_email[101]; // player account email address
};
struct ServerLSStatus_Struct {
struct LoginserverWorldStatusUpdate {
int32 status;
int32 num_players;
int32 num_zones;
};
struct ZoneInfo_Struct {
struct LoginserverZoneInfoUpdate {
uint32 zone;
uint16 count;
uint32 zone_wid;
@@ -1358,171 +1346,11 @@ struct ServerMailMessageHeader_Struct {
char message[0];
};
struct Server_Speech_Struct {
char to[64];
char from[64];
uint32 guilddbid;
int16 minstatus;
uint32 type;
char message[0];
};
struct PlayerLogTradeItemsEntry_Struct {
uint32 from_character_id;
uint16 from_slot;
uint32 to_character_id;
uint16 to_slot;
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
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 {
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
struct QSPlayerDropItem_Struct {
uint32 char_id;
bool pickup; // 0 drop, 1 pickup
uint32 zone_id;
int x;
int y;
int z;
uint16 _detail_count;
QSDropItems_Struct items[0];
};
struct QSHandinItems_Struct {
char action_type[7]; // handin, return or reward
uint16 char_slot;
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
struct QSPlayerLogHandin_Struct {
uint32 quest_id;
uint32 char_id;
MoneyUpdate_Struct char_money;
uint16 char_count;
uint32 npc_id;
MoneyUpdate_Struct npc_money;
uint16 npc_count;
uint16 _detail_count;
QSHandinItems_Struct items[0];
};
struct QSPlayerLogNPCKillSub_Struct{
uint32 NPCID;
uint32 ZoneID;
uint32 Type;
};
struct QSPlayerLogNPCKillsPlayers_Struct{
uint32 char_id;
};
struct QSPlayerLogNPCKill_Struct{
QSPlayerLogNPCKillSub_Struct s1;
QSPlayerLogNPCKillsPlayers_Struct Chars[0];
};
struct QSDeleteItems_Struct {
uint16 char_slot;
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
struct QSPlayerLogDelete_Struct {
uint32 char_id;
uint16 stack_size; // '0' indicates full stack or non-stackable item move
uint16 char_count;
QSDeleteItems_Struct items[0];
};
struct QSMoveItems_Struct {
uint16 from_slot;
uint16 to_slot;
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
struct QSPlayerLogMove_Struct {
uint32 char_id;
uint16 from_slot;
uint16 to_slot;
uint16 stack_size; // '0' indicates full stack or non-stackable item move
uint16 char_count;
bool postaction;
QSMoveItems_Struct items[0];
};
struct QSTransactionItems_Struct {
uint16 char_slot;
uint32 item_id;
uint16 charges;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
};
struct QSMerchantLogTransaction_Struct {
uint32 zone_id;
uint32 merchant_id;
MoneyUpdate_Struct merchant_money;
uint16 merchant_count;
uint32 char_id;
MoneyUpdate_Struct char_money;
uint16 char_count;
QSTransactionItems_Struct items[0];
};
struct DiscordWebhookMessage_Struct {
uint32 webhook_id;
char message[2000];
};
struct QSGeneralQuery_Struct {
char QueryString[0];
};
struct CZClientMessageString_Struct {
uint32 string_id;
uint16 chat_type;
+3 -3
View File
@@ -210,15 +210,15 @@ bool SharedDatabase::SaveCursor(
)
);
int16 i = EQ::invslot::slotCursor;
int16 i = EQ::invbag::CURSOR_BAG_BEGIN;
for (auto& it = start; it != end; ++it, i++) {
// shouldn't be anything in the queue that indexes this high
if (i > EQ::invbag::CURSOR_BAG_END) {
break;
}
const EQ::ItemInstance* inst = *it;
const int16 use_slot = i == EQ::invslot::slotCursor ? EQ::invslot::slotCursor : i;
const EQ::ItemInstance* inst = *it;
const int16 use_slot = i == EQ::invbag::CURSOR_BAG_BEGIN ? EQ::invslot::slotCursor : i;
if (!SaveInventory(char_id, inst, use_slot)) {
return false;
}
+640 -71
View File
@@ -125,9 +125,14 @@ bool IsMesmerizeSpell(uint16 spell_id)
return IsEffectInSpell(spell_id, SE_Mez);
}
bool SpellBreaksMez(uint16 spell_id)
{
return (IsValidSpell(spell_id) && IsDetrimentalSpell(spell_id) && IsAnyDamageSpell(spell_id));
}
bool IsStunSpell(uint16 spell_id)
{
return IsEffectInSpell(spell_id, SE_Stun);
return (IsValidSpell(spell_id) && IsEffectInSpell(spell_id, SE_Stun) || IsEffectInSpell(spell_id, SE_SpinTarget));
}
bool IsSummonSpell(uint16 spell_id)
@@ -154,6 +159,10 @@ bool IsSummonSpell(uint16 spell_id)
bool IsDamageSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
if (IsLifetapSpell(spell_id)) {
return false;
}
@@ -162,6 +171,32 @@ bool IsDamageSpell(uint16 spell_id)
for (int i = 0; i < EFFECT_COUNT; i++) {
const auto effect_id = spell.effect_id[i];
if (
spell.base_value[i] < 0 &&
(effect_id == SE_CurrentHPOnce || effect_id == SE_CurrentHP)
) {
return true;
}
}
return false;
}
bool IsAnyDamageSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
if (IsLifetapSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
for (int i = 0; i < EFFECT_COUNT; i++) {
const auto effect_id = spell.effect_id[i];
if (
spell.base_value[i] < 0 &&
(
@@ -179,6 +214,35 @@ bool IsDamageSpell(uint16 spell_id)
return false;
}
bool IsDamageOverTimeSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
if (IsLifetapSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
if (spell.good_effect || !spell.buff_duration_formula) {
return false;
}
for (int i = 0; i < EFFECT_COUNT; i++) {
const auto effect_id = spell.effect_id[i];
if (
spell.base_value[i] < 0 &&
effect_id == SE_CurrentHP &&
spell.buff_duration > 1
) {
return true;
}
}
return false;
}
bool IsFearSpell(uint16 spell_id)
{
@@ -409,7 +473,8 @@ bool IsSummonPetSpell(uint16 spell_id)
return (
IsEffectInSpell(spell_id, SE_SummonPet) ||
IsEffectInSpell(spell_id, SE_SummonBSTPet) ||
IsEffectInSpell(spell_id, SE_Familiar)
IsEffectInSpell(spell_id, SE_Familiar) ||
IsEffectInSpell(spell_id, SE_NecPet)
);
}
@@ -560,8 +625,7 @@ bool IsPBAENukeSpell(uint16 spell_id)
if (
IsPureNukeSpell(spell_id) &&
spell.aoe_range > 0 &&
spell.target_type == ST_AECaster
!IsTargetRequiredForSpell(spell_id)
) {
return true;
}
@@ -588,6 +652,120 @@ bool IsAERainNukeSpell(uint16 spell_id)
return false;
}
bool IsAnyNukeOrStunSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
if (IsSelfConversionSpell(spell_id) || IsEscapeSpell(spell_id)) {
return false;
}
if (
IsPBAENukeSpell(spell_id) ||
IsAERainNukeSpell(spell_id) ||
IsPureNukeSpell(spell_id) ||
IsStunSpell(spell_id) ||
(IsDamageSpell(spell_id) && !IsDamageOverTimeSpell(spell_id))
) {
return true;
}
return false;
}
bool IsAnyAESpell(uint16 spell_id) {
return (
IsValidSpell(spell_id) &&
(
IsAEDurationSpell(spell_id) ||
IsAESpell(spell_id) ||
IsAERainNukeSpell(spell_id) ||
IsAERainSpell(spell_id) ||
IsPBAESpell(spell_id) ||
IsPBAENukeSpell(spell_id)
)
);
}
bool IsAESpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
switch (spells[spell_id].target_type) {
case ST_TargetOptional:
case ST_GroupTeleport :
case ST_Target:
case ST_Self:
case ST_Animal:
case ST_Undead:
case ST_Summoned:
case ST_Tap:
case ST_Pet:
case ST_Corpse:
case ST_Plant:
case ST_Giant:
case ST_Dragon:
case ST_LDoNChest_Cursed:
case ST_Muramite:
case ST_SummonedPet:
case ST_GroupNoPets:
case ST_Group:
case ST_GroupClientAndPet:
case ST_TargetsTarget:
case ST_PetMaster:
return false;
default:
break;
}
if (
spells[spell_id].aoe_range > 0
) {
return true;
}
return false;
}
bool IsPBAESpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
if (
spell.aoe_range > 0 &&
spell.target_type == ST_AECaster
) {
return true;
}
return false;
}
bool IsAERainSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
if (
spell.aoe_range > 0 &&
spell.aoe_duration > 1000
) {
return true;
}
return false;
}
bool IsPartialResistableSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
@@ -1265,45 +1443,45 @@ bool IsCompleteHealSpell(uint16 spell_id)
}
return false;
}
bool IsFastHealSpell(uint16 spell_id)
{
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHP) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
);
bool IsFastHealSpell(uint16 spell_id) {
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHP) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
);
if (!spell_id) {
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
);
}
if (!spell_id) {
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
);
}
if (spell_id) {
if (
spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME &&
spells[spell_id].good_effect &&
!IsGroupSpell(spell_id)
) {
for (int i = 0; i < EFFECT_COUNT; i++) {
if (
spells[spell_id].base_value[i] > 0 &&
(
spells[spell_id].effect_id[i] == SE_CurrentHP ||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
)
) {
return true;
}
}
}
}
if (spell_id && IsValidSpell(spell_id)) {
if (
spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME &&
spells[spell_id].good_effect &&
!IsGroupSpell(spell_id)
) {
for (int i = 0; i < EFFECT_COUNT; i++) {
if (
spells[spell_id].base_value[i] > 0 &&
(
spells[spell_id].effect_id[i] == SE_CurrentHP ||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
)
) {
return true;
}
}
}
}
return false;
return false;
}
bool IsVeryFastHealSpell(uint16 spell_id)
@@ -1386,6 +1564,47 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id)
return false;
}
bool IsRegularPetHealSpell(uint16 spell_id)
{
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHP) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
);
if (!spell_id) {
spell_id = (
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
spell_id :
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
);
}
if (spell_id && IsValidSpell(spell_id)) {
if (
(spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_Undead) &&
!IsCompleteHealSpell(spell_id) &&
!IsHealOverTimeSpell(spell_id) &&
!IsGroupSpell(spell_id)
) {
for (int i = 0; i < EFFECT_COUNT; i++) {
if (
spells[spell_id].base_value[i] > 0 &&
spells[spell_id].buff_duration == 0 &&
(
spells[spell_id].effect_id[i] == SE_CurrentHP ||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
)
) {
return true;
}
}
}
}
return false;
}
bool IsRegularGroupHealSpell(uint16 spell_id)
{
spell_id = (
@@ -1426,11 +1645,60 @@ bool IsRegularGroupHealSpell(uint16 spell_id)
return false;
}
bool IsGroupCompleteHealSpell(uint16 spell_id)
{
bool IsGroupCompleteHealSpell(uint16 spell_id) {
if (
IsValidSpell(spell_id) &&
(
spell_id == SPELL_COMPLETE_HEAL ||
IsEffectInSpell(spell_id, SE_CompleteHeal) ||
IsPercentalHealSpell(spell_id) ||
GetSpellTriggerSpellID(spell_id, SE_CompleteHeal)
) &&
IsGroupSpell(spell_id)
) {
return true;
}
return false;
}
bool IsGroupHealOverTimeSpell(uint16 spell_id) {
if (
IsValidSpell(spell_id) &&
(
IsEffectInSpell(spell_id, SE_HealOverTime) ||
GetSpellTriggerSpellID(spell_id, SE_HealOverTime)
) &&
IsGroupSpell(spell_id)
) {
return true;
}
return false;
}
bool IsAnyHealSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
if (spell_id == SPELL_NATURES_RECOVERY) {
return false;
}
//spell_id != SPELL_ADRENALINE_SWELL &&
//spell_id != SPELL_ADRENALINE_SWELL_RK2 &&
//spell_id != SPELL_ADRENALINE_SWELL_RK3 &&
if (
IsGroupSpell(spell_id) &&
IsCompleteHealSpell(spell_id)
IsHealOverTimeSpell(spell_id) ||
IsGroupHealOverTimeSpell(spell_id) ||
IsFastHealSpell(spell_id) ||
IsVeryFastHealSpell(spell_id) ||
IsRegularSingleTargetHealSpell(spell_id) ||
IsRegularGroupHealSpell(spell_id) ||
IsCompleteHealSpell(spell_id) ||
IsGroupCompleteHealSpell(spell_id) ||
IsRegularPetHealSpell(spell_id)
) {
return true;
}
@@ -1438,22 +1706,64 @@ bool IsGroupCompleteHealSpell(uint16 spell_id)
return false;
}
bool IsGroupHealOverTimeSpell(uint16 spell_id)
{
bool IsAnyBuffSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
if (
IsGroupSpell(spell_id) &&
IsHealOverTimeSpell(spell_id) &&
spells[spell_id].buff_duration < 10
spell_id == SPELL_NATURES_RECOVERY ||
IsBuffSpell(spell_id) &&
IsBeneficialSpell(spell_id) &&
!IsBardSong(spell_id) &&
!IsEscapeSpell(spell_id) &&
(!IsSummonPetSpell(spell_id) && !IsEffectInSpell(spell_id, SE_TemporaryPets))
) {
return true;
}
return false;
}
bool IsDispelSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
if (
IsEffectInSpell(spell_id, SE_CancelMagic) ||
IsEffectInSpell(spell_id, SE_DispelBeneficial) ||
IsEffectInSpell(spell_id, SE_DispelBeneficial)
) {
return true;
}
return false;
}
bool IsEscapeSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
return (
IsInvulnerabilitySpell(spell_id) ||
IsEffectInSpell(spell_id, SE_FeignDeath) ||
IsEffectInSpell(spell_id, SE_DeathSave) ||
IsEffectInSpell(spell_id, SE_Destroy) ||
(
IsEffectInSpell(spell_id, SE_WipeHateList) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_WipeHateList)] > 0
)
);
}
bool IsDebuffSpell(uint16 spell_id)
{
if (
if (!IsValidSpell(spell_id)) {
return false;
}
return !(
IsBeneficialSpell(spell_id) ||
IsHealthSpell(spell_id) ||
IsStunSpell(spell_id) ||
@@ -1464,17 +1774,39 @@ bool IsDebuffSpell(uint16 spell_id)
IsEffectInSpell(spell_id, SE_CancelMagic) ||
IsEffectInSpell(spell_id, SE_MovementSpeed) ||
IsFearSpell(spell_id) ||
IsEffectInSpell(spell_id, SE_InstantHate)
) {
IsEffectInSpell(spell_id, SE_InstantHate) ||
IsEffectInSpell(spell_id, SE_TossUp)
);
}
bool IsHateReduxSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
return true;
return (
(
IsEffectInSpell(spell_id, SE_InstantHate) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_InstantHate)] < 0
) ||
(
IsEffectInSpell(spell_id, SE_Hate) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_Hate)] < 0
) ||
(
IsEffectInSpell(spell_id, SE_ReduceHate) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_ReduceHate)] < 0
)
);
}
bool IsResistDebuffSpell(uint16 spell_id)
{
if (
if (!IsValidSpell(spell_id)) {
return false;
}
return (
!IsBeneficialSpell(spell_id) &&
(
IsEffectInSpell(spell_id, SE_ResistFire) ||
@@ -1485,42 +1817,34 @@ bool IsResistDebuffSpell(uint16 spell_id)
IsEffectInSpell(spell_id, SE_ResistAll) ||
IsEffectInSpell(spell_id, SE_ResistCorruption)
)
) {
return true;
}
return false;
);
}
bool IsSelfConversionSpell(uint16 spell_id)
{
if (
if (!IsValidSpell(spell_id)) {
return false;
}
return (
GetSpellTargetType(spell_id) == ST_Self &&
IsEffectInSpell(spell_id, SE_CurrentMana) &&
IsEffectInSpell(spell_id, SE_CurrentHP) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentMana)] > 0 &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentHP)] < 0
) {
return true;
}
return false;
);
}
// returns true for both detrimental and beneficial buffs
bool IsBuffSpell(uint16 spell_id)
{
if (
return (
IsValidSpell(spell_id) &&
(
spells[spell_id].buff_duration ||
spells[spell_id].buff_duration_formula
)
) {
return true;
}
return false;
);
}
bool IsPersistDeathSpell(uint16 spell_id)
@@ -2367,7 +2691,7 @@ bool IsAegolismSpell(uint16 spell_id) {
bool AegolismStackingIsSymbolSpell(uint16 spell_id) {
/*
This is hardcoded to be specific to the type of HP buffs that are removed if a mob has an Aegolism buff.
*/
@@ -2383,7 +2707,7 @@ bool AegolismStackingIsSymbolSpell(uint16 spell_id) {
if ((i < 2 && spells[spell_id].effect_id[i] != SE_CHA) ||
i > 3 && spells[spell_id].effect_id[i] != SE_Blank) {
return 0;;
return 0;
}
if (i == 2 && spells[spell_id].effect_id[i] == SE_TotalHP) {
@@ -2430,3 +2754,248 @@ bool AegolismStackingIsArmorClassSpell(uint16 spell_id) {
return 0;
}
int8 SpellEffectsCount(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
int8 x = 0;
for (int i = 0; i < EFFECT_COUNT; i++) {
if (!IsBlankSpellEffect(spell_id, i)) {
++x;
}
}
return x;
}
bool IsLichSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
return (
GetSpellTargetType(spell_id) == ST_Self &&
IsEffectInSpell(spell_id, SE_CurrentMana) &&
IsEffectInSpell(spell_id, SE_CurrentHP) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentMana)] > 0 &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_CurrentHP)] < 0 &&
spells[spell_id].buff_duration > 0
);
}
bool IsValidSpellAndLoS(uint32 spell_id, bool has_los) {
if (!IsValidSpell(spell_id)) {
return false;
}
if (!has_los && IsTargetRequiredForSpell(spell_id)) {
return false;
}
return true;
}
bool IsInstantHealSpell(uint32 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
return (
IsRegularSingleTargetHealSpell(spell_id) ||
IsRegularGroupHealSpell(spell_id) ||
IsRegularPetHealSpell(spell_id) ||
IsRegularGroupHealSpell(spell_id) ||
spell_id == SPELL_COMPLETE_HEAL
);
}
bool IsResurrectSpell(uint16 spell_id)
{
if (!IsValidSpell(spell_id)) {
return false;
}
return IsEffectInSpell(spell_id, SE_Revive);
}
bool IsResistanceBuffSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
for (int i = 0; i < EFFECT_COUNT; i++) {
if (IsBlankSpellEffect(spell_id, i)) {
continue;
}
if (
spell.effect_id[i] == SE_ResistFire ||
spell.effect_id[i] == SE_ResistCold ||
spell.effect_id[i] == SE_ResistPoison ||
spell.effect_id[i] == SE_ResistDisease ||
spell.effect_id[i] == SE_ResistMagic ||
spell.effect_id[i] == SE_ResistCorruption ||
spell.effect_id[i] == SE_ResistAll
) {
return true;
}
}
return false;
}
bool IsResistanceOnlySpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
for (int i = 0; i < EFFECT_COUNT; i++) {
if (IsBlankSpellEffect(spell_id, i)) {
continue;
}
if (
spell.effect_id[i] == SE_ResistFire ||
spell.effect_id[i] == SE_ResistCold ||
spell.effect_id[i] == SE_ResistPoison ||
spell.effect_id[i] == SE_ResistDisease ||
spell.effect_id[i] == SE_ResistMagic ||
spell.effect_id[i] == SE_ResistCorruption ||
spell.effect_id[i] == SE_ResistAll
) {
continue;
}
return false;
}
return true;
}
bool IsDamageShieldOnlySpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
for (int i = 0; i < EFFECT_COUNT; i++) {
if (IsBlankSpellEffect(spell_id, i)) {
continue;
}
if (
spell.effect_id[i] != SE_DamageShield
) {
return false;
}
}
return true;
}
bool IsDamageShieldAndResistSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
const auto& spell = spells[spell_id];
for (int i = 0; i < EFFECT_COUNT; i++) {
if (IsBlankSpellEffect(spell_id, i)) {
continue;
}
if (
spell.effect_id[i] != SE_DamageShield &&
spell.effect_id[i] != SE_ResistFire &&
spell.effect_id[i] != SE_ResistCold &&
spell.effect_id[i] != SE_ResistPoison &&
spell.effect_id[i] != SE_ResistDisease &&
spell.effect_id[i] != SE_ResistMagic &&
spell.effect_id[i] != SE_ResistCorruption &&
spell.effect_id[i] != SE_ResistAll
) {
return false;
}
}
return true;
}
bool IsHateSpell(uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return false;
}
return (
(
IsEffectInSpell(spell_id, SE_Hate) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_Hate)] > 0
) ||
(
IsEffectInSpell(spell_id, SE_InstantHate) &&
spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_InstantHate)] > 0
)
);
}
bool IsDisciplineTome(const EQ::ItemData* item)
{
if (!item->IsClassCommon() || item->ItemType != EQ::item::ItemTypeSpell) {
return false;
}
//Need a way to determine the difference between a spell and a tome
//so they cant turn in a spell and get it as a discipline
//this is kinda a hack:
const std::string item_name = item->Name;
if (
!Strings::BeginsWith(item_name, "Tome of ") &&
!Strings::BeginsWith(item_name, "Skill: ")
) {
return false;
}
//we know for sure none of the int casters get disciplines
uint32 class_bit = 0;
class_bit |= 1 << (Class::Wizard - 1);
class_bit |= 1 << (Class::Enchanter - 1);
class_bit |= 1 << (Class::Magician - 1);
class_bit |= 1 << (Class::Necromancer - 1);
if (item->Classes & class_bit) {
return false;
}
const auto& spell_id = static_cast<uint32>(item->Scroll.Effect);
if (!IsValidSpell(spell_id)) {
return false;
}
if (!IsDiscipline(spell_id)) {
return false;
}
const auto &spell = spells[spell_id];
if (
spell.classes[Class::Wizard - 1] != 255 &&
spell.classes[Class::Enchanter - 1] != 255 &&
spell.classes[Class::Magician - 1] != 255 &&
spell.classes[Class::Necromancer - 1] != 255
) {
return false;
}
return true;
}
+312 -25
View File
@@ -20,6 +20,7 @@
#include "classes.h"
#include "skills.h"
#include "item_data.h"
#define SPELL_UNKNOWN 0xFFFF
#define POISON_PROC 0xFFFE
@@ -213,6 +214,10 @@
#define SPELL_BLOODTHIRST 8476
#define SPELL_AMPLIFICATION 2603
#define SPELL_DIVINE_REZ 2738
#define SPELL_NATURES_RECOVERY 2520
#define SPELL_ADRENALINE_SWELL 14445
#define SPELL_ADRENALINE_SWELL_RK2 14446
#define SPELL_ADRENALINE_SWELL_RK3 14447
// discipline IDs.
#define DISC_UNHOLY_AURA 4520
@@ -623,38 +628,294 @@ enum ProcType
enum SpellTypes : uint32
{
SpellType_Nuke = (1 << 0),
SpellType_Heal = (1 << 1),
SpellType_Root = (1 << 2),
SpellType_Buff = (1 << 3),
SpellType_Escape = (1 << 4),
SpellType_Pet = (1 << 5),
SpellType_Lifetap = (1 << 6),
SpellType_Snare = (1 << 7),
SpellType_DOT = (1 << 8),
SpellType_Dispel = (1 << 9),
SpellType_InCombatBuff = (1 << 10),
SpellType_Mez = (1 << 11),
SpellType_Charm = (1 << 12),
SpellType_Slow = (1 << 13),
SpellType_Debuff = (1 << 14),
SpellType_Cure = (1 << 15),
SpellType_Resurrect = (1 << 16),
SpellType_HateRedux = (1 << 17),
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
SpellType_PreCombatBuff = (1 << 20),
SpellType_PreCombatBuffSong = (1 << 21)
SpellType_Nuke = (1 << 0),
SpellType_Heal = (1 << 1),
SpellType_Root = (1 << 2),
SpellType_Buff = (1 << 3),
SpellType_Escape = (1 << 4),
SpellType_Pet = (1 << 5),
SpellType_Lifetap = (1 << 6),
SpellType_Snare = (1 << 7),
SpellType_DOT = (1 << 8),
SpellType_Dispel = (1 << 9),
SpellType_InCombatBuff = (1 << 10),
SpellType_Mez = (1 << 11),
SpellType_Charm = (1 << 12),
SpellType_Slow = (1 << 13),
SpellType_Debuff = (1 << 14),
SpellType_Cure = (1 << 15),
SpellType_Resurrect = (1 << 16),
SpellType_HateRedux = (1 << 17),
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
SpellType_PreCombatBuff = (1 << 20),
SpellType_PreCombatBuffSong = (1 << 21)
};
const uint32 SPELL_TYPE_MIN = (SpellType_Nuke << 1) - 1;
const uint32 SPELL_TYPE_MAX = (SpellType_PreCombatBuffSong << 1) - 1;
const uint32 SPELL_TYPE_ANY = 0xFFFFFFFF;
namespace BotSpellTypes
{
constexpr uint16 Nuke = 0;
constexpr uint16 RegularHeal = 1;
constexpr uint16 Root = 2;
constexpr uint16 Buff = 3;
constexpr uint16 Escape = 4;
constexpr uint16 Pet = 5;
constexpr uint16 Lifetap = 6;
constexpr uint16 Snare = 7;
constexpr uint16 DOT = 8;
constexpr uint16 Dispel = 9;
constexpr uint16 InCombatBuff = 10;
constexpr uint16 Mez = 11;
constexpr uint16 Charm = 12;
constexpr uint16 Slow = 13;
constexpr uint16 Debuff = 14;
constexpr uint16 Cure = 15;
constexpr uint16 Resurrect = 16;
constexpr uint16 HateRedux = 17;
constexpr uint16 InCombatBuffSong = 18;
constexpr uint16 OutOfCombatBuffSong = 19;
constexpr uint16 PreCombatBuff = 20;
constexpr uint16 PreCombatBuffSong = 21;
constexpr uint16 Fear = 22;
constexpr uint16 Stun = 23;
constexpr uint16 HateLine = 24;
constexpr uint16 GroupCures = 25;
constexpr uint16 CompleteHeal = 26;
constexpr uint16 FastHeals = 27;
constexpr uint16 VeryFastHeals = 28;
constexpr uint16 GroupHeals = 29;
constexpr uint16 GroupCompleteHeals = 30;
constexpr uint16 GroupHoTHeals = 31;
constexpr uint16 HoTHeals = 32;
constexpr uint16 AENukes = 33;
constexpr uint16 AERains = 34;
constexpr uint16 AEMez = 35;
constexpr uint16 AEStun = 36;
constexpr uint16 AEDebuff = 37;
constexpr uint16 AESlow = 38;
constexpr uint16 AESnare = 39;
constexpr uint16 AEFear = 40;
constexpr uint16 AEDispel = 41;
constexpr uint16 AERoot = 42;
constexpr uint16 AEDoT = 43;
constexpr uint16 AELifetap = 44;
constexpr uint16 AEHateLine = 45;
constexpr uint16 PBAENuke = 46;
constexpr uint16 PetBuffs = 47;
constexpr uint16 PetRegularHeals = 48;
constexpr uint16 PetCompleteHeals = 49;
constexpr uint16 PetFastHeals = 50;
constexpr uint16 PetVeryFastHeals = 51;
constexpr uint16 PetHoTHeals = 52;
constexpr uint16 PetCures = 53;
constexpr uint16 DamageShields = 54;
constexpr uint16 ResistBuffs = 55;
constexpr uint16 PetDamageShields = 56;
constexpr uint16 PetResistBuffs = 57;
// Command Spell Types
constexpr uint16 Teleport = 100; // this is handled by ^depart so uses other logic
constexpr uint16 Lull = 101;
constexpr uint16 Succor = 102;
constexpr uint16 BindAffinity = 103;
constexpr uint16 Identify = 104;
constexpr uint16 Levitate = 105;
constexpr uint16 Rune = 106;
constexpr uint16 WaterBreathing = 107;
constexpr uint16 Size = 108;
constexpr uint16 Invisibility = 109;
constexpr uint16 MovementSpeed = 110;
constexpr uint16 SendHome = 111;
constexpr uint16 SummonCorpse = 112;
constexpr uint16 AELull = 113;
// Discipline Types
constexpr uint16 Discipline = 200;
constexpr uint16 DiscAggressive = 201;
constexpr uint16 DiscDefensive = 202;
constexpr uint16 DiscUtility = 203;
constexpr uint16 START = BotSpellTypes::Nuke; // Do not remove or change this
constexpr uint16 END = BotSpellTypes::PetResistBuffs; // Do not remove this, increment as needed
constexpr uint16 COMMANDED_START = BotSpellTypes::Lull; // Do not remove or change this
constexpr uint16 COMMANDED_END = BotSpellTypes::AELull; // Do not remove this, increment as needed
constexpr uint16 DISCIPLINE_START = BotSpellTypes::Discipline; // Do not remove or change this
constexpr uint16 DISCIPLINE_END = BotSpellTypes::DiscUtility; // Do not remove this, increment as needed
}
static std::map<uint16, std::string> spellType_names = {
{ BotSpellTypes::Nuke, "Nuke" },
{ BotSpellTypes::RegularHeal, "Regular Heal" },
{ BotSpellTypes::Root, "Root" },
{ BotSpellTypes::Buff, "Buff" },
{ BotSpellTypes::Escape, "Escape" },
{ BotSpellTypes::Pet, "Pet" },
{ BotSpellTypes::Lifetap, "Lifetap" },
{ BotSpellTypes::Snare, "Snare" },
{ BotSpellTypes::DOT, "DoT" },
{ BotSpellTypes::Dispel, "Dispel" },
{ BotSpellTypes::InCombatBuff, "In-Combat Buff" },
{ BotSpellTypes::Mez, "Mez" },
{ BotSpellTypes::Charm, "Charm" },
{ BotSpellTypes::Slow, "Slow" },
{ BotSpellTypes::Debuff, "Debuff" },
{ BotSpellTypes::Cure, "Cure" },
{ BotSpellTypes::GroupCures, "Group Cure" },
{ BotSpellTypes::PetCures, "Pet Cure" },
{ BotSpellTypes::Resurrect, "Resurrect" },
{ BotSpellTypes::HateRedux, "Hate Reduction" },
{ BotSpellTypes::InCombatBuffSong, "In-Combat Buff Song" },
{ BotSpellTypes::OutOfCombatBuffSong, "Out-of-Combat Buff Song" },
{ BotSpellTypes::PreCombatBuff, "Pre-Combat Buff" },
{ BotSpellTypes::PreCombatBuffSong, "Pre-Combat Buff Song" },
{ BotSpellTypes::Fear, "Fear" },
{ BotSpellTypes::Stun, "Stun" },
{ BotSpellTypes::CompleteHeal, "Complete Heal" },
{ BotSpellTypes::FastHeals, "Fast Heal" },
{ BotSpellTypes::VeryFastHeals, "Very Fast Heal" },
{ BotSpellTypes::GroupHeals, "Group Heal" },
{ BotSpellTypes::GroupCompleteHeals, "Group Complete Heal" },
{ BotSpellTypes::GroupHoTHeals, "Group HoT Heal" },
{ BotSpellTypes::HoTHeals, "HoT Heal" },
{ BotSpellTypes::AENukes, "AE Nuke" },
{ BotSpellTypes::AERains, "AE Rain" },
{ BotSpellTypes::AEMez, "AE Mez" },
{ BotSpellTypes::AEStun, "AE Stun" },
{ BotSpellTypes::AEDebuff, "AE Debuff" },
{ BotSpellTypes::AESlow, "AE Slow" },
{ BotSpellTypes::AESnare, "AE Snare" },
{ BotSpellTypes::AEFear, "AE Fear" },
{ BotSpellTypes::AEDispel, "AE Dispel" },
{ BotSpellTypes::AERoot, "AE Root" },
{ BotSpellTypes::AEDoT, "AE DoT" },
{ BotSpellTypes::AELifetap, "AE Lifetap" },
{ BotSpellTypes::PBAENuke, "PBAE Nuke" },
{ BotSpellTypes::PetBuffs, "Pet Buff" },
{ BotSpellTypes::PetRegularHeals, "Pet Regular Heal" },
{ BotSpellTypes::PetCompleteHeals, "Pet Complete Heal" },
{ BotSpellTypes::PetFastHeals, "Pet Fast Heal" },
{ BotSpellTypes::PetVeryFastHeals, "Pet Very Fast Heal" },
{ BotSpellTypes::PetHoTHeals, "Pet HoT Heal" },
{ BotSpellTypes::DamageShields, "Damage Shield" },
{ BotSpellTypes::ResistBuffs, "Resist Buff" },
{ BotSpellTypes::PetDamageShields, "Pet Damage Shield" },
{ BotSpellTypes::PetResistBuffs, "Pet Resist Buff" },
{ BotSpellTypes::HateLine, "Hate Line" },
{ BotSpellTypes::AEHateLine, "AE Hate Line" },
{ BotSpellTypes::Lull, "Lull" },
{ BotSpellTypes::Teleport, "Teleport" },
{ BotSpellTypes::Succor, "Succor" },
{ BotSpellTypes::BindAffinity, "Bind Affinity" },
{ BotSpellTypes::Identify, "Identify" },
{ BotSpellTypes::Levitate, "Levitate" },
{ BotSpellTypes::Rune, "Rune" },
{ BotSpellTypes::WaterBreathing, "Water Breathing" },
{ BotSpellTypes::Size, "Size" },
{ BotSpellTypes::Invisibility, "Invisibility" },
{ BotSpellTypes::MovementSpeed, "Movement Speed" },
{ BotSpellTypes::SendHome, "Send Home" },
{ BotSpellTypes::SummonCorpse, "Summon Corpse" },
{ BotSpellTypes::AELull, "AE Lull" }
};
static std::map<uint16, std::string> spellType_shortNames = {
{ BotSpellTypes::Nuke, "nukes" },
{ BotSpellTypes::RegularHeal, "regularheals" },
{ BotSpellTypes::Root, "roots" },
{ BotSpellTypes::Buff, "buffs" },
{ BotSpellTypes::Escape, "escapes" },
{ BotSpellTypes::Pet, "pets" },
{ BotSpellTypes::Lifetap, "lifetaps" },
{ BotSpellTypes::Snare, "snares" },
{ BotSpellTypes::DOT, "dots" },
{ BotSpellTypes::Dispel, "dispels" },
{ BotSpellTypes::InCombatBuff, "incombatbuffs" },
{ BotSpellTypes::Mez, "mez" },
{ BotSpellTypes::Charm, "charms" },
{ BotSpellTypes::Slow, "slows" },
{ BotSpellTypes::Debuff, "debuffs" },
{ BotSpellTypes::Cure, "cures" },
{ BotSpellTypes::GroupCures, "groupcures" },
{ BotSpellTypes::PetCures, "petcures" },
{ BotSpellTypes::Resurrect, "resurrects" },
{ BotSpellTypes::HateRedux, "hateredux" },
{ BotSpellTypes::InCombatBuffSong, "incombatbuffsongs" },
{ BotSpellTypes::OutOfCombatBuffSong, "outofcombatbuffsongs" },
{ BotSpellTypes::PreCombatBuff, "precombatbuffs" },
{ BotSpellTypes::PreCombatBuffSong, "precombatbuffsongs" },
{ BotSpellTypes::Fear, "fears" },
{ BotSpellTypes::Stun, "stuns" },
{ BotSpellTypes::CompleteHeal, "completeheals" },
{ BotSpellTypes::FastHeals, "fastheals" },
{ BotSpellTypes::VeryFastHeals, "veryfastheals" },
{ BotSpellTypes::GroupHeals, "groupheals" },
{ BotSpellTypes::GroupCompleteHeals, "groupcompleteheals" },
{ BotSpellTypes::GroupHoTHeals, "grouphotheals" },
{ BotSpellTypes::HoTHeals, "hotheals" },
{ BotSpellTypes::AENukes, "aenukes" },
{ BotSpellTypes::AERains, "aerains" },
{ BotSpellTypes::AEMez, "aemez" },
{ BotSpellTypes::AEStun, "aestuns" },
{ BotSpellTypes::AEDebuff, "aedebuffs" },
{ BotSpellTypes::AESlow, "aeslows" },
{ BotSpellTypes::AESnare, "aesnares" },
{ BotSpellTypes::AEFear, "aefears" },
{ BotSpellTypes::AEDispel, "aedispels" },
{ BotSpellTypes::AERoot, "aeroots" },
{ BotSpellTypes::AEDoT, "aedots" },
{ BotSpellTypes::AELifetap, "aelifetaps" },
{ BotSpellTypes::PBAENuke, "pbaenukes" },
{ BotSpellTypes::PetBuffs, "petbuffs" },
{ BotSpellTypes::PetRegularHeals, "petregularheals" },
{ BotSpellTypes::PetCompleteHeals, "petcompleteheals" },
{ BotSpellTypes::PetFastHeals, "petfastheals" },
{ BotSpellTypes::PetVeryFastHeals, "petveryfastheals" },
{ BotSpellTypes::PetHoTHeals, "pethotheals" },
{ BotSpellTypes::DamageShields, "damageshields" },
{ BotSpellTypes::ResistBuffs, "resistbuffs" },
{ BotSpellTypes::PetDamageShields, "petdamageshields" },
{ BotSpellTypes::PetResistBuffs, "petresistbuffs" },
{ BotSpellTypes::HateLine, "hatelines" },
{ BotSpellTypes::AEHateLine, "aehatelines" },
{ BotSpellTypes::Lull, "lull" },
{ BotSpellTypes::Teleport, "teleport" },
{ BotSpellTypes::Succor, "succor" },
{ BotSpellTypes::BindAffinity, "bindaffinity" },
{ BotSpellTypes::Identify, "identify" },
{ BotSpellTypes::Levitate, "levitate" },
{ BotSpellTypes::Rune, "rune" },
{ BotSpellTypes::WaterBreathing, "waterbreathing" },
{ BotSpellTypes::Size, "size" },
{ BotSpellTypes::Invisibility, "invisibility" },
{ BotSpellTypes::MovementSpeed, "movementspeed" },
{ BotSpellTypes::SendHome, "sendhome" },
{ BotSpellTypes::SummonCorpse, "summoncorpse" },
{ BotSpellTypes::AELull, "aelull" }
};
const uint32 SPELL_TYPES_DETRIMENTAL = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow);
const uint32 SPELL_TYPES_BENEFICIAL = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong);
const uint32 SPELL_TYPES_INNATE = (SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root);
// Bot related functions
bool IsBotSpellTypeDetrimental (uint16 spell_type);
bool IsBotSpellTypeBeneficial (uint16 spell_type);
bool IsBotSpellTypeOtherBeneficial(uint16 spell_type);
bool IsBotSpellTypeInnate (uint16 spell_type);
bool IsAEBotSpellType(uint16 spell_type);
bool IsGroupBotSpellType(uint16 spell_type);
bool IsGroupTargetOnlyBotSpellType(uint16 spell_type);
bool IsPetBotSpellType(uint16 spell_type);
bool IsClientBotSpellType(uint16 spell_type);
bool IsHealBotSpellType(uint16 spell_type);
bool BotSpellTypeRequiresLoS(uint16 spell_type);
bool BotSpellTypeRequiresTarget(uint16 spell_type);
bool BotSpellTypeRequiresAEChecks(uint16 spell_type);
bool IsCommandedBotSpellType(uint16 spell_type);
bool IsPullingBotSpellType(uint16 spell_type);
uint16 GetCorrectBotSpellType(uint16 spell_type, uint16 spell_id);
uint16 GetPetBotSpellType(uint16 spell_type);
// These should not be used to determine spell category..
// They are a graphical affects (effects?) index only
// TODO: import sai list
@@ -1503,6 +1764,7 @@ bool IsTargetableAESpell(uint16 spell_id);
bool IsSacrificeSpell(uint16 spell_id);
bool IsLifetapSpell(uint16 spell_id);
bool IsMesmerizeSpell(uint16 spell_id);
bool SpellBreaksMez(uint16 spell_id);
bool IsStunSpell(uint16 spell_id);
bool IsSlowSpell(uint16 spell_id);
bool IsHasteSpell(uint16 spell_id);
@@ -1536,6 +1798,11 @@ bool IsPureNukeSpell(uint16 spell_id);
bool IsAENukeSpell(uint16 spell_id);
bool IsPBAENukeSpell(uint16 spell_id);
bool IsAERainNukeSpell(uint16 spell_id);
bool IsAnyNukeOrStunSpell(uint16 spell_id);
bool IsAnyAESpell(uint16 spell_id);
bool IsAESpell(uint16 spell_id);
bool IsPBAESpell(uint16 spell_id);
bool IsAERainSpell(uint16 spell_id);
bool IsPartialResistableSpell(uint16 spell_id);
bool IsResistableSpell(uint16 spell_id);
bool IsGroupSpell(uint16 spell_id);
@@ -1545,8 +1812,11 @@ bool IsEffectInSpell(uint16 spell_id, int effect_id);
uint16 GetSpellTriggerSpellID(uint16 spell_id, int effect_id);
bool IsBlankSpellEffect(uint16 spell_id, int effect_index);
bool IsValidSpell(uint32 spell_id);
bool IsValidSpellAndLoS(uint32 spell_id, bool has_los = true);
bool IsSummonSpell(uint16 spell_id);
bool IsDamageSpell(uint16 spell_id);
bool IsAnyDamageSpell(uint16 spell_id);
bool IsDamageOverTimeSpell(uint16 spell_i);
bool IsFearSpell(uint16 spell_id);
bool IsCureSpell(uint16 spell_id);
bool IsHarmTouchSpell(uint16 spell_id);
@@ -1585,10 +1855,16 @@ bool IsCompleteHealSpell(uint16 spell_id);
bool IsFastHealSpell(uint16 spell_id);
bool IsVeryFastHealSpell(uint16 spell_id);
bool IsRegularSingleTargetHealSpell(uint16 spell_id);
bool IsRegularPetHealSpell(uint16 spell_id);
bool IsRegularGroupHealSpell(uint16 spell_id);
bool IsGroupCompleteHealSpell(uint16 spell_id);
bool IsGroupHealOverTimeSpell(uint16 spell_id);
bool IsAnyHealSpell(uint16 spell_id);
bool IsAnyBuffSpell(uint16 spell_id);
bool IsDispelSpell(uint16 spell_id);
bool IsEscapeSpell(uint16 spell_id);
bool IsDebuffSpell(uint16 spell_id);
bool IsHateReduxSpell(uint16 spell_id);
bool IsResistDebuffSpell(uint16 spell_id);
bool IsSelfConversionSpell(uint16 spell_id);
bool IsBuffSpell(uint16 spell_id);
@@ -1628,5 +1904,16 @@ bool IsCastRestrictedSpell(uint16 spell_id);
bool IsAegolismSpell(uint16 spell_id);
bool AegolismStackingIsSymbolSpell(uint16 spell_id);
bool AegolismStackingIsArmorClassSpell(uint16 spell_id);
int8 SpellEffectsCount(uint16 spell_id);
bool IsLichSpell(uint16 spell_id);
bool IsInstantHealSpell(uint32 spell_id);
bool IsResurrectSpell(uint16 spell_id);
bool RequiresStackCheck(uint16 spell_type);
bool IsResistanceBuffSpell(uint16 spell_id);
bool IsResistanceOnlySpell(uint16 spell_id);
bool IsDamageShieldOnlySpell(uint16 spell_id);
bool IsDamageShieldAndResistSpell(uint16 spell_id);
bool IsHateSpell(uint16 spell_id);
bool IsDisciplineTome(const EQ::ItemData* item);
#endif
+710
View File
@@ -0,0 +1,710 @@
#include "spdat.h"
bool IsBotSpellTypeDetrimental(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::Nuke:
case BotSpellTypes::Root:
case BotSpellTypes::Lifetap:
case BotSpellTypes::Snare:
case BotSpellTypes::DOT:
case BotSpellTypes::Dispel:
case BotSpellTypes::Mez:
case BotSpellTypes::Charm:
case BotSpellTypes::Slow:
case BotSpellTypes::Debuff:
case BotSpellTypes::HateRedux:
case BotSpellTypes::Fear:
case BotSpellTypes::Stun:
case BotSpellTypes::AENukes:
case BotSpellTypes::AERains:
case BotSpellTypes::AEMez:
case BotSpellTypes::AEStun:
case BotSpellTypes::AEDebuff:
case BotSpellTypes::AESlow:
case BotSpellTypes::AESnare:
case BotSpellTypes::AEFear:
case BotSpellTypes::AEDispel:
case BotSpellTypes::AERoot:
case BotSpellTypes::AEDoT:
case BotSpellTypes::AELifetap:
case BotSpellTypes::PBAENuke:
case BotSpellTypes::Lull:
case BotSpellTypes::AELull:
case BotSpellTypes::HateLine:
case BotSpellTypes::AEHateLine:
return true;
default:
return false;
}
return false;
}
bool IsBotSpellTypeBeneficial(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::RegularHeal:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::FastHeals:
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::Buff:
case BotSpellTypes::Cure:
case BotSpellTypes::GroupCures:
case BotSpellTypes::PetCures:
case BotSpellTypes::DamageShields:
case BotSpellTypes::InCombatBuffSong:
case BotSpellTypes::OutOfCombatBuffSong:
case BotSpellTypes::Pet:
case BotSpellTypes::PetBuffs:
case BotSpellTypes::PreCombatBuff:
case BotSpellTypes::PreCombatBuffSong:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::ResistBuffs:
case BotSpellTypes::Resurrect:
case BotSpellTypes::Teleport:
case BotSpellTypes::Succor:
case BotSpellTypes::BindAffinity:
case BotSpellTypes::Identify:
case BotSpellTypes::Levitate:
case BotSpellTypes::Rune:
case BotSpellTypes::WaterBreathing:
case BotSpellTypes::Size:
case BotSpellTypes::Invisibility:
case BotSpellTypes::MovementSpeed:
case BotSpellTypes::SendHome:
case BotSpellTypes::SummonCorpse:
return true;
default:
return false;
}
return false;
}
bool IsBotSpellTypeOtherBeneficial(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::RegularHeal:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::FastHeals:
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::Buff:
case BotSpellTypes::Cure:
case BotSpellTypes::GroupCures:
case BotSpellTypes::PetCures:
case BotSpellTypes::DamageShields:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::PetBuffs:
case BotSpellTypes::ResistBuffs:
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::Teleport:
case BotSpellTypes::Succor:
case BotSpellTypes::BindAffinity:
case BotSpellTypes::Identify:
case BotSpellTypes::Levitate:
case BotSpellTypes::Rune:
case BotSpellTypes::WaterBreathing:
case BotSpellTypes::Size:
case BotSpellTypes::Invisibility:
case BotSpellTypes::MovementSpeed:
case BotSpellTypes::SendHome:
case BotSpellTypes::SummonCorpse:
return true;
default:
return false;
}
return false;
}
bool IsBotSpellTypeInnate(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::AENukes:
case BotSpellTypes::AERains:
case BotSpellTypes::PBAENuke:
case BotSpellTypes::Nuke:
case BotSpellTypes::AEDispel:
case BotSpellTypes::Dispel:
case BotSpellTypes::AERoot:
case BotSpellTypes::Root:
case BotSpellTypes::AESlow:
case BotSpellTypes::Slow:
case BotSpellTypes::Charm:
case BotSpellTypes::AEDebuff:
case BotSpellTypes::Debuff:
case BotSpellTypes::AEDoT:
case BotSpellTypes::DOT:
case BotSpellTypes::AELifetap:
case BotSpellTypes::Lifetap:
case BotSpellTypes::AEStun:
case BotSpellTypes::Stun:
case BotSpellTypes::AEMez:
case BotSpellTypes::Mez:
case BotSpellTypes::Lull:
case BotSpellTypes::AELull:
case BotSpellTypes::HateLine:
case BotSpellTypes::AEHateLine:
return true;
default:
return false;
}
return false;
}
bool IsAEBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::AEDebuff:
case BotSpellTypes::AEFear:
case BotSpellTypes::AEMez:
case BotSpellTypes::AENukes:
case BotSpellTypes::AERains:
case BotSpellTypes::AESlow:
case BotSpellTypes::AESnare:
case BotSpellTypes::AEStun:
case BotSpellTypes::AEDispel:
case BotSpellTypes::AEDoT:
case BotSpellTypes::PBAENuke:
case BotSpellTypes::AELifetap:
case BotSpellTypes::AERoot:
case BotSpellTypes::AEHateLine:
case BotSpellTypes::AELull:
return true;
default:
return false;
}
return false;
}
bool IsGroupBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::GroupCures:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
return true;
default:
return false;
}
return false;
}
bool IsGroupTargetOnlyBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::GroupCures:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::GroupHeals:
return true;
default:
return false;
}
return false;
}
bool IsPetBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::PetBuffs:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::PetCures:
return true;
default:
return false;
}
return false;
}
bool IsClientBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::RegularHeal:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::FastHeals:
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::Buff:
case BotSpellTypes::Cure:
case BotSpellTypes::GroupCures:
case BotSpellTypes::PetCures:
case BotSpellTypes::DamageShields:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::PetBuffs:
case BotSpellTypes::ResistBuffs:
case BotSpellTypes::PetResistBuffs:
return true;
default:
return false;
}
return false;
}
bool IsHealBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::FastHeals:
case BotSpellTypes::RegularHeal:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
return true;
default:
return false;
}
return false;
}
bool BotSpellTypeRequiresLoS(uint16 spell_type) {
if (IsAEBotSpellType(spell_type)) { // These gather their own targets later
return false;
}
switch (spell_type) {
case BotSpellTypes::RegularHeal:
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::FastHeals:
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::InCombatBuff:
return false;
default:
return true;
}
return true;
}
bool BotSpellTypeRequiresTarget(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::Pet:
case BotSpellTypes::Succor:
return false;
default:
return true;
}
return true;
}
bool BotSpellTypeRequiresAEChecks(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::AEMez:
return false;
default:
return true;
}
return true;
}
bool RequiresStackCheck(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::FastHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::RegularHeal:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::GroupCompleteHeals:
return false;
default:
return true;
}
return true;
}
bool IsCommandedBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::Charm:
case BotSpellTypes::AEFear:
case BotSpellTypes::Fear:
case BotSpellTypes::Resurrect:
case BotSpellTypes::AELull:
case BotSpellTypes::Lull:
case BotSpellTypes::Teleport:
case BotSpellTypes::Succor:
case BotSpellTypes::BindAffinity:
case BotSpellTypes::Identify:
case BotSpellTypes::Levitate:
case BotSpellTypes::Rune:
case BotSpellTypes::WaterBreathing:
case BotSpellTypes::Size:
case BotSpellTypes::Invisibility:
case BotSpellTypes::MovementSpeed:
case BotSpellTypes::SendHome:
case BotSpellTypes::SummonCorpse:
return true;
default:
return false;
}
return false;
}
bool IsPullingBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::Nuke:
case BotSpellTypes::Lifetap:
case BotSpellTypes::Snare:
case BotSpellTypes::DOT:
case BotSpellTypes::Dispel:
case BotSpellTypes::Slow:
case BotSpellTypes::Debuff:
case BotSpellTypes::Stun:
case BotSpellTypes::HateLine:
return true;
default:
return false;
}
return false;
}
uint16 GetCorrectBotSpellType(uint16 spell_type, uint16 spell_id) {
if (!IsValidSpell(spell_id)) {
return UINT16_MAX;
}
uint16 correct_type = UINT16_MAX;
SPDat_Spell_Struct spell = spells[spell_id];
std::string teleport_zone = spell.teleport_zone;
if (IsCharmSpell(spell_id)) {
correct_type = BotSpellTypes::Charm;
}
else if (IsFearSpell(spell_id)) {
correct_type = BotSpellTypes::Fear;
}
else if (IsEffectInSpell(spell_id, SE_Revive)) {
correct_type = BotSpellTypes::Resurrect;
}
else if (IsHarmonySpell(spell_id)) {
correct_type = BotSpellTypes::Lull;
}
else if (
teleport_zone.compare("") &&
!IsEffectInSpell(spell_id, SE_GateToHomeCity) &&
IsBeneficialSpell(spell_id) &&
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
) {
correct_type = BotSpellTypes::Teleport;
}
else if (
IsBeneficialSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_Succor)
) {
correct_type = BotSpellTypes::Succor;
}
else if (IsEffectInSpell(spell_id, SE_BindAffinity)) {
correct_type = BotSpellTypes::BindAffinity;
}
else if (IsEffectInSpell(spell_id, SE_Identify)) {
correct_type = BotSpellTypes::Identify;
}
else if (
spell_type == BotSpellTypes::Levitate &&
IsBeneficialSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_Levitate)
) {
correct_type = BotSpellTypes::Levitate;
}
else if (
spell_type == BotSpellTypes::Rune &&
IsBeneficialSpell(spell_id) &&
(IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))
) {
correct_type = BotSpellTypes::Rune;
}
else if (
spell_type == BotSpellTypes::WaterBreathing &&
IsBeneficialSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_WaterBreathing)
) {
correct_type = BotSpellTypes::WaterBreathing;
}
else if (
spell_type == BotSpellTypes::Size &&
IsBeneficialSpell(spell_id) &&
(IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))
) {
correct_type = BotSpellTypes::Size;
}
else if (
spell_type == BotSpellTypes::Invisibility &&
IsBeneficialSpell(spell_id) &&
(IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id))
) {
correct_type = BotSpellTypes::Invisibility;
}
else if (
spell_type == BotSpellTypes::MovementSpeed &&
IsBeneficialSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_MovementSpeed)
) {
correct_type = BotSpellTypes::MovementSpeed;
}
else if (
!teleport_zone.compare("") &&
IsBeneficialSpell(spell_id) &&
(IsEffectInSpell(spell_id, SE_Translocate) || IsEffectInSpell(spell_id, SE_GateToHomeCity))
) {
correct_type = BotSpellTypes::SendHome;
}
else if (IsEffectInSpell(spell_id, SE_SummonCorpse)) {
correct_type = BotSpellTypes::SummonCorpse;
}
if (correct_type == UINT16_MAX) {
if (
IsSummonPetSpell(spell_id) ||
IsEffectInSpell(spell_id, SE_TemporaryPets)
) {
correct_type = BotSpellTypes::Pet;
}
else if (IsMesmerizeSpell(spell_id)) {
correct_type = BotSpellTypes::Mez;
}
else if (IsEscapeSpell(spell_id)) {
correct_type = BotSpellTypes::Escape;
}
else if (
IsDetrimentalSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_Root)
) {
if (IsAnyAESpell(spell_id)) {
correct_type = BotSpellTypes::AERoot;
}
else {
correct_type = BotSpellTypes::Root;
}
}
else if (
IsDetrimentalSpell(spell_id) &&
IsLifetapSpell(spell_id)
) {
correct_type = BotSpellTypes::Lifetap;
}
else if (
IsDetrimentalSpell(spell_id) &&
IsEffectInSpell(spell_id, SE_MovementSpeed)
) {
correct_type = BotSpellTypes::Snare;
}
else if (
IsDetrimentalSpell(spell_id) &&
(IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))
) {
correct_type = BotSpellTypes::DOT;
}
else if (IsDispelSpell(spell_id)) {
correct_type = BotSpellTypes::Dispel;
}
else if (
IsDetrimentalSpell(spell_id) &&
IsSlowSpell(spell_id)
) {
correct_type = BotSpellTypes::Slow;
}
else if (
IsDebuffSpell(spell_id) &&
!IsHateReduxSpell(spell_id) &&
!IsHateSpell(spell_id)
) {
correct_type = BotSpellTypes::Debuff;
}
else if (IsHateReduxSpell(spell_id)) {
correct_type = BotSpellTypes::HateRedux;
}
else if (
IsDetrimentalSpell(spell_id) &&
IsHateSpell(spell_id)
) {
correct_type = BotSpellTypes::HateLine;
}
else if (
IsBuffSpell(spell_id) &&
IsBeneficialSpell(spell_id) &&
IsBardSong(spell_id)
) {
if (
spell_type == BotSpellTypes::InCombatBuffSong ||
spell_type == BotSpellTypes::OutOfCombatBuffSong ||
spell_type == BotSpellTypes::PreCombatBuffSong
) {
correct_type = spell_type;
}
else {
correct_type = BotSpellTypes::OutOfCombatBuffSong;
}
}
else if (
!IsBardSong(spell_id) &&
(
(IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) ||
(spell_type == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id))
)
) {
correct_type = BotSpellTypes::InCombatBuff;
}
else if (
spell_type == BotSpellTypes::PreCombatBuff &&
IsAnyBuffSpell(spell_id) &&
!IsBardSong(spell_id)
) {
correct_type = BotSpellTypes::PreCombatBuff;
}
else if (
(IsCureSpell(spell_id) && spell_type == BotSpellTypes::Cure) ||
(IsCureSpell(spell_id) && !IsAnyHealSpell(spell_id))
) {
correct_type = BotSpellTypes::Cure;
}
else if (IsAnyNukeOrStunSpell(spell_id)) {
if (IsAnyAESpell(spell_id)) {
if (IsAERainSpell(spell_id)) {
correct_type = BotSpellTypes::AERains;
}
else if (IsPBAENukeSpell(spell_id)) {
correct_type = BotSpellTypes::PBAENuke;
}
else if (IsStunSpell(spell_id)) {
correct_type = BotSpellTypes::AEStun;
}
else {
correct_type = BotSpellTypes::AENukes;
}
}
else if (IsStunSpell(spell_id)) {
correct_type = BotSpellTypes::Stun;
}
else {
correct_type = BotSpellTypes::Nuke;
}
}
else if (IsAnyHealSpell(spell_id)) {
if (IsGroupSpell(spell_id)) {
if (IsGroupCompleteHealSpell(spell_id)) {
correct_type = BotSpellTypes::GroupCompleteHeals;
}
else if (IsGroupHealOverTimeSpell(spell_id)) {
correct_type = BotSpellTypes::GroupHoTHeals;
}
else if (IsRegularGroupHealSpell(spell_id)) {
correct_type = BotSpellTypes::GroupHeals;
}
return correct_type;
}
if (IsVeryFastHealSpell(spell_id)) {
correct_type = BotSpellTypes::VeryFastHeals;
}
else if (IsFastHealSpell(spell_id)) {
correct_type = BotSpellTypes::FastHeals;
}
else if (IsCompleteHealSpell(spell_id)) {
correct_type = BotSpellTypes::CompleteHeal;
}
else if (IsHealOverTimeSpell(spell_id)) {
correct_type = BotSpellTypes::HoTHeals;
}
else if (IsRegularSingleTargetHealSpell(spell_id)) {
correct_type = BotSpellTypes::RegularHeal;
}
else if (IsRegularPetHealSpell(spell_id)) {
correct_type = BotSpellTypes::RegularHeal;
}
}
else if (IsAnyBuffSpell(spell_id)) {
correct_type = BotSpellTypes::Buff;
if (IsResistanceOnlySpell(spell_id)) {
correct_type = BotSpellTypes::ResistBuffs;
}
else if (IsDamageShieldOnlySpell(spell_id)) {
correct_type = BotSpellTypes::DamageShields;
}
}
}
return correct_type;
}
uint16 GetPetBotSpellType(uint16 spell_type) {
switch (spell_type) {
case BotSpellTypes::Buff:
return BotSpellTypes::PetBuffs;
case BotSpellTypes::RegularHeal:
return BotSpellTypes::PetRegularHeals;
case BotSpellTypes::CompleteHeal:
return BotSpellTypes::PetCompleteHeals;
case BotSpellTypes::FastHeals:
return BotSpellTypes::PetFastHeals;
case BotSpellTypes::VeryFastHeals:
return BotSpellTypes::PetVeryFastHeals;
case BotSpellTypes::HoTHeals:
return BotSpellTypes::PetHoTHeals;
case BotSpellTypes::Cure:
return BotSpellTypes::PetCures;
case BotSpellTypes::DamageShields:
return BotSpellTypes::PetDamageShields;
case BotSpellTypes::ResistBuffs:
return BotSpellTypes::PetResistBuffs;
default:
return spell_type;
}
return spell_type;
}
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.62.1-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.62.2-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,8 +42,8 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9298
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
#define CURRENT_BINARY_DATABASE_VERSION 9302
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054
#endif
+2 -4
View File
@@ -4,12 +4,11 @@ SET(eqlogin_sources
account_management.cpp
client.cpp
client_manager.cpp
database.cpp
encryption.cpp
loginserver_command_handler.cpp
loginserver_webserver.cpp
main.cpp
server_manager.cpp
world_server_manager.cpp
world_server.cpp
)
@@ -17,14 +16,13 @@ SET(eqlogin_headers
account_management.h
client.h
client_manager.h
database.h
encryption.h
loginserver_command_handler.h
loginserver_webserver.h
login_server.h
login_types.h
options.h
server_manager.h
world_server_manager.h
world_server.h
)
+125 -223
View File
@@ -1,259 +1,114 @@
#include "account_management.h"
#include "login_server.h"
#include "../common/event/task_scheduler.h"
#include "../common/event/event_loop.h"
#include "../common/net/dns.h"
#include "../common/strings.h"
#include "../common/repositories/login_accounts_repository.h"
extern LoginServer server;
EQ::Event::TaskScheduler task_runner;
/**
* @param username
* @param password
* @param email
* @param source_loginserver
* @param login_account_id
* @return
*/
int32 AccountManagement::CreateLoginServerAccount(
std::string username,
std::string password,
std::string email,
const std::string &source_loginserver,
uint32 login_account_id
)
uint64 AccountManagement::CreateLoginServerAccount(LoginAccountContext c)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(username, password, mode);
LogInfo(
"Attempting to create local login account for user [{0}] encryption algorithm [{1}] ({2})",
username,
GetEncryptionByModeId(mode),
mode
);
unsigned int db_id = 0;
if (server.db->DoesLoginServerAccountExist(username, hash, source_loginserver, 1)) {
if (LoginAccountsRepository::GetAccountFromContext(database, c).id > 0) {
LogWarning(
"Attempting to create local login account for user [{0}] login [{1}] but already exists!",
username,
source_loginserver
"Attempting to create local login account for user [{}] but already exists!",
c.username
);
return -1;
}
uint32 created_account_id = 0;
if (login_account_id > 0) {
created_account_id = server.db->CreateLoginDataWithID(username, hash, source_loginserver, login_account_id);
}
else {
created_account_id = server.db->CreateLoginAccount(username, hash, source_loginserver, email);
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
if (a.id > 0) {
return (int64) a.id;
}
if (created_account_id > 0) {
LogInfo(
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) id: [{3}]",
username,
GetEncryptionByModeId(mode),
mode,
created_account_id
);
return (int32) created_account_id;
}
LogError("Failed to create local login account for user [{0}]!", username);
LogError("Failed to create local login account for user [{}] !", c.username);
return 0;
}
/**
* @param username
* @param password
* @param email
* @return
*/
bool AccountManagement::CreateLoginserverWorldAdminAccount(
const std::string &username,
const std::string &password,
const std::string &email,
const std::string &first_name,
const std::string &last_name,
const std::string &ip_address
)
uint64 AccountManagement::CheckLoginserverUserCredentials(LoginAccountContext c)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(username, password, mode);
LogInfo(
"Attempting to create world admin account | username [{0}] encryption algorithm [{1}] ({2})",
username,
GetEncryptionByModeId(mode),
mode
);
if (server.db->DoesLoginserverWorldAdminAccountExist(username)) {
LogWarning(
"Attempting to create world admin account for user [{0}] but already exists!",
username
);
return false;
}
uint32 created_world_admin_id = server.db->CreateLoginserverWorldAdminAccount(
username,
hash,
first_name,
last_name,
email,
ip_address
);
if (created_world_admin_id > 0) {
LogInfo(
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) new admin id [{3}]",
username,
GetEncryptionByModeId(mode),
mode,
created_world_admin_id
);
return true;
}
LogError("Failed to create world admin account account for user [{0}]!", username);
return false;
}
/**
* @param in_account_username
* @param in_account_password
* @return
*/
uint32 AccountManagement::CheckLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password,
const std::string &source_loginserver
)
{
auto mode = server.options.GetEncryptionMode();
Database::DbLoginServerAccount
login_server_admin = server.db->GetLoginServerAccountByAccountName(
in_account_username,
source_loginserver
);
if (!login_server_admin.loaded) {
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
if (!a.id) {
LogError(
"account [{0}] source_loginserver [{1}] not found!",
in_account_username,
source_loginserver
"account [{}] source_loginserver [{}] not found!",
c.username,
c.source_loginserver
);
return false;
return 0;
}
bool validated_credentials = eqcrypt_verify_hash(
in_account_username,
in_account_password,
login_server_admin.account_password,
mode
);
bool validated_credentials = eqcrypt_verify_hash(c.username, c.password, a.account_password, mode);
if (!validated_credentials) {
LogError(
"account [{0}] source_loginserver [{1}] invalid credentials!",
in_account_username,
source_loginserver
"account [{}] source_loginserver [{}] invalid credentials!",
c.username,
c.source_loginserver
);
return 0;
}
LogInfo(
"account [{0}] source_loginserver [{1}] credentials validated success!",
in_account_username,
source_loginserver
"account [{}] source_loginserver [{}] credentials validated success!",
c.username,
c.source_loginserver
);
return login_server_admin.id;
return a.id;
}
/**
* @param in_account_username
* @param in_account_password
* @return
*/
bool AccountManagement::UpdateLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password,
const std::string &source_loginserver
)
bool AccountManagement::UpdateLoginserverUserCredentials(LoginAccountContext c)
{
auto mode = server.options.GetEncryptionMode();
Database::DbLoginServerAccount
login_server_account = server.db->GetLoginServerAccountByAccountName(
in_account_username,
source_loginserver
);
if (!login_server_account.loaded) {
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
if (!a.id) {
LogError(
"account [{0}] source_loginserver [{1}] not found!",
in_account_username,
source_loginserver
"account [{}] source_loginserver [{}] not found!",
c.username,
c.source_loginserver
);
return false;
}
server.db->UpdateLoginserverAccountPasswordHash(
in_account_username,
source_loginserver,
eqcrypt_hash(
in_account_username,
in_account_password,
mode
)
);
LoginAccountsRepository::UpdateAccountPassword(database, a, c.password);
LogInfo(
"account [{0}] source_loginserver [{1}] credentials updated!",
in_account_username,
source_loginserver
"account [{}] source_loginserver [{}] credentials updated!",
c.username,
c.source_loginserver
);
return true;
}
/**
* @param in_account_username
* @param in_account_password
*/
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
const std::string &in_account_username,
const std::string &in_account_password
)
bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(LoginAccountContext c)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(in_account_username, in_account_password, mode);
bool updated_account = server.db->UpdateLoginWorldAdminAccountPasswordByUsername(
in_account_username,
hash
auto hash = eqcrypt_hash(
c.username,
c.password,
mode
);
auto a = LoginServerAdminsRepository::GetByName(database, c.username);
if (!a.id) {
LogError(
"account_name [{}] not found!",
c.username
);
return false;
}
a.account_password = hash;
auto updated_account = LoginServerAdminsRepository::UpdateOne(database, a);
LogInfo(
"[{}] account_name [{}] status [{}]",
__func__,
in_account_username,
"account_name [{}] status [{}]",
c.username,
(updated_account ? "success" : "failed")
);
@@ -262,15 +117,7 @@ bool AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
constexpr int REQUEST_TIMEOUT_MS = 1500;
/**
* @param in_account_username
* @param in_account_password
* @return
*/
uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password
)
uint64 AccountManagement::CheckExternalLoginserverUserCredentials(LoginAccountContext c)
{
auto res = task_runner.Enqueue(
[&]() -> uint32 {
@@ -278,11 +125,11 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
uint32 ret = 0;
EQ::Net::DaybreakConnectionManager mgr;
std::shared_ptr<EQ::Net::DaybreakConnection> c;
std::shared_ptr<EQ::Net::DaybreakConnection> conn;
mgr.OnNewConnection(
[&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
c = connection;
conn = connection;
}
);
@@ -296,7 +143,7 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
EQ::Net::DynamicPacket p;
p.PutUInt16(0, 1); //OP_SessionReady
p.PutUInt32(2, 2);
c->QueuePacket(p);
conn->QueuePacket(p);
}
else if (EQ::Net::StatusDisconnected == to) {
running = false;
@@ -310,13 +157,12 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
switch (opcode) {
case 0x0017: //OP_ChatMessage
{
size_t buffer_len =
in_account_username.length() + in_account_password.length() + 2;
size_t buffer_len = c.username.length() + c.password.length() + 2;
std::unique_ptr<char[]> buffer(new char[buffer_len]);
strcpy(&buffer[0], in_account_username.c_str());
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
strcpy(&buffer[0], c.username.c_str());
strcpy(&buffer[c.username.length() + 1], c.password.c_str());
size_t encrypted_len = buffer_len;
@@ -330,11 +176,11 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
p.PutUInt32(2, 3);
eqcrypt_block(&buffer[0], buffer_len, (char *) p.Data() + 12, true);
c->QueuePacket(p);
conn->QueuePacket(p);
break;
}
case 0x0018: {
auto encrypt_size = p.Length() - 12;
auto encrypt_size = p.Length() - 12;
if (encrypt_size % 8 > 0) {
encrypt_size = (encrypt_size / 8) * 8;
}
@@ -394,15 +240,15 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
return res.get();
}
uint32 AccountManagement::HealthCheckUserLogin()
uint64 AccountManagement::HealthCheckUserLogin()
{
std::string in_account_username = "healthcheckuser";
std::string in_account_password = "healthcheckpassword";
auto res = task_runner.Enqueue(
[&]() -> uint32 {
[&]() -> uint64 {
bool running = true;
uint32 ret = 0;
uint64 ret = 0;
EQ::Net::DaybreakConnectionManager mgr;
std::shared_ptr<EQ::Net::DaybreakConnection> c;
@@ -461,7 +307,7 @@ uint32 AccountManagement::HealthCheckUserLogin()
break;
}
case 0x0018: {
auto encrypt_size = p.Length() - 12;
auto encrypt_size = p.Length() - 12;
if (encrypt_size % 8 > 0) {
encrypt_size = (encrypt_size / 8) * 8;
}
@@ -487,11 +333,11 @@ uint32 AccountManagement::HealthCheckUserLogin()
mgr.Connect("127.0.0.1", 5999);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
auto &loop = EQ::EventLoop::Get();
auto &loop = EQ::EventLoop::Get();
while (running) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() > 2000) {
ret = 0;
ret = 0;
running = false;
}
@@ -504,3 +350,59 @@ uint32 AccountManagement::HealthCheckUserLogin()
return res.get();
}
bool AccountManagement::CreateLoginserverWorldAdminAccount(
const std::string &username,
const std::string &password,
const std::string &email,
const std::string &first_name,
const std::string &last_name,
const std::string &ip_address
)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(username, password, mode);
LogInfo(
"Attempting to create world admin account | username [{}] encryption algorithm [{}] ({})",
username,
GetEncryptionByModeId(mode),
mode
);
auto a = LoginServerAdminsRepository::GetByName(database, username);
if (a.id > 0) {
LogWarning(
"Attempting to create world admin account for user [{}] but already exists!",
username
);
return false;
}
a = LoginServerAdminsRepository::NewEntity();
a.account_name = username;
a.account_password = hash;
a.first_name = first_name;
a.last_name = last_name;
a.email = email;
a.registration_ip_address = ip_address;
a.registration_date = std::time(nullptr);
a = LoginServerAdminsRepository::InsertOne(database, a);
if (a.id > 0) {
LogInfo(
"Account creation success for user [{}] encryption algorithm [{}] ({}) new admin id [{}]",
username,
GetEncryptionByModeId(mode),
mode,
a.id
);
return true;
}
LogError("Failed to create world admin account account for user [{}] !", username);
return false;
}
+12 -66
View File
@@ -3,32 +3,22 @@
#include "iostream"
#include "../common/types.h"
#include "login_types.h"
#include "encryption.h"
#include "login_server.h"
extern LoginServer server;
extern Database database;
class AccountManagement {
public:
static uint64 CreateLoginServerAccount(LoginAccountContext c);
static uint64 CheckLoginserverUserCredentials(LoginAccountContext c);
static bool UpdateLoginserverUserCredentials(LoginAccountContext c);
static uint64 CheckExternalLoginserverUserCredentials(LoginAccountContext c);
static bool UpdateLoginserverWorldAdminAccountPasswordByName(LoginAccountContext c);
static uint64 HealthCheckUserLogin();
/**
* @param username
* @param password
* @param email
* @param source_loginserver
* @param login_account_id
* @return
*/
static int32 CreateLoginServerAccount(
std::string username,
std::string password,
std::string email = "",
const std::string &source_loginserver = "local",
uint32 login_account_id = 0
);
/**
* @param username
* @param password
* @param email
* @return
*/
static bool CreateLoginserverWorldAdminAccount(
const std::string &username,
const std::string &password,
@@ -37,50 +27,6 @@ public:
const std::string &last_name = "",
const std::string &ip_address = ""
);
/**
* @param in_account_username
* @param in_account_password
* @return
*/
static uint32 CheckLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password,
const std::string &source_loginserver = "local"
);
/**
* @param in_account_username
* @param in_account_password
* @return
*/
static bool UpdateLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password,
const std::string &source_loginserver = "local"
);
/**
* @param in_account_username
* @param in_account_password
* @return
*/
static uint32 CheckExternalLoginserverUserCredentials(
const std::string &in_account_username,
const std::string &in_account_password
);
/**
* @param in_account_username
* @param in_account_password
* @return
*/
static bool UpdateLoginserverWorldAdminAccountPasswordByName(
const std::string &in_account_username,
const std::string &in_account_password
);
static uint32 HealthCheckUserLogin();
};
+242 -378
View File
@@ -1,25 +1,18 @@
#include "client.h"
#include "login_server.h"
#include "../common/misc_functions.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
#include "encryption.h"
#include "account_management.h"
extern LoginServer server;
/**
* @param c
* @param v
*/
Client::Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v)
{
m_connection = c;
m_client_version = v;
m_client_status = cs_not_sent_session_ready;
m_account_id = 0;
m_play_server_id = 0;
m_play_sequence_id = 0;
m_connection = c;
m_client_version = v;
m_client_status = cs_not_sent_session_ready;
m_account_id = 0;
m_selected_play_server_id = 0;
m_play_sequence_id = 0;
}
bool Client::Process()
@@ -43,8 +36,8 @@ bool Client::Process()
switch (app->GetOpcode()) {
case OP_SessionReady: {
LogInfo("Session ready received from client account {}", GetClientDescription());
Handle_SessionReady((const char *) app->pBuffer, app->Size());
LogInfo("Session ready received from client account {}", GetClientLoggingDescription());
HandleSessionReady((const char *) app->pBuffer, app->Size());
break;
}
case OP_Login: {
@@ -53,9 +46,9 @@ bool Client::Process()
break;
}
LogInfo("Login received from client {}", GetClientDescription());
LogInfo("Login received from client {}", GetClientLoggingDescription());
Handle_Login((const char *) app->pBuffer, app->Size());
HandleLogin((const char *) app->pBuffer, app->Size());
break;
}
case OP_ServerListRequest: {
@@ -64,18 +57,18 @@ bool Client::Process()
break;
}
LogInfo("Server list request received from client {}", GetClientDescription());
LogInfo("Server list request received from client {}", GetClientLoggingDescription());
SendServerListPacket(*(uint32_t *) app->pBuffer);
break;
}
case OP_PlayEverquestRequest: {
if (app->Size() < sizeof(PlayEverquestRequest_Struct)) {
if (app->Size() < sizeof(PlayEverquestRequest)) {
LogError("Play received but it is too small, discarding");
break;
}
Handle_Play((const char *) app->pBuffer);
SendPlayToWorld((const char *) app->pBuffer);
break;
}
}
@@ -87,13 +80,7 @@ bool Client::Process()
return true;
}
/**
* Sends our reply to session ready packet
*
* @param data
* @param size
*/
void Client::Handle_SessionReady(const char *data, unsigned int size)
void Client::HandleSessionReady(const char *data, unsigned int size)
{
if (m_client_status != cs_not_sent_session_ready) {
LogError("Session ready received again after already being received");
@@ -107,11 +94,8 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
m_client_status = cs_waiting_for_login;
/**
* The packets are identical between the two versions
*/
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply_Struct));
auto buf = reinterpret_cast<LoginHandShakeReply_Struct*>(outapp->pBuffer);
auto *outapp = new EQApplicationPacket(OP_ChatMessage, sizeof(LoginHandShakeReply));
auto buf = reinterpret_cast<LoginHandShakeReply *>(outapp->pBuffer);
buf->base_header.sequence = 0x02;
buf->base_reply.success = true;
buf->base_reply.error_str_id = 0x65; // 101 "No Error"
@@ -120,13 +104,7 @@ void Client::Handle_SessionReady(const char *data, unsigned int size)
delete outapp;
}
/**
* Verifies login and send a reply
*
* @param data
* @param size
*/
void Client::Handle_Login(const char *data, unsigned int size)
void Client::HandleLogin(const char *data, unsigned int size)
{
if (m_client_status != cs_waiting_for_login) {
LogError("Login received after already having logged in");
@@ -134,41 +112,37 @@ void Client::Handle_Login(const char *data, unsigned int size)
}
// login user/pass are variable length after unencrypted opcode and base message header (size includes opcode)
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage_Struct);
int data_size = size - header_size;
constexpr int header_size = sizeof(uint16_t) + sizeof(LoginBaseMessage);
int data_size = size - header_size;
if (size <= header_size) {
LogError("Login received packet of size: {0}, this would cause a buffer overflow, discarding", size);
LogError("Login received packet of size: {}, this would cause a buffer overflow, discarding", size);
return;
}
if (data_size % 8 != 0) {
LogError("Login received packet of size: {0}, this would cause a block corruption, discarding", size);
LogError("Login received packet of size: {}, this would cause a block corruption, discarding", size);
return;
}
char *login_packet_buffer = nullptr;
unsigned int db_account_id = 0;
std::string db_loginserver = "local";
if (server.options.CanAutoLinkAccounts()) {
if (std::getenv("LSPX")) {
db_loginserver = "eqemu";
}
std::string db_account_password_hash;
std::string outbuffer;
outbuffer.resize(data_size);
if (outbuffer.length() == 0) {
if (outbuffer.empty()) {
LogError("Corrupt buffer sent to server, no length");
return;
}
// data starts at base message header (opcode not included)
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage_Struct), data_size, &outbuffer[0], 0);
auto r = eqcrypt_block(data + sizeof(LoginBaseMessage), data_size, &outbuffer[0], false);
if (r == nullptr) {
LogError("Failed to decrypt eqcrypt block");
return;
@@ -182,131 +156,114 @@ void Client::Handle_Login(const char *data, unsigned int size)
return;
}
// std::cout << "User: " << user << std::endl;
// only need to copy the base header for reply options, ignore login info
memcpy(&m_llrs, data, sizeof(LoginBaseMessage_Struct));
memcpy(&m_login_base_message, data, sizeof(LoginBaseMessage));
bool result = false;
if (outbuffer[0] == 0 && outbuffer[1] == 0) {
// std::cout << "Seq: " << m_login_base_message.sequence << std::endl;
// std::cout << "compressed: " << m_login_base_message.compressed << std::endl;
// std::cout << "encrypt_type: " << m_login_base_message.encrypt_type << std::endl;
// std::cout << "unk3: " << m_login_base_message.unk3 << std::endl;
bool login_success = false;
bool token_login = outbuffer[0] == 0 && outbuffer[1] == 0;
if (token_login) {
if (server.options.IsTokenLoginAllowed()) {
cred = (&outbuffer[2 + user.length()]);
result = server.db->GetLoginTokenDataFromToken(
cred,
m_connection->GetRemoteAddr(),
db_account_id,
db_loginserver,
user
);
cred = (&outbuffer[2 + user.length()]);
// todo: implement token login
// SELECT login_server, username, account_id FROM login_tickets WHERE expires > NOW() AND id='{}' AND ip_address='{}' LIMIT 1
// login_success ? DoSuccessfulLogin(user, db_account_id, db_loginserver) : SendFailedLogin();
SendFailedLogin();
}
return;
}
else {
if (server.options.IsPasswordLoginAllowed()) {
cred = (&outbuffer[1 + user.length()]);
auto components = Strings::Split(user, ':');
if (components.size() == 2) {
db_loginserver = components[0];
user = components[1];
}
// health checks
if (ProcessHealthCheck(user)) {
DoFailedLogin();
return;
}
// normal login
cred = (&outbuffer[1 + user.length()]);
auto components = Strings::Split(user, ':');
if (components.size() == 2) {
db_loginserver = components[0];
user = components[1];
}
LogInfo(
"Attempting password based login [{0}] login [{1}]",
user,
db_loginserver
);
// health checks
if (ProcessHealthCheck(user)) {
SendFailedLogin();
return;
}
ParseAccountString(user, user, db_loginserver);
LogInfo(
"Attempting password based login [{}] login [{}]",
user,
db_loginserver
);
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id)) {
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
ParseAccountString(user, user, db_loginserver);
#ifdef LSPX
// if user updated their password on the login server, update it here by validating their credentials with the login server
if (!result && db_loginserver == "eqemu") {
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(user, cred);
if (account_id > 0) {
auto encryption_mode = server.options.GetEncryptionMode();
server.db->UpdateLoginserverAccountPasswordHash(
user,
db_loginserver,
eqcrypt_hash(user, cred, encryption_mode)
);
LogInfo("Updating eqemu account [{}] password hash", account_id);
result = true;
}
LoginAccountContext c = {};
c.username = user;
c.password = cred;
c.source_loginserver = db_loginserver;
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
if (a.id > 0) {
login_success = VerifyAndUpdateLoginHash(c, a);
// if user updated their password on the login server, update it here by validating their credentials with the login server
if (std::getenv("LSPX") && !login_success && db_loginserver == "eqemu") {
LogInfo("LSPX | Attempting login account via [{}]", db_loginserver);
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
LogInfo("LSPX | External login account id [{}]", account_id);
if (account_id > 0) {
auto updated_account = LoginAccountsRepository::UpdateAccountPassword(database, a, cred);
if (!updated_account.id) {
LogError("Failed to update eqemu account [{}] password hash", account_id);
SendFailedLogin();
return;
}
#endif
LogDebug("Success [{0}]", (result ? "true" : "false"));
}
else {
m_client_status = cs_creating_account;
AttemptLoginAccountCreation(user, cred, db_loginserver);
LogInfo("Updating eqemu account [{}] password hash", account_id);
DoSuccessfulLogin(updated_account);
return;
}
}
LogInfo("Successful login [{}]", (login_success ? "true" : "false"));
login_success ? DoSuccessfulLogin(a) : SendFailedLogin();
return;
}
/**
* Login accepted
*/
if (result) {
LogInfo(
"login [{0}] user [{1}] Login succeeded",
db_loginserver,
user
);
DoSuccessfulLogin(user, db_account_id, db_loginserver);
}
else {
LogInfo(
"login [{0}] user [{1}] Login failed",
db_loginserver,
user
);
DoFailedLogin();
}
// if we are here, the account does not exist
m_client_status = cs_creating_account;
AttemptLoginAccountCreation(c);
}
/**
* Sends a packet to the requested server to see if the client is allowed or not
*
* @param data
*/
void Client::Handle_Play(const char *data)
void Client::SendPlayToWorld(const char *data)
{
if (m_client_status != cs_logged_in) {
LogError("Client sent a play request when they were not logged in, discarding");
return;
}
const auto *play = (const PlayEverquestRequest_Struct *) data;
const auto *play = (const PlayEverquestRequest *) data;
auto server_id_in = (unsigned int) play->server_number;
auto sequence_in = (unsigned int) play->base_header.sequence;
LogInfo(
"[Handle_Play] Play received from client [{}] server number [{}] sequence [{}]",
"[SendPlayToWorld] Play received from client [{}] server number [{}] sequence [{}]",
GetAccountName(),
server_id_in,
sequence_in
);
m_play_server_id = (unsigned int) play->server_number;
m_play_sequence_id = sequence_in;
m_play_server_id = server_id_in;
server.server_manager->SendUserToWorldRequest(server_id_in, m_account_id, m_loginserver_name);
m_selected_play_server_id = (unsigned int) play->server_number;
m_play_sequence_id = sequence_in;
m_selected_play_server_id = server_id_in;
server.server_manager->SendUserLoginToWorldRequest(server_id_in, m_account_id, m_loginserver_name);
}
/**
* @param seq
*/
void Client::SendServerListPacket(uint32 seq)
{
auto app = server.server_manager->CreateServerListPacket(this, seq);
@@ -316,11 +273,11 @@ void Client::SendServerListPacket(uint32 seq)
void Client::SendPlayResponse(EQApplicationPacket *outapp)
{
LogInfo("Sending play response for {}", GetClientDescription());
LogInfo("Sending play response for {}", GetClientLoggingDescription());
m_connection->QueuePacket(outapp);
}
void Client::GenerateKey()
void Client::GenerateRandomLoginKey()
{
m_key.clear();
int count = 0;
@@ -339,229 +296,193 @@ void Client::GenerateKey()
}
}
/**
* @param user
* @param pass
* @param loginserver
*/
void Client::AttemptLoginAccountCreation(
const std::string &user,
const std::string &pass,
const std::string &loginserver
)
void Client::AttemptLoginAccountCreation(LoginAccountContext c)
{
LogInfo("user [{}] loginserver [{}]", user, loginserver);
LogInfo("user [{}] loginserver [{}]", c.username, c.source_loginserver);
#ifdef LSPX
if (loginserver == "eqemu") {
LogInfo("Attempting login account creation via '{0}'", loginserver);
if (!server.options.CanAutoLinkAccounts()) {
LogInfo("CanAutoLinkAccounts disabled - sending failed login");
DoFailedLogin();
return;
}
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
user,
pass
);
if (std::getenv("LSPX") && c.source_loginserver == "eqemu") {
LogInfo("LSPX | Attempting login account creation via [{}]", c.source_loginserver);
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
c.login_account_id = account_id;
if (account_id > 0) {
LogInfo("Found and creating eqemu account [{}]", account_id);
CreateEQEmuAccount(user, pass, account_id);
LogInfo("LSPX | Found and creating eqemu account [{}]", account_id);
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
if (a.id > 0) {
DoSuccessfulLogin(a);
return;
}
}
LogInfo("LSPX | External authentication failed for user [{}]", c.username);
SendFailedLogin();
return;
}
if (server.options.CanAutoCreateAccounts() && c.source_loginserver == "local") {
LogInfo("CanAutoCreateAccounts enabled, attempting to crate account [{}]", c.username);
auto a = LoginAccountsRepository::CreateAccountFromContext(database, c);
if (a.id > 0) {
DoSuccessfulLogin(a);
return;
}
DoFailedLogin();
return;
}
#endif
if (server.options.CanAutoCreateAccounts() && loginserver == "local") {
LogInfo("CanAutoCreateAccounts enabled, attempting to creating account [{0}]", user);
CreateLocalAccount(user, pass);
return;
}
DoFailedLogin();
SendFailedLogin();
}
void Client::DoFailedLogin()
void Client::SendFailedLogin()
{
m_stored_user.clear();
m_stored_pass.clear();
m_stored_username.clear();
m_stored_password.clear();
// unencrypted
LoginBaseMessage_Struct base_header{};
base_header.sequence = m_llrs.sequence; // login (3)
base_header.encrypt_type = m_llrs.encrypt_type;
LoginBaseMessage h{};
h.sequence = m_login_base_message.sequence; // login (3)
h.encrypt_type = m_login_base_message.encrypt_type;
// encrypted
PlayerLoginReply_Struct login_reply{};
login_reply.base_reply.success = false;
login_reply.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
PlayerLoginReply r{};
r.base_reply.success = false;
r.base_reply.error_str_id = 105; // Error - The username and/or password were not valid
char encrypted_buffer[80] = {0};
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block for failed login");
}
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
EQApplicationPacket outapp(OP_LoginAccepted, outsize);
outapp.WriteData(&base_header, sizeof(base_header));
outapp.WriteData(&h, sizeof(h));
outapp.WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
m_connection->QueuePacket(&outapp);
m_client_status = cs_failed_to_login;
}
/**
* Verifies a login hash, will also attempt to update a login hash if needed
*
* @param account_username
* @param source_loginserver
* @param account_password
* @param password_hash
* @return
*/
bool Client::VerifyLoginHash(
const std::string &account_username,
const std::string &source_loginserver,
const std::string &account_password,
const std::string &password_hash
)
bool Client::VerifyAndUpdateLoginHash(LoginAccountContext c, const LoginAccountsRepository::LoginAccounts &a)
{
auto encryption_mode = server.options.GetEncryptionMode();
if (eqcrypt_verify_hash(account_username, account_password, password_hash, encryption_mode)) {
if (eqcrypt_verify_hash(a.account_name, c.password, a.account_password, encryption_mode)) {
return true;
}
else {
if (server.options.IsUpdatingInsecurePasswords()) {
if (encryption_mode < EncryptionModeArgon2) {
encryption_mode = EncryptionModeArgon2;
}
uint32 insecure_source_encryption_mode = 0;
if (password_hash.length() == CryptoHash::md5_hash_length) {
for (int i = EncryptionModeMD5; i <= EncryptionModeMD5Triple; ++i) {
if (i != encryption_mode &&
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
insecure_source_encryption_mode = i;
}
}
}
else if (password_hash.length() == CryptoHash::sha1_hash_length && insecure_source_encryption_mode == 0) {
for (int i = EncryptionModeSHA; i <= EncryptionModeSHATriple; ++i) {
if (i != encryption_mode &&
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
insecure_source_encryption_mode = i;
}
}
}
else if (password_hash.length() == CryptoHash::sha512_hash_length && insecure_source_encryption_mode == 0) {
for (int i = EncryptionModeSHA512; i <= EncryptionModeSHA512Triple; ++i) {
if (i != encryption_mode &&
eqcrypt_verify_hash(account_username, account_password, password_hash, i)) {
insecure_source_encryption_mode = i;
}
}
}
if (encryption_mode < EncryptionModeArgon2) {
encryption_mode = EncryptionModeArgon2;
}
if (insecure_source_encryption_mode > 0) {
LogInfo(
"[{}] Updated insecure password user [{}] loginserver [{}] from mode [{}] ({}) to mode [{}] ({})",
__func__,
account_username,
source_loginserver,
GetEncryptionByModeId(insecure_source_encryption_mode),
insecure_source_encryption_mode,
GetEncryptionByModeId(encryption_mode),
encryption_mode
);
uint32 insecure_source_encryption_mode = 0;
server.db->UpdateLoginserverAccountPasswordHash(
account_username,
source_loginserver,
eqcrypt_hash(
account_username,
account_password,
encryption_mode
)
);
return true;
auto verify_encryption_mode = [&](int start, int end) {
for (int i = start; i <= end; ++i) {
if (i != encryption_mode && eqcrypt_verify_hash(a.account_name, c.password, a.account_password, i)) {
insecure_source_encryption_mode = i;
}
}
};
switch (a.account_password.length()) {
case CryptoHash::md5_hash_length:
verify_encryption_mode(EncryptionModeMD5, EncryptionModeMD5Triple);
break;
case CryptoHash::sha1_hash_length:
if (insecure_source_encryption_mode == 0) {
verify_encryption_mode(EncryptionModeSHA, EncryptionModeSHATriple);
}
break;
case CryptoHash::sha512_hash_length:
if (insecure_source_encryption_mode == 0) {
verify_encryption_mode(EncryptionModeSHA512, EncryptionModeSHA512Triple);
}
break;
}
if (insecure_source_encryption_mode > 0) {
LogInfo(
"Updated insecure password user [{}] loginserver [{}] from mode [{}] ({}) to mode [{}] ({})",
c.username,
c.source_loginserver,
GetEncryptionByModeId(insecure_source_encryption_mode),
insecure_source_encryption_mode,
GetEncryptionByModeId(encryption_mode),
encryption_mode
);
LoginAccountsRepository::UpdateAccountPassword(database, a, c.password);
return true;
}
return false;
}
/**
* @param in_account_name
* @param db_account_id
* @param db_loginserver
*/
void Client::DoSuccessfulLogin(
const std::string& in_account_name,
int db_account_id,
const std::string &db_loginserver
)
void Client::DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts &a)
{
m_stored_user.clear();
m_stored_pass.clear();
m_stored_username.clear();
m_stored_password.clear();
server.client_manager->RemoveExistingClient(db_account_id, db_loginserver);
LogInfo(
"Successful login for user id [{}] account name [{}] login server [{}]",
a.id,
a.account_name,
a.source_loginserver
);
server.client_manager->RemoveExistingClient(a.id, a.source_loginserver);
in_addr in{};
in.s_addr = m_connection->GetRemoteIP();
server.db->UpdateLSAccountData(db_account_id, std::string(inet_ntoa(in)));
GenerateKey();
a.last_ip_address = std::string(inet_ntoa(in));
LoginAccountsRepository::UpdateOne(database, a);
m_account_id = db_account_id;
m_account_name = in_account_name;
m_loginserver_name = db_loginserver;
GenerateRandomLoginKey();
m_account_id = a.id;
m_account_name = a.account_name;
m_loginserver_name = a.source_loginserver;
// unencrypted
LoginBaseMessage_Struct base_header{};
base_header.sequence = m_llrs.sequence;
base_header.compressed = false;
base_header.encrypt_type = m_llrs.encrypt_type;
base_header.unk3 = m_llrs.unk3;
LoginBaseMessage h{};
h.sequence = m_login_base_message.sequence;
h.compressed = false;
h.encrypt_type = m_login_base_message.encrypt_type;
h.unk3 = m_login_base_message.unk3;
// not serializing any of the variable length strings so just use struct directly
PlayerLoginReply_Struct login_reply{};
login_reply.base_reply.success = true;
login_reply.base_reply.error_str_id = 101; // No Error
login_reply.unk1 = 0;
login_reply.unk2 = 0;
login_reply.lsid = db_account_id;
login_reply.failed_attempts = 0;
login_reply.show_player_count = server.options.IsShowPlayerCountEnabled();
login_reply.offer_min_days = 99;
login_reply.offer_min_views = -1;
login_reply.offer_cooldown_minutes = 0;
login_reply.web_offer_number = 0;
login_reply.web_offer_min_days = 99;
login_reply.web_offer_min_views = -1;
login_reply.web_offer_cooldown_minutes = 0;
memcpy(login_reply.key, m_key.c_str(), m_key.size());
PlayerLoginReply r{};
r.base_reply.success = true;
r.base_reply.error_str_id = 101; // No Error
r.unk1 = 0;
r.unk2 = 0;
r.lsid = a.id;
r.failed_attempts = 0;
r.show_player_count = server.options.IsShowPlayerCountEnabled();
r.offer_min_days = 99;
r.offer_min_views = -1;
r.offer_cooldown_minutes = 0;
r.web_offer_number = 0;
r.web_offer_min_days = 99;
r.web_offer_min_views = -1;
r.web_offer_cooldown_minutes = 0;
memcpy(r.key, m_key.c_str(), m_key.size());
SendExpansionPacketData(login_reply);
SendExpansionPacketData(r);
char encrypted_buffer[80] = {0};
auto rc = eqcrypt_block((const char*)&login_reply, sizeof(login_reply), encrypted_buffer, 1);
auto rc = eqcrypt_block((const char *) &r, sizeof(r), encrypted_buffer, 1);
if (rc == nullptr) {
LogDebug("Failed to encrypt eqcrypt block");
}
constexpr int outsize = sizeof(LoginBaseMessage_Struct) + sizeof(encrypted_buffer);
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
outapp->WriteData(&base_header, sizeof(base_header));
constexpr int outsize = sizeof(LoginBaseMessage) + sizeof(encrypted_buffer);
auto outapp = std::make_unique<EQApplicationPacket>(OP_LoginAccepted, outsize);
outapp->WriteData(&h, sizeof(h));
outapp->WriteData(&encrypted_buffer, sizeof(encrypted_buffer));
m_connection->QueuePacket(outapp.get());
@@ -569,19 +490,21 @@ void Client::DoSuccessfulLogin(
m_client_status = cs_logged_in;
}
void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
void Client::SendExpansionPacketData(PlayerLoginReply &plrs)
{
SerializeBuffer buf;
//from eqlsstr_us.txt id of each expansion, excluding 'Everquest'
int ExpansionLookup[20] = { 3007, 3008, 3009, 3010, 3012,
3014, 3031, 3033, 3036, 3040,
3045, 3046, 3047, 3514, 3516,
3518, 3520, 3522, 3524 };
int ExpansionLookup[20] = {
3007, 3008, 3009, 3010, 3012,
3014, 3031, 3033, 3036, 3040,
3045, 3046, 3047, 3514, 3516,
3518, 3520, 3522, 3524
};
if (server.options.IsDisplayExpansions()) {
int32_t expansion = server.options.GetMaxExpansions();
int32_t expansion = server.options.GetMaxExpansions();
int32_t owned_expansion = (expansion << 1) | 1;
if (m_client_version == cv_sod) {
@@ -593,15 +516,14 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
buf.WriteInt32(19); //number of expansions to include in packet
//generate expansion data
for (int i = 0; i < 19; i++)
{
buf.WriteInt32(i); //sequenctial number
buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own
for (int i = 0; i < 19; i++) {
buf.WriteInt32(i); //sequenctial number
buf.WriteInt32((expansion & (1 << i)) == (1 << i) ? 0x01 : 0x00); //1 own 0 not own
buf.WriteInt8(0x00);
buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt
buf.WriteInt32(0x179E); //from eqlsstr_us.txt for buttons/order
buf.WriteInt32(0xFFFFFFFF); //end identification
buf.WriteInt8(0x0); //force order window to appear 1 appear 0 not appear
buf.WriteInt32(ExpansionLookup[i]); //from eqlsstr_us.txt
buf.WriteInt32(0x179E); //from eqlsstr_us.txt for buttons/order
buf.WriteInt32(0xFFFFFFFF); //end identification
buf.WriteInt8(0x0); //force order window to appear 1 appear 0 not appear
buf.WriteInt8(0x0);
buf.WriteInt32(0x0000);
buf.WriteInt32(0x0000);
@@ -612,79 +534,21 @@ void Client::SendExpansionPacketData(PlayerLoginReply_Struct& plrs)
m_connection->QueuePacket(out.get());
}
else if (m_client_version == cv_titanium)
{
if (expansion >= EQ::expansions::bitPoR)
{
else if (m_client_version == cv_titanium) {
if (expansion >= EQ::expansions::bitPoR) {
// Titanium shipped with 10 expansions. Set owned expansions to be max 10.
plrs.offer_min_days = ((EQ::expansions::bitDoD << 2) | 1) - 2;
}
else
{
else {
plrs.offer_min_days = owned_expansion;
}
// Titanium shipped with 10 expansions. Set owned expansions to be max 10.
plrs.web_offer_min_views = ((EQ::expansions::bitDoD << 2) | 1) - 2;
}
}
}
/**
* @param username
* @param password
*/
void Client::CreateLocalAccount(const std::string &username, const std::string &password)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(username, password, mode);
unsigned int db_id = 0;
if (!server.db->CreateLoginData(username, hash, "local", db_id)) {
DoFailedLogin();
}
else {
DoSuccessfulLogin(username, db_id, "local");
}
}
/**
* @param in_account_name
* @param in_account_password
* @param loginserver_account_id
*/
void Client::CreateEQEmuAccount(
const std::string &in_account_name,
const std::string &in_account_password,
unsigned int loginserver_account_id
)
{
auto mode = server.options.GetEncryptionMode();
auto hash = eqcrypt_hash(in_account_name, in_account_password, mode);
if (server.db->DoesLoginServerAccountExist(in_account_name, hash, "eqemu", loginserver_account_id)) {
DoSuccessfulLogin(in_account_name, loginserver_account_id, "eqemu");
return;
}
if (!server.db->CreateLoginDataWithID(in_account_name, hash, "eqemu", loginserver_account_id)) {
DoFailedLogin();
}
else {
DoSuccessfulLogin(in_account_name, loginserver_account_id, "eqemu");
}
}
bool Client::ProcessHealthCheck(std::string username)
{
if (username == "healthcheckuser") {
return true;
}
return false;
}
std::string Client::GetClientDescription()
std::string Client::GetClientLoggingDescription()
{
in_addr in{};
in.s_addr = GetConnection()->GetRemoteIP();
+34 -178
View File
@@ -8,204 +8,60 @@
#include "../common/net/dns.h"
#include "../common/net/daybreak_connection.h"
#include "login_types.h"
#include "../common/repositories/login_accounts_repository.h"
#include <memory>
/**
* Client class, controls a single client and it's connection to the login server
*/
class Client {
public:
/**
* Constructor, sets our connection to c and version to v
*
* @param c
* @param v
*/
Client(std::shared_ptr<EQStreamInterface> c, LSClientVersion v);
/**
* Destructor
*/
~Client() {}
/**
* Processes the client's connection and does various actions
*
* @return
*/
bool Process();
void HandleSessionReady(const char *data, unsigned int size);
void HandleLogin(const char *data, unsigned int size);
/**
* Sends our reply to session ready packet
*
* @param data
* @param size
*/
void Handle_SessionReady(const char *data, unsigned int size);
/**
* Verifies login and send a reply
*
* @param data
* @param size
*/
void Handle_Login(const char *data, unsigned int size);
/**
* Sends the expansion data packet
*
* Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy)
* Rof uses a seperate data packet specifically for the expansion data
* Live, as of July 2021 uses a similar but slightly different seperate data packet
*
* @param PlayerLoginReply_Struct
*
*/
void SendExpansionPacketData(PlayerLoginReply_Struct& plrs);
/**
* Sends a packet to the requested server to see if the client is allowed or not
*
* @param data
*/
void Handle_Play(const char *data);
/**
* Sends a server list packet to the client
*
* @param seq
*/
// Sends the expansion data packet
// Titanium uses the encrypted data block to contact the expansion (You own xxx:) and the max expansions (of yyy)
// Rof uses a separate data packet specifically for the expansion data
// Live, as of July 2021 uses a similar but slightly different seperate data packet
void SendExpansionPacketData(PlayerLoginReply &plrs);
void SendPlayToWorld(const char *data);
void SendServerListPacket(uint32 seq);
/**
* Sends the input packet to the client and clears our play response states
*
* @param outapp
*/
void SendPlayResponse(EQApplicationPacket *outapp);
/**
* Generates a random login key for the client during login
*/
void GenerateKey();
/**
* Gets the account id of this client
*
* @return
*/
void GenerateRandomLoginKey();
unsigned int GetAccountID() const { return m_account_id; }
/**
* Gets the loginserver name of this client
*
* @return
*/
std::string GetLoginServerName() const { return m_loginserver_name; }
/**
* Gets the account name of this client
*
* @return
*/
std::string GetAccountName() const { return m_account_name; }
/**
* Returns a description for the client for logging
* @return std::string
*/
std::string GetClientDescription();
/**
* Gets the key generated at login for this client
*
* @return
*/
std::string GetKey() const { return m_key; }
/**
* Gets the server selected to be played on for this client
*
* @return
*/
unsigned int GetPlayServerID() const { return m_play_server_id; }
/**
* Gets the play sequence state for this client
*
* @return
*/
unsigned int GetPlaySequence() const { return m_play_sequence_id; }
/**
* Gets the client version
*
* @return
*/
std::string GetClientLoggingDescription();
std::string GetLoginKey() const { return m_key; }
unsigned int GetSelectedPlayServerID() const { return m_selected_play_server_id; }
unsigned int GetCurrentPlaySequence() const { return m_play_sequence_id; }
LSClientVersion GetClientVersion() const { return m_client_version; }
/**
* Gets the connection for this client
*
* @return
*/
std::shared_ptr<EQStreamInterface> GetConnection() { return m_connection; }
/**
* Attempts to create a login account
*
* @param user
* @param pass
* @param loginserver
*/
void AttemptLoginAccountCreation(const std::string &user, const std::string &pass, const std::string &loginserver);
/**
* Does a failed login
*/
void DoFailedLogin();
/**
* Verifies a login hash, will also attempt to update a login hash if needed
*
* @param account_username
* @param source_loginserver
* @param account_password
* @param password_hash
* @return
*/
bool VerifyLoginHash(
const std::string &account_username,
const std::string &source_loginserver,
const std::string &account_password,
const std::string &password_hash
);
void DoSuccessfulLogin(const std::string& in_account_name, int db_account_id, const std::string &db_loginserver);
void CreateLocalAccount(const std::string &username, const std::string &password);
void CreateEQEmuAccount(const std::string &in_account_name, const std::string &in_account_password, unsigned int loginserver_account_id);
void AttemptLoginAccountCreation(LoginAccountContext c);
void SendFailedLogin();
bool VerifyAndUpdateLoginHash(LoginAccountContext c, const LoginAccountsRepository::LoginAccounts& a);
void DoSuccessfulLogin(LoginAccountsRepository::LoginAccounts& a);
private:
EQ::Random m_random;
std::shared_ptr<EQStreamInterface> m_connection;
LSClientVersion m_client_version;
LSClientStatus m_client_status;
std::string m_account_name;
unsigned int m_account_id;
std::string m_loginserver_name;
unsigned int m_play_server_id;
unsigned int m_play_sequence_id;
std::string m_key;
EQ::Random m_random;
std::shared_ptr<EQStreamInterface> m_connection;
LSClientVersion m_client_version;
LSClientStatus m_client_status;
std::string m_account_name;
unsigned int m_account_id;
std::string m_loginserver_name;
unsigned int m_selected_play_server_id;
unsigned int m_play_sequence_id;
std::string m_key;
std::unique_ptr<EQ::Net::DaybreakConnectionManager> m_login_connection_manager;
std::shared_ptr<EQ::Net::DaybreakConnection> m_login_connection;
LoginBaseMessage_Struct m_llrs;
std::string m_stored_user;
std::string m_stored_pass;
static bool ProcessHealthCheck(std::string username);
LoginBaseMessage m_login_base_message;
std::string m_stored_username;
std::string m_stored_password;
static bool ProcessHealthCheck(std::string username) {
return username == "healthcheckuser";
}
};
#endif
+61 -79
View File
@@ -4,12 +4,12 @@
extern LoginServer server;
extern bool run_server;
#include "../common/eqemu_logsys.h"
#include "../common/misc.h"
#include "../common/path_manager.h"
#include "../common/file.h"
void CheckTitaniumOpcodeFile(const std::string &path) {
void CheckTitaniumOpcodeFile(const std::string &path)
{
if (File::Exists(path)) {
return;
}
@@ -32,7 +32,8 @@ void CheckTitaniumOpcodeFile(const std::string &path) {
}
}
void CheckSoDOpcodeFile(const std::string& path) {
void CheckSoDOpcodeFile(const std::string &path)
{
if (File::Exists(path)) {
return;
}
@@ -56,7 +57,8 @@ void CheckSoDOpcodeFile(const std::string& path) {
}
}
void CheckLarionOpcodeFile(const std::string& path) {
void CheckLarionOpcodeFile(const std::string &path)
{
if (File::Exists(path)) {
return;
}
@@ -87,8 +89,8 @@ ClientManager::ClientManager()
EQStreamManagerInterfaceOptions titanium_opts(titanium_port, false, false);
titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
titanium_ops = new RegularOpcodeManager;
m_titanium_stream = new EQ::Net::EQStreamManager(titanium_opts);
m_titanium_ops = new RegularOpcodeManager;
std::string opcodes_path = fmt::format(
"{}/{}",
@@ -98,34 +100,34 @@ ClientManager::ClientManager()
CheckTitaniumOpcodeFile(opcodes_path);
if (!titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
if (!m_titanium_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for Titanium file [{0}]",
"ClientManager fatal error: couldn't load opcodes for Titanium file [{}]",
server.config.GetVariableString("client_configuration", "titanium_opcodes", "login_opcodes.conf")
);
run_server = false;
}
titanium_stream->OnNewConnection(
m_titanium_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo(
"New Titanium client connection from [{0}:{1}]",
"New Titanium client connection from [{}:{}]",
long2ip(stream->GetRemoteIP()),
stream->GetRemotePort()
);
stream->SetOpcodeManager(&titanium_ops);
stream->SetOpcodeManager(&m_titanium_ops);
Client *c = new Client(stream, cv_titanium);
clients.push_back(c);
m_clients.push_back(c);
}
);
int sod_port = server.config.GetVariableInt("client_configuration", "sod_port", 5999);
EQStreamManagerInterfaceOptions sod_opts(sod_port, false, false);
sod_stream = new EQ::Net::EQStreamManager(sod_opts);
sod_ops = new RegularOpcodeManager;
m_sod_stream = new EQ::Net::EQStreamManager(sod_opts);
m_sod_ops = new RegularOpcodeManager;
opcodes_path = fmt::format(
"{}/{}",
@@ -135,26 +137,26 @@ ClientManager::ClientManager()
CheckSoDOpcodeFile(opcodes_path);
if (!sod_ops->LoadOpcodes(opcodes_path.c_str())) {
if (!m_sod_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for SoD file {0}",
"ClientManager fatal error: couldn't load opcodes for SoD file {}",
server.config.GetVariableString("client_configuration", "sod_opcodes", "login_opcodes.conf").c_str()
);
run_server = false;
}
sod_stream->OnNewConnection(
m_sod_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo(
"New SoD+ client connection from [{0}:{1}]",
"New SoD+ client connection from [{}:{}]",
long2ip(stream->GetRemoteIP()),
stream->GetRemotePort()
);
stream->SetOpcodeManager(&sod_ops);
stream->SetOpcodeManager(&m_sod_ops);
auto *c = new Client(stream, cv_sod);
clients.push_back(c);
m_clients.push_back(c);
}
);
@@ -162,8 +164,8 @@ ClientManager::ClientManager()
EQStreamManagerInterfaceOptions larion_opts(larion_port, false, false);
larion_stream = new EQ::Net::EQStreamManager(larion_opts);
larion_ops = new RegularOpcodeManager;
m_larion_stream = new EQ::Net::EQStreamManager(larion_opts);
m_larion_ops = new RegularOpcodeManager;
opcodes_path = fmt::format(
"{}/{}",
@@ -173,115 +175,95 @@ ClientManager::ClientManager()
CheckLarionOpcodeFile(opcodes_path);
if (!larion_ops->LoadOpcodes(opcodes_path.c_str())) {
if (!m_larion_ops->LoadOpcodes(opcodes_path.c_str())) {
LogError(
"ClientManager fatal error: couldn't load opcodes for Larion file [{0}]",
"ClientManager fatal error: couldn't load opcodes for Larion file [{}]",
server.config.GetVariableString("client_configuration", "larion_opcodes", "login_opcodes.conf")
);
run_server = false;
}
larion_stream->OnNewConnection(
m_larion_stream->OnNewConnection(
[this](std::shared_ptr<EQ::Net::EQStream> stream) {
LogInfo(
"New Larion client connection from [{0}:{1}]",
"New Larion client connection from [{}:{}]",
long2ip(stream->GetRemoteIP()),
stream->GetRemotePort()
);
stream->SetOpcodeManager(&larion_ops);
Client* c = new Client(stream, cv_larion);
clients.push_back(c);
stream->SetOpcodeManager(&m_larion_ops);
Client *c = new Client(stream, cv_larion);
m_clients.push_back(c);
}
);
}
ClientManager::~ClientManager()
{
if (titanium_stream) {
delete titanium_stream;
}
if (titanium_ops) {
delete titanium_ops;
}
if (sod_stream) {
delete sod_stream;
}
if (sod_ops) {
delete sod_ops;
}
delete m_titanium_stream;
delete m_titanium_ops;
delete m_sod_stream;
delete m_sod_ops;
}
void ClientManager::Process()
{
ProcessDisconnect();
auto iter = clients.begin();
while (iter != clients.end()) {
if ((*iter)->Process() == false) {
for (auto it = m_clients.begin(); it != m_clients.end();) {
Client *c = *it;
if (!c->Process()) {
LogWarning("Client had a fatal error and had to be removed from the login");
delete (*iter);
iter = clients.erase(iter);
delete c;
it = m_clients.erase(it);
}
else {
++iter;
++it;
}
}
}
void ClientManager::ProcessDisconnect()
{
auto iter = clients.begin();
while (iter != clients.end()) {
std::shared_ptr<EQStreamInterface> c = (*iter)->GetConnection();
if (c->CheckState(CLOSED)) {
auto it = m_clients.begin();
while (it != m_clients.end()) {
Client *c = *it;
if (c->GetConnection()->CheckState(CLOSED)) {
LogInfo("Client disconnected from the server, removing client");
delete (*iter);
iter = clients.erase(iter);
delete c;
it = m_clients.erase(it);
}
else {
++iter;
++it;
}
}
}
/**
* @param account_id
* @param loginserver
*/
void ClientManager::RemoveExistingClient(unsigned int account_id, const std::string &loginserver)
{
auto iter = clients.begin();
while (iter != clients.end()) {
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
auto it = m_clients.begin();
while (it != m_clients.end()) {
Client *c = *it;
if (c->GetAccountID() == account_id && c->GetLoginServerName() == loginserver) {
LogInfo("Client attempting to log in existing client already logged in, removing existing client");
delete (*iter);
iter = clients.erase(iter);
delete c;
it = m_clients.erase(it);
}
else {
++iter;
++it;
}
}
}
/**
* @param account_id
* @param loginserver
* @return
*/
Client *ClientManager::GetClient(unsigned int account_id, const std::string &loginserver)
{
auto iter = clients.begin();
while (iter != clients.end()) {
if ((*iter)->GetAccountID() == account_id && (*iter)->GetLoginServerName().compare(loginserver) == 0) {
return (*iter);
auto iter = std::find_if(
m_clients.begin(), m_clients.end(),
[&](Client *c) {
return c->GetAccountID() == account_id && c->GetLoginServerName() == loginserver;
}
++iter;
}
);
return nullptr;
return (iter != m_clients.end()) ? *iter : nullptr;
}
+9 -42
View File
@@ -7,56 +7,23 @@
#include "client.h"
#include <list>
/**
* Client manager class, holds all the client objects and does basic processing.
*/
class ClientManager {
public:
/**
* Constructor: sets up the stream factories and opcode managers
*/
ClientManager();
/**
* Destructor: shuts down the streams and opcode managers
*/
~ClientManager();
/**
* Processes every client in the internal list, removes them if necessary.
*/
void Process();
/**
* Removes a client with a certain account id
*
* @param account_id
* @param loginserver
*/
void RemoveExistingClient(unsigned int account_id, const std::string &loginserver);
/**
* Gets a client (if exists) by their account id
*
* @param account_id
* @param loginserver
* @return
*/
Client *GetClient(unsigned int account_id, const std::string &loginserver);
void RemoveExistingClient(unsigned int c, const std::string &loginserver);
Client *GetClient(unsigned int c, const std::string &loginserver);
private:
/**
* Processes disconnected clients, removes them if necessary
*/
void ProcessDisconnect();
std::list<Client *> clients;
OpcodeManager *titanium_ops;
EQ::Net::EQStreamManager *titanium_stream;
OpcodeManager *sod_ops;
EQ::Net::EQStreamManager *sod_stream;
OpcodeManager *larion_ops;
EQ::Net::EQStreamManager* larion_stream;
std::list<Client *> m_clients;
OpcodeManager *m_titanium_ops;
EQ::Net::EQStreamManager *m_titanium_stream;
OpcodeManager *m_sod_ops;
EQ::Net::EQStreamManager *m_sod_stream;
OpcodeManager *m_larion_ops;
EQ::Net::EQStreamManager *m_larion_stream;
};
#endif
-680
View File
@@ -1,680 +0,0 @@
#include "../common/global_define.h"
#include "database.h"
#include "login_server.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
#include "../common/util/uuid.h"
extern LoginServer server;
/**
* Initial connect
*
* @param user
* @param pass
* @param host
* @param port
* @param name
*/
Database::Database(
std::string user,
std::string pass,
std::string host,
std::string port,
std::string name
)
{
uint32 errnum = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
if (!Open(
host.c_str(),
user.c_str(),
pass.c_str(),
name.c_str(),
Strings::ToUnsignedInt(port),
&errnum,
errbuf
)
) {
LogError("Failed to connect to database: Error: [{0}]", errbuf);
exit(1);
}
else {
LogInfo("Using database [{0}] at [{1}:{2}]", name, host, port);
}
}
/**
* Deconstructor
*/
Database::~Database()
{
if (m_database) {
mysql_close(m_database);
}
}
/**
* @param name
* @param loginserver
* @param password
* @param id
* @return
*/
bool Database::GetLoginDataFromAccountInfo(
const std::string &name,
const std::string &loginserver,
std::string &password,
unsigned int &id
)
{
auto query = fmt::format(
"SELECT id, account_password FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}' LIMIT 1",
Strings::Escape(name),
Strings::Escape(loginserver)
);
auto results = QueryDatabase(query);
if (results.RowCount() != 1) {
LogDebug(
"Could not find account for name [{0}] login [{1}]",
name,
loginserver
);
return false;
}
if (!results.Success()) {
return false;
}
auto row = results.begin();
id = Strings::ToUnsignedInt(row[0]);
password = row[1];
LogDebug(
"Found account for name [{0}] login [{1}]",
name,
loginserver
);
return true;
}
/**
* @param token
* @param ip
* @param db_account_id
* @param db_loginserver
* @param user
* @return
*/
bool Database::GetLoginTokenDataFromToken(
const std::string &token,
const std::string &ip,
unsigned int &db_account_id,
std::string &db_loginserver,
std::string &user
)
{
auto query = fmt::format("SELECT login_server, username, account_id FROM login_tickets WHERE expires > NOW()"
" AND id='{0}' AND ip_address='{1}' LIMIT 1",
Strings::Escape(token),
Strings::Escape(ip));
auto results = QueryDatabase(query);
if (results.RowCount() == 0 || !results.Success()) {
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
db_loginserver = row[0];
user = row[1];
db_account_id = Strings::ToUnsignedInt(row[2]);
return true;
}
return false;
}
/**
* @param loginserver
* @return
*/
unsigned int Database::GetFreeID(const std::string &loginserver)
{
auto query = fmt::format(
"SELECT IFNULL(MAX(id), 0) + 1 FROM login_accounts WHERE source_loginserver = '{0}'",
Strings::Escape(loginserver)
);
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) {
return 0;
}
auto row = results.begin();
return Strings::ToUnsignedInt(row[0]);
}
/**
* @param name
* @param password
* @param loginserver
* @param id
* @return
*/
bool Database::CreateLoginData(
const std::string &name,
const std::string &password,
const std::string &loginserver,
unsigned int &id
)
{
uint32 free_id = GetFreeID(loginserver);
id = free_id;
return CreateLoginDataWithID(name, password, loginserver, free_id);
}
/**
* @param name
* @param password
* @param loginserver
* @param email
* @return
*/
uint32 Database::CreateLoginAccount(
const std::string &name,
const std::string &password,
const std::string &loginserver,
const std::string &email
)
{
uint32 free_id = GetFreeID(loginserver);
if (free_id <= 0) {
return 0;
}
auto query = fmt::format(
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
"VALUES ({0}, '{1}', '{2}', '{3}', '{4}', NOW(), '127.0.0.1', NOW())",
free_id,
Strings::Escape(loginserver),
Strings::Escape(name),
Strings::Escape(password),
Strings::Escape(email)
);
auto results = QueryDatabase(query);
return (results.Success() ? free_id : 0);
}
/**
* @param in_account_name
* @param in_account_password
* @param loginserver
* @param id
* @return
*/
bool Database::CreateLoginDataWithID(
const std::string &in_account_name,
const std::string &in_account_password,
const std::string &loginserver,
unsigned int id
)
{
if (id == 0) {
return false;
}
auto query = fmt::format(
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
"VALUES ({0}, '{1}', '{2}', '{3}', 'local_creation', NOW(), '127.0.0.1', NOW())",
id,
Strings::Escape(loginserver),
Strings::Escape(in_account_name),
Strings::Escape(in_account_password)
);
auto results = QueryDatabase(query);
return results.Success();
}
/**
* @param name
* @param password
* @param loginserver
* @param id
* @return
*/
bool Database::DoesLoginServerAccountExist(
const std::string &name,
const std::string &password,
const std::string &loginserver,
unsigned int id
)
{
if (id == 0) {
return false;
}
auto query = fmt::format(
"SELECT account_name FROM login_accounts WHERE account_name = '{0}' AND source_loginserver = '{1}'",
Strings::Escape(name),
Strings::Escape(loginserver)
);
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) {
return false;
}
return true;
}
/**
* @param name
* @param loginserver
* @param hash
*/
void Database::UpdateLoginserverAccountPasswordHash(
const std::string &name,
const std::string &loginserver,
const std::string &hash
)
{
LogDebug(
"name [{0}] loginserver [{1}] hash [{2}]",
name,
loginserver,
hash
);
auto query = fmt::format(
"UPDATE login_accounts SET account_password = '{0}' WHERE account_name = '{1}' AND source_loginserver = '{2}'",
hash,
Strings::Escape(name),
Strings::Escape(loginserver)
);
QueryDatabase(query);
}
/**
* @param short_name
* @param long_name
* @param login_world_server_admin_id
* @return
*/
Database::DbWorldRegistration Database::GetWorldRegistration(
const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id
)
{
auto query = fmt::format(
"SELECT\n"
" WSR.id,\n"
" WSR.tag_description,\n"
" WSR.is_server_trusted,\n"
" SLT.id,\n"
" SLT.description,\n"
" ifnull(WSR.login_server_admin_id, 0) AS login_server_admin_id\n"
"FROM\n"
" login_world_servers AS WSR\n"
" JOIN login_server_list_types AS SLT ON WSR.login_server_list_type_id = SLT.id\n"
"WHERE\n"
" WSR.short_name = '{}' AND WSR.long_name = '{}' AND WSR.login_server_admin_id = {} LIMIT 1",
Strings::Escape(short_name),
Strings::Escape(long_name),
login_world_server_admin_id
);
Database::DbWorldRegistration r{};
auto results = QueryDatabase(query);
if (!results.Success() || results.RowCount() != 1) {
return r;
}
auto row = results.begin();
r.loaded = true;
r.server_id = Strings::ToInt(row[0]);
r.server_description = row[1];
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 = Strings::ToUnsignedInt(row[5]);
if (r.server_admin_id <= 0) {
return r;
}
auto world_registration_query = fmt::format(
"SELECT account_name, account_password FROM login_server_admins WHERE id = {0} LIMIT 1",
r.server_admin_id
);
auto world_registration_results = QueryDatabase(world_registration_query);
if (world_registration_results.Success() && world_registration_results.RowCount() == 1) {
auto world_registration_row = world_registration_results.begin();
r.server_admin_account_name = world_registration_row[0];
r.server_admin_account_password = world_registration_row[1];
}
return r;
}
/**
* @param id
* @param ip_address
*/
void Database::UpdateLSAccountData(unsigned int id, std::string ip_address)
{
auto query = fmt::format(
"UPDATE login_accounts SET last_ip_address = '{0}', last_login_date = NOW() where id = {1}",
ip_address,
id
);
QueryDatabase(query);
}
/**
* @param id
* @param name
* @param password
* @param email
*/
void Database::UpdateLSAccountInfo(
unsigned int id,
std::string name,
std::string password,
std::string email
)
{
auto query = fmt::format(
"REPLACE login_accounts SET id = {0}, account_name = '{1}', account_password = sha('{2}'), "
"account_email = '{3}', last_ip_address = '0.0.0.0', last_login_date = now()",
id,
Strings::Escape(name),
Strings::Escape(password),
Strings::Escape(email)
);
QueryDatabase(query);
}
/**
* @param id
* @param long_name
* @param ip_address
*/
void Database::UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address)
{
auto query = fmt::format(
"UPDATE login_world_servers SET last_login_date = NOW(), last_ip_address = '{0}', long_name = '{1}' WHERE id = {2}",
ip_address,
Strings::Escape(long_name),
id
);
QueryDatabase(query);
}
/**
* @param id
* @param admin_account_password_hash
*/
bool Database::UpdateLoginWorldAdminAccountPassword(
unsigned int id,
const std::string &admin_account_password_hash
)
{
auto results = QueryDatabase(
fmt::format(
"UPDATE login_server_admins SET account_password = '{}' WHERE id = {}",
Strings::Escape(admin_account_password_hash),
id
)
);
return results.Success();
}
/**
*
* @param admin_account_username
* @param admin_account_password_hash
*/
bool Database::UpdateLoginWorldAdminAccountPasswordByUsername(
const std::string &admin_account_username,
const std::string &admin_account_password_hash
)
{
auto results = QueryDatabase(
fmt::format(
"UPDATE login_server_admins SET account_password = '{}' WHERE account_name = '{}'",
Strings::Escape(admin_account_password_hash),
Strings::Escape(admin_account_username)
)
);
return results.Success();
}
/**
* @param server_long_name
* @param server_short_name
* @param id
* @return
*/
bool Database::CreateWorldRegistration(
std::string server_long_name,
std::string server_short_name,
std::string server_remote_ip,
unsigned int &id,
unsigned int &server_admin_id
)
{
auto results = QueryDatabase("SELECT IFNULL(max(id), 0) + 1 FROM login_world_servers");
if (!results.Success() || results.RowCount() != 1) {
return false;
}
auto row = results.begin();
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 = ''",
id,
Strings::Escape(server_long_name),
Strings::Escape(server_short_name),
server_remote_ip,
server_admin_id
);
auto insert_results = QueryDatabase(insert_query);
if (!insert_results.Success()) {
LogError(
"Failed to register world server {0} - {1}",
server_long_name,
server_short_name
);
return false;
}
return true;
}
/**
* @param long_name
* @param short_name
* @param id
* @return
*/
std::string Database::CreateLoginserverApiToken(
bool write_mode,
bool read_mode
)
{
std::string token = EQ::Util::UUID::Generate().ToString();
auto query = fmt::format(
"INSERT INTO login_api_tokens (token, can_write, can_read, created_at) VALUES ('{0}', {1}, {2}, NOW())",
token,
(write_mode ? "1" : "0"),
(read_mode ? "1" : "0")
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return "";
}
return token;
}
/**
* @param long_name
* @param short_name
* @param id
* @return
*/
MySQLRequestResult Database::GetLoginserverApiTokens()
{
return QueryDatabase("SELECT token, can_write, can_read FROM login_api_tokens");
}
/**
* @param account_name
* @param account_password
* @param first_name
* @param last_name
* @param email
* @param ip_address
* @return
*/
uint32 Database::CreateLoginserverWorldAdminAccount(
const std::string &account_name,
const std::string &account_password,
const std::string &first_name,
const std::string &last_name,
const std::string &email,
const std::string &ip_address
)
{
auto query = fmt::format(
"INSERT INTO login_server_admins (account_name, account_password, first_name, last_name, email, registration_date, "
"registration_ip_address) "
"VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', NOW(), '{5}')",
Strings::Escape(account_name),
Strings::Escape(account_password),
Strings::Escape(first_name),
Strings::Escape(last_name),
Strings::Escape(email),
ip_address
);
auto results = QueryDatabase(query);
return (results.Success() ? results.LastInsertedID() : 0);
}
/**
* @param account_name
* @return
*/
bool Database::DoesLoginserverWorldAdminAccountExist(
const std::string &account_name
)
{
auto query = fmt::format(
"SELECT account_name FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
Strings::Escape(account_name)
);
auto results = QueryDatabase(query);
return (results.RowCount() == 1);
}
/**
* @param account_name
* @return
*/
Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &account_name)
{
auto query = fmt::format(
"SELECT id, account_name, account_password, first_name, last_name, email, registration_date, registration_ip_address"
" FROM login_server_admins WHERE account_name = '{0}' LIMIT 1",
Strings::Escape(account_name)
);
auto results = QueryDatabase(query);
Database::DbLoginServerAdmin r{};
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = Strings::ToUnsignedInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.first_name = row[3];
r.last_name = row[4];
r.email = row[5];
r.registration_date = row[7];
r.registration_ip_address = row[8];
}
return r;
}
/**
* @param account_name
* @return
*/
Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
const std::string &account_name,
const std::string &source_loginserver
)
{
auto query = fmt::format(
"SELECT id, account_name, account_password, account_email, source_loginserver, last_ip_address, last_login_date, "
"created_at, updated_at"
" FROM login_accounts WHERE account_name = '{0}' and source_loginserver = '{1}' LIMIT 1",
Strings::Escape(account_name),
Strings::Escape(source_loginserver)
);
auto results = QueryDatabase(query);
Database::DbLoginServerAccount r{};
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = Strings::ToUnsignedInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.account_email = row[3];
r.source_loginserver = row[4];
r.last_ip_address = row[5];
r.last_login_date = row[6];
r.created_at = row[7];
r.updated_at = row[8];
}
return r;
}
-286
View File
@@ -1,286 +0,0 @@
#ifndef EQEMU_DATABASEMYSQL_H
#define EQEMU_DATABASEMYSQL_H
#include "../common/dbcore.h"
#include "../common/eqemu_logsys.h"
#include <string>
#include <sstream>
#include <stdlib.h>
#include <mysql.h>
class Database : public DBcore {
public:
Database() { m_database = nullptr; }
/**
* Constructor, tries to set our database to connect to the supplied options.
*
* @param user
* @param pass
* @param host
* @param port
* @param name
*/
Database(std::string user, std::string pass, std::string host, std::string port, std::string name);
/**
* Destructor, frees our database if needed.
*/
~Database();
/**
* Retrieves the login data (password hash and account id) from the account name provided needed for client login procedure.
* @param name
* @param loginserver
* @param password
* @param id
* @return
*/
bool GetLoginDataFromAccountInfo(
const std::string &name,
const std::string &loginserver,
std::string &password,
unsigned int &id
);
/**
* @param token
* @param ip
* @param db_account_id
* @param db_loginserver
* @param user
* @return
*/
bool GetLoginTokenDataFromToken(
const std::string &token,
const std::string &ip,
unsigned int &db_account_id,
std::string &db_loginserver,
std::string &user
);
/**
* @param loginserver
* @return
*/
unsigned int GetFreeID(const std::string &loginserver);
/**
* @param name
* @param password
* @param loginserver
* @param id
* @return
*/
bool CreateLoginData(
const std::string &name,
const std::string &password,
const std::string &loginserver,
unsigned int &id
);
/**
* @param in_account_name
* @param in_account_password
* @param loginserver
* @param id
* @return
*/
bool CreateLoginDataWithID(
const std::string &in_account_name,
const std::string &in_account_password,
const std::string &loginserver,
unsigned int id
);
/**
* @param name
* @param loginserver
* @param hash
*/
void UpdateLoginserverAccountPasswordHash(
const std::string &name,
const std::string &loginserver,
const std::string &hash);
/**
* @param name
* @param password
* @param loginserver
* @param id
* @return
*/
bool DoesLoginServerAccountExist(
const std::string &name,
const std::string &password,
const std::string &loginserver,
unsigned int id
);
struct DbWorldRegistration {
bool loaded = false;
int32 server_id = 0;
int8 server_list_type = 3;
bool is_server_trusted = false;
std::string server_description;
std::string server_list_description;
std::string server_admin_account_name;
std::string server_admin_account_password;
uint32 server_admin_id;
};
/**
* Retrieves the world registration from the long and short names provided
* Needed for world login procedure
* Returns true if the record was found, false otherwise
*
* @param short_name
* @param long_name
* @param login_world_server_admin_id
* @return
*/
Database::DbWorldRegistration GetWorldRegistration(
const std::string &short_name,
const std::string &long_name,
uint32 login_world_server_admin_id
);
/**
* @param id
* @param ip_address
*/
void UpdateLSAccountData(unsigned int id, std::string ip_address);
/**
* @param id
* @param name
* @param password
* @param email
*/
void UpdateLSAccountInfo(unsigned int id, std::string name, std::string password, std::string email);
/**
* @param id
* @param long_name
* @param ip_address
*/
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
/**
* @param server_long_name
* @param server_short_name
* @param id
* @return
*/
bool CreateWorldRegistration(
std::string server_long_name,
std::string server_short_name,
std::string server_remote_ip,
unsigned int &id,
unsigned int &server_admin_id
);
/**
* @param write_mode
* @param read_mode
* @return
*/
std::string CreateLoginserverApiToken(bool write_mode, bool read_mode);
MySQLRequestResult GetLoginserverApiTokens();
/**
* @param account_name
* @param account_password
* @param first_name
* @param last_name
* @param email
* @param ip_address
* @return
*/
uint32 CreateLoginserverWorldAdminAccount(
const std::string &account_name,
const std::string &account_password,
const std::string &first_name,
const std::string &last_name,
const std::string &email,
const std::string &ip_address
);
/**
* @param account_name
* @return
*/
bool DoesLoginserverWorldAdminAccountExist(const std::string &account_name);
struct DbLoginServerAdmin {
bool loaded = false;
uint32 id;
std::string account_name;
std::string account_password;
std::string first_name;
std::string last_name;
std::string email;
std::string registration_date;
std::string registration_ip_address;
};
Database::DbLoginServerAdmin GetLoginServerAdmin(const std::string &account_name);
struct DbLoginServerAccount {
bool loaded = false;
uint32 id;
std::string account_name;
std::string account_password;
std::string account_email;
std::string source_loginserver;
std::string last_login_date;
std::string last_ip_address;
std::string created_at;
std::string updated_at;
};
Database::DbLoginServerAccount GetLoginServerAccountByAccountName(
const std::string &account_name,
const std::string &source_loginserver = "local"
);
/**
* @param id
* @param admin_account_password_hash
*/
bool UpdateLoginWorldAdminAccountPassword(
unsigned int id,
const std::string& admin_account_password_hash
);
/**
* @param admin_account_username
* @param admin_account_password_hash
*/
bool UpdateLoginWorldAdminAccountPasswordByUsername(
const std::string &admin_account_username,
const std::string &admin_account_password_hash
);
/**
* @param name
* @param password
* @param loginserver
* @param email
* @return
*/
uint32 CreateLoginAccount(
const std::string &name,
const std::string &password,
const std::string &loginserver = "local",
const std::string &email = "local_creation"
);
protected:
MYSQL *m_database{};
};
#endif
+4 -48
View File
@@ -21,10 +21,6 @@
#endif
/**
* @param mode
* @return
*/
std::string GetEncryptionByModeId(uint32 mode)
{
switch (mode) {
@@ -61,13 +57,6 @@ std::string GetEncryptionByModeId(uint32 mode)
}
}
/**
* @param buffer_in
* @param buffer_in_sz
* @param buffer_out
* @param enc
* @return
*/
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc)
{
#ifdef EQEMU_USE_MBEDTLS
@@ -113,7 +102,7 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
unsigned char iv[8];
memset(&key, 0, MBEDTLS_DES_KEY_SIZE);
memset(&iv, 0, 8);
mbedtls_des_context context;
mbedtls_des_setkey_dec(&context, key);
mbedtls_des_crypt_cbc(&context, MBEDTLS_DES_DECRYPT, buffer_in_sz, iv, (const unsigned char*)buffer_in, (unsigned char*)buffer_out);
@@ -123,23 +112,19 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
#ifdef EQEMU_USE_OPENSSL
DES_key_schedule k;
DES_cblock v;
memset(&k, 0, sizeof(DES_key_schedule));
memset(&v, 0, sizeof(DES_cblock));
if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) {
return nullptr;
}
DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc);
#endif
return buffer_out;
}
/**
* @param msg
* @return
*/
std::string eqcrypt_md5(const std::string &msg)
{
std::string ret;
@@ -174,10 +159,6 @@ std::string eqcrypt_md5(const std::string &msg)
return ret;
}
/**
* @param msg
* @return
*/
std::string eqcrypt_sha1(const std::string &msg)
{
std::string ret;
@@ -212,10 +193,6 @@ std::string eqcrypt_sha1(const std::string &msg)
return ret;
}
/**
* @param msg
* @return
*/
std::string eqcrypt_sha512(const std::string &msg)
{
std::string ret;
@@ -252,10 +229,6 @@ std::string eqcrypt_sha512(const std::string &msg)
#ifdef ENABLE_SECURITY
/**
* @param msg
* @return
*/
std::string eqcrypt_argon2(const std::string &msg)
{
char buffer[crypto_pwhash_STRBYTES] = {0};
@@ -275,10 +248,6 @@ std::string eqcrypt_argon2(const std::string &msg)
return ret;
}
/**
* @param msg
* @return
*/
std::string eqcrypt_scrypt(const std::string &msg)
{
char buffer[crypto_pwhash_scryptsalsa208sha256_STRBYTES] = {0};
@@ -300,12 +269,6 @@ std::string eqcrypt_scrypt(const std::string &msg)
#endif
/**
* @param username
* @param password
* @param mode
* @return
*/
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode)
{
switch (mode) {
@@ -346,13 +309,6 @@ std::string eqcrypt_hash(const std::string &username, const std::string &passwor
}
}
/**
* @param username
* @param password
* @param pwhash
* @param mode
* @return
*/
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode)
{
switch (mode) {
+30 -4
View File
@@ -2,6 +2,9 @@
#include <string>
#include "../common/types.h"
#include "login_types.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
enum EncryptionMode {
EncryptionModeMD5 = 1,
@@ -26,11 +29,34 @@ namespace CryptoHash {
const int sha512_hash_length = 128;
}
/**
* @param mode
* @return
*/
std::string GetEncryptionByModeId(uint32 mode);
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc);
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
struct EncryptionResult {
std::string password;
int mode = 0;
std::string mode_name;
};
static EncryptionResult EncryptPasswordFromContext(LoginAccountContext c, int mode = EncryptionModeSCrypt)
{
if (mode == 0) {
LogError("Encryption mode not set!");
return {};
}
EncryptionResult r;
r.password = eqcrypt_hash(
c.username,
c.password,
mode
);
r.mode = mode;
r.mode_name = GetEncryptionByModeId(r.mode);
LogInfo("Encrypted password for user [{}] using mode [{}] ({})", c.username, r.mode_name, r.mode);
return r;
}
+5 -10
View File
@@ -3,29 +3,24 @@
#include <utility>
#include "../common/json_config.h"
#include "database.h"
#include "encryption.h"
#include "options.h"
#include "server_manager.h"
#include "world_server_manager.h"
#include "client_manager.h"
#include "loginserver_webserver.h"
/**
* Login server struct, Contains every variable for the server that needs to exist outside the scope of main()
*/
struct LoginServer
{
struct LoginServer {
public:
LoginServer() : db(nullptr), server_manager(nullptr) {
LoginServer() : server_manager(nullptr)
{
}
EQ::JsonConfigFile config;
Database *db;
LoginserverWebserver::TokenManager *token_manager{};
Options options;
ServerManager *server_manager;
WorldServerManager *server_manager;
ClientManager *client_manager{};
};
+57 -29
View File
@@ -4,30 +4,30 @@
#pragma pack(1)
// unencrypted base message header in all packets
struct LoginBaseMessage_Struct {
struct LoginBaseMessage {
int32_t sequence; // request type/login sequence (2: handshake, 3: login, 4: serverlist, ...)
bool compressed; // true: deflated
int8_t encrypt_type; // 1: invert (unused) 2: des (2 for encrypted player logins and order expansions) (client uses what it sent, ignores in reply)
int32_t unk3; // unused?
};
struct LoginBaseReplyMessage_Struct {
struct LoginBaseReplyMessage {
bool success; // 0: failure (shows error string) 1: success
int32_t error_str_id; // last error eqlsstr id, default: 101 (no error)
char str[1]; // variable length, unknown (may be unused, this struct is a common pattern elsewhere)
};
struct LoginHandShakeReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
char unknown[1]; // variable length string
struct LoginHandShakeReply {
LoginBaseMessage base_header;
LoginBaseReplyMessage base_reply;
char unknown[1]; // variable length string
};
// variable length, can use directly if not serializing strings
struct PlayerLoginReply_Struct {
struct PlayerLoginReply {
// base header excluded to make struct data easier to encrypt
//LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
//LoginBaseMessage base_header;
LoginBaseReplyMessage base_reply;
int8_t unk1; // (default: 0)
int8_t unk2; // (default: 0)
@@ -47,7 +47,7 @@ struct PlayerLoginReply_Struct {
};
// variable length, for reference
struct LoginClientServerData_Struct {
struct LoginClientServerData {
char ip[1];
int32_t server_type; // legends, preferred, standard
int32_t server_id;
@@ -59,24 +59,24 @@ struct LoginClientServerData_Struct {
};
// variable length, for reference
struct ServerListReply_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
struct ServerListReply {
LoginBaseMessage base_header;
LoginBaseReplyMessage base_reply;
int32_t server_count;
LoginClientServerData_Struct servers[0];
int32_t server_count;
LoginClientServerData servers[0];
};
struct PlayEverquestRequest_Struct {
LoginBaseMessage_Struct base_header;
uint32 server_number;
struct PlayEverquestRequest {
LoginBaseMessage base_header;
uint32 server_number;
};
// SCJoinServerReply
struct PlayEverquestResponse_Struct {
LoginBaseMessage_Struct base_header;
LoginBaseReplyMessage_Struct base_reply;
uint32 server_number;
struct PlayEverquestResponse {
LoginBaseMessage base_header;
LoginBaseReplyMessage base_reply;
uint32 server_number;
};
#pragma pack()
@@ -95,6 +95,34 @@ enum LSClientStatus {
cs_logged_in
};
struct LoginWorldContext {
std::string long_name;
std::string short_name;
std::string password;
std::string password_hash;
int64 admin_id = 0;
};
struct LoginWorldAdminAccountContext {
int64 id;
std::string username;
std::string password;
std::string password_hash;
std::string email;
std::string first_name;
std::string last_name;
std::string ip_address;
};
struct LoginAccountContext {
std::string username;
std::string password;
std::string email;
std::string source_loginserver = "local";
uint32 login_account_id = 0;
bool password_is_encrypted = false;
};
namespace LS {
namespace ServerStatusFlags {
enum eServerStatusFlags {
@@ -123,13 +151,13 @@ namespace LS {
};
namespace ErrStr {
constexpr static int ERROR_NONE = 101; // No Error
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
constexpr static int ERROR_NONE = 101; // No Error
constexpr static int ERROR_UNKNOWN = 102; // Error - Unknown Error Occurred
constexpr static int ERROR_ACTIVE_CHARACTER = 111; // Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again.
constexpr static int ERROR_SERVER_UNAVAILABLE = 326; // That server is currently unavailable. Please check the EverQuest webpage for current server status and try again later.
constexpr static int ERROR_ACCOUNT_SUSPENDED = 337; // This account is currently suspended. Please contact customer service for more information.
constexpr static int ERROR_ACCOUNT_BANNED = 338; // This account is currently banned. Please contact customer service for more information.
constexpr static int ERROR_WORLD_MAX_CAPACITY = 339; // The world server is currently at maximum capacity and not allowing further logins until the number of players online decreases. Please try again later.
};
}
-4
View File
@@ -33,10 +33,6 @@ CREATE TABLE `login_server_list_types` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `login_server_list_types` (`id`, `description`) VALUES ('1', 'Legends'),
('2', 'Preferred'),
('3', 'Standard');
DROP TABLE IF EXISTS `login_world_servers`;
CREATE TABLE `login_world_servers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+39 -95
View File
@@ -5,15 +5,11 @@
#include "login_server.h"
#include "loginserver_webserver.h"
#include "account_management.h"
#include "../common/repositories/login_api_tokens_repository.h"
extern LoginServer server;
namespace LoginserverCommandHandler {
/**
* @param argc
* @param argv
*/
void CommandHandler(int argc, char **argv)
{
if (argc == 1) { return; }
@@ -22,14 +18,7 @@ namespace LoginserverCommandHandler {
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
EQEmuCommand::DisplayDebug(cmd);
/**
* Declare command mapping
*/
auto function_map = EQEmuCommand::function_map;
/**
* Register commands
*/
function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials;
function_map["login-user:check-external-credentials"] = &LoginserverCommandHandler::CheckExternalLoginserverUserCredentials;
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
@@ -43,12 +32,6 @@ namespace LoginserverCommandHandler {
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Creates Loginserver API Token";
@@ -69,22 +52,22 @@ namespace LoginserverCommandHandler {
bool can_write = cmd[{"-w", "--write"}];
if (!can_read || !can_write) {
LogInfo("[{0}] --read or --write must be set or both!", __func__);
LogInfo("--read or --write must be set or both!");
exit(1);
}
std::string token = server.db->CreateLoginserverApiToken(can_write, can_read);
if (!token.empty()) {
LogInfo("[{0}] Created Loginserver API token [{1}]", __func__, token);
auto t = LoginApiTokensRepository::NewEntity();
t.can_read = can_read;
t.can_write = can_write;
t.token = EQ::Util::UUID::Generate().ToString();
t.created_at = std::time(nullptr);
auto created = LoginApiTokensRepository::InsertOne(database, t);
if (created.id) {
LogInfo("Created Loginserver API token [{}] [{}]", created.id, created.token);
}
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Lists Loginserver API Tokens";
@@ -96,9 +79,10 @@ namespace LoginserverCommandHandler {
server.token_manager = new LoginserverWebserver::TokenManager;
server.token_manager->LoadApiTokens();
for (auto &it : server.token_manager->loaded_api_tokens) {
for (auto &it: server.token_manager->loaded_api_tokens) {
LogInfo(
"token [{0}] can_write [{1}] can_read [{2}]",
"token id [{}] [{}] can_write [{}] can_read [{}]",
it.second.id,
it.second.token,
it.second.can_write,
it.second.can_read
@@ -106,12 +90,6 @@ namespace LoginserverCommandHandler {
}
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Creates Local Loginserver Account";
@@ -130,19 +108,14 @@ namespace LoginserverCommandHandler {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
AccountManagement::CreateLoginServerAccount(
cmd(2).str(),
cmd(3).str(),
cmd("--email").str()
);
LoginAccountContext c;
c.username = cmd(2).str();
c.password = cmd(3).str();
c.email = cmd("--email").str();
AccountManagement::CreateLoginServerAccount(c);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Creates Loginserver World Administrator Account";
@@ -167,12 +140,6 @@ namespace LoginserverCommandHandler {
);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Check user login credentials";
@@ -189,20 +156,15 @@ namespace LoginserverCommandHandler {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
auto res = AccountManagement::CheckLoginserverUserCredentials(
cmd(2).str(),
cmd(3).str()
);
LoginAccountContext c;
c.username = cmd(2).str();
c.password = cmd(3).str();
LogInfo("Credentials were {0}", res != 0 ? "accepted" : "not accepted");
auto res = AccountManagement::CheckLoginserverUserCredentials(c);
LogInfo("Credentials were {}", res != 0 ? "accepted" : "not accepted");
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Change user login credentials";
@@ -219,18 +181,12 @@ namespace LoginserverCommandHandler {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
AccountManagement::UpdateLoginserverUserCredentials(
cmd(2).str(),
cmd(3).str()
);
LoginAccountContext c;
c.username = cmd(2).str();
c.password = cmd(3).str();
AccountManagement::UpdateLoginserverUserCredentials(c);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Check user external login credentials";
@@ -247,20 +203,14 @@ namespace LoginserverCommandHandler {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(
cmd(2).str(),
cmd(3).str()
);
LoginAccountContext c;
c.username = cmd(2).str();
c.password = cmd(3).str();
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(c);
LogInfo("Credentials were {0}", res ? "accepted" : "not accepted");
LogInfo("Credentials were {}", res ? "accepted" : "not accepted");
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void UpdateLoginserverWorldAdminAccountPassword(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Update world admin account password";
@@ -277,18 +227,12 @@ namespace LoginserverCommandHandler {
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(
cmd(2).str(),
cmd(3).str()
);
LoginAccountContext c;
c.username = cmd(2).str();
c.password = cmd(3).str();
AccountManagement::UpdateLoginserverWorldAdminAccountPasswordByName(c);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void HealthCheckLogin(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Checks login health using a test user";
+91 -141
View File
@@ -1,9 +1,10 @@
#include "loginserver_webserver.h"
#include "server_manager.h"
#include "world_server_manager.h"
#include "login_server.h"
#include "../common/json/json.h"
#include "../common/strings.h"
#include "account_management.h"
#include "../common/repositories/login_api_tokens_repository.h"
extern LoginServer server;
@@ -13,9 +14,6 @@ namespace LoginserverWebserver {
constexpr static int HTTP_RESPONSE_BAD_REQUEST = 400;
constexpr static int HTTP_RESPONSE_UNAUTHORIZED = 401;
/**
* @param api
*/
void RegisterRoutes(httplib::Server &api)
{
server.token_manager = new LoginserverWebserver::TokenManager;
@@ -27,21 +25,21 @@ namespace LoginserverWebserver {
return;
}
Json::Value response;
auto iter = server.server_manager->getWorldServers().begin();
while (iter != server.server_manager->getWorldServers().end()) {
Json::Value response;
auto iter = server.server_manager->GetWorldServers().begin();
for (const auto &s: server.server_manager->GetWorldServers()) {
Json::Value row;
row["server_long_name"] = (*iter)->GetServerLongName();
row["server_short_name"] = (*iter)->GetServerShortName();
row["server_list_type_id"] = (*iter)->GetServerListID();
row["server_status"] = (*iter)->GetStatus();
row["zones_booted"] = (*iter)->GetZonesBooted();
row["local_ip"] = (*iter)->GetLocalIP();
row["remote_ip"] = (*iter)->GetRemoteIP();
row["players_online"] = (*iter)->GetPlayersOnline();
row["world_id"] = (*iter)->GetServerId();
row["server_long_name"] = s->GetServerLongName();
row["server_short_name"] = s->GetServerShortName();
row["server_list_type_id"] = s->GetServerListID();
row["server_status"] = s->GetStatus();
row["zones_booted"] = s->GetZonesBooted();
row["local_ip"] = s->GetLocalIP();
row["remote_ip"] = s->GetRemoteIP();
row["players_online"] = s->GetPlayersOnline();
row["world_id"] = s->GetServerId();
response.append(row);
++iter;
}
LoginserverWebserver::SendResponse(response, res);
@@ -54,10 +52,10 @@ namespace LoginserverWebserver {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
std::string email = request_body.get("email", "").asString();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
std::string email = req.get("email", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -67,7 +65,12 @@ namespace LoginserverWebserver {
return;
}
int32 account_created_id = AccountManagement::CreateLoginServerAccount(username, password, email);
LoginAccountContext c;
c.username = username;
c.password = password;
c.email = email;
int32 account_created_id = AccountManagement::CreateLoginServerAccount(c);
if (account_created_id > 0) {
response["message"] = "Account created successfully!";
response["data"]["account_id"] = account_created_id;
@@ -91,11 +94,11 @@ namespace LoginserverWebserver {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
std::string email = request_body.get("email", "").asString();
uint32 login_account_id = request_body.get("login_account_id", "").asInt();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
std::string email = req.get("email", "").asString();
uint32 login_account_id = req.get("login_account_id", "").asInt();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -105,14 +108,14 @@ namespace LoginserverWebserver {
return;
}
std::string source_loginserver = "eqemu";
int32 account_created_id = AccountManagement::CreateLoginServerAccount(
username,
password,
email,
source_loginserver,
login_account_id
);
LoginAccountContext c;
c.username = username;
c.password = password;
c.email = email;
c.source_loginserver = "eqemu";
c.login_account_id = login_account_id;
int32 account_created_id = AccountManagement::CreateLoginServerAccount(c);
if (account_created_id > 0) {
response["message"] = "Account created successfully!";
@@ -137,9 +140,9 @@ namespace LoginserverWebserver {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -149,11 +152,11 @@ namespace LoginserverWebserver {
return;
}
uint32 login_account_id = AccountManagement::CheckLoginserverUserCredentials(
username,
password
);
LoginAccountContext c;
c.username = username;
c.password = password;
uint32 login_account_id = AccountManagement::CheckLoginserverUserCredentials(c);
if (login_account_id > 0) {
response["message"] = "Credentials valid!";
response["data"]["account_id"] = login_account_id;
@@ -173,9 +176,9 @@ namespace LoginserverWebserver {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -185,24 +188,20 @@ namespace LoginserverWebserver {
return;
}
Database::DbLoginServerAccount
login_server_account = server.db->GetLoginServerAccountByAccountName(
username
);
LoginAccountContext c;
c.username = username;
c.password = password;
if (!login_server_account.loaded) {
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
if (!a.id) {
res.status = HTTP_RESPONSE_BAD_REQUEST;
response["error"] = "Failed to find associated loginserver account!";
LoginserverWebserver::SendResponse(response, res);
return;
}
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
username,
password
);
if (credentials_valid) {
bool success = AccountManagement::UpdateLoginserverUserCredentials(c);
if (success) {
response["message"] = "Loginserver account credentials updated!";
}
else {
@@ -214,16 +213,15 @@ namespace LoginserverWebserver {
}
);
api.Post(
"/v1/account/credentials/update/external", [](const httplib::Request &request, httplib::Response &res) {
if (!LoginserverWebserver::TokenManager::AuthCanWrite(request, res)) {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -234,25 +232,20 @@ namespace LoginserverWebserver {
std::string source_loginserver = "eqemu";
Database::DbLoginServerAccount
login_server_account = server.db->GetLoginServerAccountByAccountName(
username,
source_loginserver
);
LoginAccountContext c;
c.username = username;
c.password = password;
c.source_loginserver = source_loginserver;
if (!login_server_account.loaded) {
auto a = LoginAccountsRepository::GetAccountFromContext(database, c);
if (!a.id) {
response["error"] = "Failed to find associated loginserver account!";
LoginserverWebserver::SendResponse(response, res);
return;
}
bool credentials_valid = AccountManagement::UpdateLoginserverUserCredentials(
username,
password,
source_loginserver
);
if (credentials_valid) {
bool success = AccountManagement::UpdateLoginserverUserCredentials(c);
if (success) {
response["message"] = "Loginserver account credentials updated!";
}
else {
@@ -269,9 +262,9 @@ namespace LoginserverWebserver {
return;
}
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
Json::Value req = LoginserverWebserver::ParseRequestBody(request);
std::string username = req.get("username", "").asString();
std::string password = req.get("password", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {
@@ -280,10 +273,10 @@ namespace LoginserverWebserver {
return;
}
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(
username,
password
);
LoginAccountContext c;
c.username = username;
c.password = password;
uint32 account_id = AccountManagement::CheckExternalLoginserverUserCredentials(c);
if (account_id > 0) {
response["message"] = "Credentials valid!";
@@ -301,7 +294,7 @@ namespace LoginserverWebserver {
api.Get(
"/probes/healthcheck", [](const httplib::Request &request, httplib::Response &res) {
Json::Value response;
uint32 login_response = AccountManagement::HealthCheckUserLogin();
uint32 login_response = AccountManagement::HealthCheckUserLogin();
response["status"] = login_response;
if (login_response == 0) {
@@ -317,10 +310,6 @@ namespace LoginserverWebserver {
);
}
/**
* @param payload
* @param res
*/
void SendResponse(const Json::Value &payload, httplib::Response &res)
{
if (res.get_header_value("response_set") == "true") {
@@ -342,10 +331,6 @@ namespace LoginserverWebserver {
res.set_content(response_payload.str(), "application/json");
}
/**
* @param payload
* @param res
*/
Json::Value ParseRequestBody(const httplib::Request &request)
{
Json::Value request_body;
@@ -364,13 +349,9 @@ namespace LoginserverWebserver {
return request_body;
}
/**
* @param request
* @param res
*/
bool LoginserverWebserver::TokenManager::AuthCanRead(const httplib::Request &request, httplib::Response &res)
{
LoginserverWebserver::TokenManager::token_data
LoginserverWebserver::TokenManager::Token
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
if (!user_token.can_read) {
@@ -384,7 +365,7 @@ namespace LoginserverWebserver {
res.set_header("response_set", "true");
LogWarning(
"AuthCanRead access failure remote_address [{0}] user_agent [{1}]",
"AuthCanRead access failure remote_address [{}] user_agent [{}]",
user_token.remote_address,
user_token.user_agent
);
@@ -395,13 +376,9 @@ namespace LoginserverWebserver {
return true;
}
/**
* @param request
* @param res
*/
bool LoginserverWebserver::TokenManager::AuthCanWrite(const httplib::Request &request, httplib::Response &res)
{
LoginserverWebserver::TokenManager::token_data
LoginserverWebserver::TokenManager::Token
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
if (!user_token.can_write) {
@@ -415,7 +392,7 @@ namespace LoginserverWebserver {
res.set_header("response_set", "true");
LogWarning(
"AuthCanWrite access failure remote_address [{0}] user_agent [{1}]",
"AuthCanWrite access failure remote_address [{}] user_agent [{}]",
user_token.remote_address,
user_token.user_agent
);
@@ -426,20 +403,16 @@ namespace LoginserverWebserver {
return true;
}
/**
* @param request
* @return
*/
LoginserverWebserver::TokenManager::token_data
LoginserverWebserver::TokenManager::Token
LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(
const httplib::Request &request
)
{
std::string authorization_key;
LoginserverWebserver::TokenManager::token_data user_token{};
LoginserverWebserver::TokenManager::Token user_token{};
for (const auto &header : request.headers) {
for (const auto &header: request.headers) {
auto header_key = header.first;
auto header_value = header.second;
if (header_key == "Authorization") {
@@ -460,7 +433,7 @@ namespace LoginserverWebserver {
}
LogDebug(
"Authentication Request | remote_address [{0}] user_agent [{1}] authorization_key [{2}] request_path [{3}]",
"Authentication Request | remote_address [{}] user_agent [{}] authorization_key [{}] request_path [{}]",
user_token.remote_address,
user_token.user_agent,
authorization_key,
@@ -470,43 +443,24 @@ namespace LoginserverWebserver {
return user_token;
}
/**
* Loads API Tokens
*/
void TokenManager::LoadApiTokens()
{
auto results = server.db->GetLoginserverApiTokens();
int token_count = 0;
for (auto row = results.begin(); row != results.end(); ++row) {
LoginserverWebserver::TokenManager::token_data token_data;
token_data.token = row[0];
token_data.can_write = Strings::ToInt(row[1]) > 0;
token_data.can_read = Strings::ToInt(row[2]) > 0;
int token_count = 0;
LogDebug(
"Inserting api token to internal list [{0}] write {1} read {2}",
token_data.token,
token_data.can_read,
token_data.can_write
);
server.token_manager->loaded_api_tokens.emplace(
std::make_pair(
token_data.token,
token_data
)
);
for (auto &t: LoginApiTokensRepository::GetWhere(database, "TRUE ORDER BY id ASC")) {
LoginserverWebserver::TokenManager::Token td;
td.id = t.id;
td.token = t.token;
td.can_write = t.can_write;
td.can_read = t.can_read;
server.token_manager->loaded_api_tokens.emplace(std::make_pair(td.token, td));
token_count++;
}
LogInfo("Loaded [{}] API token(s)", token_count);
}
/**
* @param token
* @return
*/
bool TokenManager::TokenExists(const std::string &token)
{
auto it = server.token_manager->loaded_api_tokens.find(token);
@@ -514,11 +468,7 @@ namespace LoginserverWebserver {
return !(it == server.token_manager->loaded_api_tokens.end());
}
/**
* @param token
* @return
*/
LoginserverWebserver::TokenManager::token_data TokenManager::GetToken(
LoginserverWebserver::TokenManager::Token TokenManager::GetToken(
const std::string &token
)
{
+5 -4
View File
@@ -12,7 +12,8 @@ namespace LoginserverWebserver {
public:
TokenManager() = default;
struct token_data {
struct Token {
int id;
std::string token;
bool can_read;
bool can_write;
@@ -20,12 +21,12 @@ namespace LoginserverWebserver {
std::string remote_address;
};
std::map<std::string, token_data> loaded_api_tokens{};
std::map<std::string, Token> loaded_api_tokens{};
void LoadApiTokens();
static bool TokenExists(const std::string &token);
token_data GetToken(const std::string &token);
static token_data CheckApiAuthorizationHeaders(const httplib::Request &request);
Token GetToken(const std::string &token);
static Token CheckApiAuthorizationHeaders(const httplib::Request &request);
static bool AuthCanRead(const httplib::Request &request, httplib::Response &res);
static bool AuthCanWrite(const httplib::Request &request, httplib::Response &res);
};
+51 -97
View File
@@ -12,18 +12,23 @@
#include "loginserver_command_handler.h"
#include "../common/strings.h"
#include "../common/path_manager.h"
#include "../common/database.h"
#include "../common/events/player_event_logs.h"
#include "../common/zone_store.h"
#include <time.h>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <thread>
LoginServer server;
EQEmuLogSys LogSys;
bool run_server = true;
PathManager path;
LoginServer server;
EQEmuLogSys LogSys;
bool run_server = true;
PathManager path;
Database database;
PlayerEventLogs player_event_logs;
ZoneStore zone_store;
void ResolveAddresses();
void CatchSignal(int sig_num)
{
}
@@ -32,14 +37,16 @@ void LoadDatabaseConnection()
{
LogInfo("MySQL Database Init");
server.db = new Database(
if (!database.Connect(
server.config.GetVariableString("database", "host", "localhost"),
server.config.GetVariableString("database", "user", "root"),
server.config.GetVariableString("database", "password", ""),
server.config.GetVariableString("database", "host", "localhost"),
server.config.GetVariableString("database", "port", "3306"),
server.config.GetVariableString("database", "db", "peq")
);
server.config.GetVariableString("database", "db", "peq"),
server.config.GetVariableInt("database", "port", 3306)
)) {
LogError("Cannot continue without a database connection");
std::exit(1);
}
}
void LoadServerConfig()
@@ -49,9 +56,6 @@ void LoadServerConfig()
);
LogInfo("Config System Init");
/**
* Worldservers
*/
server.options.RejectDuplicateServers(
server.config.GetVariableBool(
"worldservers",
@@ -82,41 +86,33 @@ void LoadServerConfig()
)
);
/**
* Expansion Display Settings
*/
server.options.DisplayExpansions(
server.config.GetVariableBool(
"client_configuration",
"display_expansions",
false
)); //disable by default
)
);
server.options.MaxExpansions(
server.config.GetVariableInt(
"client_configuration",
"max_expansions_mask",
67108863
)); //enable display of all expansions
/**
* Account
*/
server.options.AutoCreateAccounts(server.config.GetVariableBool("account", "auto_create_accounts", true));
server.options.AutoLinkAccounts(server.config.GetVariableBool("account", "auto_link_accounts", false));
#ifdef LSPX
server.options.EQEmuLoginServerAddress(
server.config.GetVariableString(
"general",
"eqemu_loginserver_address",
"login.eqemulator.net:5999"
)
);
#endif
/**
* Default Loginserver Name (Don't change)
*/
server.options.AutoCreateAccounts(server.config.GetVariableBool("account", "auto_create_accounts", true));
if (std::getenv("LSPX")) {
server.options.EQEmuLoginServerAddress(
server.config.GetVariableString(
"general",
"eqemu_loginserver_address",
"login.eqemulator.net:5999"
)
);
}
server.options.DefaultLoginServerName(
server.config.GetVariableString(
"general",
@@ -125,10 +121,6 @@ void LoadServerConfig()
)
);
/**
* Security
*/
#ifdef ENABLE_SECURITY
server.options.EncryptionMode(server.config.GetVariableInt("security", "mode", 13));
#else
@@ -136,14 +128,6 @@ void LoadServerConfig()
#endif
server.options.AllowTokenLogin(server.config.GetVariableBool("security", "allow_token_login", false));
server.options.AllowPasswordLogin(server.config.GetVariableBool("security", "allow_password_login", true));
server.options.UpdateInsecurePasswords(
server.config.GetVariableBool(
"security",
"update_insecure_passwords",
true
)
);
}
void start_web_server()
@@ -151,7 +135,7 @@ void start_web_server()
Sleep(1);
int web_api_port = server.config.GetVariableInt("web_api", "port", 6000);
LogInfo("Webserver API now listening on port [{0}]", web_api_port);
LogInfo("Webserver API now listening on port [{}]", web_api_port);
httplib::Server api;
@@ -180,9 +164,7 @@ int main(int argc, char **argv)
path.LoadPaths();
/**
* Command handler
*/
// command handler
if (argc > 1) {
LogSys.SilenceConsoleLogging();
@@ -197,43 +179,23 @@ int main(int argc, char **argv)
}
LoadServerConfig();
/**
* mysql connect
*/
LoadDatabaseConnection();
if (argc == 1) {
LogSys.SetDatabase(server.db)
LogSys.SetDatabase(&database)
->SetLogPath("logs")
->LoadLogDatabaseSettings()
->StartFileLogs();
}
/**
* make sure our database got created okay, otherwise cleanup and exit
*/
if (!server.db) {
LogError("Database Initialization Failure");
LogInfo("Log System Shutdown");
return 1;
}
/**
* create server manager
*/
LogInfo("Server Manager Init");
server.server_manager = new ServerManager();
server.server_manager = new WorldServerManager();
if (!server.server_manager) {
LogError("Server Manager Failed to Start");
LogInfo("Database System Shutdown");
delete server.db;
return 1;
}
/**
* create client manager
*/
LogInfo("Client Manager Init");
server.client_manager = new ClientManager();
if (!server.client_manager) {
@@ -242,7 +204,6 @@ int main(int argc, char **argv)
delete server.server_manager;
LogInfo("Database System Shutdown");
delete server.db;
return 1;
}
@@ -256,37 +217,33 @@ int main(int argc, char **argv)
LogInfo("Server Started");
/**
* Web API
*/
bool web_api_enabled = server.config.GetVariableBool("web_api", "enabled", true);
if (web_api_enabled) {
std::thread web_api_thread(start_web_server);
web_api_thread.detach();
}
LogInfo("[Config] [Account] CanAutoCreateAccounts [{0}]", server.options.CanAutoCreateAccounts());
LogInfo("[Config] [ClientConfiguration] DisplayExpansions [{0}]", server.options.IsDisplayExpansions());
LogInfo("[Config] [ClientConfiguration] MaxExpansions [{0}]", server.options.GetMaxExpansions());
LogInfo("[Config] [Account] CanAutoCreateAccounts [{}]", server.options.CanAutoCreateAccounts());
LogInfo("[Config] [ClientConfiguration] DisplayExpansions [{}]", server.options.IsDisplayExpansions());
LogInfo("[Config] [ClientConfiguration] MaxExpansions [{}]", server.options.GetMaxExpansions());
#ifdef LSPX
LogInfo("[Config] [Account] CanAutoLinkAccounts [{0}]", server.options.CanAutoLinkAccounts());
#endif
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{0}]", server.options.IsRejectingDuplicateServers());
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{0}]", server.options.IsUnregisteredAllowed());
LogInfo("[Config] [WorldServer] ShowPlayerCount [{0}]", server.options.IsShowPlayerCountEnabled());
if (std::getenv("LSPX")) {
LogInfo("[Config] [Account] LSPX [on]");
}
LogInfo("[Config] [WorldServer] IsRejectingDuplicateServers [{}]", server.options.IsRejectingDuplicateServers());
LogInfo("[Config] [WorldServer] IsUnregisteredAllowed [{}]", server.options.IsUnregisteredAllowed());
LogInfo("[Config] [WorldServer] ShowPlayerCount [{}]", server.options.IsShowPlayerCountEnabled());
LogInfo(
"[Config] [WorldServer] DevAndTestServersListBottom [{0}]",
"[Config] [WorldServer] DevAndTestServersListBottom [{}]",
server.options.IsWorldDevTestServersListBottom()
);
LogInfo(
"[Config] [WorldServer] SpecialCharactersStartListBottom [{0}]",
"[Config] [WorldServer] SpecialCharactersStartListBottom [{}]",
server.options.IsWorldSpecialCharacterStartListBottom()
);
LogInfo("[Config] [Security] GetEncryptionMode [{0}]", server.options.GetEncryptionMode());
LogInfo("[Config] [Security] IsTokenLoginAllowed [{0}]", server.options.IsTokenLoginAllowed());
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
LogInfo("[Config] [Security] IsUpdatingInsecurePasswords [{0}]", server.options.IsUpdatingInsecurePasswords());
LogInfo("[Config] [Security] GetEncryptionMode [{}]", server.options.GetEncryptionMode());
LogInfo("[Config] [Security] IsTokenLoginAllowed [{}]", server.options.IsTokenLoginAllowed());
Timer keepalive(INTERSERVER_TIMER); // does auto-reconnect
@@ -295,7 +252,7 @@ int main(int argc, char **argv)
if (keepalive.Check()) {
keepalive.Start();
server.db->ping();
database.ping();
}
if (!run_server) {
@@ -319,8 +276,5 @@ int main(int argc, char **argv)
LogInfo("Server Manager Shutdown");
delete server.server_manager;
LogInfo("Database System Shutdown");
delete server.db;
return 0;
}

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