Compare commits

...

252 Commits

Author SHA1 Message Date
KimLS d6bdaa5c6e Saving and loading of guids for items, still needs a lot of work, esp with corpses. No auditing yet 2023-03-06 23:59:07 -08:00
KimLS 593127fb7e GUID interface. 2023-03-06 13:51:00 -08:00
Alex King 67df6f62b7 [Cleanup] Remove unused ^evacuate and ^succor subcommands from bot_command.h (#3039)
# Notes
- These are unused.
2023-03-05 12:19:58 -05:00
Alex King 4572dbc426 [Cleanup] Remove unused BotAA struct in bot_structs.h (#3038)
# Notes
- This is unused.
2023-03-05 12:19:52 -05:00
Alex King e8cc160572 [Cleanup] Remove unused bot structs in bot_structs.h (#3037)
# Notes
- These are unused.
2023-03-05 12:19:42 -05:00
Alex King 8c9adca852 [Cleanup] Utilize SetFilter in client.cpp (#3036)
# Notes
- This function was unused, make use of it.
2023-03-05 12:19:22 -05:00
Alex King b53310e23b [Cleanup] Remove unused AbilityTimer variable in client.h (#3035)
# Notes
- This is unused.
2023-03-05 12:19:16 -05:00
Alex King 14f01dc2d7 [Cleanup] Remove unused client queued work variable in client.cpp/client.h (#3034)
# Notes
- This is unused.
2023-03-05 12:19:09 -05:00
Alex King a4d6509e6d [Cleanup] Remove unused player update variables in client.cpp/client.h (#3033)
# Notes
- These are unused.
2023-03-05 12:18:56 -05:00
Alex King fc835bfb0e [Cleanup] Remove unused HandleUpdateTasksOnKill in client.h (#3032)
# Notes
- This is unused.
2023-03-05 12:18:51 -05:00
Alex King 9ec4e5ade0 [Cleanup] Remove unused command variables in client.cpp (#3031)
# Notes
- These are unused.
2023-03-05 12:18:36 -05:00
Alex King 6b65e93a06 [Cleanup] Remove unused SaveBackup in client.h (#3030)
# Notes
- This is unused and does nothing in both Perl and Lua.
2023-03-05 12:18:26 -05:00
Chris Miles a0a28fef04 [Strings] Add exception handling to converters themselves (#3029) 2023-03-04 19:39:55 -06:00
Trent 034feb4ff4 [Bots] Place BOT_COMMAND_CHAR inside messages (#3027)
* Fix bot depart list

* Update bot_command.cpp

* Update bot_command.cpp

---------

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

Notes:

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

Default state: Disabled/False.

* Update ruletypes.h

---------

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

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

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

* [Rules] Add Multiplier for Heroic Stats.

* Add bots

* update SendStatsWindow

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

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

* [Strings] Add more number formatters

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

* Rebase cleanup

* Changes/benchmarks/tests

---------

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

* Add rule toggle.

---------

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

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

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

* Update npc.h

* Update npc.cpp

* Update npc.h

---------

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

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

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

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

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

* Formatting

* More formatting

* Update CurrentPlayerChannels to use vector of channel names

* Put log statement back in place

* Remove channel limit in db query

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

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

* Update client_packet.cpp

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

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

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

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

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

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

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

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

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

* Move to Mob.

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

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

* Refactor, and take into account loregroups above 0 properly

* Update tradeskills.cpp

* formatting for suggestions.

* commenting, update formatting.

---------

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

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

# Lua
- Add `mob:HasSpecialAbilities()`

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

* Move to NPC.

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

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

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

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

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

* Remove debug comment.

* Use zone not NPC.

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

* Change to share underlying pointers.

* Push up mutex changes

* Post rebase

* Formatting

---------

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

* Update ucs.cpp

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

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

* Update doors.cpp

* Tweaks

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

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

* Cleanup

* formatting

* it's beautiful

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

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

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

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

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

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

# Notes
- Cleanup messages and logic.

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

* remove/add exceptions where makes sense like buffs

* fixes

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

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

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

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

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

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

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

* Update mob.cpp

---------

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

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

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

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

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

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

* formatting

* Add Saylinks to lore message output.

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

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

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

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

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

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

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

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

* Fix

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

* Tweak

* Formatting

* Additional tweak

* Adjustment

* Update export naming

* Formatting

* Indenting

* Finalizing formatting

* Indenting adjustments

* Use tab character setting

* Remove double tabs

* Update exp.cpp

---------

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

* [Bots & Merrcs] Add Support for TrySympatheticProc

* [Bots & Merrcs] Add Support for TrySympatheticProc

* Cleanup

* formatting

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

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

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

* Update inventory.cpp

* Update inventory.cpp

* Update lua_general.cpp

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

- Export `$target` to `EVENT_TARGET_CHANGE`.

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

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

* Update mob.cpp

* Update mob.cpp

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

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

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

- Allows operators to use player scripts for item destroys.

* Update lua_parser_events.h

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

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

* Optional parsing.

* Update object.cpp

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

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

* Add optional parsing to fish/forage events.

* Update forage.cpp

* Fix missing event param

---------

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

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

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

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

* Optional parsing.

* Update corpse.cpp

* Cleanup

* Export changes

---------

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

- Optionally parse this event instead of always doing so.

* Cleanup

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

- Optionally parses these events instead of always doing so.

* [Quest API] Optionally parse EVENT_LEVEL_UP and EVENT_LEVEL_DOWN

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

- Optionally parse these events instead of always doing so.

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

- Optionally parse these events instead of always doing so.

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

- Optionally parse these events instead of always doing so.

* Update tradeskills.cpp

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

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

* Cleanup

* PR comment fixes

---------

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

- Optionally parse these events instead of always doing so.

* Update attack.cpp

* Update attack.cpp

---------

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

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

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

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

* Remove unused reference, fix other PR

* Update task_client_state.cpp

---------

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

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

* Cleanup

* Update task_client_state.cpp

* [Quest API] Optionally parse task events

- Optionally parses these events instead of always doing so.

* Update task_client_state.cpp

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

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

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

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

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

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

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

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

* Optional EVENT_ATTACK

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

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

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

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

* [Quest API] Optionally parse EVENT_WARP

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

* Revert "[Quest API] Optionally parse EVENT_WARP"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Batch processing in world

* Cleanup

* Cleanup

* Update player_event_logs.cpp

* Add player zoning event

* Use generics

* Comments

* Add events

* Add more events

* AA_GAIN, AA_PURCHASE, FORAGE_SUCCESS, FORAGE_FAILURE

* FISH_SUCCESS, FISH_FAILURE, ITEM_DESTROY

* Add charges to ITEM_DESTROY

* WENT_ONLINE, WENT_OFFLINE

* LEVEL_GAIN, LEVEL_LOSS

* LOOT_ITEM

* MERCHANT_PURCHASE

* MERCHANT_SELL

* SKILL_UP

* Add events

* Add more events

* TASK_ACCEPT, TASK_COMPLETE, and TASK_UPDATE

* GROUNDSPAWN_PICKUP

* SAY

* REZ_ACCEPTED

* COMBINE_FAILURE and COMBINE_SUCCESS

* DROPPED_ITEM

* DEATH

* SPLIT_MONEY

* TRADER_PURCHASE and TRADER_SELL

* DISCOVER_ITEM

* Convert GM_COMMAND to use new macro

* Convert ZONING event to use macro

* Revert some code changes

* Revert "Revert some code changes"

This reverts commit d53682f997e89a053a660761085913245db91e9d.

* Add cereal generation support to repositories

* TRADE

* Formatting

* Cleanup

* Relocate discord_manager to discord folder

* Discord sending plumbing

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

* More discord sending plumbing

* More discord message formatting work

* More discord formatting work

* Discord formatting of events

* Format WENT_ONLINE, WENT_OFFLINE

* Add merchant purchase event

* Handle Discord MERCHANT_SELL formatter

* Update player_event_discord_formatter.cpp

* Tweaks

* Implement retention truncation

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

* Process on initial bootup

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

* Reload player event settings when logs are reloaded in game

* Set settings defaults

* Update player_event_logs.cpp

* Update player_event_logs.cpp

* Set retention days on boot

* Update player_event_logs.cpp

* Player Handin Event Testing.

Testing player handin stuff.

* Cleanup.

* Finish NPC Handin.

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

* Fix for windows _inline

* Bump to cpp20 default, ignore excessive warnings on windows

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

* Windows compile fixes

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Create 2022_12_19_player_events_tables.sql

* [Formatters] Work on Discord Formatters

* Handin money.

* Format header

* [Formatters] Work on Discord Formatters

* Format

* Format

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

* [Formatters] More Work on Formatters.

* Add missing #endif

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

* NPC Handin Discord Formatter

* Update player_event_logs.cpp

* Discover Item Discord Formatter

* Dropped Item Discord Formatter

* Split Money Discord Formatter

* Trader Discord Formatters

* Cleanup.

* Trade Event Discord Formatter Groundwork

* SAY don't record GM commands

* GM_Command don't record #help

* Update player_event_logs.cpp

* Fill in more event data

* Post rebase fixes

* Post rebase fix

* Discord formatting adjustments

* Add event deprecation or unimplemented tag support

* Trade events

* Add return money and sanity checks.

* Update schema

* Update ucs.cpp

* Update client.cpp

* Update 2022_12_19_player_events_tables.sql

* Implement archive single line

* Replace hackers table and functions with PossibleHack player event

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

* Update bot_command.cpp

* Record NPC kill events ALL / Named / Raid

* Add BatchEventProcessIntervalSeconds rule

* Naming

* Update CMakeLists.txt

* Update database_schema.h

* Remove logging function and methods

* DB version

* Cleanup SendPlayerHandinEvent

---------

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

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

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

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

* Update bot.cpp

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

* Add mercs where applicable

* Cleanup verbose if statements

* typo

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

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

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

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

* Update eq_constants.h

* Update zonedb.h

* Update tradeskills.cpp

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

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

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

* Add Mercs correctly

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

* Update version.h

* Redirect stderr

* Update should-release to filter non-master

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

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

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

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

* Handle reward window

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

* Update client_packet.cpp

* Update client_packet.cpp

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

* Tweak order

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

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

* Change fallback for wp, not really needed for safety

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

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

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

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

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

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

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

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

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

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

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

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

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

* Update lua_parser_events.cpp

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

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

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

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

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

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

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

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

* Return invalid slots to owner.
2023-01-29 12:49:44 -05:00
Alex King 549d731849 [Bug Fix] Resolve issue with max buff count being 25 in ROF2. (#2800)
# Notes
- This allows ROF2 to properly utilize their max buff count.
- May cause issues with older clients.
2023-01-28 17:40:11 -06:00
Natedog2012 68a34565f9 [Bugfix] Add SetItemCooldown to tell client exact timer of item when clicked and export to perl and lua (#2795)
Items that are on cooldown but client doesn't show.. clicking item will fix the timer in client
2023-01-27 17:31:14 -06:00
Aeadoin c05f951f81 [Bots] Add Override methods for GetMax Buffs/Songs/Total slots (#2801) 2023-01-27 18:00:50 -05:00
Akkadius dc64561b3c [Release] 22.2.0 2023-01-27 01:13:38 -06:00
Akkadius cb2aee2713 [Release] 22.2.0 2023-01-27 01:12:30 -06:00
Chris Miles 0730b6b588 [Crash] Fix crash issue with log formatting during character creation (#2798) 2023-01-26 20:40:58 -06:00
Aeadoin 826550acac [Bots] Add EVENT_UNEQUIP_ITEM_BOT & EVENT_EQUIP_ITEM_BOT (#2796)
* Initial Commit, need to test.

* Add unequip events.

* const auto
2023-01-26 19:49:20 -05:00
Alex King b71b3f5be0 [Bots] ^create and ^viewcombos popup messages fix. (#2797)
# Notes
- These messages were showing weirdly and inconsistently, cleaned them up to show at max 4 per line.
- `^viewcombos` now shows class name and ID in the popup title.
- `^create help` now shows proper class names and IDs instead of `{}`.
2023-01-26 18:44:21 -05:00
Natedog2012 1fe79f430c [Feature] ResetItemCooldown added to lua/perl and fix item re-cast times to show properly (#2793)
* Testing.

* Add ResetItemCooldown and port it over to perl

* This flag needs to be set for updating shared item cooldowns

* Properly set item recast for all item types, on corpses, on looting

* SummonItem properly sets recast timers of summoned items

* Rename variable to avoid confusion and change manifest to be more specific

* Sanity check item_d

* Recast -1 added as RECAST_TYPE_UNLINKED_ITEM
ResetItemCooldown will still remove cooldown of item that we don't have so when we acquire it the cooldown is reset

* change magic numbers

* more magic numbers

* More constants yay

* Remove unneeded export DeleteItemRecastTimer

* Remove duplicate message, this is handled by the client in this part of the code

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2023-01-25 20:09:08 -06:00
Alex King e5dabe0afc [Git] Add CMake Files to .gitignore (#2792)
* [Git] Add CMake Files to GitIgnore

* Update .drone.yml
2023-01-24 18:37:14 -06:00
Alex King 5720ffbcb6 [Release] 22.1.2 (#2791) 2023-01-24 17:18:42 -06:00
Alex King 2b0c778ad1 [Bug Fix] Fix nullptr spell in BCSpells::Load() (#2790)
* [Bug Fix] Fix nullptr spell in BCSpells::Load()

# Notes
- Fix possible `nullptr` where we didn't check if spell was valid before using it.

* Cleanup.
2023-01-24 17:57:12 -05:00
Alex King bf39a0540c [Cleanup] Cleanup #door Command. (#2783)
* [Cleanup] Cleanup #door Command.

# Notes
- Resolves an issue with `.1` versus `0.1`.
- Resolves an issue with updating a pre-existing door.
- Adds `heading` to the update/insert.

* Update doors.cpp
2023-01-24 16:37:21 -06:00
Chris Miles 08c8393988 [CI/CD] Build / Release Pipeline Changes (#2788)
* Test

* Test

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Kill excessive warnings

* Split

* Remove 7z from build scripts

* Linux

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Test

* Update .drone.yml

* Naming

* Test upload

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Yolo

* Yolo

* Update .drone.yml

* Update .drone.yml

* Copy

* Yolo

* Release without bots

* Update .drone.yml

* Update .drone.yml

* Test pipeline

* Remove debug

* Update .drone.yml

* Filter pipeline stage

* Update .drone.yml

* Test

* Bots release 22.0.5 (Test)

* Release bot test #2

* Check if release

* Update .drone.yml

* Update .drone.yml

* exit 78

* Update .drone.yml

* Update .drone.yml

* Add version checks

* Update .drone.yml

* Update .drone.yml

* Test

* Update build-release.bat

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update build-release.bat

* Update build-release.bat

* Test pipeline

* Update CHANGELOG.md

* Bump

* Update build-release.bat

* Update build-release.bat

* Shuffle

* Take #45354

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* F

* Update windows-build.ps1

* Consolidate

* Run it

* Pop cache back in

* Update linux-build.sh

* Another release test

* Update linux-build.sh

* Update linux-build.sh

* Update CMakeLists.txt

* Trim windows assets

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* [22.1.0] Release

* Crash reporting

* Add version tag injection in the build pipeline

* Update windows-build.ps1

* Test

* Test

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Kill excessive warnings

* Split

* Remove 7z from build scripts

* Linux

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Test

* Update .drone.yml

* Naming

* Test upload

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Yolo

* Yolo

* Update .drone.yml

* Update .drone.yml

* Copy

* Yolo

* Release without bots

* Update .drone.yml

* Update .drone.yml

* Test pipeline

* Remove debug

* Update .drone.yml

* Filter pipeline stage

* Update .drone.yml

* Test

* Bots release 22.0.5 (Test)

* Release bot test #2

* Check if release

* Update .drone.yml

* Update .drone.yml

* exit 78

* Update .drone.yml

* Update .drone.yml

* Add version checks

* Update .drone.yml

* Update .drone.yml

* Test

* Update build-release.bat

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update build-release.bat

* Update build-release.bat

* Test pipeline

* Update CHANGELOG.md

* Bump

* Update build-release.bat

* Update build-release.bat

* Shuffle

* Take #45354

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* F

* Update windows-build.ps1

* Consolidate

* Run it

* Pop cache back in

* Update linux-build.sh

* Another release test

* Update linux-build.sh

* Update linux-build.sh

* Update CMakeLists.txt

* Trim windows assets

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* Update windows-build.ps1

* [22.1.0] Release

* Crash reporting

* Add version tag injection in the build pipeline

* Update windows-build.ps1

* Full crash report on windows.

* Update endpoint

* [22.1.1] Release

* [skip ci] update .drone.yml

* Filter

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update .drone.yml

* Update CHANGELOG.md

Co-authored-by: KimLS <KimLS@peqtgc.com>
2023-01-24 16:37:04 -06:00
Alex King 8c12f7b431 [Bug Fix] Remove duplicate logic in GetActSpellHealing reducing HOT criticals (#2786)
# Notes
- Removes duplicate critical chance roll in `Mob::GetActSpellHealing`.
- Not sure if this was Live-like or an oversight, but it seems to drastically reduce the possibility of a HOT getting a critical.
- A 1% chance becomes a 0.01% chance being we have to roll twice.
2023-01-24 12:39:46 -06:00
Chris Miles 037be84f38 [Crash] Fix rarer world crash issue where scheduler database was not available (#2789) 2023-01-24 12:38:26 -06:00
421 changed files with 18570 additions and 8023 deletions
+80 -9
View File
@@ -1,7 +1,8 @@
---
kind: pipeline
type: docker
name: EQEmulator Server Linux CI
name: Build Linux
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
@@ -10,18 +11,88 @@ concurrency:
volumes:
- name: cache
host:
path: /var/lib/cache
path: /var/lib/cache-release
steps:
- name: server-build
# Source build script https://github.com/Akkadius/akk-stack/blob/master/containers/eqemu-server/Dockerfile#L20
- name: Build Linux X64
image: akkadius/eqemu-server:v11
environment:
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
commands:
- sudo chown eqemu:eqemu /drone/src/ * -R
- sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
- git submodule init && git submodule update && mkdir -p build && cd build && cmake -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O0 -g -DNDEBUG" -G 'Unix Makefiles' .. && make -j$((`nproc`-4))
- curl https://raw.githubusercontent.com/Akkadius/eqemu-install-v2/master/eqemu_config.json --output eqemu_config.json
- ./bin/tests
- ./utils/scripts/build/linux-build.sh
volumes:
- name: cache
path: /home/eqemu/.ccache/
---
kind: pipeline
type: exec
name: Build Windows
# Limits how many of these builds can run on the drone runner at a time, this isn't about cores
concurrency:
limit: 1
platform:
os: windows
arch: amd64
steps:
- name: Build Windows X64
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- .\utils\scripts\build\windows-build.ps1
---
kind: pipeline
type: docker
name: Publish Artifacts to Github
steps:
- name: Upload Artifacts
image: akkadius/eqemu-build-releaser:v3
environment:
RCLONE_CONFIG_REMOTE_TYPE: ftp
RCLONE_FTP_HOST: drone.akkadius.com
RCLONE_FTP_USER: artifacts
RCLONE_FTP_PASS:
from_secret: RCLONE_FTP_PASS
GH_RELEASE_GITHUB_API_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
commands:
- ./utils/scripts/build/should-release/should-release
- rclone config create remote ftp env_auth true > /dev/null
- |
rclone copy remote: --include "eqemu-server*.zip" .
- gh-release --assets=eqemu-server-linux-x64.zip,eqemu-server-windows-x64.zip -y
- |
rclone delete remote: --include "eqemu-server*.zip"
trigger:
branch:
- master
event:
- push
depends_on:
- Build Windows
- Build Linux
+9 -1
View File
@@ -62,4 +62,12 @@ compile_flags.txt
.cache/
# vscode generated settings
.vscode/
.vscode/
# Build pipeline
!utils/scripts/build/
!utils/scripts/build/should-release/should-release
!utils/scripts/build/should-release/should-release.exe
# CMake Files
cmake-build-relwithdebinfo/*
+1068
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -23,6 +23,7 @@ IF(MSVC)
ADD_DEFINITIONS(-D_HAS_AUTO_PTR_ETC) # for Luabind on C++17
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
ADD_DEFINITIONS( "/W0 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo /Os")
ELSE(MSVC)
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC)
+3 -3
View File
@@ -1,7 +1,7 @@
# EQEmulator Core Server
|Travis CI (Linux)|Appveyor (Windows x86) |Appveyor (Windows x64) |
|:---:|:---:|:---:|
|[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) |[![Build status](https://ci.appveyor.com/api/projects/status/v3utuu0dttm2cqd0?svg=true)](https://ci.appveyor.com/project/KimLS/server) |[![Build status](https://ci.appveyor.com/api/projects/status/scr25kmntx36c1ub?svg=true)](https://ci.appveyor.com/project/KimLS/server-87crp) |
| Drone (Linux x64) | Drone (Windows x64) |
|:---:|:---:|
|[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |[![Build Status](http://drone.akkadius.com/api/badges/EQEmu/Server/status.svg)](http://drone.akkadius.com/EQEmu/Server) |
***
-21
View File
@@ -1,21 +0,0 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-bots.zip
-21
View File
@@ -1,21 +0,0 @@
version: 1.0.{build}
branches:
only:
- master
image: Visual Studio 2017
configuration: RelWithDebInfo
clone_folder: c:\projects\eqemu
init:
- ps: git config --global core.autocrlf input
cache: c:\tools\vcpkg\installed\
before_build:
- ps: "$wc = New-Object System.Net.WebClient\n$wc.DownloadFile(\"http://strawberryperl.com/download/5.26.2.1/strawberry-perl-5.26.2.1-64bit-portable.zip\", \"c:\\projects\\eqemu\\strawberry-perl-5.26.2.1-64bit-portable.zip\")\ncd c:\\projects\\eqemu\n7z x c:/projects/eqemu/strawberry-perl-5.26.2.1-64bit-portable.zip -oc:/projects/eqemu/strawberry-perl-portable -y\n(Get-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h).replace('#define PERL_STATIC_INLINE static __inline__', '#define PERL_STATIC_INLINE static __inline') | Set-Content C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/config.h\nvcpkg install boost-geometry:x64-windows boost-dynamic-bitset:x64-windows luajit:x64-windows libsodium:x64-windows libmysql:x64-windows openssl:x64-windows zlib:x64-windows \nmkdir build\ncd build\ncmake -G \"Visual Studio 15 2017 Win64\" -DEQEMU_BUILD_TESTS=ON -DEQEMU_BUILD_LOGIN=ON -DPERL_EXECUTABLE=\"C:/projects/eqemu/strawberry-perl-portable/perl/bin/perl.exe\" -DPERL_INCLUDE_PATH=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE\" -DPERL_LIBRARY=\"C:/projects/eqemu/strawberry-perl-portable/perl/lib/CORE/libperl526.a\" -DCMAKE_TOOLCHAIN_FILE=\"c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake\" .."
build:
project: C:\projects\eqemu\build\EQEmu.sln
parallel: true
verbosity: minimal
after_build:
- cmd: >-
7z a build_x64-no-bots.zip C:\projects\eqemu\build\bin\RelWithDebInfo\*.exe C:\projects\eqemu\build\bin\RelWithDebInfo\*.dll C:\projects\eqemu\build\bin\RelWithDebInfo\*.pdb C:\projects\eqemu\build\libs\zlibng\RelWithDebInfo\*.dll
appveyor PushArtifact build_x64-no-bots.zip
+3 -3
View File
@@ -86,7 +86,7 @@ int main(int argc, char **argv)
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -183,7 +183,7 @@ bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
}
auto row = results.begin();
if (row[0] && atoi(row[0]) > 0) {
if (row[0] && Strings::ToInt(row[0]) > 0) {
return true;
}
@@ -207,7 +207,7 @@ int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
}
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
void ExportSkillCaps(SharedDatabase *db)
+17 -17
View File
@@ -83,7 +83,7 @@ int main(int argc, char **argv) {
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
@@ -241,10 +241,10 @@ void ImportSkillCaps(SharedDatabase *db) {
}
int class_id, skill_id, level, cap;
class_id = atoi(split[0].c_str());
skill_id = atoi(split[1].c_str());
level = atoi(split[2].c_str());
cap = atoi(split[3].c_str());
class_id = Strings::ToInt(split[0].c_str());
skill_id = Strings::ToInt(split[1].c_str());
level = Strings::ToInt(split[2].c_str());
cap = Strings::ToInt(split[3].c_str());
std::string sql = StringFormat("INSERT INTO skill_caps(class, skillID, level, cap) VALUES(%d, %d, %d, %d)",
class_id, skill_id, level, cap);
@@ -280,16 +280,16 @@ void ImportBaseData(SharedDatabase *db) {
int level, class_id;
double hp, mana, end, unk1, unk2, hp_fac, mana_fac, end_fac;
level = atoi(split[0].c_str());
class_id = atoi(split[1].c_str());
hp = atof(split[2].c_str());
mana = atof(split[3].c_str());
end = atof(split[4].c_str());
unk1 = atof(split[5].c_str());
unk2 = atof(split[6].c_str());
hp_fac = atof(split[7].c_str());
mana_fac = atof(split[8].c_str());
end_fac = atof(split[9].c_str());
level = Strings::ToInt(split[0].c_str());
class_id = Strings::ToInt(split[1].c_str());
hp = Strings::ToFloat(split[2].c_str());
mana = Strings::ToFloat(split[3].c_str());
end = Strings::ToFloat(split[4].c_str());
unk1 = Strings::ToFloat(split[5].c_str());
unk2 = Strings::ToFloat(split[6].c_str());
hp_fac = Strings::ToFloat(split[7].c_str());
mana_fac = Strings::ToFloat(split[8].c_str());
end_fac = Strings::ToFloat(split[9].c_str());
sql = StringFormat("INSERT INTO base_data(level, class, hp, mana, end, unk1, unk2, hp_fac, "
"mana_fac, end_fac) VALUES(%d, %d, %f, %f, %f, %f, %f, %f, %f, %f)",
@@ -339,8 +339,8 @@ void ImportDBStrings(SharedDatabase *db) {
int id, type;
std::string value;
id = atoi(split[0].c_str());
type = atoi(split[1].c_str());
id = Strings::ToInt(split[0].c_str());
type = Strings::ToInt(split[1].c_str());
if(split.size() >= 3) {
value = ::Strings::Escape(split[2]);
+13 -8
View File
@@ -33,9 +33,11 @@ SET(common_sources
eq_stream_proxy.cpp
eqtime.cpp
event_sub.cpp
events/player_event_logs.cpp
events/player_event_discord_formatter.cpp
expedition_lockout_timer.cpp
extprofile.cpp
discord_manager.cpp
discord/discord_manager.cpp
faction.cpp
file.cpp
guild_base.cpp
@@ -198,7 +200,6 @@ SET(repositories
repositories/base/base_dynamic_zones_repository.h
repositories/base/base_dynamic_zone_members_repository.h
repositories/base/base_dynamic_zone_templates_repository.h
repositories/base/base_eventlog_repository.h
repositories/base/base_expeditions_repository.h
repositories/base/base_expedition_lockouts_repository.h
repositories/base/base_faction_association_repository.h
@@ -218,7 +219,6 @@ SET(repositories
repositories/base/base_guilds_repository.h
repositories/base/base_guild_ranks_repository.h
repositories/base/base_guild_relations_repository.h
repositories/base/base_hackers_repository.h
repositories/base/base_horses_repository.h
repositories/base/base_instance_list_repository.h
repositories/base/base_instance_list_player_repository.h
@@ -264,6 +264,8 @@ SET(repositories
repositories/base/base_pets_equipmentset_repository.h
repositories/base/base_pets_equipmentset_entries_repository.h
repositories/base/base_player_titlesets_repository.h
repositories/base/base_player_event_log_settings_repository.h
repositories/base/base_player_event_logs_repository.h
repositories/base/base_quest_globals_repository.h
repositories/base/base_raid_details_repository.h
repositories/base/base_raid_members_repository.h
@@ -376,7 +378,6 @@ SET(repositories
repositories/dynamic_zones_repository.h
repositories/dynamic_zone_members_repository.h
repositories/dynamic_zone_templates_repository.h
repositories/eventlog_repository.h
repositories/expeditions_repository.h
repositories/expedition_lockouts_repository.h
repositories/faction_association_repository.h
@@ -396,7 +397,6 @@ SET(repositories
repositories/guilds_repository.h
repositories/guild_ranks_repository.h
repositories/guild_relations_repository.h
repositories/hackers_repository.h
repositories/horses_repository.h
repositories/instance_list_repository.h
repositories/instance_list_player_repository.h
@@ -442,6 +442,8 @@ SET(repositories
repositories/pets_equipmentset_repository.h
repositories/pets_equipmentset_entries_repository.h
repositories/player_titlesets_repository.h
repositories/player_event_log_settings_repository.h
repositories/player_event_logs_repository.h
repositories/quest_globals_repository.h
repositories/raid_details_repository.h
repositories/raid_members_repository.h
@@ -507,7 +509,7 @@ SET(common_headers
dbcore.h
deity.h
discord/discord.h
discord_manager.h
discord/discord_manager.h
dynamic_zone_base.h
emu_constants.h
emu_limits.h
@@ -530,6 +532,9 @@ SET(common_headers
eq_stream_locator.h
eq_stream_proxy.h
eqtime.h
events/player_event_logs.h
events/player_event_discord_formatter.h
events/player_events.h
errmsg.h
event_sub.h
expedition_lockout_timer.h
@@ -608,6 +613,7 @@ SET(common_headers
event/event_loop.h
event/task.h
event/timer.h
json/json_archive_single_line.h
json/json.h
json/json-forwards.h
net/console_server.h
@@ -661,8 +667,7 @@ SET(common_headers
StackWalker/StackWalker.h
util/memory_stream.h
util/directory.h
util/uuid.h
)
util/uuid.h)
SOURCE_GROUP(Event FILES
event/event_loop.h
+115 -5
View File
@@ -3,13 +3,96 @@
#include "crash.h"
#include "strings.h"
#include "process/process.h"
#include "http/httplib.h"
#include "http/uri.h"
#include "json/json.h"
#include "version.h"
#include "eqemu_config.h"
#include "serverinfo.h"
#include "rulesys.h"
#include "platform.h"
#include <cstdio>
#include <vector>
#if WINDOWS
#define popen _popen
#endif
void SendCrashReport(const std::string &crash_report)
{
// can configure multiple endpoints if need be
std::vector<std::string> endpoints = {
"http://spire.akkadius.com/api/v1/analytics/server-crash-report",
// "http://localhost:3010/api/v1/analytics/server-crash-report", // development
};
auto config = EQEmuConfig::get();
for (auto &e: endpoints) {
uri u(e);
std::string base_url = fmt::format("{}://{}", u.get_scheme(), u.get_host());
if (u.get_port()) {
base_url += fmt::format(":{}", u.get_port());
}
// client
httplib::Client r(base_url);
r.set_connection_timeout(1, 0);
r.set_read_timeout(1, 0);
r.set_write_timeout(1, 0);
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
// os info
auto os = EQ::GetOS();
auto cpus = EQ::GetCPUs();
auto process_id = EQ::GetPID();
auto rss = EQ::GetRSS() / 1048576.0;
auto uptime = static_cast<uint32>(EQ::GetUptime());
// payload
Json::Value p;
p["platform_name"] = GetPlatformName();
p["crash_report"] = crash_report;
p["server_version"] = CURRENT_VERSION;
p["compile_date"] = COMPILE_DATE;
p["compile_time"] = COMPILE_TIME;
p["server_name"] = config->LongName;
p["server_short_name"] = config->ShortName;
p["uptime"] = uptime;
p["os_machine"] = os.machine;
p["os_release"] = os.release;
p["os_version"] = os.version;
p["os_sysname"] = os.sysname;
p["process_id"] = process_id;
p["rss_memory"] = rss;
p["cpus"] = cpus.size();
p["origination_info"] = "";
if (!LogSys.origination_info.zone_short_name.empty()) {
p["origination_info"] = fmt::format(
"{} ({}) instance_id [{}]",
LogSys.origination_info.zone_short_name,
LogSys.origination_info.zone_long_name,
LogSys.origination_info.instance_id
);
}
std::stringstream payload;
payload << p;
if (auto res = r.Post(e, payload.str(), "application/json")) {
if (res->status == 200) {
LogInfo("Sent crash report");
}
else {
LogError("Failed to send crash report to [{}]", e);
}
}
}
}
#if defined(_WINDOWS) && defined(CRASH_LOGGING)
#include "StackWalker.h"
@@ -21,22 +104,30 @@ public:
EQEmuStackWalker(DWORD dwProcessId, HANDLE hProcess) : StackWalker(dwProcessId, hProcess) { }
virtual void OnOutput(LPCSTR szText) {
char buffer[4096];
for(int i = 0; i < 4096; ++i) {
if(szText[i] == 0) {
for (int i = 0; i < 4096; ++i) {
if (szText[i] == 0) {
buffer[i] = '\0';
break;
}
if(szText[i] == '\n' || szText[i] == '\r') {
if (szText[i] == '\n' || szText[i] == '\r') {
buffer[i] = ' ';
} else {
}
else {
buffer[i] = szText[i];
}
}
std::string line = buffer;
_lines.push_back(line);
Log(Logs::General, Logs::Crash, buffer);
StackWalker::OnOutput(szText);
}
const std::vector<std::string>& const GetLines() { return _lines; }
private:
std::vector<std::string> _lines;
};
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
@@ -110,7 +201,20 @@ LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
if(EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
{
EQEmuStackWalker sw; sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
EQEmuStackWalker sw;
sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord);
if (RuleB(Analytics, CrashReporting)) {
std::string crash_report;
auto& lines = sw.GetLines();
for (auto& line : lines) {
crash_report += line;
crash_report += "\n";
}
SendCrashReport(crash_report);
}
}
return EXCEPTION_EXECUTE_HANDLER;
@@ -181,12 +285,18 @@ void print_trace()
}
std::ifstream input(temp_output_file);
std::string crash_report;
for (std::string line; getline(input, line);) {
LogCrash("{}", line);
crash_report += fmt::format("{}\n", line);
}
std::remove(temp_output_file.c_str());
if (RuleB(Analytics, CrashReporting)) {
SendCrashReport(crash_report);
}
exit(1);
}
+1 -1
View File
@@ -313,7 +313,7 @@ namespace cron
{
try
{
return static_cast<cron_int>(std::stoul(text.data()));
return static_cast<cron_int>(Strings::ToUnsignedInt(text.data()));
}
catch (std::exception const & ex)
{
+64 -102
View File
@@ -121,10 +121,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, const char *
auto row = results.begin();
auto id = std::stoul(row[0]);
auto id = Strings::ToUnsignedInt(row[0]);
if (oStatus) {
*oStatus = std::stoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
return id;
@@ -202,11 +202,11 @@ int16 Database::CheckStatus(uint32 account_id)
}
auto row = results.begin();
int16 status = std::stoi(row[0]);
int16 status = Strings::ToInt(row[0]);
int32 date_diff = 0;
if (row[1]) {
date_diff = std::stoi(row[1]);
date_diff = Strings::ToInt(row[1]);
}
if (date_diff > 0) {
@@ -345,7 +345,7 @@ bool Database::ReserveName(uint32 account_id, char* name) {
std::string query = StringFormat("SELECT `account_id`, `name` FROM `character_data` WHERE `name` = '%s'", name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
if (row[0] && atoi(row[0]) > 0){
if (row[0] && Strings::ToInt(row[0]) > 0){
LogInfo("Account: [{}] tried to request name: [{}], but it is already taken", account_id, name);
return false;
}
@@ -387,7 +387,7 @@ bool Database::DeleteCharacter(char *character_name)
std::string query = StringFormat("SELECT `id` from `character_data` WHERE `name` = '%s'", character_name);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
character_id = atoi(row[0]);
character_id = Strings::ToInt(row[0]);
}
if (character_id <= 0) {
@@ -787,7 +787,7 @@ uint32 Database::GetCharacterID(const char *name) {
auto row = results.begin();
if (results.RowCount() == 1)
{
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
return 0;
}
@@ -812,10 +812,10 @@ uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
auto row = results.begin();
uint32 accountId = atoi(row[0]);
uint32 accountId = Strings::ToInt(row[0]);
if (oCharID)
*oCharID = atoi(row[1]);
*oCharID = Strings::ToInt(row[1]);
return accountId;
}
@@ -832,7 +832,7 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
uint32 Database::GetAccountIDByName(std::string account_name, std::string loginserver, int16* status, uint32* lsid) {
@@ -852,14 +852,14 @@ uint32 Database::GetAccountIDByName(std::string account_name, std::string logins
}
auto row = results.begin();
auto account_id = std::stoul(row[0]);
auto account_id = Strings::ToUnsignedInt(row[0]);
if (status) {
*status = static_cast<int16>(std::stoi(row[1]));
*status = static_cast<int16>(Strings::ToInt(row[1]));
}
if (lsid) {
*lsid = row[2] ? std::stoul(row[2]) : 0;
*lsid = row[2] ? Strings::ToUnsignedInt(row[2]) : 0;
}
return account_id;
@@ -880,7 +880,7 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID
strcpy(name, row[0]);
if (row[1] && oLSAccountID) {
*oLSAccountID = atoi(row[1]);
*oLSAccountID = Strings::ToInt(row[1]);
}
}
@@ -968,7 +968,7 @@ bool Database::LoadVariables() {
std::string key, value;
for (auto row = results.begin(); row != results.end(); ++row) {
varcache.last_update = atoi(row[2]); // ahh should we be comparing if this is newer?
varcache.last_update = Strings::ToInt(row[2]); // ahh should we be comparing if this is newer?
key = row[0];
value = row[1];
std::transform(std::begin(key), std::end(key), std::begin(key), ::tolower); // keys are lower case, DB doesn't have to be
@@ -1052,15 +1052,15 @@ bool Database::GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zon
auto row = results.begin();
if(graveyard_zoneid != nullptr)
*graveyard_zoneid = atoi(row[0]);
*graveyard_zoneid = Strings::ToInt(row[0]);
if(graveyard_x != nullptr)
*graveyard_x = atof(row[1]);
*graveyard_x = Strings::ToFloat(row[1]);
if(graveyard_y != nullptr)
*graveyard_y = atof(row[2]);
*graveyard_y = Strings::ToFloat(row[2]);
if(graveyard_z != nullptr)
*graveyard_z = atof(row[3]);
*graveyard_z = Strings::ToFloat(row[3]);
if(graveyard_heading != nullptr)
*graveyard_heading = atof(row[4]);
*graveyard_heading = Strings::ToFloat(row[4]);
return true;
}
@@ -1168,13 +1168,13 @@ uint32 Database::GetAccountIDFromLSID(
}
for (auto row = results.begin(); row != results.end(); ++row) {
account_id = std::stoi(row[0]);
account_id = Strings::ToInt(row[0]);
if (in_account_name) {
strcpy(in_account_name, row[1]);
}
if (in_status) {
*in_status = std::stoi(row[2]);
*in_status = Strings::ToInt(row[2]);
}
}
@@ -1198,7 +1198,7 @@ void Database::GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus) {
if (oAccountName)
strcpy(oAccountName, row[0]);
if (oStatus)
*oStatus = atoi(row[1]);
*oStatus = Strings::ToInt(row[1]);
}
void Database::ClearMerchantTemp(){
@@ -1244,7 +1244,7 @@ uint8 Database::GetServerType() {
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
bool Database::MoveCharacterToZone(uint32 character_id, uint32 zone_id)
@@ -1281,44 +1281,6 @@ bool Database::MoveCharacterToZone(const char *charname, uint32 zone_id)
return results.RowsAffected() != 0;
}
bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
std::string query = StringFormat("INSERT INTO `hackers` (account, name, hacked) values('%s','%s','%s')", accountname, charactername, hacked);
auto results = QueryDatabase(query);
if (!results.Success()) {
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
std::string query = StringFormat("INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const std::string &hacked, const char* zone) {
//Utilize the "hacker" table, but also give zone information.
auto query = fmt::format("INSERT INTO hackers(account, name, hacked, zone) values('{}', '{}', '{}', '{}')",
accountname, charactername, hacked, zone);
auto results = QueryDatabase(query);
if (!results.Success())
{
return false;
}
return results.RowsAffected() != 0;
}
uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
{
uint16 race_cap = 0;
@@ -1334,7 +1296,7 @@ uint8 Database::GetRaceSkill(uint8 skillid, uint8 in_race)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level)
@@ -1350,12 +1312,12 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
if (results.Success() && results.RowsAffected() != 0)
{
auto row = results.begin();
skill_level = atoi(row[0]);
skill_formula = atoi(row[1]);
skill_cap = atoi(row[2]);
if (atoi(row[3]) > skill_cap)
skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = atoi(row[4]);
skill_level = Strings::ToInt(row[0]);
skill_formula = Strings::ToInt(row[1]);
skill_cap = Strings::ToInt(row[2]);
if (Strings::ToInt(row[3]) > skill_cap)
skill_cap2 = (Strings::ToInt(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
skill_cap3 = Strings::ToInt(row[4]);
}
int race_skill = GetRaceSkill(skillid,in_race);
@@ -1400,10 +1362,10 @@ uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id
}
auto row = results.begin();
auto character_id = std::stoul(row[0]);
*account_id = std::stoul(row[1]);
*zone_id = std::stoul(row[2]);
*instance_id = std::stoul(row[3]);
auto character_id = Strings::ToUnsignedInt(row[0]);
*account_id = Strings::ToUnsignedInt(row[1]);
*zone_id = Strings::ToUnsignedInt(row[2]);
*instance_id = Strings::ToUnsignedInt(row[3]);
return character_id;
}
@@ -1526,7 +1488,7 @@ uint32 Database::GetGroupID(const char* name){
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
@@ -1540,7 +1502,7 @@ std::string Database::GetGroupLeaderForLogin(std::string character_name) {
if (results.Success() && results.RowCount()) {
auto row = results.begin();
group_id = std::stoul(row[0]);
group_id = Strings::ToUnsignedInt(row[0]);
}
if (!group_id) {
@@ -1629,7 +1591,7 @@ char *Database::GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* mainta
strcpy(mentoree, row[5]);
if (mentor_percent)
*mentor_percent = atoi(row[6]);
*mentor_percent = Strings::ToInt(row[6]);
if(GLAA && results.LengthOfColumn(7) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[7], sizeof(GroupLeadershipAA_Struct));
@@ -1676,7 +1638,7 @@ uint8 Database::GetAgreementFlag(uint32 acctid) {
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
void Database::SetAgreementFlag(uint32 acctid) {
@@ -1762,7 +1724,7 @@ uint32 Database::GetRaidID(const char* name)
}
if (row[0]) // would it ever be possible to have a null here?
return atoi(row[0]);
return Strings::ToInt(row[0]);
return 0;
}
@@ -1845,7 +1807,7 @@ void Database::GetGroupLeadershipInfo(uint32 gid, uint32 rid, char *maintank,
strcpy(mentoree, row[4]);
if (mentor_percent)
*mentor_percent = atoi(row[5]);
*mentor_percent = Strings::ToInt(row[5]);
if (GLAA && results.LengthOfColumn(6) == sizeof(GroupLeadershipAA_Struct))
memcpy(GLAA, row[6], sizeof(GroupLeadershipAA_Struct));
@@ -2018,16 +1980,16 @@ bool Database::GetAdventureStats(uint32 char_id, AdventureStats_Struct *as)
auto row = results.begin();
as->success.guk = atoi(row[0]);
as->success.mir = atoi(row[1]);
as->success.mmc = atoi(row[2]);
as->success.ruj = atoi(row[3]);
as->success.tak = atoi(row[4]);
as->failure.guk = atoi(row[5]);
as->failure.mir = atoi(row[6]);
as->failure.mmc = atoi(row[7]);
as->failure.ruj = atoi(row[8]);
as->failure.tak = atoi(row[9]);
as->success.guk = Strings::ToInt(row[0]);
as->success.mir = Strings::ToInt(row[1]);
as->success.mmc = Strings::ToInt(row[2]);
as->success.ruj = Strings::ToInt(row[3]);
as->success.tak = Strings::ToInt(row[4]);
as->failure.guk = Strings::ToInt(row[5]);
as->failure.mir = Strings::ToInt(row[6]);
as->failure.mmc = Strings::ToInt(row[7]);
as->failure.ruj = Strings::ToInt(row[8]);
as->failure.tak = Strings::ToInt(row[9]);
as->failure.total = as->failure.guk + as->failure.mir + as->failure.mmc + as->failure.ruj + as->failure.tak;
as->success.total = as->success.guk + as->success.mir + as->success.mmc + as->success.ruj + as->success.tak;
@@ -2046,7 +2008,7 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
uint32 Database::GetGroupIDByCharID(uint32 character_id)
@@ -2068,7 +2030,7 @@ uint32 Database::GetGroupIDByCharID(uint32 character_id)
return 0;
auto row = results.begin();
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
uint32 Database::GetRaidIDByCharID(uint32 character_id) {
@@ -2082,7 +2044,7 @@ uint32 Database::GetRaidIDByCharID(uint32 character_id) {
);
auto results = QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
return atoi(row[0]);
return Strings::ToInt(row[0]);
}
return 0;
}
@@ -2096,7 +2058,7 @@ int Database::CountInvSnapshots() {
auto row = results.begin();
int64 count = atoll(row[0]);
int64 count = Strings::ToBigInt(row[0]);
if (count > 2147483647)
return -2;
if (count < 0)
@@ -2132,12 +2094,12 @@ struct TimeOfDay_Struct Database::LoadTime(time_t &realtime)
else{
auto row = results.begin();
eqTime.minute = atoi(row[0]);
eqTime.hour = atoi(row[1]);
eqTime.day = atoi(row[2]);
eqTime.month = atoi(row[3]);
eqTime.year = atoi(row[4]);
realtime = atoi(row[5]);
eqTime.minute = Strings::ToInt(row[0]);
eqTime.hour = Strings::ToInt(row[1]);
eqTime.day = Strings::ToInt(row[2]);
eqTime.month = Strings::ToInt(row[3]);
eqTime.year = Strings::ToInt(row[4]);
realtime = Strings::ToInt(row[5]);
}
return eqTime;
@@ -2164,7 +2126,7 @@ int Database::GetIPExemption(std::string account_ip) {
}
auto row = results.begin();
return std::stoi(row[0]);
return Strings::ToInt(row[0]);
}
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
@@ -2178,7 +2140,7 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
auto results = QueryDatabase(query);
if (results.Success() && results.RowCount()) {
auto row = results.begin();
exemption_id = std::stoul(row[0]);
exemption_id = Strings::ToUnsignedInt(row[0]);
}
query = fmt::format(
@@ -2204,7 +2166,7 @@ int Database::GetInstanceID(uint32 char_id, uint32 zone_id) {
if (results.Success() && results.RowCount() > 0) {
auto row = results.begin();
return atoi(row[0]);;
return Strings::ToInt(row[0]);;
}
return 0;
-5
View File
@@ -34,8 +34,6 @@
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class MySQLRequestResult;
class Client;
@@ -108,9 +106,6 @@ public:
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
bool ReserveName(uint32 account_id, char *name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
bool SetHackerFlag(const char *accountname, const char *charactername, const char *hacked);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const char *hacked, const char *zone);
bool SetMQDetectionFlag(const char *accountname, const char *charactername, const std::string &hacked, const char *zone);
bool UpdateName(const char *oldname, const char *newname);
bool CopyCharacter(
const std::string& source_character_name,
+19 -18
View File
@@ -476,10 +476,11 @@ bool Database::CheckDatabaseConversions() {
CheckDatabaseConvertPPDeblob();
CheckDatabaseConvertCorpseDeblob();
RuleManager::Instance()->LoadRules(this, "default", false);
auto *r = RuleManager::Instance();
r->LoadRules(this, "default", false);
if (!RuleB(Bots, Enabled) && DoesTableExist("bot_data")) {
LogInfo("Bot tables found but rule not enabled, enabling");
RuleManager::Instance()->SetRule("Bots:Enabled", "true", this, true, true);
r->SetRule("Bots:Enabled", "true", this, true, true);
}
/* Run EQEmu Server script (Checks for database updates) */
@@ -529,7 +530,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`");
results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) {
number_of_characters = atoi(row[0]);
number_of_characters = Strings::ToInt(row[0]);
printf("Number of Characters in Database: %i \n", number_of_characters);
}
@@ -928,19 +929,19 @@ bool Database::CheckDatabaseConvertPPDeblob(){
for (auto row = results.begin(); row != results.end(); ++row) {
char_iter_count++;
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", atoi(row[0]));
squery = StringFormat("SELECT `id`, `profile`, `name`, `level`, `account_id`, `firstlogon`, `lfg`, `lfp`, `mailkey`, `xtargets`, `inspectmessage`, `extprofile` FROM `character_` WHERE `id` = %i", Strings::ToInt(row[0]));
auto results2 = QueryDatabase(squery);
auto row2 = results2.begin();
pp = (Convert::PlayerProfile_Struct*)row2[1];
e_pp = (ExtendedProfile_Struct*)row2[11];
character_id = atoi(row[0]);
account_id = atoi(row2[4]);
character_id = Strings::ToInt(row[0]);
account_id = Strings::ToInt(row2[4]);
/* Convert some data from the character_ table that is still relevant */
firstlogon = atoi(row2[5]);
lfg = atoi(row2[6]);
lfp = atoi(row2[7]);
firstlogon = Strings::ToInt(row2[5]);
lfg = Strings::ToInt(row2[6]);
lfp = Strings::ToInt(row2[7]);
mailkey = row2[8];
xtargets = atoi(row2[9]);
xtargets = Strings::ToInt(row2[9]);
inspectmessage = row2[10];
/* Verify PP Integrity */
@@ -1566,7 +1567,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
rquery = StringFormat("SELECT DISTINCT charid FROM character_corpses");
results = QueryDatabase(rquery);
for (auto row = results.begin(); row != results.end(); ++row) {
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", atoi(row[0]));
std::string squery = StringFormat("SELECT id, charname, data, time_of_death, is_rezzed FROM character_corpses WHERE `charid` = %i", Strings::ToInt(row[0]));
auto results2 = QueryDatabase(squery);
for (auto row2 = results2.begin(); row2 != results2.end(); ++row2) {
in_datasize = results2.LengthOfColumn(2);
@@ -1598,7 +1599,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
c_type = "NULL";
continue;
}
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << atoi(row2[0]) << std::endl;
std::cout << "Converting Corpse: [OK] [" << c_type << "]: " << "ID: " << Strings::ToInt(row2[0]) << std::endl;
if (is_sof){
scquery = StringFormat("UPDATE `character_corpses` SET \n"
@@ -1669,7 +1670,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc->item_tint[6].color,
dbpc->item_tint[7].color,
dbpc->item_tint[8].color,
atoi(row2[0])
Strings::ToInt(row2[0])
);
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
@@ -1681,7 +1682,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToInt(row2[0]),
dbpc->items[i].equipSlot,
dbpc->items[i].item_id,
dbpc->items[i].charges,
@@ -1697,7 +1698,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
}
else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToInt(row2[0]),
dbpc->items[i].equipSlot,
dbpc->items[i].item_id,
dbpc->items[i].charges,
@@ -1777,7 +1778,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
dbpc_c->item_tint[6].color,
dbpc_c->item_tint[7].color,
dbpc_c->item_tint[8].color,
atoi(row2[0])
Strings::ToInt(row2[0])
);
if (scquery != ""){ auto sc_results = QueryDatabase(scquery); }
@@ -1790,7 +1791,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
scquery = StringFormat("REPLACE INTO `character_corpse_items` \n"
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToInt(row2[0]),
dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id,
dbpc_c->items[i].charges,
@@ -1806,7 +1807,7 @@ bool Database::CheckDatabaseConvertCorpseDeblob(){
}
else{
scquery = scquery + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
atoi(row2[0]),
Strings::ToInt(row2[0]),
dbpc_c->items[i].equipSlot,
dbpc_c->items[i].item_id,
dbpc_c->items[i].charges,
+6 -6
View File
@@ -167,8 +167,8 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
auto row = results.begin();
if (atoi(row[0]) <= max) {
instance_id = atoi(row[0]);
if (Strings::ToInt(row[0]) <= max) {
instance_id = Strings::ToInt(row[0]);
return true;
}
@@ -194,7 +194,7 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
max_reserved_instance_id++;
for (auto row : results) {
if (max_reserved_instance_id < std::stoul(row[0])) {
if (max_reserved_instance_id < Strings::ToUnsignedInt(row[0])) {
instance_id = max_reserved_instance_id;
return true;
}
@@ -301,7 +301,7 @@ uint16 Database::GetInstanceID(uint32 zone_id, uint32 character_id, int16 versio
auto row = results.begin();
return static_cast<uint16>(std::stoul(row[0]));
return static_cast<uint16>(Strings::ToUnsignedInt(row[0]));
}
std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id)
@@ -328,7 +328,7 @@ std::vector<uint16> Database::GetInstanceIDs(uint32 zone_id, uint32 character_id
}
for (auto row : results) {
l.push_back(static_cast<uint16>(std::stoul(row[0])));
l.push_back(static_cast<uint16>(Strings::ToUnsignedInt(row[0])));
}
return l;
@@ -409,7 +409,7 @@ void Database::AssignRaidToInstance(uint32 raid_id, uint32 instance_id)
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
auto l = GroupIdRepository::GetWhere(
auto l = RaidMembersRepository::GetWhere(
*this,
fmt::format(
"raidid = {}",
+2 -2
View File
@@ -321,13 +321,11 @@ namespace DatabaseSchema {
"discord_webhooks",
"dynamic_zone_members",
"dynamic_zones",
"eventlog",
"expedition_lockouts",
"expeditions",
"gm_ips",
"group_id",
"group_leaders",
"hackers",
"instance_list",
"ip_exemptions",
"item_tick",
@@ -343,6 +341,8 @@ namespace DatabaseSchema {
"respawn_times",
"saylink",
"server_scheduled_events",
"player_event_log_settings",
"player_event_logs",
"shared_task_activity_state",
"shared_task_dynamic_zones",
"shared_task_members",
+54 -48
View File
@@ -34,14 +34,16 @@
DBcore::DBcore()
{
mysql_init(&mysql);
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
mysql = mysql_init(nullptr);
mysqlOwner = true;
pHost = nullptr;
pUser = nullptr;
pPassword = nullptr;
pDatabase = nullptr;
pCompress = false;
pSSL = false;
pStatus = Closed;
m_mutex = new Mutex;
}
DBcore::~DBcore()
@@ -51,16 +53,10 @@ DBcore::~DBcore()
* are re-using the default database connection pointer when we dont have an
* external configuration setup ex: (content_database)
*/
std::string mysql_connection_host;
if (mysql.host) {
mysql_connection_host = mysql.host;
if (mysqlOwner) {
mysql_close(mysql);
}
if (GetOriginHost() != mysql_connection_host) {
return;
}
mysql_close(&mysql);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -70,17 +66,18 @@ DBcore::~DBcore()
// Sends the MySQL server a keepalive
void DBcore::ping()
{
if (!MDatabase.trylock()) {
if (!m_mutex->trylock()) {
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
return;
}
mysql_ping(&mysql);
MDatabase.unlock();
mysql_ping(mysql);
m_mutex->unlock();
}
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
{
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
return r;
}
bool DBcore::DoesTableExist(std::string table_name)
@@ -95,18 +92,16 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
BenchTimer timer;
timer.reset();
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
// Reconnect if we are not connected before hand.
if (pStatus != Connected) {
Open();
}
// request query. != 0 indicates some kind of error.
if (mysql_real_query(&mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(&mysql);
if (mysql_real_query(mysql, query, querylen) != 0) {
unsigned int errorNumber = mysql_errno(mysql);
if (errorNumber == CR_SERVER_GONE_ERROR) {
pStatus = Error;
@@ -130,26 +125,26 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32) mysql_errno(mysql), errorBuffer);
}
auto errorBuffer = new char[MYSQL_ERRMSG_SIZE];
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
/**
* Error logging
*/
if (mysql_errno(&mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(&mysql), mysql_error(&mysql), query);
if (mysql_errno(mysql) > 0 && strlen(query) > 0) {
LogMySQLError("[{}] [{}]\n[{}]", mysql_errno(mysql), mysql_error(mysql), query);
}
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql), errorBuffer);
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(mysql), errorBuffer);
}
// successful query. get results.
MYSQL_RES *res = mysql_store_result(&mysql);
MYSQL_RES *res = mysql_store_result(mysql);
uint32 rowCount = 0;
if (res != nullptr) {
@@ -158,10 +153,10 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
MySQLRequestResult requestResult(
res,
(uint32) mysql_affected_rows(&mysql),
(uint32) mysql_affected_rows(mysql),
rowCount,
(uint32) mysql_field_count(&mysql),
(uint32) mysql_insert_id(&mysql)
(uint32) mysql_field_count(mysql),
(uint32) mysql_insert_id(mysql)
);
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
@@ -207,7 +202,7 @@ uint32 DBcore::DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen)
{
// No good reason to lock the DB, we only need it in the first place to check char encoding.
// LockMutex lock(&MDatabase);
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
return mysql_real_escape_string(mysql, tobuf, frombuf, fromlen);
}
bool DBcore::Open(
@@ -222,7 +217,7 @@ bool DBcore::Open(
bool iSSL
)
{
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
safe_delete_array(pHost);
safe_delete_array(pUser);
safe_delete_array(pPassword);
@@ -242,13 +237,13 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (errbuf) {
errbuf[0] = 0;
}
LockMutex lock(&MDatabase);
LockMutex lock(m_mutex);
if (GetStatus() == Connected) {
return true;
}
if (GetStatus() == Error) {
mysql_close(&mysql);
mysql_init(&mysql); // Initialize structure again
mysql_close(mysql);
mysql_init(mysql); // Initialize structure again
}
if (!pHost) {
return false;
@@ -265,7 +260,7 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
if (pSSL) {
flags |= CLIENT_SSL;
}
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
if (mysql_real_connect(mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
pStatus = Connected;
std::string connected_origin_host = pHost;
@@ -275,21 +270,16 @@ bool DBcore::Open(uint32 *errnum, char *errbuf)
}
else {
if (errnum) {
*errnum = mysql_errno(&mysql);
*errnum = mysql_errno(mysql);
}
if (errbuf) {
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(mysql), mysql_error(mysql));
}
pStatus = Error;
return false;
}
}
void DBcore::SetMysql(MYSQL *mysql)
{
DBcore::mysql = *mysql;
}
const std::string &DBcore::GetOriginHost() const
{
return origin_host;
@@ -299,3 +289,19 @@ void DBcore::SetOriginHost(const std::string &origin_host)
{
DBcore::origin_host = origin_host;
}
std::string DBcore::Escape(const std::string& s)
{
const std::size_t s_len = s.length();
std::vector<char> temp((s_len * 2) + 1, '\0');
mysql_real_escape_string(mysql, temp.data(), s.c_str(), s_len);
return temp.data();
}
void DBcore::SetMutex(Mutex *mutex)
{
safe_delete(m_mutex);
DBcore::m_mutex = mutex;
}
+14 -4
View File
@@ -12,6 +12,7 @@
#include <mysql.h>
#include <string.h>
#include <mutex>
class DBcore {
public:
@@ -27,16 +28,22 @@ public:
void TransactionBegin();
void TransactionCommit();
void TransactionRollback();
std::string Escape(const std::string& s);
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
void ping();
MYSQL *getMySQL() { return &mysql; }
void SetMysql(MYSQL *mysql);
const std::string &GetOriginHost() const;
void SetOriginHost(const std::string &origin_host);
bool DoesTableExist(std::string table_name);
void SetMySQL(const DBcore &o)
{
mysql = o.mysql;
mysqlOwner = false;
}
void SetMutex(Mutex *mutex);
protected:
bool Open(
const char *iHost,
@@ -53,10 +60,13 @@ protected:
private:
bool Open(uint32 *errnum = nullptr, char *errbuf = nullptr);
MYSQL mysql;
Mutex MDatabase;
MYSQL* mysql;
bool mysqlOwner;
Mutex *m_mutex;
eStatus pStatus;
std::mutex m_query_lock{};
std::string origin_host;
char *pHost;
+93 -13
View File
@@ -1,22 +1,17 @@
#include <cereal/archives/json.hpp>
#include <cereal/archives/binary.hpp>
#include "discord.h"
#include "../http/httplib.h"
#include "../json/json.h"
#include "../strings.h"
#include "../eqemu_logsys.h"
#include "../events/player_event_logs.h"
constexpr int MAX_RETRIES = 10;
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return;
}
// validate
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
@@ -28,7 +23,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url.c_str());
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
@@ -46,9 +41,9 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
if (auto res = cli.Post(endpoint, payload.str(), "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
@@ -62,7 +57,7 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
@@ -81,6 +76,74 @@ void Discord::SendWebhookMessage(const std::string &message, const std::string &
}
}
void Discord::SendPlayerEventMessage(
const PlayerEvent::PlayerEventContainer &e,
const std::string &webhook_url
)
{
if (!ValidateWebhookUrl(webhook_url)) {
return;
}
auto s = Strings::Split(webhook_url, '/');
// url
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
std::string endpoint = Strings::Replace(webhook_url, base_url, "");
// client
httplib::Client cli(base_url);
cli.set_connection_timeout(0, 15000000); // 15 sec
cli.set_read_timeout(15, 0); // 15 seconds
cli.set_write_timeout(15, 0); // 15 seconds
httplib::Headers headers = {
{"Content-Type", "application/json"}
};
std::string payload = PlayerEventLogs::GetDiscordPayloadFromEvent(e);
if (payload.empty()) {
return;
}
bool retry = true;
int retries = 0;
int retry_timer = 1000;
while (retry) {
if (auto res = cli.Post(endpoint, payload, "application/json")) {
if (res->status != 200 && res->status != 204) {
LogError("Code [{}] Error [{}]", res->status, res->body);
}
if (res->status == 429) {
if (!res->body.empty()) {
std::stringstream ss(res->body);
Json::Value response;
try {
ss >> response;
}
catch (std::exception const &ex) {
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
}
retry_timer = Strings::ToInt(response["retry_after"].asString()) + 500;
}
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
}
if (res->status == 204) {
retry = false;
}
if (retries > MAX_RETRIES) {
LogDiscord("Retries exceeded for player event message");
retry = false;
}
retries++;
}
}
}
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
{
if (category_id == Logs::LogCategory::MySQLQuery) {
@@ -89,3 +152,20 @@ std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string
return message + "\n";
}
bool Discord::ValidateWebhookUrl(const std::string &webhook_url)
{
// validate
if (webhook_url.empty()) {
LogDiscord("[webhook_url] is empty");
return false;
}
// validate
if (!Strings::Contains(webhook_url, "http://") && !Strings::Contains(webhook_url, "https://")) {
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
return false;
}
return true;
}
+5
View File
@@ -4,11 +4,16 @@
#include <string>
#include "../types.h"
#include "../http/httplib.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class Discord {
public:
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
static void SendPlayerEventMessage(const PlayerEvent::PlayerEventContainer& e, const std::string &webhook_url);
static bool ValidateWebhookUrl(const std::string &webhook_url);
};
@@ -1,7 +1,6 @@
#include "discord_manager.h"
#include "../common/discord/discord.h"
#include "../common/eqemu_logsys.h"
#include "../common/strings.h"
#include "../../common/discord/discord.h"
#include "../events/player_event_logs.h"
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
{
@@ -55,7 +54,6 @@ void DiscordManager::ProcessMessageQueue()
message = "";
}
}
// final flush
if (!message.empty()) {
Discord::SendWebhookMessage(
@@ -67,3 +65,11 @@ void DiscordManager::ProcessMessageQueue()
webhook_message_queue.clear();
webhook_queue_lock.unlock();
}
void DiscordManager::QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e)
{
auto w = player_event_logs.GetDiscordWebhookUrlFromEventType(e.player_event_log.event_type_id);
if (!w.empty()) {
Discord::SendPlayerEventMessage(e, w);
}
}
@@ -4,12 +4,15 @@
#include <mutex>
#include <map>
#include <vector>
#include "../common/types.h"
#include "../../common/types.h"
#include "../repositories/player_event_logs_repository.h"
#include "../events/player_events.h"
class DiscordManager {
public:
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
void ProcessMessageQueue();
void QueuePlayerEventMessage(const PlayerEvent::PlayerEventContainer& e);
private:
std::mutex webhook_queue_lock{};
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
+27 -8
View File
@@ -79,6 +79,8 @@
#define ANIM_DEATH 0x73
#define ANIM_LOOT 0x69
constexpr int16 RECAST_TYPE_UNLINKED_ITEM = -1;
typedef enum {
eaStanding = 0,
eaSitting, //1
@@ -1015,15 +1017,32 @@ enum Anonymity : uint8
Roleplaying
};
enum ZoningMessage : int8
{
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
enum ZoningMessage : int8 {
ZoneNoMessage = 0,
ZoneSuccess = 1,
ZoneNotReady = -1,
ZoneValidPC = -2,
ZoneStoryZone = -3,
ZoneNoExpansion = -6,
ZoneNoExperience = -7
};
enum class RecipeCountType : uint8
{
Component,
Container,
Fail,
Salvage,
Success
};
#define ALT_CURRENCY_ID_RADIANT 4
#define ALT_CURRENCY_ID_EBON 5
enum ResurrectionActions
{
Decline,
Accept
};
#endif /*COMMON_EQ_CONSTANTS_H*/
+13 -11
View File
@@ -29,7 +29,7 @@
#include "textures.h"
static const uint32 BUFF_COUNT = 25;
static const uint32 BUFF_COUNT = 42;
static const uint32 PET_BUFF_COUNT = 30;
static const uint32 MAX_MERC = 100;
static const uint32 MAX_MERC_GRADES = 10;
@@ -3632,17 +3632,19 @@ struct LevelAppearance_Struct { //Sends a little graphic on level up
};
struct MerchantList {
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
uint32 id;
uint32 slot;
uint32 item;
int16 faction_required;
int8 level_required;
uint8 min_status;
uint8 max_status;
uint16 alt_currency_cost;
uint32 classes_required;
uint8 probability;
std::string bucket_name;
std::string bucket_value;
uint8 bucket_comparison;
uint8 bucket_comparison;
};
struct TempMerchantList {
@@ -4545,7 +4547,7 @@ struct ItemVerifyReply_Struct {
struct ItemRecastDelay_Struct {
/*000*/ uint32 recast_delay; // in seconds
/*004*/ uint32 recast_type;
/*008*/ uint32 unknown008;
/*008*/ bool ignore_casting_requirement; //Ignores recast times allows items to be reset?
/*012*/
};
+19 -18
View File
@@ -19,6 +19,7 @@
#include "../common/global_define.h"
#include "eqemu_config.h"
#include "misc_functions.h"
#include "strings.h"
#include <iostream>
#include <sstream>
@@ -33,13 +34,13 @@ void EQEmuConfig::parse_config()
LongName = _root["server"]["world"].get("longname", "").asString();
WorldAddress = _root["server"]["world"].get("address", "").asString();
LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
MaxClients = Strings::ToInt(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
SharedKey = _root["server"]["world"].get("key", "").asString();
LoginCount = 0;
if (_root["server"]["world"]["loginserver"].isObject()) {
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginPort = Strings::ToInt(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
LoginLegacy = false;
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") { LoginLegacy = true; }
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
@@ -62,7 +63,7 @@ void EQEmuConfig::parse_config()
auto loginconfig = new LoginConfig;
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginPort = Strings::ToInt(_root["server"]["world"][str].get("port", "5998").asString().c_str());
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
@@ -85,15 +86,15 @@ void EQEmuConfig::parse_config()
Locked = false;
if (_root["server"]["world"].get("locked", "false").asString() == "true") { Locked = true; }
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
WorldTCPPort = Strings::ToInt(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetTCPPort = Strings::ToInt(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
TelnetEnabled = false;
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") { TelnetEnabled = true; }
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPPort = Strings::ToInt(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
WorldHTTPEnabled = false;
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") {
@@ -108,9 +109,9 @@ void EQEmuConfig::parse_config()
* UCS
*/
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
ChatPort = Strings::ToInt(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
MailPort = Strings::ToInt(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
/**
* Database
@@ -118,7 +119,7 @@ void EQEmuConfig::parse_config()
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabasePort = Strings::ToInt(_root["server"]["database"].get("port", "3306").asString().c_str());
DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
/**
@@ -127,14 +128,14 @@ void EQEmuConfig::parse_config()
ContentDbUsername = _root["server"]["content_database"].get("username", "").asString();
ContentDbPassword = _root["server"]["content_database"].get("password", "").asString();
ContentDbHost = _root["server"]["content_database"].get("host", "").asString();
ContentDbPort = atoi(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbPort = Strings::ToInt(_root["server"]["content_database"].get("port", 0).asString().c_str());
ContentDbName = _root["server"]["content_database"].get("db", "").asString();
/**
* QS
*/
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabasePort = Strings::ToInt(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
@@ -142,9 +143,9 @@ void EQEmuConfig::parse_config()
/**
* Zones
*/
DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
DefaultStatus = Strings::ToInt(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
ZonePortLow = Strings::ToInt(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
ZonePortHigh = Strings::ToInt(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
/**
* Files
@@ -174,10 +175,10 @@ void EQEmuConfig::parse_config()
/**
* Launcher
*/
RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
RestartWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
TerminateWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
InitialBootWait = Strings::ToInt(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
ZoneBootInterval = Strings::ToInt(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
#ifdef WIN32
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
#else
+3 -1
View File
@@ -136,6 +136,7 @@ namespace Logs {
PacketServerToServer,
Bugs,
QuestErrors,
PlayerEvents,
MaxCategoryID /* Don't Remove this */
};
@@ -230,7 +231,8 @@ namespace Logs {
"Packet C->S",
"Packet S->S",
"Bugs",
"QuestErrors"
"QuestErrors",
"PlayerEvents",
};
}
+10
View File
@@ -784,6 +784,16 @@
OutF(LogSys, Logs::Detail, Logs::QuestErrors, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEvents(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::PlayerEvents))\
OutF(LogSys, Logs::General, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogPlayerEventsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PlayerEvents))\
OutF(LogSys, Logs::Detail, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,214 @@
#ifndef EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#define EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
#include <string>
#include "player_events.h"
#include "../repositories/base/base_player_event_logs_repository.h"
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
struct DiscordField {
std::string name;
std::string value;
bool is_inline;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(value),
cereal::make_nvp("inline", is_inline)
);
}
};
struct DiscordAuthor {
std::string name;
std::string icon_url;
std::string url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(name),
CEREAL_NVP(icon_url),
CEREAL_NVP(url)
);
}
};
struct DiscordEmbed {
std::vector<DiscordField> fields;
std::string title;
std::string description;
std::string timestamp;
DiscordAuthor author;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(fields),
CEREAL_NVP(title),
CEREAL_NVP(description),
CEREAL_NVP(timestamp),
CEREAL_NVP(author)
);
}
};
struct DiscordWebhook {
std::vector<DiscordEmbed> embeds;
std::string content;
std::string avatar_url;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(embeds),
CEREAL_NVP(avatar_url),
CEREAL_NVP(content)
);
}
};
class PlayerEventDiscordFormatter {
public:
static std::string GetCurrentTimestamp();
static std::string FormatEventSay(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::SayEvent &e);
static std::string
FormatGMCommand(const PlayerEvent::PlayerEventContainer &c, const PlayerEvent::GMCommandEvent &e);
static void BuildDiscordField(
std::vector<DiscordField> *f,
const std::string &name,
const std::string &value,
bool is_inline = true
);
static void BuildBaseEmbed(
std::vector<DiscordEmbed> *e,
const std::vector<DiscordField> &f,
PlayerEvent::PlayerEventContainer c
);
static std::string FormatWithNodata(const PlayerEvent::PlayerEventContainer &c);
static std::string FormatAAGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAGainedEvent &e
);
static std::string FormatAAPurchasedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::AAPurchasedEvent &e
);
static std::string FormatDeathEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DeathEvent &e
);
static std::string FormatFishSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::FishSuccessEvent &e
);
static std::string FormatForageSuccessEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ForageSuccessEvent &e
);
static std::string FormatDestroyItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DestroyItemEvent &e
);
static std::string FormatDiscoverItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DiscoverItemEvent &e
);
static std::string FormatDroppedItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::DroppedItemEvent &e
);
static std::string FormatLevelGainedEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelGainedEvent &e
);
static std::string FormatLevelLostEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LevelLostEvent &e
);
static std::string FormatLootItemEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::LootItemEvent &e
);
static std::string FormatGroundSpawnPickupEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::GroundSpawnPickupEvent &e
);
static std::string FormatMerchantPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantPurchaseEvent &e
);
static std::string FormatMerchantSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::MerchantSellEvent &e
);
static std::string FormatNPCHandinEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::HandinEvent &e
);
static std::string FormatSkillUpEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SkillUpEvent &e
);
static std::string FormatTaskAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskAcceptEvent &e
);
static std::string FormatTaskCompleteEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskCompleteEvent &e
);
static std::string FormatTaskUpdateEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TaskUpdateEvent &e
);
static std::string FormatTradeEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TradeEvent &e
);
static std::string FormatTraderPurchaseEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderPurchaseEvent &e
);
static std::string FormatTraderSellEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::TraderSellEvent &e
);
static std::string FormatResurrectAcceptEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ResurrectAcceptEvent &e
);
static std::string FormatSplitMoneyEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::SplitMoneyEvent &e
);
static std::string FormatCombineEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::CombineEvent &e
);
static std::string FormatZoningEvent(
const PlayerEvent::PlayerEventContainer &c,
const PlayerEvent::ZoningEvent &e
);
static DiscordWebhook BuildDiscordWebhook(
const PlayerEvent::PlayerEventContainer &p,
std::vector<DiscordEmbed> &embeds
);
};
#endif //EQEMU_PLAYER_EVENT_DISCORD_FORMATTER_H
+708
View File
@@ -0,0 +1,708 @@
#include <cereal/archives/json.hpp>
#include "player_event_logs.h"
#include "player_event_discord_formatter.h"
#include "../platform.h"
#include "../rulesys.h"
const uint32 PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL = 60 * 60 * 1000; // 1 hour
// general initialization routine
void PlayerEventLogs::Init()
{
m_process_batch_events_timer.SetTimer(RuleI(Logging, BatchPlayerEventProcessIntervalSeconds) * 1000);
m_process_retention_truncation_timer.SetTimer(PROCESS_RETENTION_TRUNCATION_TIMER_INTERVAL);
ValidateDatabaseConnection();
// initialize settings array
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].id = i;
m_settings[i].event_name = PlayerEvent::EventName[i];
m_settings[i].event_enabled = 1;
m_settings[i].retention_days = 0;
m_settings[i].discord_webhook_id = 0;
}
SetSettingsDefaults();
// initialize settings from database
auto s = PlayerEventLogSettingsRepository::All(*m_database);
std::vector<int> db{};
db.reserve(s.size());
for (auto &e: s) {
if (e.id >= PlayerEvent::MAX) {
continue;
}
m_settings[e.id] = e;
db.emplace_back(e.id);
}
// insert entries that don't exist in database
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
bool is_in_database = std::find(db.begin(), db.end(), i) != db.end();
bool is_deprecated = Strings::Contains(PlayerEvent::EventName[i], "Deprecated");
bool is_implemented = !Strings::Contains(PlayerEvent::EventName[i], "Unimplemented");
// remove when deprecated
if (is_deprecated && is_in_database) {
LogInfo("[Deprecated] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
// remove when unimplemented if present
if (!is_implemented && is_in_database) {
LogInfo("[Unimplemented] Removing PlayerEvent [{}] ({})", PlayerEvent::EventName[i], i);
PlayerEventLogSettingsRepository::DeleteWhere(*m_database, fmt::format("id = {}", i));
}
bool is_missing_in_database = std::find(db.begin(), db.end(), i) == db.end();
if (is_missing_in_database && is_implemented && !is_deprecated) {
LogInfo(
"[New] PlayerEvent [{}] ({})",
PlayerEvent::EventName[i],
i
);
auto c = PlayerEventLogSettingsRepository::NewEntity();
c.id = i;
c.event_name = PlayerEvent::EventName[i];
c.event_enabled = m_settings[i].event_enabled;
c.retention_days = m_settings[i].retention_days;
PlayerEventLogSettingsRepository::InsertOne(*m_database, c);
}
}
bool processing_in_world = !RuleB(Logging, PlayerEventsQSProcess) && IsWorld();
bool processing_in_qs = RuleB(Logging, PlayerEventsQSProcess) && IsQueryServ();
// on initial boot process truncation
if (processing_in_world || processing_in_qs) {
ProcessRetentionTruncation();
}
}
// set the database object, during initialization
PlayerEventLogs *PlayerEventLogs::SetDatabase(Database *db)
{
m_database = db;
return this;
}
// validates whether the connection is valid or not, used in initialization
bool PlayerEventLogs::ValidateDatabaseConnection()
{
if (!m_database) {
LogError("No database connection");
return false;
}
return true;
}
// determines if the passed in event is enabled or not
// this is used to gate logic or events from firing off
// this is used prior to building the events, we don't want to
// build the events, send them through the stack in a function call
// only to discard them immediately afterwards, very wasteful on resources
// the quest api currently does this
bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
{
return m_settings[event].event_enabled ? m_settings[event].event_enabled : false;
}
// this processes any current player events on the queue
void PlayerEventLogs::ProcessBatchQueue()
{
m_batch_queue_lock.lock();
if (m_record_batch_queue.empty()) {
m_batch_queue_lock.unlock();
return;
}
BenchTimer benchmark;
// flush many
PlayerEventLogsRepository::InsertMany(*m_database, m_record_batch_queue);
LogPlayerEventsDetail(
"Processing batch player event log queue of [{}] took [{}]",
m_record_batch_queue.size(),
benchmark.elapsed()
);
// empty
m_record_batch_queue = {};
m_batch_queue_lock.unlock();
}
// adds a player event to the queue
void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &log)
{
m_batch_queue_lock.lock();
m_record_batch_queue.emplace_back(log);
m_batch_queue_lock.unlock();
}
// fills common event data in the SendEvent function
void PlayerEventLogs::FillPlayerEvent(
const PlayerEvent::PlayerEvent &p,
PlayerEventLogsRepository::PlayerEventLogs &n
)
{
n.account_id = p.account_id;
n.character_id = p.character_id;
n.zone_id = p.zone_id;
n.instance_id = p.instance_id;
n.x = p.x;
n.y = p.y;
n.z = p.z;
n.heading = p.heading;
}
// builds the dynamic packet used to ship the player event over the wire
// supports serializing the struct so it can be rebuilt on the other end
std::unique_ptr<ServerPacket>
PlayerEventLogs::BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e)
{
EQ::Net::DynamicPacket dyn_pack;
dyn_pack.PutSerialize(0, e);
auto pack_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length();
auto pack = std::make_unique<ServerPacket>(ServerOP_PlayerEvent, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerSendPlayerEvent_Struct *>(pack->pBuffer);
buf->cereal_size = static_cast<uint32_t>(dyn_pack.Length());
memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length());
return pack;
}
const PlayerEventLogSettingsRepository::PlayerEventLogSettings *PlayerEventLogs::GetSettings() const
{
return m_settings;
}
bool PlayerEventLogs::IsEventDiscordEnabled(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return false;
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return false;
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return true;
}
return false;
}
std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_type_id)
{
// out of bounds check
if (event_type_id >= PlayerEvent::EventType::MAX) {
return "";
}
// make sure webhook id is set
if (m_settings[event_type_id].discord_webhook_id == 0) {
return "";
}
// ensure there is a matching webhook to begin with
if (!LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url.empty()) {
return LogSys.GetDiscordWebhooks()[m_settings[event_type_id].discord_webhook_id].webhook_url;
}
return "";
}
// GM_COMMAND | [x] Implemented Formatter
// ZONING | [x] Implemented Formatter
// AA_GAIN | [x] Implemented Formatter
// AA_PURCHASE | [x] Implemented Formatter
// FORAGE_SUCCESS | [x] Implemented Formatter
// FORAGE_FAILURE | [x] Implemented Formatter
// FISH_SUCCESS | [x] Implemented Formatter
// FISH_FAILURE | [x] Implemented Formatter
// ITEM_DESTROY | [x] Implemented Formatter
// WENT_ONLINE | [x] Implemented Formatter
// WENT_OFFLINE | [x] Implemented Formatter
// LEVEL_GAIN | [x] Implemented Formatter
// LEVEL_LOSS | [x] Implemented Formatter
// LOOT_ITEM | [x] Implemented Formatter
// MERCHANT_PURCHASE | [x] Implemented Formatter
// MERCHANT_SELL | [x] Implemented Formatter
// GROUP_JOIN | [] Implemented Formatter
// GROUP_LEAVE | [] Implemented Formatter
// RAID_JOIN | [] Implemented Formatter
// RAID_LEAVE | [] Implemented Formatter
// GROUNDSPAWN_PICKUP | [x] Implemented Formatter
// NPC_HANDIN | [x] Implemented Formatter
// SKILL_UP | [x] Implemented Formatter
// TASK_ACCEPT | [x] Implemented Formatter
// TASK_UPDATE | [x] Implemented Formatter
// TASK_COMPLETE | [x] Implemented Formatter
// TRADE | [] Implemented Formatter
// GIVE_ITEM | [] Implemented Formatter
// SAY | [x] Implemented Formatter
// REZ_ACCEPTED | [x] Implemented Formatter
// DEATH | [x] Implemented Formatter
// COMBINE_FAILURE | [x] Implemented Formatter
// COMBINE_SUCCESS | [x] Implemented Formatter
// DROPPED_ITEM | [x] Implemented Formatter
// SPLIT_MONEY | [x] Implemented Formatter
// DZ_JOIN | [] Implemented Formatter
// DZ_LEAVE | [] Implemented Formatter
// TRADER_PURCHASE | [x] Implemented Formatter
// TRADER_SELL | [x] Implemented Formatter
// BANDOLIER_CREATE | [] Implemented Formatter
// BANDOLIER_SWAP | [] Implemented Formatter
// DISCOVER_ITEM | [X] Implemented Formatter
std::string PlayerEventLogs::GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e)
{
std::string payload;
switch (e.player_event_log.event_type_id) {
case PlayerEvent::AA_GAIN: {
PlayerEvent::AAGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAGainedEvent(e, n);
break;
}
case PlayerEvent::AA_PURCHASE: {
PlayerEvent::AAPurchasedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatAAPurchasedEvent(e, n);
break;
}
case PlayerEvent::COMBINE_FAILURE:
case PlayerEvent::COMBINE_SUCCESS: {
PlayerEvent::CombineEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatCombineEvent(e, n);
break;
}
case PlayerEvent::DEATH: {
PlayerEvent::DeathEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDeathEvent(e, n);
break;
}
case PlayerEvent::DISCOVER_ITEM: {
PlayerEvent::DiscoverItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDiscoverItemEvent(e, n);
break;
}
case PlayerEvent::DROPPED_ITEM: {
PlayerEvent::DroppedItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDroppedItemEvent(e, n);
break;
}
case PlayerEvent::FISH_FAILURE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FISH_SUCCESS: {
PlayerEvent::FishSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatFishSuccessEvent(e, n);
break;
}
case PlayerEvent::FORAGE_FAILURE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::FORAGE_SUCCESS: {
PlayerEvent::ForageSuccessEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatForageSuccessEvent(e, n);
break;
}
case PlayerEvent::ITEM_DESTROY: {
PlayerEvent::DestroyItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatDestroyItemEvent(e, n);
break;
}
case PlayerEvent::LEVEL_GAIN: {
PlayerEvent::LevelGainedEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelGainedEvent(e, n);
break;
}
case PlayerEvent::LEVEL_LOSS: {
PlayerEvent::LevelLostEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLevelLostEvent(e, n);
break;
}
case PlayerEvent::LOOT_ITEM: {
PlayerEvent::LootItemEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatLootItemEvent(e, n);
break;
}
case PlayerEvent::GROUNDSPAWN_PICKUP: {
PlayerEvent::GroundSpawnPickupEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGroundSpawnPickupEvent(e, n);
break;
}
case PlayerEvent::NPC_HANDIN: {
PlayerEvent::HandinEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatNPCHandinEvent(e, n);
break;
}
case PlayerEvent::SAY: {
PlayerEvent::SayEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatEventSay(e, n);
break;
}
case PlayerEvent::GM_COMMAND: {
PlayerEvent::GMCommandEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatGMCommand(e, n);
break;
}
case PlayerEvent::SKILL_UP: {
PlayerEvent::SkillUpEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSkillUpEvent(e, n);
break;
}
case PlayerEvent::SPLIT_MONEY: {
PlayerEvent::SplitMoneyEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatSplitMoneyEvent(e, n);
break;
}
case PlayerEvent::TASK_ACCEPT: {
PlayerEvent::TaskAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskAcceptEvent(e, n);
break;
}
case PlayerEvent::TASK_COMPLETE: {
PlayerEvent::TaskCompleteEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskCompleteEvent(e, n);
break;
}
case PlayerEvent::TASK_UPDATE: {
PlayerEvent::TaskUpdateEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTaskUpdateEvent(e, n);
break;
}
case PlayerEvent::TRADE: {
PlayerEvent::TradeEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTradeEvent(e, n);
break;
}
case PlayerEvent::TRADER_PURCHASE: {
PlayerEvent::TraderPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderPurchaseEvent(e, n);
break;
}
case PlayerEvent::TRADER_SELL: {
PlayerEvent::TraderSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatTraderSellEvent(e, n);
break;
}
case PlayerEvent::REZ_ACCEPTED: {
PlayerEvent::ResurrectAcceptEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatResurrectAcceptEvent(e, n);
break;
}
case PlayerEvent::WENT_ONLINE:
case PlayerEvent::WENT_OFFLINE: {
payload = PlayerEventDiscordFormatter::FormatWithNodata(e);
break;
}
case PlayerEvent::MERCHANT_PURCHASE: {
PlayerEvent::MerchantPurchaseEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantPurchaseEvent(e, n);
break;
}
case PlayerEvent::MERCHANT_SELL: {
PlayerEvent::MerchantSellEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatMerchantSellEvent(e, n);
break;
}
case PlayerEvent::ZONING: {
PlayerEvent::ZoningEvent n{};
std::stringstream ss;
{
ss << e.player_event_log.event_data;
cereal::JSONInputArchive ar(ss);
n.serialize(ar);
}
payload = PlayerEventDiscordFormatter::FormatZoningEvent(e, n);
break;
}
default: {
LogInfo(
"Player event [{}] ({}) Discord formatter not implemented",
e.player_event_log.event_type_name,
e.player_event_log.event_type_id
);
}
}
return payload;
}
// general process function, used in world or QS depending on rule Logging:PlayerEventsQSProcess
void PlayerEventLogs::Process()
{
if (m_process_batch_events_timer.Check() || m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
ProcessBatchQueue();
}
if (m_process_retention_truncation_timer.Check()) {
ProcessRetentionTruncation();
}
}
void PlayerEventLogs::ProcessRetentionTruncation()
{
LogInfo("Running truncation");
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
if (m_settings[i].retention_days > 0) {
int deleted_count = PlayerEventLogsRepository::DeleteWhere(
*m_database,
fmt::format(
"event_type_id = {} AND created_at < (NOW() - INTERVAL {} DAY)",
i,
m_settings[i].retention_days
)
);
if (deleted_count > 0) {
LogInfo(
"Truncated [{}] events of type [{}] ({}) older than [{}] days",
deleted_count,
PlayerEvent::EventName[i],
i,
m_settings[i].retention_days
);
}
}
}
}
void PlayerEventLogs::ReloadSettings()
{
for (auto &e: PlayerEventLogSettingsRepository::All(*m_database)) {
m_settings[e.id] = e;
}
}
const int32_t RETENTION_DAYS_DEFAULT = 7;
void PlayerEventLogs::SetSettingsDefaults()
{
m_settings[PlayerEvent::GM_COMMAND].event_enabled = 1;
m_settings[PlayerEvent::ZONING].event_enabled = 1;
m_settings[PlayerEvent::AA_GAIN].event_enabled = 1;
m_settings[PlayerEvent::AA_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::FORAGE_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FORAGE_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::FISH_SUCCESS].event_enabled = 0;
m_settings[PlayerEvent::FISH_FAILURE].event_enabled = 0;
m_settings[PlayerEvent::ITEM_DESTROY].event_enabled = 1;
m_settings[PlayerEvent::WENT_ONLINE].event_enabled = 0;
m_settings[PlayerEvent::WENT_OFFLINE].event_enabled = 0;
m_settings[PlayerEvent::LEVEL_GAIN].event_enabled = 1;
m_settings[PlayerEvent::LEVEL_LOSS].event_enabled = 1;
m_settings[PlayerEvent::LOOT_ITEM].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::MERCHANT_SELL].event_enabled = 1;
m_settings[PlayerEvent::GROUP_JOIN].event_enabled = 0;
m_settings[PlayerEvent::GROUP_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::RAID_JOIN].event_enabled = 0;
m_settings[PlayerEvent::RAID_LEAVE].event_enabled = 0;
m_settings[PlayerEvent::GROUNDSPAWN_PICKUP].event_enabled = 1;
m_settings[PlayerEvent::NPC_HANDIN].event_enabled = 1;
m_settings[PlayerEvent::SKILL_UP].event_enabled = 0;
m_settings[PlayerEvent::TASK_ACCEPT].event_enabled = 1;
m_settings[PlayerEvent::TASK_UPDATE].event_enabled = 1;
m_settings[PlayerEvent::TASK_COMPLETE].event_enabled = 1;
m_settings[PlayerEvent::TRADE].event_enabled = 1;
m_settings[PlayerEvent::GIVE_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SAY].event_enabled = 0;
m_settings[PlayerEvent::REZ_ACCEPTED].event_enabled = 1;
m_settings[PlayerEvent::DEATH].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_FAILURE].event_enabled = 1;
m_settings[PlayerEvent::COMBINE_SUCCESS].event_enabled = 1;
m_settings[PlayerEvent::DROPPED_ITEM].event_enabled = 1;
m_settings[PlayerEvent::SPLIT_MONEY].event_enabled = 1;
m_settings[PlayerEvent::DZ_JOIN].event_enabled = 1;
m_settings[PlayerEvent::DZ_LEAVE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_PURCHASE].event_enabled = 1;
m_settings[PlayerEvent::TRADER_SELL].event_enabled = 1;
m_settings[PlayerEvent::BANDOLIER_CREATE].event_enabled = 0;
m_settings[PlayerEvent::BANDOLIER_SWAP].event_enabled = 0;
m_settings[PlayerEvent::DISCOVER_ITEM].event_enabled = 1;
m_settings[PlayerEvent::POSSIBLE_HACK].event_enabled = 1;
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
}
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef EQEMU_PLAYER_EVENT_LOGS_H
#define EQEMU_PLAYER_EVENT_LOGS_H
#include "../repositories/player_event_log_settings_repository.h"
#include "player_events.h"
#include "../servertalk.h"
#include "../repositories/player_event_logs_repository.h"
#include "../timer.h"
#include "../json/json_archive_single_line.h"
#include <cereal/archives/json.hpp>
#include <mutex>
class PlayerEventLogs {
public:
void Init();
void ReloadSettings();
PlayerEventLogs *SetDatabase(Database *db);
bool ValidateDatabaseConnection();
bool IsEventEnabled(PlayerEvent::EventType event);
void Process();
// batch queue
void AddToQueue(const PlayerEventLogsRepository::PlayerEventLogs &logs);
// main event record generic function
// can ingest any struct event types
template<typename T>
std::unique_ptr<ServerPacket> RecordEvent(
PlayerEvent::EventType t,
const PlayerEvent::PlayerEvent &p,
T e
)
{
auto n = PlayerEventLogsRepository::NewEntity();
FillPlayerEvent(p, n);
n.event_type_id = t;
std::stringstream ss;
{
cereal::JSONOutputArchiveSingleLine ar(ss);
e.serialize(ar);
}
n.event_type_name = PlayerEvent::EventName[t];
n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str();
n.created_at = std::time(nullptr);
auto c = PlayerEvent::PlayerEventContainer{
.player_event = p,
.player_event_log = n
};
return BuildPlayerEventPacket(c);
}
[[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const;
bool IsEventDiscordEnabled(int32_t event_type_id);
std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id);
static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e);
private:
Database *m_database; // reference to database
PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{};
// batch queue is used to record events in batch
std::vector<PlayerEventLogsRepository::PlayerEventLogs> m_record_batch_queue{};
static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n);
static std::unique_ptr<ServerPacket>
BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e);
// timers
Timer m_process_batch_events_timer; // events processing timer
Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings
// processing
std::mutex m_batch_queue_lock{};
void ProcessBatchQueue();
void ProcessRetentionTruncation();
void SetSettingsDefaults();
};
extern PlayerEventLogs player_event_logs;
#endif //EQEMU_PLAYER_EVENT_LOGS_H
+971
View File
@@ -0,0 +1,971 @@
#ifndef EQEMU_PLAYER_EVENTS_H
#define EQEMU_PLAYER_EVENTS_H
#include <string>
#include <cereal/cereal.hpp>
#include "../types.h"
#include "../repositories/player_event_logs_repository.h"
namespace PlayerEvent {
enum EventType {
GM_COMMAND = 1,
ZONING,
AA_GAIN,
AA_PURCHASE,
FORAGE_SUCCESS,
FORAGE_FAILURE,
FISH_SUCCESS,
FISH_FAILURE,
ITEM_DESTROY,
WENT_ONLINE,
WENT_OFFLINE,
LEVEL_GAIN,
LEVEL_LOSS,
LOOT_ITEM,
MERCHANT_PURCHASE,
MERCHANT_SELL,
GROUP_JOIN, // unimplemented
GROUP_LEAVE, // unimplemented
RAID_JOIN, // unimplemented
RAID_LEAVE, // unimplemented
GROUNDSPAWN_PICKUP,
NPC_HANDIN,
SKILL_UP,
TASK_ACCEPT,
TASK_UPDATE,
TASK_COMPLETE,
TRADE,
GIVE_ITEM, // unimplemented
SAY,
REZ_ACCEPTED,
DEATH,
COMBINE_FAILURE,
COMBINE_SUCCESS,
DROPPED_ITEM,
SPLIT_MONEY,
DZ_JOIN, // unimplemented
DZ_LEAVE, // unimplemented
TRADER_PURCHASE,
TRADER_SELL,
BANDOLIER_CREATE, // unimplemented
BANDOLIER_SWAP, // unimplemented
DISCOVER_ITEM,
POSSIBLE_HACK,
KILLED_NPC,
KILLED_NAMED_NPC,
KILLED_RAID_NPC,
ITEM_CREATION,
MAX // dont remove
};
// Don't ever remove items, even if they are deprecated
// If event is deprecated just tag (Deprecated) in the name
// If event is unimplemented just tag (Unimplemented) in the name
// Events don't get saved to the database if unimplemented or deprecated
// Events tagged as deprecated will get automatically removed
static const char *EventName[PlayerEvent::MAX] = {
"None",
"GM Command",
"Zoning",
"AA Gain",
"AA Purchase",
"Forage Success",
"Forage Failure",
"Fish Success",
"Fish Failure",
"Item Destroy",
"Went Online",
"Went Offline",
"Level Gain",
"Level Loss",
"Loot Item",
"Merchant Purchase",
"Merchant Sell",
"Group Join (Unimplemented)",
"Group Leave (Unimplemented)",
"Raid Join (Unimplemented)",
"Raid Leave (Unimplemented)",
"Groundspawn Pickup",
"NPC Handin",
"Skill Up",
"Task Accept",
"Task Update",
"Task Complete",
"Trade",
"Given Item (Unimplemented)",
"Say",
"Rez Accepted",
"Death",
"Combine Failure",
"Combine Success",
"Dropped Item",
"Split Money",
"DZ Join (Unimplemented)",
"DZ Leave (Unimplemented)",
"Trader Purchase",
"Trader Sell",
"Bandolier Create (Unimplemented)",
"Bandolier Swap (Unimplemented)",
"Discover Item",
"Possible Hack",
"Killed NPC",
"Killed Named NPC",
"Killed Raid NPC",
"Item Creation"
};
// Generic struct used by all events
struct PlayerEvent {
int64 account_id;
std::string account_name;
int64 character_id;
std::string character_name;
int64 guild_id;
std::string guild_name;
int zone_id;
std::string zone_short_name;
std::string zone_long_name;
int instance_id;
float x;
float y;
float z;
float heading;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(account_id),
CEREAL_NVP(account_name),
CEREAL_NVP(character_id),
CEREAL_NVP(character_name),
CEREAL_NVP(guild_id),
CEREAL_NVP(guild_name),
CEREAL_NVP(zone_id),
CEREAL_NVP(zone_short_name),
CEREAL_NVP(zone_long_name),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading)
);
}
};
// contains metadata in use for things like log/discord formatters
// along with the actual event to be persisted
struct PlayerEventContainer {
PlayerEvent player_event;
PlayerEventLogsRepository::PlayerEventLogs player_event_log;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(player_event),
CEREAL_NVP(player_event_log)
);
}
};
// used in events with no extra data
struct EmptyEvent {
std::string noop; // noop, gets discard upstream
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(noop)
);
}
};
// used in Trade event
struct ItemCreationEvent {
int64 item_id;
std::string item_name;
uint16 to_slot;
int16 charges;
uint32 aug1;
uint32 aug2;
uint32 aug3;
uint32 aug4;
uint32 aug5;
uint32 aug6;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(to_slot),
CEREAL_NVP(charges),
CEREAL_NVP(aug1),
CEREAL_NVP(aug2),
CEREAL_NVP(aug3),
CEREAL_NVP(aug4),
CEREAL_NVP(aug5),
CEREAL_NVP(aug6),
CEREAL_NVP(attuned)
);
}
};
// used in Trade event
struct TradeItem {
int64 item_id;
std::string item_name;
int32 slot;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot)
);
}
};
// used in Trade event
class TradeItemEntry {
public:
uint16 slot;
uint32 item_id;
std::string item_name;
uint16 charges;
uint32 aug_1_item_id;
std::string aug_1_item_name;
uint32 aug_2_item_id;
std::string aug_2_item_name;
uint32 aug_3_item_id;
std::string aug_3_item_name;
uint32 aug_4_item_id;
std::string aug_4_item_name;
uint32 aug_5_item_id;
std::string aug_5_item_name;
uint32 aug_6_item_id;
std::string aug_6_item_name;
bool in_bag;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(slot),
CEREAL_NVP(item_id),
CEREAL_NVP(charges),
CEREAL_NVP(aug_1_item_id),
CEREAL_NVP(aug_2_item_id),
CEREAL_NVP(aug_3_item_id),
CEREAL_NVP(aug_4_item_id),
CEREAL_NVP(aug_5_item_id),
CEREAL_NVP(in_bag)
);
}
};
/**
* Events
*/
struct Money {
int32 platinum;
int32 gold;
int32 silver;
int32 copper;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(platinum),
CEREAL_NVP(gold),
CEREAL_NVP(silver),
CEREAL_NVP(copper)
);
}
};
struct TradeEvent {
uint32 character_1_id;
std::string character_1_name;
uint32 character_2_id;
std::string character_2_name;
Money character_1_give_money;
Money character_2_give_money;
std::vector<TradeItemEntry> character_1_give_items;
std::vector<TradeItemEntry> character_2_give_items;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(character_1_id),
CEREAL_NVP(character_1_name),
CEREAL_NVP(character_2_id),
CEREAL_NVP(character_2_name),
CEREAL_NVP(character_1_give_money),
CEREAL_NVP(character_2_give_money),
CEREAL_NVP(character_1_give_items),
CEREAL_NVP(character_2_give_items)
);
}
};
struct GMCommandEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ZoningEvent {
std::string from_zone_long_name;
std::string from_zone_short_name;
int32 from_zone_id;
int32 from_instance_id;
int32 from_instance_version;
std::string to_zone_long_name;
std::string to_zone_short_name;
int32 to_zone_id;
int32 to_instance_id;
int32 to_instance_version;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_zone_long_name),
CEREAL_NVP(from_zone_short_name),
CEREAL_NVP(from_zone_id),
CEREAL_NVP(from_instance_id),
CEREAL_NVP(from_instance_version),
CEREAL_NVP(to_zone_long_name),
CEREAL_NVP(to_zone_short_name),
CEREAL_NVP(to_zone_id),
CEREAL_NVP(to_instance_id),
CEREAL_NVP(to_instance_version)
);
}
};
struct AAGainedEvent {
uint32 aa_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(CEREAL_NVP(aa_gained));
}
};
struct AAPurchasedEvent {
int32 aa_id;
int32 aa_cost;
int32 aa_previous_id;
int32 aa_next_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(aa_id),
CEREAL_NVP(aa_cost),
CEREAL_NVP(aa_previous_id),
CEREAL_NVP(aa_next_id)
);
}
};
struct ForageSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct FishSuccessEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct DestroyItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
std::string reason;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(reason),
CEREAL_NVP(charges)
);
}
};
struct LevelGainedEvent {
uint32 from_level;
uint8 to_level;
int levels_gained;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_gained)
);
}
};
struct LevelLostEvent {
uint32 from_level;
uint8 to_level;
int levels_lost;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(from_level),
CEREAL_NVP(to_level),
CEREAL_NVP(levels_lost)
);
}
};
struct LootItemEvent {
uint32 item_id;
std::string item_name;
int16 charges;
uint32 npc_id;
std::string corpse_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(npc_id),
CEREAL_NVP(corpse_name)
);
}
};
struct MerchantPurchaseEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct MerchantSellEvent {
uint32 npc_id;
std::string merchant_name;
uint32 merchant_type;
uint32 item_id;
std::string item_name;
int16 charges;
uint32 cost;
uint32 alternate_currency_id;
uint64 player_money_balance;
uint64 player_currency_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(merchant_name),
CEREAL_NVP(merchant_type),
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(cost),
CEREAL_NVP(alternate_currency_id),
CEREAL_NVP(player_money_balance),
CEREAL_NVP(player_currency_balance)
);
}
};
struct SkillUpEvent {
uint32 skill_id;
int value;
int16 max_skill;
std::string against_who;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(skill_id),
CEREAL_NVP(value),
CEREAL_NVP(max_skill),
CEREAL_NVP(against_who)
);
}
};
struct TaskAcceptEvent {
uint32 npc_id;
std::string npc_name;
uint32 task_id;
std::string task_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(task_id),
CEREAL_NVP(task_name)
);
}
};
struct TaskUpdateEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct TaskCompleteEvent {
uint32 task_id;
std::string task_name;
uint32 activity_id;
uint32 done_count;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(task_id),
CEREAL_NVP(task_name),
CEREAL_NVP(activity_id),
CEREAL_NVP(done_count)
);
}
};
struct GroundSpawnPickupEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
struct SayEvent {
std::string message;
std::string target;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message),
CEREAL_NVP(target)
);
}
};
struct ResurrectAcceptEvent {
std::string resurrecter_name;
std::string spell_name;
uint32 spell_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(resurrecter_name),
CEREAL_NVP(spell_name),
CEREAL_NVP(spell_id)
);
}
};
struct CombineEvent {
uint32 recipe_id;
std::string recipe_name;
uint32 made_count;
uint32 tradeskill_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(recipe_id),
CEREAL_NVP(recipe_name),
CEREAL_NVP(made_count),
CEREAL_NVP(tradeskill_id)
);
}
};
struct DroppedItemEvent {
uint32 item_id;
std::string item_name;
int16 slot_id;
uint32 charges;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(slot_id),
CEREAL_NVP(charges)
);
}
};
struct DeathEvent {
uint32 killer_id;
std::string killer_name;
int64 damage;
uint32 spell_id;
std::string spell_name;
int skill_id;
std::string skill_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(killer_id),
CEREAL_NVP(killer_name),
CEREAL_NVP(damage),
CEREAL_NVP(spell_id),
CEREAL_NVP(spell_name),
CEREAL_NVP(skill_id),
CEREAL_NVP(skill_name)
);
}
};
struct SplitMoneyEvent {
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderPurchaseEvent {
uint32 item_id;
std::string item_name;
uint32 trader_id;
std::string trader_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(trader_id),
CEREAL_NVP(trader_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct TraderSellEvent {
uint32 item_id;
std::string item_name;
uint32 buyer_id;
std::string buyer_name;
uint32 price;
uint32 charges;
uint32 total_cost;
uint64 player_money_balance;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(buyer_id),
CEREAL_NVP(buyer_name),
CEREAL_NVP(price),
CEREAL_NVP(charges),
CEREAL_NVP(total_cost),
CEREAL_NVP(player_money_balance)
);
}
};
struct DiscoverItemEvent {
uint32 item_id;
std::string item_name;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name)
);
}
};
class HandinEntry {
public:
uint32 item_id;
std::string item_name;
uint16 charges;
bool attuned;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(item_id),
CEREAL_NVP(item_name),
CEREAL_NVP(charges),
CEREAL_NVP(attuned)
);
}
};
class HandinMoney {
public:
uint32 copper;
uint32 silver;
uint32 gold;
uint32 platinum;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(copper),
CEREAL_NVP(silver),
CEREAL_NVP(gold),
CEREAL_NVP(platinum)
);
}
};
struct HandinEvent {
uint32 npc_id;
std::string npc_name;
std::vector<HandinEntry> handin_items;
HandinMoney handin_money;
std::vector<HandinEntry> return_items;
HandinMoney return_money;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(handin_items),
CEREAL_NVP(handin_money),
CEREAL_NVP(return_items),
CEREAL_NVP(return_money)
);
}
};
struct PossibleHackEvent {
std::string message;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(message)
);
}
};
struct KilledNPCEvent {
uint32 npc_id;
std::string npc_name;
uint32 combat_time_seconds;
uint64 total_damage_per_second_taken;
uint64 total_heal_per_second_taken;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(npc_id),
CEREAL_NVP(npc_name),
CEREAL_NVP(combat_time_seconds),
CEREAL_NVP(total_damage_per_second_taken),
CEREAL_NVP(total_heal_per_second_taken)
);
}
};
}
#endif //EQEMU_PLAYER_EVENTS_H
#define RecordPlayerEventLog(event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
#define RecordPlayerEventLogWithClient(c, event_type, event_data) do {\
if (player_event_logs.IsEventEnabled(event_type)) {\
worldserver.SendPacket(\
player_event_logs.RecordEvent(\
event_type,\
(c)->GetPlayerEvent(),\
event_data\
).get()\
);\
}\
} while (0)
+1 -1
View File
@@ -132,7 +132,7 @@ enum { //reuse times
InstillDoubtReuseTime = 9,
FishingReuseTime = 11,
ForagingReuseTime = 50,
MendReuseTime = 290,
MendReuseTime = 360,
BashReuseTime = 5,
BackstabReuseTime = 9,
KickReuseTime = 5,
+17 -17
View File
@@ -61,7 +61,7 @@ bool BaseGuildManager::LoadGuilds() {
}
for (auto row=results.begin();row!=results.end();++row)
_CreateGuild(atoi(row[0]), row[1], atoi(row[2]), atoi(row[3]), row[4], row[5], row[6], row[7]);
_CreateGuild(Strings::ToInt(row[0]), row[1], Strings::ToInt(row[2]), Strings::ToInt(row[3]), row[4], row[5], row[6], row[7]);
LogInfo("Loaded [{}] Guilds", Strings::Commify(std::to_string(results.RowCount())));
@@ -75,8 +75,8 @@ bool BaseGuildManager::LoadGuilds() {
for (auto row=results.begin();row!=results.end();++row)
{
uint32 guild_id = atoi(row[0]);
uint8 rankn = atoi(row[1]);
uint32 guild_id = Strings::ToInt(row[0]);
uint8 rankn = Strings::ToInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -131,7 +131,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
auto row = results.begin();
info = _CreateGuild(guild_id, row[0], atoi(row[1]), atoi(row[2]), row[3], row[4], row[5], row[6]);
info = _CreateGuild(guild_id, row[0], Strings::ToInt(row[1]), Strings::ToInt(row[2]), row[3], row[4], row[5], row[6]);
query = StringFormat("SELECT guild_id, `rank`, title, can_hear, can_speak, can_invite, can_remove, can_promote, can_demote, can_motd, can_warpeace "
"FROM guild_ranks WHERE guild_id=%lu", (unsigned long)guild_id);
@@ -144,7 +144,7 @@ bool BaseGuildManager::RefreshGuild(uint32 guild_id) {
for (auto row=results.begin();row!=results.end();++row)
{
uint8 rankn = atoi(row[1]);
uint8 rankn = Strings::ToInt(row[1]);
if(rankn > GUILD_MAX_RANK) {
LogGuilds("Found invalid (too high) rank [{}] for guild [{}], skipping", rankn, guild_id);
@@ -787,7 +787,7 @@ bool BaseGuildManager::GetBankerFlag(uint32 CharID)
auto row = results.begin();
bool IsBanker = atoi(row[0]);
bool IsBanker = Strings::ToInt(row[0]);
return IsBanker;
}
@@ -817,7 +817,7 @@ bool BaseGuildManager::GetAltFlag(uint32 CharID)
auto row = results.begin();
bool IsAlt = atoi(row[0]);
bool IsAlt = Strings::ToInt(row[0]);
return IsAlt;
}
@@ -873,19 +873,19 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` "
static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) {
//fields from `characer_`
into.char_id = atoi(row[0]);
into.char_id = Strings::ToInt(row[0]);
into.char_name = row[1];
into.class_ = atoi(row[2]);
into.level = atoi(row[3]);
into.time_last_on = atoul(row[4]);
into.zone_id = atoi(row[5]);
into.class_ = Strings::ToInt(row[2]);
into.level = Strings::ToInt(row[3]);
into.time_last_on = Strings::ToUnsignedInt(row[4]);
into.zone_id = Strings::ToInt(row[5]);
//fields from `guild_members`, leave at defaults if missing
into.guild_id = row[6] ? atoi(row[6]) : GUILD_NONE;
into.rank = row[7] ? atoi(row[7]) : (GUILD_MAX_RANK+1);
into.guild_id = row[6] ? Strings::ToInt(row[6]) : GUILD_NONE;
into.rank = row[7] ? Strings::ToInt(row[7]) : (GUILD_MAX_RANK+1);
into.tribute_enable = row[8] ? (row[8][0] == '0'?false:true) : false;
into.total_tribute = row[9] ? atoi(row[9]) : 0;
into.last_tribute = row[10]? atoul(row[10]) : 0; //timestamp
into.total_tribute = row[9] ? Strings::ToInt(row[9]) : 0;
into.last_tribute = row[10]? Strings::ToUnsignedInt(row[10]) : 0; //timestamp
into.banker = row[11]? (row[11][0] == '0'?false:true) : false;
into.public_note = row[12]? row[12] : "";
into.alt = row[13]? (row[13][0] == '0'?false:true) : false;
@@ -1258,7 +1258,7 @@ uint32 BaseGuildManager::GetGuildIDByCharacterID(uint32 character_id)
}
auto row = results.begin();
auto guild_id = std::stoul(row[0]);
auto guild_id = Strings::ToUnsignedInt(row[0]);
return guild_id;
}
+4 -2
View File
@@ -272,6 +272,8 @@ inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
#include <brotli/encode.h>
#endif
#include "../strings.h"
/*
* Declaration
*/
@@ -3812,12 +3814,12 @@ inline bool brotli_decompressor::decompress(const char *data,
if (std::regex_match(b, e, cm, re_another_range)) {
ssize_t first = -1;
if (!cm.str(1).empty()) {
first = static_cast<ssize_t>(std::stoll(cm.str(1)));
first = static_cast<ssize_t>(Strings::ToBigInt(cm.str(1)));
}
ssize_t last = -1;
if (!cm.str(2).empty()) {
last = static_cast<ssize_t>(std::stoll(cm.str(2)));
last = static_cast<ssize_t>(Strings::ToBigInt(cm.str(2)));
}
if (first != -1 && last != -1 && first > last) {
+50 -16
View File
@@ -24,16 +24,16 @@
#include "rulesys.h"
#include "shareddb.h"
#include "strings.h"
#include "util/uuid.h"
//#include "../common/light_source.h"
#include <limits.h>
//#include <iostream>
int32 NextItemInstSerialNumber = 1;
uint32 NextItemInstSerialNumber = 1;
static inline int32 GetNextItemInstSerialNumber() {
static inline uint32 GetNextItemInstSerialNumber() {
// The Bazaar relies on each item a client has up for Trade having a unique
// identifier. This 'SerialNumber' is sent in Serialized item packets and
@@ -45,7 +45,7 @@ static inline int32 GetNextItemInstSerialNumber() {
// NextItemInstSerialNumber is the next one to hand out.
//
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
if(NextItemInstSerialNumber >= INT_MAX)
if(NextItemInstSerialNumber >= UINT_MAX)
NextItemInstSerialNumber = 1;
else
NextItemInstSerialNumber++;
@@ -56,13 +56,21 @@ static inline int32 GetNextItemInstSerialNumber() {
//
// class EQ::ItemInstance
//
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
EQ::ItemInstance::ItemInstance(const ItemData* item, const std::string& guid, int16 charges) {
m_use_type = ItemInstNormal;
if(item) {
m_item = new ItemData(*item);
} else {
m_item = nullptr;
}
if (guid.empty()) {
m_guid = EQ::Util::UUID::Generate().ToString();
}
else {
m_guid = guid;
}
m_charges = charges;
m_price = 0;
m_attuned = false;
@@ -72,7 +80,7 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
else
m_color = 0;
m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_serial_number = GetNextItemInstSerialNumber();
m_exp = 0;
m_evolveLvl = 0;
@@ -85,9 +93,10 @@ EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
m_currentslot = 0;
}
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, const std::string& guid, int16 charges) {
m_use_type = ItemInstNormal;
m_item = db->GetItem(item_id);
if(m_item) {
@@ -97,6 +106,13 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
m_item = nullptr;
}
if (guid.empty()) {
m_guid = EQ::Util::UUID::Generate().ToString();
}
else {
m_guid = guid;
}
m_charges = charges;
m_price = 0;
m_merchantslot = 0;
@@ -106,7 +122,7 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
else
m_color = 0;
m_merchantcount = 1;
m_SerialNumber = GetNextItemInstSerialNumber();
m_serial_number = GetNextItemInstSerialNumber();
m_exp = 0;
m_evolveLvl = 0;
@@ -119,17 +135,20 @@ EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
m_currentslot = 0;
}
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
m_use_type = use_type;
m_guid = EQ::Util::UUID::Generate().ToString();
m_item = nullptr;
m_charges = 0;
m_price = 0;
m_attuned = false;
m_merchantslot = 0;
m_color = 0;
m_serial_number = 0;
m_exp = 0;
m_evolveLvl = 0;
m_activated = false;
@@ -141,6 +160,8 @@ EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
m_ornament_hero_model = 0;
m_recast_timestamp = 0;
m_new_id_file = 0;
m_currentslot = 0;
m_merchantcount = 0;
}
// Make a copy of an EQ::ItemInstance object
@@ -152,6 +173,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
else
m_item = nullptr;
m_guid = copy.m_guid;
m_charges=copy.m_charges;
m_price=copy.m_price;
m_color=copy.m_color;
@@ -176,7 +198,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) {
m_custom_data[iter->first] = iter->second;
}
m_SerialNumber = copy.m_SerialNumber;
m_serial_number = copy.m_serial_number;
m_custom_data = copy.m_custom_data;
m_timers = copy.m_timers;
@@ -358,15 +380,27 @@ int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
return (i <= invaug::SOCKET_END) ? i : INVALID_INDEX;
}
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
{
if (!m_item || !m_item->IsClassCommon())
return false;
if (!m_item || !m_item->IsClassCommon()) {
return false;
}
if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
if (
(
!GetItem(slot) &&
m_item->AugSlotVisible[slot]
) &&
augment_type == -1 ||
(
m_item->AugSlotType[slot] &&
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
)
) {
return true;
}
return false;
return false;
}
// Retrieve item inside container
@@ -598,7 +632,7 @@ bool EQ::ItemInstance::UpdateOrnamentationInfo() {
SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
if (strlen(ornamentItem->IDFile) > 2)
{
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
SetOrnamentationIDFile(Strings::ToInt(&ornamentItem->IDFile[2]));
}
else
{
+10 -7
View File
@@ -69,9 +69,9 @@ namespace EQ
/////////////////////////
// Constructors/Destructor
ItemInstance(const ItemData* item = nullptr, int16 charges = 0);
ItemInstance(const ItemData* item, const std::string& guid, int16 charges);
ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges = 0);
ItemInstance(SharedDatabase *db, uint32 item_id, const std::string &guid, int16 charges);
ItemInstance(ItemInstTypes use_type);
@@ -79,6 +79,8 @@ namespace EQ
~ItemInstance();
inline std::string GetGuid() const { return m_guid; }
// Query item type
bool IsType(item::ItemClass item_class) const;
@@ -101,8 +103,8 @@ namespace EQ
//
bool IsAugmentable() const;
bool AvailableWearSlot(uint32 aug_wear_slots) const;
int8 AvailableAugmentSlot(int32 augtype) const;
bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const;
int8 AvailableAugmentSlot(int32 augment_type) const;
bool IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const;
inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : 0); }
inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == item::ItemEffectExpendable) || (m_item->ItemType == item::ItemTypePotion)) : false); }
@@ -225,8 +227,8 @@ namespace EQ
std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(InternalSerializedItem_Struct)); return ser; }
void Serialize(OutBuffer& ob, int16 slot_id) const { InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); }
inline int32 GetSerialNumber() const { return m_SerialNumber; }
inline void SetSerialNumber(int32 id) { m_SerialNumber = id; }
inline int32 GetSerialNumber() const { return m_serial_number; }
inline void SetSerialNumber(int32 id) { m_serial_number = id; }
std::map<std::string, ::Timer>& GetTimers() { return m_timers; }
void SetTimer(std::string name, uint32 time);
@@ -303,6 +305,7 @@ namespace EQ
void _PutItem(uint8 index, ItemInstance* inst) { m_contents[index] = inst; }
std::string m_guid;
ItemInstTypes m_use_type; // Usage type for item
const ItemData* m_item; // Ptr to item data
int16 m_charges; // # of charges for chargeable items
@@ -312,7 +315,7 @@ namespace EQ
int16 m_currentslot;
bool m_attuned;
int32 m_merchantcount; //number avaliable on the merchant, -1=unlimited
int32 m_SerialNumber; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_serial_number; // Unique identifier for this instance of an item. Needed for Bazaar.
uint32 m_exp;
int8 m_evolveLvl;
bool m_activated;
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -18,6 +18,7 @@
#include "misc.h"
#include "types.h"
#include <cstring>
#include "strings.h"
std::map<int,std::string> DBFieldNames;
@@ -150,7 +151,7 @@ static char *temp=nullptr;
return false;
}
ptr++;
uint32 id = atoi(field[id_pos].c_str());
uint32 id = Strings::ToInt(field[id_pos].c_str());
items[id]=field;
for(i=0;i<10;i++) {
+2 -1
View File
@@ -21,6 +21,7 @@
#include "misc_functions.h"
#include <string.h>
#include <time.h>
#include "strings.h"
#ifndef WIN32
#include <netinet/in.h>
@@ -130,7 +131,7 @@ bool ParseAddress(const char* iAddress, uint32* oIP, uint16* oPort, char* errbuf
if (*oIP == 0)
return false;
if (oPort)
*oPort = atoi(sep.arg[1]);
*oPort = Strings::ToInt(sep.arg[1]);
return true;
}
return false;
+3 -3
View File
@@ -2095,13 +2095,13 @@ namespace SoF
}
else
{
val = atoi(&emu->lastName[2]);
val = Strings::ToInt(&emu->lastName[2]);
}
}
else
{
sep[0] = nullptr;
ofs = atoi(&emu->lastName[2]);
ofs = Strings::ToInt(&emu->lastName[2]);
sep[0] = '=';
if ((sep[1] < '0') || (sep[1] > '9'))
{
@@ -2109,7 +2109,7 @@ namespace SoF
}
else
{
val = atoi(&sep[1]);
val = Strings::ToInt(&sep[1]);
}
}
+16 -11
View File
@@ -22,26 +22,31 @@
EQEmuExePlatform exe_platform = ExePlatformNone;
void RegisterExecutablePlatform(EQEmuExePlatform p) {
void RegisterExecutablePlatform(EQEmuExePlatform p)
{
exe_platform = p;
}
const EQEmuExePlatform& GetExecutablePlatform() {
const EQEmuExePlatform &GetExecutablePlatform()
{
return exe_platform;
}
/**
* @return
*/
int GetExecutablePlatformInt(){
int GetExecutablePlatformInt()
{
return exe_platform;
}
/**
* Returns platform name by string
*
* @return
*/
bool IsWorld()
{
return exe_platform == EQEmuExePlatform::ExePlatformWorld;
}
bool IsQueryServ()
{
return exe_platform == EQEmuExePlatform::ExePlatformQueryServ;
}
std::string GetPlatformName()
{
switch (GetExecutablePlatformInt()) {
+2
View File
@@ -44,5 +44,7 @@ void RegisterExecutablePlatform(EQEmuExePlatform p);
const EQEmuExePlatform& GetExecutablePlatform();
int GetExecutablePlatformInt();
std::string GetPlatformName();
bool IsWorld();
bool IsQueryServ();
#endif
+1 -1
View File
@@ -288,7 +288,7 @@ bool PTimerList::Load(Database *db) {
PersistentTimer *cur;
for (auto row = results.begin(); row != results.end(); ++row) {
type = atoi(row[0]);
type = Strings::ToInt(row[0]);
start_time = strtoul(row[1], nullptr, 10);
timer_time = strtoul(row[2], nullptr, 10);
enabled = (row[3][0] == '1');
@@ -69,6 +69,7 @@ public:
int32_t expansion_bitmask;
uint8_t enforce_spell_settings;
uint8_t archery_setting;
uint32_t caster_range;
};
static std::string PrimaryKey()
@@ -129,6 +130,7 @@ public:
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -185,6 +187,7 @@ public:
"expansion_bitmask",
"enforce_spell_settings",
"archery_setting",
"caster_range",
};
}
@@ -275,6 +278,7 @@ public:
e.expansion_bitmask = -1;
e.enforce_spell_settings = 0;
e.archery_setting = 0;
e.caster_range = 0;
return e;
}
@@ -361,6 +365,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
return e;
}
@@ -443,6 +448,7 @@ public:
v.push_back(columns[47] + " = " + std::to_string(e.expansion_bitmask));
v.push_back(columns[48] + " = " + std::to_string(e.enforce_spell_settings));
v.push_back(columns[49] + " = " + std::to_string(e.archery_setting));
v.push_back(columns[50] + " = " + std::to_string(e.caster_range));
auto results = db.QueryDatabase(
fmt::format(
@@ -514,6 +520,7 @@ public:
v.push_back(std::to_string(e.expansion_bitmask));
v.push_back(std::to_string(e.enforce_spell_settings));
v.push_back(std::to_string(e.archery_setting));
v.push_back(std::to_string(e.caster_range));
auto results = db.QueryDatabase(
fmt::format(
@@ -593,6 +600,7 @@ public:
v.push_back(std::to_string(e.expansion_bitmask));
v.push_back(std::to_string(e.enforce_spell_settings));
v.push_back(std::to_string(e.archery_setting));
v.push_back(std::to_string(e.caster_range));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -676,6 +684,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
all_entries.push_back(e);
}
@@ -750,6 +759,7 @@ public:
e.expansion_bitmask = static_cast<int32_t>(atoi(row[47]));
e.enforce_spell_settings = static_cast<uint8_t>(strtoul(row[48], nullptr, 10));
e.archery_setting = static_cast<uint8_t>(strtoul(row[49], nullptr, 10));
e.caster_range = static_cast<uint32_t>(strtoul(row[50], nullptr, 10));
all_entries.push_back(e);
}
@@ -1,412 +0,0 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_EVENTLOG_REPOSITORY_H
#define EQEMU_BASE_EVENTLOG_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseEventlogRepository {
public:
struct Eventlog {
uint32_t id;
std::string accountname;
uint32_t accountid;
int32_t status;
std::string charname;
std::string target;
std::string time;
std::string descriptiontype;
std::string description;
int32_t event_nid;
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"accountname",
"accountid",
"status",
"charname",
"target",
"time",
"descriptiontype",
"description",
"event_nid",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"accountname",
"accountid",
"status",
"charname",
"target",
"time",
"descriptiontype",
"description",
"event_nid",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("eventlog");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static Eventlog NewEntity()
{
Eventlog e{};
e.id = 0;
e.accountname = "";
e.accountid = 0;
e.status = 0;
e.charname = "";
e.target = "None";
e.time = std::time(nullptr);
e.descriptiontype = "";
e.description = "";
e.event_nid = 0;
return e;
}
static Eventlog GetEventlog(
const std::vector<Eventlog> &eventlogs,
int eventlog_id
)
{
for (auto &eventlog : eventlogs) {
if (eventlog.id == eventlog_id) {
return eventlog;
}
}
return NewEntity();
}
static Eventlog FindOne(
Database& db,
int eventlog_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
eventlog_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int eventlog_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
eventlog_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const Eventlog &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.accountname) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.accountid));
v.push_back(columns[3] + " = " + std::to_string(e.status));
v.push_back(columns[4] + " = '" + Strings::Escape(e.charname) + "'");
v.push_back(columns[5] + " = '" + Strings::Escape(e.target) + "'");
v.push_back(columns[6] + " = '" + Strings::Escape(e.time) + "'");
v.push_back(columns[7] + " = '" + Strings::Escape(e.descriptiontype) + "'");
v.push_back(columns[8] + " = '" + Strings::Escape(e.description) + "'");
v.push_back(columns[9] + " = " + std::to_string(e.event_nid));
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static Eventlog InsertOne(
Database& db,
Eventlog e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.accountname) + "'");
v.push_back(std::to_string(e.accountid));
v.push_back(std::to_string(e.status));
v.push_back("'" + Strings::Escape(e.charname) + "'");
v.push_back("'" + Strings::Escape(e.target) + "'");
v.push_back("'" + Strings::Escape(e.time) + "'");
v.push_back("'" + Strings::Escape(e.descriptiontype) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.event_nid));
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<Eventlog> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.accountname) + "'");
v.push_back(std::to_string(e.accountid));
v.push_back(std::to_string(e.status));
v.push_back("'" + Strings::Escape(e.charname) + "'");
v.push_back("'" + Strings::Escape(e.target) + "'");
v.push_back("'" + Strings::Escape(e.time) + "'");
v.push_back("'" + Strings::Escape(e.descriptiontype) + "'");
v.push_back("'" + Strings::Escape(e.description) + "'");
v.push_back(std::to_string(e.event_nid));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Eventlog> All(Database& db)
{
std::vector<Eventlog> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<Eventlog> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Eventlog> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Eventlog e{};
e.id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.accountname = row[1] ? row[1] : "";
e.accountid = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.status = static_cast<int32_t>(atoi(row[3]));
e.charname = row[4] ? row[4] : "";
e.target = row[5] ? row[5] : "";
e.time = row[6] ? row[6] : "";
e.descriptiontype = row[7] ? row[7] : "";
e.description = row[8] ? row[8] : "";
e.event_nid = static_cast<int32_t>(atoi(row[9]));
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
};
#endif //EQEMU_BASE_EVENTLOG_REPOSITORY_H
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseMerchantlistRepository {
public:
struct Merchantlist {
@@ -24,6 +25,8 @@ public:
int32_t item;
int16_t faction_required;
uint8_t level_required;
uint8_t min_status;
uint8_t max_status;
uint16_t alt_currency_cost;
int32_t classes_required;
int32_t probability;
@@ -49,6 +52,8 @@ public:
"item",
"faction_required",
"level_required",
"min_status",
"max_status",
"alt_currency_cost",
"classes_required",
"probability",
@@ -70,6 +75,8 @@ public:
"item",
"faction_required",
"level_required",
"min_status",
"max_status",
"alt_currency_cost",
"classes_required",
"probability",
@@ -125,6 +132,8 @@ public:
e.item = 0;
e.faction_required = -100;
e.level_required = 0;
e.min_status = 0;
e.max_status = 255;
e.alt_currency_cost = 0;
e.classes_required = 65535;
e.probability = 100;
@@ -160,8 +169,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
merchantlist_id
)
);
@@ -175,16 +185,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
return e;
}
@@ -223,16 +235,18 @@ public:
v.push_back(columns[2] + " = " + std::to_string(e.item));
v.push_back(columns[3] + " = " + std::to_string(e.faction_required));
v.push_back(columns[4] + " = " + std::to_string(e.level_required));
v.push_back(columns[5] + " = " + std::to_string(e.alt_currency_cost));
v.push_back(columns[6] + " = " + std::to_string(e.classes_required));
v.push_back(columns[7] + " = " + std::to_string(e.probability));
v.push_back(columns[8] + " = '" + Strings::Escape(e.bucket_name) + "'");
v.push_back(columns[9] + " = '" + Strings::Escape(e.bucket_value) + "'");
v.push_back(columns[10] + " = " + std::to_string(e.bucket_comparison));
v.push_back(columns[11] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[12] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[13] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[14] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
v.push_back(columns[5] + " = " + std::to_string(e.min_status));
v.push_back(columns[6] + " = " + std::to_string(e.max_status));
v.push_back(columns[7] + " = " + std::to_string(e.alt_currency_cost));
v.push_back(columns[8] + " = " + std::to_string(e.classes_required));
v.push_back(columns[9] + " = " + std::to_string(e.probability));
v.push_back(columns[10] + " = '" + Strings::Escape(e.bucket_name) + "'");
v.push_back(columns[11] + " = '" + Strings::Escape(e.bucket_value) + "'");
v.push_back(columns[12] + " = " + std::to_string(e.bucket_comparison));
v.push_back(columns[13] + " = " + std::to_string(e.min_expansion));
v.push_back(columns[14] + " = " + std::to_string(e.max_expansion));
v.push_back(columns[15] + " = '" + Strings::Escape(e.content_flags) + "'");
v.push_back(columns[16] + " = '" + Strings::Escape(e.content_flags_disabled) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -259,6 +273,8 @@ public:
v.push_back(std::to_string(e.item));
v.push_back(std::to_string(e.faction_required));
v.push_back(std::to_string(e.level_required));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.max_status));
v.push_back(std::to_string(e.alt_currency_cost));
v.push_back(std::to_string(e.classes_required));
v.push_back(std::to_string(e.probability));
@@ -303,6 +319,8 @@ public:
v.push_back(std::to_string(e.item));
v.push_back(std::to_string(e.faction_required));
v.push_back(std::to_string(e.level_required));
v.push_back(std::to_string(e.min_status));
v.push_back(std::to_string(e.max_status));
v.push_back(std::to_string(e.alt_currency_cost));
v.push_back(std::to_string(e.classes_required));
v.push_back(std::to_string(e.probability));
@@ -351,16 +369,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -390,16 +410,18 @@ public:
e.item = static_cast<int32_t>(atoi(row[2]));
e.faction_required = static_cast<int16_t>(atoi(row[3]));
e.level_required = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[5], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[6]));
e.probability = static_cast<int32_t>(atoi(row[7]));
e.bucket_name = row[8] ? row[8] : "";
e.bucket_value = row[9] ? row[9] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[10], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[11]));
e.max_expansion = static_cast<int8_t>(atoi(row[12]));
e.content_flags = row[13] ? row[13] : "";
e.content_flags_disabled = row[14] ? row[14] : "";
e.min_status = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.max_status = static_cast<uint8_t>(strtoul(row[6], nullptr, 10));
e.alt_currency_cost = static_cast<uint16_t>(strtoul(row[7], nullptr, 10));
e.classes_required = static_cast<int32_t>(atoi(row[8]));
e.probability = static_cast<int32_t>(atoi(row[9]));
e.bucket_name = row[10] ? row[10] : "";
e.bucket_value = row[11] ? row[11] : "";
e.bucket_comparison = static_cast<uint8_t>(strtoul(row[12], nullptr, 10));
e.min_expansion = static_cast<int8_t>(atoi(row[13]));
e.max_expansion = static_cast<int8_t>(atoi(row[14]));
e.content_flags = row[15] ? row[15] : "";
e.content_flags_disabled = row[16] ? row[16] : "";
all_entries.push_back(e);
}
@@ -16,11 +16,14 @@
#include "../../strings.h"
#include <ctime>
class BaseNpcScaleGlobalBaseRepository {
public:
struct NpcScaleGlobalBase {
int32_t type;
int32_t level;
std::string zone_id_list;
std::string instance_version_list;
int32_t ac;
int32_t hp;
int32_t accuracy;
@@ -59,6 +62,8 @@ public:
return {
"type",
"level",
"zone_id_list",
"instance_version_list",
"ac",
"hp",
"accuracy",
@@ -93,6 +98,8 @@ public:
return {
"type",
"level",
"zone_id_list",
"instance_version_list",
"ac",
"hp",
"accuracy",
@@ -159,34 +166,36 @@ public:
{
NpcScaleGlobalBase e{};
e.type = 0;
e.level = 0;
e.ac = 0;
e.hp = 0;
e.accuracy = 0;
e.slow_mitigation = 0;
e.attack = 0;
e.strength = 0;
e.stamina = 0;
e.dexterity = 0;
e.agility = 0;
e.intelligence = 0;
e.wisdom = 0;
e.charisma = 0;
e.magic_resist = 0;
e.cold_resist = 0;
e.fire_resist = 0;
e.poison_resist = 0;
e.disease_resist = 0;
e.corruption_resist = 0;
e.physical_resist = 0;
e.min_dmg = 0;
e.max_dmg = 0;
e.hp_regen_rate = 0;
e.attack_delay = 0;
e.spell_scale = 100;
e.heal_scale = 100;
e.special_abilities = "";
e.type = 0;
e.level = 0;
e.zone_id_list = "";
e.instance_version_list = "";
e.ac = 0;
e.hp = 0;
e.accuracy = 0;
e.slow_mitigation = 0;
e.attack = 0;
e.strength = 0;
e.stamina = 0;
e.dexterity = 0;
e.agility = 0;
e.intelligence = 0;
e.wisdom = 0;
e.charisma = 0;
e.magic_resist = 0;
e.cold_resist = 0;
e.fire_resist = 0;
e.poison_resist = 0;
e.disease_resist = 0;
e.corruption_resist = 0;
e.physical_resist = 0;
e.min_dmg = 0;
e.max_dmg = 0;
e.hp_regen_rate = 0;
e.attack_delay = 0;
e.spell_scale = 100;
e.heal_scale = 100;
e.special_abilities = "";
return e;
}
@@ -212,8 +221,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
npc_scale_global_base_id
)
);
@@ -222,34 +232,36 @@ public:
if (results.RowCount() == 1) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = static_cast<int32_t>(atoi(row[5]));
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[25]));
e.attack_delay = static_cast<int32_t>(atoi(row[26]));
e.spell_scale = static_cast<int32_t>(atoi(row[27]));
e.heal_scale = static_cast<int32_t>(atoi(row[28]));
e.special_abilities = row[29] ? row[29] : "";
return e;
}
@@ -285,32 +297,34 @@ public:
v.push_back(columns[0] + " = " + std::to_string(e.type));
v.push_back(columns[1] + " = " + std::to_string(e.level));
v.push_back(columns[2] + " = " + std::to_string(e.ac));
v.push_back(columns[3] + " = " + std::to_string(e.hp));
v.push_back(columns[4] + " = " + std::to_string(e.accuracy));
v.push_back(columns[5] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[6] + " = " + std::to_string(e.attack));
v.push_back(columns[7] + " = " + std::to_string(e.strength));
v.push_back(columns[8] + " = " + std::to_string(e.stamina));
v.push_back(columns[9] + " = " + std::to_string(e.dexterity));
v.push_back(columns[10] + " = " + std::to_string(e.agility));
v.push_back(columns[11] + " = " + std::to_string(e.intelligence));
v.push_back(columns[12] + " = " + std::to_string(e.wisdom));
v.push_back(columns[13] + " = " + std::to_string(e.charisma));
v.push_back(columns[14] + " = " + std::to_string(e.magic_resist));
v.push_back(columns[15] + " = " + std::to_string(e.cold_resist));
v.push_back(columns[16] + " = " + std::to_string(e.fire_resist));
v.push_back(columns[17] + " = " + std::to_string(e.poison_resist));
v.push_back(columns[18] + " = " + std::to_string(e.disease_resist));
v.push_back(columns[19] + " = " + std::to_string(e.corruption_resist));
v.push_back(columns[20] + " = " + std::to_string(e.physical_resist));
v.push_back(columns[21] + " = " + std::to_string(e.min_dmg));
v.push_back(columns[22] + " = " + std::to_string(e.max_dmg));
v.push_back(columns[23] + " = " + std::to_string(e.hp_regen_rate));
v.push_back(columns[24] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[25] + " = " + std::to_string(e.spell_scale));
v.push_back(columns[26] + " = " + std::to_string(e.heal_scale));
v.push_back(columns[27] + " = '" + Strings::Escape(e.special_abilities) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.zone_id_list) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(columns[4] + " = " + std::to_string(e.ac));
v.push_back(columns[5] + " = " + std::to_string(e.hp));
v.push_back(columns[6] + " = " + std::to_string(e.accuracy));
v.push_back(columns[7] + " = " + std::to_string(e.slow_mitigation));
v.push_back(columns[8] + " = " + std::to_string(e.attack));
v.push_back(columns[9] + " = " + std::to_string(e.strength));
v.push_back(columns[10] + " = " + std::to_string(e.stamina));
v.push_back(columns[11] + " = " + std::to_string(e.dexterity));
v.push_back(columns[12] + " = " + std::to_string(e.agility));
v.push_back(columns[13] + " = " + std::to_string(e.intelligence));
v.push_back(columns[14] + " = " + std::to_string(e.wisdom));
v.push_back(columns[15] + " = " + std::to_string(e.charisma));
v.push_back(columns[16] + " = " + std::to_string(e.magic_resist));
v.push_back(columns[17] + " = " + std::to_string(e.cold_resist));
v.push_back(columns[18] + " = " + std::to_string(e.fire_resist));
v.push_back(columns[19] + " = " + std::to_string(e.poison_resist));
v.push_back(columns[20] + " = " + std::to_string(e.disease_resist));
v.push_back(columns[21] + " = " + std::to_string(e.corruption_resist));
v.push_back(columns[22] + " = " + std::to_string(e.physical_resist));
v.push_back(columns[23] + " = " + std::to_string(e.min_dmg));
v.push_back(columns[24] + " = " + std::to_string(e.max_dmg));
v.push_back(columns[25] + " = " + std::to_string(e.hp_regen_rate));
v.push_back(columns[26] + " = " + std::to_string(e.attack_delay));
v.push_back(columns[27] + " = " + std::to_string(e.spell_scale));
v.push_back(columns[28] + " = " + std::to_string(e.heal_scale));
v.push_back(columns[29] + " = '" + Strings::Escape(e.special_abilities) + "'");
auto results = db.QueryDatabase(
fmt::format(
@@ -334,6 +348,8 @@ public:
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.level));
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back("'" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(std::to_string(e.ac));
v.push_back(std::to_string(e.hp));
v.push_back(std::to_string(e.accuracy));
@@ -391,6 +407,8 @@ public:
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.level));
v.push_back("'" + Strings::Escape(e.zone_id_list) + "'");
v.push_back("'" + Strings::Escape(e.instance_version_list) + "'");
v.push_back(std::to_string(e.ac));
v.push_back(std::to_string(e.hp));
v.push_back(std::to_string(e.accuracy));
@@ -450,34 +468,36 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = static_cast<int32_t>(atoi(row[5]));
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[25]));
e.attack_delay = static_cast<int32_t>(atoi(row[26]));
e.spell_scale = static_cast<int32_t>(atoi(row[27]));
e.heal_scale = static_cast<int32_t>(atoi(row[28]));
e.special_abilities = row[29] ? row[29] : "";
all_entries.push_back(e);
}
@@ -502,34 +522,36 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
NpcScaleGlobalBase e{};
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.ac = static_cast<int32_t>(atoi(row[2]));
e.hp = static_cast<int32_t>(atoi(row[3]));
e.accuracy = static_cast<int32_t>(atoi(row[4]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[5]));
e.attack = static_cast<int32_t>(atoi(row[6]));
e.strength = static_cast<int32_t>(atoi(row[7]));
e.stamina = static_cast<int32_t>(atoi(row[8]));
e.dexterity = static_cast<int32_t>(atoi(row[9]));
e.agility = static_cast<int32_t>(atoi(row[10]));
e.intelligence = static_cast<int32_t>(atoi(row[11]));
e.wisdom = static_cast<int32_t>(atoi(row[12]));
e.charisma = static_cast<int32_t>(atoi(row[13]));
e.magic_resist = static_cast<int32_t>(atoi(row[14]));
e.cold_resist = static_cast<int32_t>(atoi(row[15]));
e.fire_resist = static_cast<int32_t>(atoi(row[16]));
e.poison_resist = static_cast<int32_t>(atoi(row[17]));
e.disease_resist = static_cast<int32_t>(atoi(row[18]));
e.corruption_resist = static_cast<int32_t>(atoi(row[19]));
e.physical_resist = static_cast<int32_t>(atoi(row[20]));
e.min_dmg = static_cast<int32_t>(atoi(row[21]));
e.max_dmg = static_cast<int32_t>(atoi(row[22]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[23]));
e.attack_delay = static_cast<int32_t>(atoi(row[24]));
e.spell_scale = static_cast<int32_t>(atoi(row[25]));
e.heal_scale = static_cast<int32_t>(atoi(row[26]));
e.special_abilities = row[27] ? row[27] : "";
e.type = static_cast<int32_t>(atoi(row[0]));
e.level = static_cast<int32_t>(atoi(row[1]));
e.zone_id_list = row[2] ? row[2] : "";
e.instance_version_list = row[3] ? row[3] : "";
e.ac = static_cast<int32_t>(atoi(row[4]));
e.hp = static_cast<int32_t>(atoi(row[5]));
e.accuracy = static_cast<int32_t>(atoi(row[6]));
e.slow_mitigation = static_cast<int32_t>(atoi(row[7]));
e.attack = static_cast<int32_t>(atoi(row[8]));
e.strength = static_cast<int32_t>(atoi(row[9]));
e.stamina = static_cast<int32_t>(atoi(row[10]));
e.dexterity = static_cast<int32_t>(atoi(row[11]));
e.agility = static_cast<int32_t>(atoi(row[12]));
e.intelligence = static_cast<int32_t>(atoi(row[13]));
e.wisdom = static_cast<int32_t>(atoi(row[14]));
e.charisma = static_cast<int32_t>(atoi(row[15]));
e.magic_resist = static_cast<int32_t>(atoi(row[16]));
e.cold_resist = static_cast<int32_t>(atoi(row[17]));
e.fire_resist = static_cast<int32_t>(atoi(row[18]));
e.poison_resist = static_cast<int32_t>(atoi(row[19]));
e.disease_resist = static_cast<int32_t>(atoi(row[20]));
e.corruption_resist = static_cast<int32_t>(atoi(row[21]));
e.physical_resist = static_cast<int32_t>(atoi(row[22]));
e.min_dmg = static_cast<int32_t>(atoi(row[23]));
e.max_dmg = static_cast<int32_t>(atoi(row[24]));
e.hp_regen_rate = static_cast<int32_t>(atoi(row[25]));
e.attack_delay = static_cast<int32_t>(atoi(row[26]));
e.spell_scale = static_cast<int32_t>(atoi(row[27]));
e.heal_scale = static_cast<int32_t>(atoi(row[28]));
e.special_abilities = row[29] ? row[29] : "";
all_entries.push_back(e);
}
@@ -9,22 +9,21 @@
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_HACKERS_REPOSITORY_H
#define EQEMU_BASE_HACKERS_REPOSITORY_H
#ifndef EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
class BaseHackersRepository {
class BasePlayerEventLogSettingsRepository {
public:
struct Hackers {
int32_t id;
std::string account;
std::string name;
std::string hacked;
std::string zone;
std::string date;
struct PlayerEventLogSettings {
int64_t id;
std::string event_name;
int8_t event_enabled;
int32_t retention_days;
int32_t discord_webhook_id;
};
static std::string PrimaryKey()
@@ -36,11 +35,10 @@ public:
{
return {
"id",
"account",
"name",
"hacked",
"zone",
"date",
"event_name",
"event_enabled",
"retention_days",
"discord_webhook_id",
};
}
@@ -48,11 +46,10 @@ public:
{
return {
"id",
"account",
"name",
"hacked",
"zone",
"date",
"event_name",
"event_enabled",
"retention_days",
"discord_webhook_id",
};
}
@@ -68,7 +65,7 @@ public:
static std::string TableName()
{
return std::string("hackers");
return std::string("player_event_log_settings");
}
static std::string BaseSelect()
@@ -89,57 +86,56 @@ public:
);
}
static Hackers NewEntity()
static PlayerEventLogSettings NewEntity()
{
Hackers e{};
PlayerEventLogSettings e{};
e.id = 0;
e.account = "";
e.name = "";
e.hacked = "";
e.zone = "";
e.date = std::time(nullptr);
e.id = 0;
e.event_name = "";
e.event_enabled = 0;
e.retention_days = 0;
e.discord_webhook_id = 0;
return e;
}
static Hackers GetHackers(
const std::vector<Hackers> &hackerss,
int hackers_id
static PlayerEventLogSettings GetPlayerEventLogSettings(
const std::vector<PlayerEventLogSettings> &player_event_log_settingss,
int player_event_log_settings_id
)
{
for (auto &hackers : hackerss) {
if (hackers.id == hackers_id) {
return hackers;
for (auto &player_event_log_settings : player_event_log_settingss) {
if (player_event_log_settings.id == player_event_log_settings_id) {
return player_event_log_settings;
}
}
return NewEntity();
}
static Hackers FindOne(
static PlayerEventLogSettings FindOne(
Database& db,
int hackers_id
int player_event_log_settings_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
hackers_id
PrimaryKey(),
player_event_log_settings_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
return e;
}
@@ -149,7 +145,7 @@ public:
static int DeleteOne(
Database& db,
int hackers_id
int player_event_log_settings_id
)
{
auto results = db.QueryDatabase(
@@ -157,7 +153,7 @@ public:
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
hackers_id
player_event_log_settings_id
)
);
@@ -166,18 +162,18 @@ public:
static int UpdateOne(
Database& db,
const Hackers &e
const PlayerEventLogSettings &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = '" + Strings::Escape(e.account) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.hacked) + "'");
v.push_back(columns[4] + " = '" + Strings::Escape(e.zone) + "'");
v.push_back(columns[5] + " = '" + Strings::Escape(e.date) + "'");
v.push_back(columns[0] + " = " + std::to_string(e.id));
v.push_back(columns[1] + " = '" + Strings::Escape(e.event_name) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.event_enabled));
v.push_back(columns[3] + " = " + std::to_string(e.retention_days));
v.push_back(columns[4] + " = " + std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -192,19 +188,18 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static Hackers InsertOne(
static PlayerEventLogSettings InsertOne(
Database& db,
Hackers e
PlayerEventLogSettings e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.account) + "'");
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back("'" + Strings::Escape(e.hacked) + "'");
v.push_back("'" + Strings::Escape(e.zone) + "'");
v.push_back("'" + Strings::Escape(e.date) + "'");
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -226,7 +221,7 @@ public:
static int InsertMany(
Database& db,
const std::vector<Hackers> &entries
const std::vector<PlayerEventLogSettings> &entries
)
{
std::vector<std::string> insert_chunks;
@@ -235,11 +230,10 @@ public:
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back("'" + Strings::Escape(e.account) + "'");
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back("'" + Strings::Escape(e.hacked) + "'");
v.push_back("'" + Strings::Escape(e.zone) + "'");
v.push_back("'" + Strings::Escape(e.date) + "'");
v.push_back("'" + Strings::Escape(e.event_name) + "'");
v.push_back(std::to_string(e.event_enabled));
v.push_back(std::to_string(e.retention_days));
v.push_back(std::to_string(e.discord_webhook_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -257,9 +251,9 @@ public:
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<Hackers> All(Database& db)
static std::vector<PlayerEventLogSettings> All(Database& db)
{
std::vector<Hackers> all_entries;
std::vector<PlayerEventLogSettings> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -271,14 +265,13 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
all_entries.push_back(e);
}
@@ -286,9 +279,9 @@ public:
return all_entries;
}
static std::vector<Hackers> GetWhere(Database& db, const std::string &where_filter)
static std::vector<PlayerEventLogSettings> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<Hackers> all_entries;
std::vector<PlayerEventLogSettings> all_entries;
auto results = db.QueryDatabase(
fmt::format(
@@ -301,14 +294,13 @@ public:
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
Hackers e{};
PlayerEventLogSettings e{};
e.id = static_cast<int32_t>(atoi(row[0]));
e.account = row[1] ? row[1] : "";
e.name = row[2] ? row[2] : "";
e.hacked = row[3] ? row[3] : "";
e.zone = row[4] ? row[4] : "";
e.date = row[5] ? row[5] : "";
e.id = strtoll(row[0], nullptr, 10);
e.event_name = row[1] ? row[1] : "";
e.event_enabled = static_cast<int8_t>(atoi(row[2]));
e.retention_days = static_cast<int32_t>(atoi(row[3]));
e.discord_webhook_id = static_cast<int32_t>(atoi(row[4]));
all_entries.push_back(e);
}
@@ -369,4 +361,4 @@ public:
};
#endif //EQEMU_BASE_HACKERS_REPOSITORY_H
#endif //EQEMU_BASE_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -0,0 +1,465 @@
/**
* DO NOT MODIFY THIS FILE
*
* This repository was automatically generated and is NOT to be modified directly.
* Any repository modifications are meant to be made to the repository extending the base.
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
#define EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
#include <cereal/cereal.hpp>
class BasePlayerEventLogsRepository {
public:
struct PlayerEventLogs {
int64_t id;
int64_t account_id;
int64_t character_id;
int32_t zone_id;
int32_t instance_id;
float x;
float y;
float z;
float heading;
int32_t event_type_id;
std::string event_type_name;
std::string event_data;
time_t created_at;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(id),
CEREAL_NVP(account_id),
CEREAL_NVP(character_id),
CEREAL_NVP(zone_id),
CEREAL_NVP(instance_id),
CEREAL_NVP(x),
CEREAL_NVP(y),
CEREAL_NVP(z),
CEREAL_NVP(heading),
CEREAL_NVP(event_type_id),
CEREAL_NVP(event_type_name),
CEREAL_NVP(event_data),
CEREAL_NVP(created_at)
);
}
};
static std::string PrimaryKey()
{
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"id",
"account_id",
"character_id",
"zone_id",
"instance_id",
"x",
"y",
"z",
"heading",
"event_type_id",
"event_type_name",
"event_data",
"created_at",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"id",
"account_id",
"character_id",
"zone_id",
"instance_id",
"x",
"y",
"z",
"heading",
"event_type_id",
"event_type_name",
"event_data",
"UNIX_TIMESTAMP(created_at)",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string SelectColumnsRaw()
{
return std::string(Strings::Implode(", ", SelectColumns()));
}
static std::string TableName()
{
return std::string("player_event_logs");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
SelectColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static PlayerEventLogs NewEntity()
{
PlayerEventLogs e{};
e.id = 0;
e.account_id = 0;
e.character_id = 0;
e.zone_id = 0;
e.instance_id = 0;
e.x = 0;
e.y = 0;
e.z = 0;
e.heading = 0;
e.event_type_id = 0;
e.event_type_name = "";
e.event_data = "";
e.created_at = 0;
return e;
}
static PlayerEventLogs GetPlayerEventLogs(
const std::vector<PlayerEventLogs> &player_event_logss,
int player_event_logs_id
)
{
for (auto &player_event_logs : player_event_logss) {
if (player_event_logs.id == player_event_logs_id) {
return player_event_logs;
}
}
return NewEntity();
}
static PlayerEventLogs FindOne(
Database& db,
int player_event_logs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
player_event_logs_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
return e;
}
return NewEntity();
}
static int DeleteOne(
Database& db,
int player_event_logs_id
)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
player_event_logs_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
Database& db,
const PlayerEventLogs &e
)
{
std::vector<std::string> v;
auto columns = Columns();
v.push_back(columns[1] + " = " + std::to_string(e.account_id));
v.push_back(columns[2] + " = " + std::to_string(e.character_id));
v.push_back(columns[3] + " = " + std::to_string(e.zone_id));
v.push_back(columns[4] + " = " + std::to_string(e.instance_id));
v.push_back(columns[5] + " = " + std::to_string(e.x));
v.push_back(columns[6] + " = " + std::to_string(e.y));
v.push_back(columns[7] + " = " + std::to_string(e.z));
v.push_back(columns[8] + " = " + std::to_string(e.heading));
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static PlayerEventLogs InsertOne(
Database& db,
PlayerEventLogs e
)
{
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", v)
)
);
if (results.Success()) {
e.id = results.LastInsertedID();
return e;
}
e = NewEntity();
return e;
}
static int InsertMany(
Database& db,
const std::vector<PlayerEventLogs> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.account_id));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.zone_id));
v.push_back(std::to_string(e.instance_id));
v.push_back(std::to_string(e.x));
v.push_back(std::to_string(e.y));
v.push_back(std::to_string(e.z));
v.push_back(std::to_string(e.heading));
v.push_back(std::to_string(e.event_type_id));
v.push_back("'" + db.Escape(e.event_type_name) + "'");
v.push_back("'" + db.Escape(e.event_data) + "'");
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<PlayerEventLogs> All(Database& db)
{
std::vector<PlayerEventLogs> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static std::vector<PlayerEventLogs> GetWhere(Database& db, const std::string &where_filter)
{
std::vector<PlayerEventLogs> all_entries;
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {}",
BaseSelect(),
where_filter
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
PlayerEventLogs e{};
e.id = strtoll(row[0], nullptr, 10);
e.account_id = strtoll(row[1], nullptr, 10);
e.character_id = strtoll(row[2], nullptr, 10);
e.zone_id = static_cast<int32_t>(atoi(row[3]));
e.instance_id = static_cast<int32_t>(atoi(row[4]));
e.x = strtof(row[5], nullptr);
e.y = strtof(row[6], nullptr);
e.z = strtof(row[7], nullptr);
e.heading = strtof(row[8], nullptr);
e.event_type_id = static_cast<int32_t>(atoi(row[9]));
e.event_type_name = row[10] ? row[10] : "";
e.event_data = row[11] ? row[11] : "";
e.created_at = strtoll(row[12] ? row[12] : "-1", nullptr, 10);
all_entries.push_back(e);
}
return all_entries;
}
static int DeleteWhere(Database& db, const std::string &where_filter)
{
auto results = db.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {}",
TableName(),
where_filter
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int Truncate(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"TRUNCATE TABLE {}",
TableName()
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int64 GetMaxId(Database& db)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COALESCE(MAX({}), 0) FROM {}",
PrimaryKey(),
TableName()
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static int64 Count(Database& db, const std::string &where_filter = "")
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT COUNT(*) FROM {} {}",
TableName(),
(where_filter.empty() ? "" : "WHERE " + where_filter)
)
);
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
};
#endif //EQEMU_BASE_PLAYER_EVENT_LOGS_REPOSITORY_H
@@ -5,6 +5,8 @@
#include "../strings.h"
#include "base/base_character_data_repository.h"
class CharacterDataRepository: public BaseCharacterDataRepository {
public:
@@ -44,7 +46,6 @@ public:
*/
// Custom extended repository methods here
};
#endif //EQEMU_CHARACTER_DATA_REPOSITORY_H
@@ -172,7 +172,7 @@ public:
DELETE FROM {}
WHERE dynamic_zone_id IN ({});
),
TableName(), fmt::join(dynamic_zone_ids, ",")
TableName(), Strings::Join(dynamic_zone_ids, ",")
));
}
}
@@ -75,7 +75,7 @@ public:
FROM expedition_lockouts
WHERE expedition_id IN ({})
),
fmt::join(expedition_ids, ",")
Strings::Join(expedition_ids, ",")
));
all_entries.reserve(results.RowCount());
+1 -1
View File
@@ -62,7 +62,7 @@ public:
std::vector<CharacterExpedition> entries;
auto joined_character_names = fmt::format("'{}'", fmt::join(character_names, "','"));
auto joined_character_names = fmt::format("'{}'", Strings::Join(character_names, "','"));
auto results = db.QueryDatabase(fmt::format(SQL(
SELECT
@@ -1,11 +1,11 @@
#ifndef EQEMU_HACKERS_REPOSITORY_H
#define EQEMU_HACKERS_REPOSITORY_H
#ifndef EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_hackers_repository.h"
#include "base/base_player_event_log_settings_repository.h"
class HackersRepository: public BaseHackersRepository {
class PlayerEventLogSettingsRepository: public BasePlayerEventLogSettingsRepository {
public:
/**
@@ -32,10 +32,10 @@ public:
*
* Example custom methods in a repository
*
* HackersRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* HackersRepository::GetWhereNeverExpires()
* HackersRepository::GetWhereXAndY()
* HackersRepository::DeleteWhereXAndY()
* PlayerEventLogSettingsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* PlayerEventLogSettingsRepository::GetWhereNeverExpires()
* PlayerEventLogSettingsRepository::GetWhereXAndY()
* PlayerEventLogSettingsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
@@ -47,4 +47,4 @@ public:
};
#endif //EQEMU_HACKERS_REPOSITORY_H
#endif //EQEMU_PLAYER_EVENT_LOG_SETTINGS_REPOSITORY_H
@@ -1,11 +1,11 @@
#ifndef EQEMU_EVENTLOG_REPOSITORY_H
#define EQEMU_EVENTLOG_REPOSITORY_H
#ifndef EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
#define EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
#include "base/base_eventlog_repository.h"
#include "base/base_player_event_logs_repository.h"
class EventlogRepository: public BaseEventlogRepository {
class PlayerEventLogsRepository: public BasePlayerEventLogsRepository {
public:
/**
@@ -32,10 +32,10 @@ public:
*
* Example custom methods in a repository
*
* EventlogRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* EventlogRepository::GetWhereNeverExpires()
* EventlogRepository::GetWhereXAndY()
* EventlogRepository::DeleteWhereXAndY()
* PlayerEventLogsRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* PlayerEventLogsRepository::GetWhereNeverExpires()
* PlayerEventLogsRepository::GetWhereXAndY()
* PlayerEventLogsRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
@@ -47,4 +47,4 @@ public:
};
#endif //EQEMU_EVENTLOG_REPOSITORY_H
#endif //EQEMU_PLAYER_EVENT_LOGS_REPOSITORY_H
+12 -3
View File
@@ -141,11 +141,11 @@ bool RuleManager::SetRule(const std::string &rule_name, const std::string &rule_
switch (type) {
case IntRule:
m_RuleIntValues[index] = atoi(rule_value.c_str());
m_RuleIntValues[index] = Strings::ToInt(rule_value.c_str());
LogRules("Set rule [{}] to value [{}]", rule_name, m_RuleIntValues[index]);
break;
case RealRule:
m_RuleRealValues[index] = atof(rule_value.c_str());
m_RuleRealValues[index] = Strings::ToFloat(rule_value.c_str());
LogRules("Set rule [{}] to value [{:.2f}]", rule_name, m_RuleRealValues[index]);
break;
case BoolRule:
@@ -385,7 +385,16 @@ void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) {
e.rule_value = rule_value;
e.notes = rule_notes;
RuleValuesRepository::UpdateOne(*db, e);
db->QueryDatabase(
fmt::format(
"UPDATE rule_values SET rule_value = '{}', notes = '{}' WHERE ruleset_id = {} AND rule_name = '{}'",
rule_value,
Strings::Escape(rule_notes),
e.ruleset_id,
e.rule_name
)
);
return;
}
+24 -2
View File
@@ -93,6 +93,12 @@ RULE_INT(Character, ItemEnduranceRegenCap, 15, "Limit on endurance regeneration
RULE_INT(Character, ItemExtraDmgCap, 150, "Cap for bonuses to melee skills like Bash, Frenzy, etc.")
RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Character, Hastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_REAL(Character, HeroicStrengthMultiplier, 1.00, "Multplier scales benefits from Heroic Strength. Grants 25 Base Endurance, 0.05 Endurance Regen, 1 Melee Damage each Hit, and 1 Shield AC per 10 Heroic Strength.")
RULE_REAL(Character, HeroicStaminaMultiplier, 1.00, "Multplier scales benefits from Heroic Stamina. Grants 25 Base Endurance, 0.05 Endurance Regen, 100 Base HP, and 0.5 HP Regen per 10 Heroic Stamina.")
RULE_REAL(Character, HeroicAgilityMultiplier, 1.00, "Multplier scales benefits from Heroic Agility. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Avoidance AC per 10 Heroic Agility. (Rule does not change Dodge Chance)")
RULE_REAL(Character, HeroicDexterityMultiplier, 1.00, "Multplier scales benefits from Heroic Dexterity. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Archery/Throwing Damage each hit per 10 Heroic Dexterity. (Rule does not change Assassinate/Headshot/Block/Parry/Riposte Chances)")
RULE_REAL(Character, HeroicWisdomMultiplier, 1.00, "Multplier scales benefits from Heroic Wisdom. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Wisdom.")
RULE_REAL(Character, HeroicIntelligenceMultiplier, 1.00, "Multplier scales benefits from Heroic Intelligence. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Intelligence.")
RULE_INT(Character, SkillUpModifier, 100, "The probability for a skill-up is multiplied by value/100")
RULE_BOOL(Character, SharedBankPlat, false, "Shared bank platinum. Off by default to prevent duplication")
RULE_BOOL(Character, BindAnywhere, false, "Allows players to bind their soul anywhere in the world")
@@ -197,9 +203,14 @@ RULE_BOOL(Character, PetZoneWithOwner, true, "Should Pets Zone with Owner")
RULE_BOOL(Character, FullManaOnDeath, true, "On death set mana to full")
RULE_BOOL(Character, FullEndurOnDeath, true, "On death set endurance to full")
RULE_INT(Character, ExperiencePercentCapPerKill, -1, "Caps the percentage of experience that can be gained per kill. -1 disables the cap; 0 blocks all (non-aa) xp.")
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier based on number of players in group, default is true")
RULE_BOOL(Character, EnableGroupEXPModifier, true, "Enable or disable the group experience modifier in group, default is true")
RULE_BOOL(Character, EnableGroupMemberEXPModifier, true, "Enable or disable the group member experience modifier based on number of players in group, default is true")
RULE_REAL(Character, GroupMemberEXPModifier, 0.2, "Sets the group experience modifier per members between 2 and 5, default is 0.2")
RULE_REAL(Character, FullGroupEXPModifier, 2.16, "Sets the group experience modifier for a full group, default is 2.16")
RULE_BOOL(Character, IgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid experience modifier, default is true")
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -315,8 +326,8 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Map)
RULE_BOOL(Map, FixPathingZOnSendTo, false, "Try to repair Z coordinates in the SendTo routine as well")
RULE_BOOL(Map, FixZWhenPathing, true, "Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)")
RULE_REAL(Map, DistanceCanTravelBeforeAdjustment, 10.0, "Distance a mob can path before FixZ is called, depends on FixZWhenPathing")
RULE_BOOL(Map, MobZVisualDebug, false, "Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss)")
RULE_BOOL(Map, MobPathingVisualDebug, false, "Displays nodes in pathing points in realtime to help with visual debugging")
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20, "At runtime in SendTo: maximum change in Z to allow the BestZ code to apply")
RULE_INT(Map, FindBestZHeightAdjust, 1, "Adds this to the current Z before seeking the best Z position")
RULE_CATEGORY_END()
@@ -430,6 +441,7 @@ RULE_BOOL(Spells, IllusionsAlwaysPersist, false, "Allows Illusions to persist be
RULE_BOOL(Spells, UseItemCastMessage, false, "Enable to use the \"item begins to glow\" messages when casting from an item.")
RULE_BOOL(Spells, TargetsTargetRequiresCombatRange, true, "Disable to remove combat range requirement from Target's Target Spell Target Type")
RULE_BOOL(Spells, NPCBuffLevelRestrictions, false, "Impose BuffLevelRestrictions on NPCs if true")
RULE_BOOL(Spells, ResurrectionEffectsBlock, true, "If enabled, resurrection effects cannot be overwritten.")
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
@@ -583,6 +595,7 @@ RULE_INT(Range, SongMessages, 75, "The packet range in which song messages are s
RULE_INT(Range, ClientPositionUpdates, 300, "Distance in which the own changed position is communicated to other clients")
RULE_INT(Range, CriticalDamage, 80, "The packet range in which critical hit messages are sent")
RULE_INT(Range, MobCloseScanDistance, 600, "Close scan distance")
RULE_INT(Range, MaxDistanceToClickDoors, 100, "Max distance that a client can click a door from (Client says 'You can't reach that' at roughly 25-50 for most doors)")
RULE_CATEGORY_END()
RULE_CATEGORY(Bots)
@@ -623,6 +636,7 @@ RULE_BOOL(Chat, EnableVoiceMacros, true, "Enable voice macros")
RULE_BOOL(Chat, EnableMailKeyIPVerification, true, "Setting whether the authenticity of the client should be verified via its IP address when accessing the InGame mailbox")
RULE_BOOL(Chat, EnableAntiSpam, true, "Enable anti-spam system for chat")
RULE_BOOL(Chat, SuppressCommandErrors, false, "Do not suppress command errors by default")
RULE_BOOL(Chat, ChannelsIgnoreNameFilter, false, "Ignore name filtering when creating new chat channels")
RULE_INT(Chat, MaxPermanentPlayerChannels, 0, "Maximum number of permanent chat channels a player can make. Default 0.")
RULE_INT(Chat, MinStatusToBypassAntiSpam, 100, "Minimum status to bypass the anti-spam system")
RULE_INT(Chat, MinimumMessagesPerInterval, 4, "Minimum number of chat messages allowed per interval. The karma value is added to this value")
@@ -744,6 +758,7 @@ RULE_BOOL(Inventory, DeleteTransformationMold, true, "False if you want mold to
RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any weapon transformation")
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
RULE_BOOL(Inventory, AllowMultipleOfSameAugment, false, "Allows multiple of the same augment to be placed in an item via #augmentitem or MQ2, set to true to allow")
RULE_INT(Inventory, AlternateAugmentationSealer, 53, "Allows RoF+ clients to augment items from a special container type")
RULE_CATEGORY_END()
RULE_CATEGORY(Client)
@@ -766,9 +781,16 @@ RULE_INT(Faction, DubiouslyFactionMinimum, -500, "Minimum faction for dubiously"
RULE_INT(Faction, ThreateninglyFactionMinimum, -750, "Minimum faction for threateningly")
RULE_CATEGORY_END()
RULE_CATEGORY(Analytics)
RULE_BOOL(Analytics, CrashReporting, true, "Automatic crash reporting analytics for EQEmu Server developers")
RULE_CATEGORY_END()
RULE_CATEGORY(Logging)
RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp::main:309] Loading variables...")
RULE_BOOL(Logging, WorldGMSayLogging, true, "Relay worldserver logging to zone processes via GM say output")
RULE_BOOL(Logging, PlayerEventsQSProcess, false, "Have query server process player events instead of world. Useful when wanting to use a dedicated server and database for processing player events on separate disk")
RULE_INT(Logging, BatchPlayerEventProcessIntervalSeconds, 5, "This is the interval in which player events are processed in world or qs")
RULE_INT(Logging, BatchPlayerEventProcessChunkSize, 10000, "This is the cap of events that can be inserted into the queue before a force flush. This is to keep from hitting MySQL max_allowed_packet and killing the connection")
RULE_CATEGORY_END()
RULE_CATEGORY(HotReload)
+4
View File
@@ -143,6 +143,10 @@ bool ServerEventScheduler::ValidateDatabaseConnection()
// this helps inform decisions to tell all zones to reload their events
bool ServerEventScheduler::CheckIfEventsChanged()
{
if (!m_database) {
return false;
}
auto events = ServerScheduledEventsRepository::GetWhere(*m_database, "deleted_at is null");
// first check if the size changed, if it did this is the easiest step
+20 -12
View File
@@ -281,6 +281,9 @@
#define ServerOP_QSSendQuery 0x5006
#define ServerOP_QSPlayerDropItem 0x5007
// player events
#define ServerOP_PlayerEvent 0x5100
enum {
CZUpdateType_Character,
CZUpdateType_Group,
@@ -1308,10 +1311,10 @@ struct Server_Speech_Struct {
char message[0];
};
struct QSTradeItems_Struct {
uint32 from_id;
struct PlayerLogTradeItemsEntry_Struct {
uint32 from_character_id;
uint16 from_slot;
uint32 to_id;
uint32 to_character_id;
uint16 to_slot;
uint32 item_id;
uint16 charges;
@@ -1322,15 +1325,15 @@ struct QSTradeItems_Struct {
uint32 aug_5;
};
struct QSPlayerLogTrade_Struct {
uint32 char1_id;
MoneyUpdate_Struct char1_money;
uint16 char1_count;
uint32 char2_id;
MoneyUpdate_Struct char2_money;
uint16 char2_count;
uint16 _detail_count;
QSTradeItems_Struct items[0];
struct PlayerLogTrade_Struct {
uint32 character_1_id;
MoneyUpdate_Struct character_1_money;
uint16 character_1_item_count;
uint32 character_2_id;
MoneyUpdate_Struct character_2_money;
uint16 character_2_item_count;
uint16 _detail_count;
PlayerLogTradeItemsEntry_Struct item_entries[0];
};
struct QSDropItems_Struct {
@@ -1806,6 +1809,11 @@ struct ServerDzCreateSerialized_Struct {
char cereal_data[0];
};
struct ServerSendPlayerEvent_Struct {
uint32_t cereal_size;
char cereal_data[0];
};
struct ServerFlagUpdate_Struct {
uint32 account_id;
int16 admin;
+416 -407
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -139,7 +139,7 @@ public:
uint32 aug6 = 0,
bool attuned = 0
);
EQ::ItemInstance *CreateBaseItem(const EQ::ItemData *item, int16 charges = 0);
EQ::ItemInstance *CreateBaseItem(const EQ::ItemData *item, const std::string &guid, int16 charges);
void GetItemsCount(int32 &item_count, uint32 &max_id);
void LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id);
+113 -15
View File
@@ -191,24 +191,23 @@ std::string Strings::Escape(const std::string &s)
bool Strings::IsNumber(const std::string &s)
{
try {
auto r = stoi(s);
return true;
}
catch (std::exception &) {
return false;
for (char const &c: s) {
if (c == s[0] && s[0] == '-') {
continue;
}
if (std::isdigit(c) == 0) {
return false;
}
}
return true;
}
bool Strings::IsFloat(const std::string &s)
{
try {
auto r = stof(s);
return true;
}
catch (std::exception &) {
return false;
}
char* ptr;
strtof(s.c_str(), &ptr);
return (*ptr) == '\0';
}
std::string Strings::Join(const std::vector<std::string> &ar, const std::string &delim)
@@ -225,6 +224,20 @@ std::string Strings::Join(const std::vector<std::string> &ar, const std::string
return ret;
}
std::string Strings::Join(const std::vector<uint32_t> &ar, const std::string &delim)
{
std::string ret;
for (size_t i = 0; i < ar.size(); ++i) {
if (i != 0) {
ret += delim;
}
ret += std::to_string(ar[i]);
}
return ret;
}
void
Strings::FindReplace(std::string &string_subject, const std::string &search_string, const std::string &replace_string)
{
@@ -714,7 +727,7 @@ uint32 Strings::TimeToSeconds(std::string time_string)
time_unit.end()
);
auto unit = std::stoul(time_unit);
auto unit = Strings::ToUnsignedInt(time_unit);
uint32 duration = 0;
if (Strings::Contains(time_string, "s")) {
@@ -741,7 +754,7 @@ bool Strings::ToBool(std::string bool_string)
Strings::Contains(bool_string, "on") ||
Strings::Contains(bool_string, "enable") ||
Strings::Contains(bool_string, "enabled") ||
(Strings::IsNumber(bool_string) && std::stoi(bool_string))
(Strings::IsNumber(bool_string) && Strings::ToInt(bool_string))
) {
return true;
}
@@ -763,3 +776,88 @@ std::string Strings::Random(size_t length)
std::generate_n(str.begin(), length, randchar);
return str;
}
// a wrapper for stoi which will return a fallback if the string
// fails to cast to a number
int Strings::ToInt(const std::string &s, int fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoi(s);
}
catch (std::exception &) {
return fallback;
}
}
int64 Strings::ToBigInt(const std::string &s, int64 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoll(s);
}
catch (std::exception &) {
return fallback;
}
}
uint32 Strings::ToUnsignedInt(const std::string &s, uint32 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoul(s);
}
catch (std::exception &) {
return fallback;
}
}
uint64 Strings::ToUnsignedBigInt(const std::string &s, uint64 fallback)
{
if (!Strings::IsNumber(s)) {
return fallback;
}
try {
return std::stoull(s);
}
catch (std::exception &) {
return fallback;
}
}
float Strings::ToFloat(const std::string &s, float fallback)
{
if (!Strings::IsFloat(s)) {
return fallback;
}
try {
return std::stof(s);
}
catch (std::exception &) {
return fallback;
}
}
std::string Strings::RemoveNumbers(std::string s)
{
int current = 0;
for (int i = 0; i < s.length(); i++) {
if (!isdigit(s[i])) {
s[current] = s[i];
current++;
}
}
return s.substr(0, current);
}
+7
View File
@@ -86,7 +86,13 @@ class Strings {
public:
static bool Contains(std::vector<std::string> container, std::string element);
static bool Contains(const std::string& subject, const std::string& search);
static int ToInt(const std::string &s, int fallback = 0);
static int64 ToBigInt(const std::string &s, int64 fallback = 0);
static uint32 ToUnsignedInt(const std::string &s, uint32 fallback = 0);
static uint64 ToUnsignedBigInt(const std::string &s, uint64 fallback = 0);
static float ToFloat(const std::string &s, float fallback = 0.0f);
static bool IsNumber(const std::string &s);
static std::string RemoveNumbers(std::string s);
static bool IsFloat(const std::string &s);
static const std::string ToLower(std::string s);
static const std::string ToUpper(std::string s);
@@ -106,6 +112,7 @@ public:
static std::string GetBetween(const std::string &s, std::string start_delim, std::string stop_delim);
static std::string Implode(std::string glue, std::vector<std::string> src);
static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
static std::string MillisecondsToTime(int duration);
static std::string Money(uint32 platinum, uint32 gold = 0, uint32 silver = 0, uint32 copper = 0);
static std::string NumberToWords(unsigned long long int n);
+1 -1
View File
@@ -192,7 +192,7 @@ bool atobool(const char *iBool)
if (!strcasecmp(iBool, "n")) {
return false;
}
if (atoi(iBool)) {
if (Strings::ToInt(iBool)) {
return true;
}
return false;
+6
View File
@@ -42,6 +42,8 @@
#include <cstring>
#include <iostream>
inline bool g_is_forced_tty = std::getenv("IS_TTY");
namespace rang {
/* For better compability with most of terminals do not use any style settings
@@ -220,6 +222,10 @@ inline bool isMsysPty(int fd) noexcept
inline bool isTerminal(const std::streambuf *osbuf) noexcept
{
if (g_is_forced_tty) {
return g_is_forced_tty;
}
using std::cerr;
using std::clog;
using std::cout;
-1
View File
@@ -16,7 +16,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Disgrace: for windows compile
#ifndef WIN32
#include <sys/time.h>
+15 -15
View File
@@ -18,14 +18,22 @@
*
*/
#ifndef _EQEMU_VERSION_H
#define _EQEMU_VERSION_H
#ifndef EQEMU_VERSION_H
#define EQEMU_VERSION_H
#define LOGIN_VERSION "0.8.0"
#define EQEMU_PROTOCOL_VERSION "0.3.10"
#define CURRENT_VERSION "2.0"
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.4.5-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__
#ifndef WIN32
#define LAST_MODIFIED __TIME__
#else
#define LAST_MODIFIED __TIMESTAMP__
#endif
/**
* Every time a Database SQL is added to Github increment CURRENT_BINARY_DATABASE_VERSION
@@ -34,16 +42,8 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9217
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9037
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
#ifndef WIN32
#define LAST_MODIFIED __TIME__
#else
#define LAST_MODIFIED __TIMESTAMP__
#endif
#define CURRENT_BINARY_DATABASE_VERSION 9222
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9038
#endif
+1 -1
View File
@@ -381,7 +381,7 @@ uint32 AccountManagement::CheckExternalLoginserverUserCredentials(
auto s = Strings::Split(server.options.GetEQEmuLoginServerAddress(), ':');
if (s.size() == 2) {
auto address = s[0];
auto port = std::stoi(s[1]);
auto port = Strings::ToInt(s[1]);
EQ::Net::DNSLookup(
address, port, false, [&](const std::string &addr) {
+2 -1
View File
@@ -26,10 +26,11 @@ bool Client::Process()
{
EQApplicationPacket *app = m_connection->PopPacket();
while (app) {
auto o = m_connection->GetOpcodeManager();
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
m_connection->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
o->EmuToEQ(app->GetOpcode()) == 0 ? app->GetProtocolOpcode() : o->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
+11 -11
View File
@@ -32,7 +32,7 @@ Database::Database(
user.c_str(),
pass.c_str(),
name.c_str(),
std::stoi(port),
Strings::ToInt(port),
&errnum,
errbuf
)
@@ -93,7 +93,7 @@ bool Database::GetLoginDataFromAccountInfo(
auto row = results.begin();
id = atoi(row[0]);
id = Strings::ToInt(row[0]);
password = row[1];
LogDebug(
@@ -145,7 +145,7 @@ bool Database::GetLoginTokenDataFromToken(
}
if (strcmp(row[2], "login_server_id") == 0) {
db_account_id = atoi(row[3]);
db_account_id = Strings::ToInt(row[3]);
found_login_id = true;
continue;
}
@@ -178,7 +178,7 @@ unsigned int Database::GetFreeID(const std::string &loginserver)
auto row = results.begin();
return std::stoi(row[0]);
return Strings::ToInt(row[0]);
}
/**
@@ -368,12 +368,12 @@ Database::DbWorldRegistration Database::GetWorldRegistration(
auto row = results.begin();
r.loaded = true;
r.server_id = std::stoi(row[0]);
r.server_id = Strings::ToInt(row[0]);
r.server_description = row[1];
r.server_list_type = std::stoi(row[3]);
r.is_server_trusted = std::stoi(row[2]) > 0;
r.server_list_type = Strings::ToInt(row[3]);
r.is_server_trusted = Strings::ToInt(row[2]) > 0;
r.server_list_description = row[4];
r.server_admin_id = std::stoi(row[5]);
r.server_admin_id = Strings::ToInt(row[5]);
if (r.server_admin_id <= 0) {
return r;
@@ -513,7 +513,7 @@ bool Database::CreateWorldRegistration(
auto row = results.begin();
id = std::stoi(row[0]);
id = Strings::ToInt(row[0]);
auto insert_query = fmt::format(
"INSERT INTO login_world_servers SET id = {0}, long_name = '{1}', short_name = '{2}', last_ip_address = '{3}', \n"
"login_server_list_type_id = 3, login_server_admin_id = {4}, is_server_trusted = 0, tag_description = ''",
@@ -647,7 +647,7 @@ Database::DbLoginServerAdmin Database::GetLoginServerAdmin(const std::string &ac
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = std::stoi(row[0]);
r.id = Strings::ToInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.first_name = row[3];
@@ -683,7 +683,7 @@ Database::DbLoginServerAccount Database::GetLoginServerAccountByAccountName(
if (results.RowCount() == 1) {
auto row = results.begin();
r.loaded = true;
r.id = std::stoi(row[0]);
r.id = Strings::ToInt(row[0]);
r.account_name = row[1];
r.account_password = row[2];
r.account_email = row[3];
+2 -2
View File
@@ -480,8 +480,8 @@ namespace LoginserverWebserver {
for (auto row = results.begin(); row != results.end(); ++row) {
LoginserverWebserver::TokenManager::token_data token_data;
token_data.token = row[0];
token_data.can_write = std::stoi(row[1]) > 0;
token_data.can_read = std::stoi(row[2]) > 0;
token_data.can_write = Strings::ToInt(row[1]) > 0;
token_data.can_read = Strings::ToInt(row[2]) > 0;
LogDebug(
"Inserting api token to internal list [{0}] write {1} read {2}",
+7
View File
@@ -288,9 +288,16 @@ int main(int argc, char **argv)
LogInfo("[Config] [Security] IsPasswordLoginAllowed [{0}]", server.options.IsPasswordLoginAllowed());
LogInfo("[Config] [Security] IsUpdatingInsecurePasswords [{0}]", server.options.IsUpdatingInsecurePasswords());
Timer keepalive(INTERSERVER_TIMER); // does auto-reconnect
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
if (keepalive.Check()) {
keepalive.Start();
server.db->ping();
}
if (!run_server) {
EQ::EventLoop::Get().Shutdown();
return;
+8
View File
@@ -0,0 +1,8 @@
{
"name": "eqemu-server",
"version": "22.4.5",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
}
}
+9 -10
View File
@@ -50,7 +50,6 @@
#include "../common/strings.h"
#include "../common/servertalk.h"
void QSDatabase::AddSpeech(
const char *from,
const char *to,
@@ -125,7 +124,7 @@ void QSDatabase::LogPlayerDropItem(QSPlayerDropItem_Struct *QS)
}
}
void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
void QSDatabase::LogPlayerTrade(PlayerLogTrade_Struct *QS, uint32 detailCount)
{
std::string query = StringFormat(
@@ -134,10 +133,10 @@ void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
"`char1_sp` = '%i', `char1_cp` = '%i', `char1_items` = '%i', "
"`char2_id` = '%i', `char2_pp` = '%i', `char2_gp` = '%i', "
"`char2_sp` = '%i', `char2_cp` = '%i', `char2_items` = '%i'",
QS->char1_id, QS->char1_money.platinum, QS->char1_money.gold,
QS->char1_money.silver, QS->char1_money.copper, QS->char1_count,
QS->char2_id, QS->char2_money.platinum, QS->char2_money.gold,
QS->char2_money.silver, QS->char2_money.copper, QS->char2_count
QS->character_1_id, QS->character_1_money.platinum, QS->character_1_money.gold,
QS->character_1_money.silver, QS->character_1_money.copper, QS->character_1_item_count,
QS->character_2_id, QS->character_2_money.platinum, QS->character_2_money.gold,
QS->character_2_money.silver, QS->character_2_money.copper, QS->character_2_item_count
);
auto results = QueryDatabase(query);
if (!results.Success()) {
@@ -157,10 +156,10 @@ void QSDatabase::LogPlayerTrade(QSPlayerLogTrade_Struct *QS, uint32 detailCount)
"`from_id` = '%i', `from_slot` = '%i', `to_id` = '%i', `to_slot` = '%i', "
"`item_id` = '%i', `charges` = '%i', `aug_1` = '%i', `aug_2` = '%i', "
"`aug_3` = '%i', `aug_4` = '%i', `aug_5` = '%i'",
lastIndex, QS->items[i].from_id, QS->items[i].from_slot,
QS->items[i].to_id, QS->items[i].to_slot, QS->items[i].item_id,
QS->items[i].charges, QS->items[i].aug_1, QS->items[i].aug_2,
QS->items[i].aug_3, QS->items[i].aug_4, QS->items[i].aug_5
lastIndex, QS->item_entries[i].from_character_id, QS->item_entries[i].from_slot,
QS->item_entries[i].to_character_id, QS->item_entries[i].to_slot, QS->item_entries[i].item_id,
QS->item_entries[i].charges, QS->item_entries[i].aug_1, QS->item_entries[i].aug_2,
QS->item_entries[i].aug_3, QS->item_entries[i].aug_4, QS->item_entries[i].aug_5
);
results = QueryDatabase(query);
if (!results.Success()) {
+1 -3
View File
@@ -33,13 +33,11 @@
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class QSDatabase : public Database {
public:
void AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type);
void LogPlayerTrade(QSPlayerLogTrade_Struct* QS, uint32 DetailCount);
void LogPlayerTrade(PlayerLogTrade_Struct* QS, uint32 DetailCount);
void LogPlayerDropItem(QSPlayerDropItem_Struct* QS);
void LogPlayerHandin(QSPlayerLogHandin_Struct* QS, uint32 DetailCount);
void LogPlayerNPCKill(QSPlayerLogNPCKill_Struct* QS, uint32 Members);
+3 -3
View File
@@ -44,15 +44,15 @@ bool LFGuildManager::LoadDatabase()
}
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 type = atoul(row[0]);
uint32 type = Strings::ToUnsignedInt(row[0]);
if(type == 0)
{
PlayerLookingForGuild p(row[1], row[2], atoul(row[3]), atoul(row[5]), atoul(row[6]), atoul(row[7]), atoul(row[8]));
PlayerLookingForGuild p(row[1], row[2], Strings::ToUnsignedInt(row[3]), Strings::ToUnsignedInt(row[5]), Strings::ToUnsignedInt(row[6]), Strings::ToUnsignedInt(row[7]), Strings::ToUnsignedInt(row[8]));
Players.push_back(p);
continue;
}
GuildLookingForPlayers g(row[1], row[2], atoul(row[3]), atoul(row[4]), atoul(row[5]), atoul(row[6]), atoul(row[7]), atoul(row[8]));
GuildLookingForPlayers g(row[1], row[2], Strings::ToUnsignedInt(row[3]), Strings::ToUnsignedInt(row[4]), Strings::ToUnsignedInt(row[5]), Strings::ToUnsignedInt(row[6]), Strings::ToUnsignedInt(row[7]), Strings::ToUnsignedInt(row[8]));
Guilds.push_back(g);
}
+9
View File
@@ -33,6 +33,7 @@
#include "worldserver.h"
#include "../common/path_manager.h"
#include "../common/zone_store.h"
#include "../common/events/player_event_logs.h"
#include <list>
#include <signal.h>
#include <thread>
@@ -47,6 +48,7 @@ WorldServer *worldserver = 0;
EQEmuLogSys LogSys;
PathManager path;
ZoneStore zone_store;
PlayerEventLogs player_event_logs;
void CatchSignal(int sig_num)
{
@@ -106,6 +108,9 @@ int main()
/* Load Looking For Guild Manager */
lfguildmanager.LoadDatabase();
Timer player_event_process_timer(1000);
player_event_logs.SetDatabase(&database)->Init();
auto loop_fn = [&](EQ::Timer* t) {
Timer::SetCurrentTime();
@@ -117,6 +122,10 @@ int main()
if (LFGuildExpireTimer.Check()) {
lfguildmanager.ExpireEntries();
}
if (player_event_process_timer.Check()) {
player_event_logs.Process();
}
};
EQ::Timer process_timer(loop_fn);
+14 -1
View File
@@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "lfguild.h"
#include "queryservconfig.h"
#include "worldserver.h"
#include "../common/events/player_events.h"
#include "../common/events/player_event_logs.h"
#include <iomanip>
#include <iostream>
#include <stdarg.h>
@@ -89,6 +91,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
case 0: {
break;
}
case ServerOP_PlayerEvent: {
auto n = PlayerEvent::PlayerEventContainer{};
auto s = (ServerSendPlayerEvent_Struct *) p.Data();
EQ::Util::MemoryStreamReader ss(s->cereal_data, s->cereal_size);
cereal::BinaryInputArchive archive(ss);
archive(n);
player_event_logs.AddToQueue(n.player_event_log);
break;
}
case ServerOP_KeepAlive: {
break;
}
@@ -100,7 +113,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
break;
}
case ServerOP_QSPlayerLogTrades: {
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct *) p.Data();
PlayerLogTrade_Struct *QS = (PlayerLogTrade_Struct *) p.Data();
database.LogPlayerTrade(QS, QS->_detail_count);
break;
}
+1 -1
View File
@@ -124,7 +124,7 @@ int main(int argc, char **argv)
return 1;
}
} else {
content_db.SetMysql(database.getMySQL());
content_db.SetMySQL(database);
}
LogSys.SetDatabase(&database)
+4 -3
View File
@@ -46,8 +46,7 @@ int main()
auto ConfigLoadResult = EQEmuConfig::LoadConfig();
Config = EQEmuConfig::get();
try {
std::ofstream outfile("test_output.txt");
std::unique_ptr<Test::Output> output(new Test::TextOutput(Test::TextOutput::Verbose, outfile));
std::unique_ptr<Test::Output> output(new Test::TextOutput(Test::TextOutput::Verbose));
Test::Suite tests;
tests.add(new MemoryMappedFileTest());
tests.add(new IPCMutexTest());
@@ -60,7 +59,9 @@ int main()
tests.add(new SkillsUtilsTest());
tests.add(new TaskStateTest());
tests.run(*output, true);
} catch (...) {
}
catch (std::exception &ex) {
LogError("Test Failure [{}]", ex.what());
return -1;
}
return 0;
+22
View File
@@ -31,6 +31,8 @@ public:
TEST_ADD(StringUtilTest::SearchDeliminatedStringTest);
TEST_ADD(StringUtilTest::SplitStringTest);
TEST_ADD(StringUtilTest::FromCharsTest);
TEST_ADD(StringUtilTest::TestIsFloat);
TEST_ADD(StringUtilTest::TestIsNumber);
}
~StringUtilTest() {
@@ -116,6 +118,26 @@ public:
TEST_ASSERT(float_value == 3.14f);
}
void TestIsFloat() {
TEST_ASSERT_EQUALS(Strings::IsFloat("0.23424523"), true);
TEST_ASSERT_EQUALS(Strings::IsFloat("12312312313.23424523"), true);
TEST_ASSERT_EQUALS(Strings::IsFloat("12312312313"), true);
TEST_ASSERT_EQUALS(Strings::IsFloat(".234234"), true);
TEST_ASSERT_EQUALS(Strings::IsFloat(".234234f"), false);
TEST_ASSERT_EQUALS(Strings::IsFloat("Johnson"), false);
}
void TestIsNumber() {
TEST_ASSERT_EQUALS(Strings::IsNumber("0.23424523"), false);
TEST_ASSERT_EQUALS(Strings::IsNumber("12312312313.23424523"), false);
TEST_ASSERT_EQUALS(Strings::IsNumber("12312312313"), true);
TEST_ASSERT_EQUALS(Strings::IsNumber("12312312313f"), false); // character at end
TEST_ASSERT_EQUALS(Strings::IsNumber("18446744073709551616"), true); // 64
TEST_ASSERT_EQUALS(Strings::IsNumber("-18"), true);
TEST_ASSERT_EQUALS(Strings::IsNumber("-f18"), false);
TEST_ASSERT_EQUALS(Strings::IsNumber("-18446744073709551616"), true); // 64
}
};
#endif
+7 -7
View File
@@ -48,10 +48,10 @@ ChatChannel::ChatChannel(std::string inName, std::string inOwner, std::string in
m_moderated = false;
LogDebug(
"New ChatChannel created: Name: [{}], Owner: [{}], Password: [{}], MinStatus: [{}]",
m_name.c_str(),
m_owner.c_str(),
m_password.c_str(),
"New ChatChannel created: Name: [{}] Owner: [{}] Password: [{}] MinStatus: [{}]",
m_name,
m_owner,
m_password,
m_minimum_status
);
@@ -78,7 +78,7 @@ ChatChannel *ChatChannelList::CreateChannel(
{
uint8 max_perm_player_channels = RuleI(Chat, MaxPermanentPlayerChannels);
if (!database.CheckChannelNameFilter(name)) {
if (!RuleB(Chat, ChannelsIgnoreNameFilter) && !database.CheckChannelNameFilter(name)) {
if (!(owner == SYSTEM_OWNER)) {
return nullptr;
}
@@ -657,7 +657,7 @@ ChatChannel *ChatChannelList::RemoveClientFromChannel(const std::string& in_chan
std::string channel_name = in_channel_name;
if (in_channel_name.length() > 0 && isdigit(channel_name[0])) {
channel_name = c->ChannelSlotName(atoi(in_channel_name.c_str()));
channel_name = c->ChannelSlotName(Strings::ToInt(in_channel_name.c_str()));
}
auto *required_channel = FindChannel(channel_name);
@@ -667,7 +667,7 @@ ChatChannel *ChatChannelList::RemoveClientFromChannel(const std::string& in_chan
}
LogDebug("Client [{}] removed from channel [{}]. Channel is owned by {}. Command directed: {}", c->GetName(), channel_name, required_channel->GetOwnerName(), command_directed);
if (c->GetName() == required_channel->GetOwnerName() && command_directed) { // Check if the client that is leaving is the the channel owner
if (c->GetName() == required_channel->GetOwnerName() && command_directed) { // Check if the client that is leaving is the channel owner
LogDebug("Owner left the channel [{}], removing channel from database...", channel_name);
database.DeleteChatChannel(channel_name); // Remove the channel from the database.
LogDebug("Flagging [{}] channel as temporary...", channel_name);
+20 -16
View File
@@ -379,14 +379,14 @@ static void ProcessSetMessageStatus(std::string SetMessageCommand) {
if (NumEnd == std::string::npos) {
MessageNumber = atoi(SetMessageCommand.substr(NumStart).c_str());
MessageNumber = Strings::ToInt(SetMessageCommand.substr(NumStart).c_str());
database.SetMessageStatus(MessageNumber, Status);
break;
}
MessageNumber = atoi(SetMessageCommand.substr(NumStart, NumEnd - NumStart).c_str());
MessageNumber = Strings::ToInt(SetMessageCommand.substr(NumStart, NumEnd - NumStart).c_str());
database.SetMessageStatus(MessageNumber, Status);
@@ -643,10 +643,11 @@ void Clientlist::Process()
while (KeyValid && !(*it)->GetForceDisconnect() && (app = (*it)->ClientStream->PopPacket())) {
EmuOpcode opcode = app->GetOpcode();
auto o = (*it)->ClientStream->GetOpcodeManager();
LogPacketClientServer(
"[{}] [{:#06x}] Size [{}] {}",
OpcodeManager::EmuToName(app->GetOpcode()),
(*it)->ClientStream->GetOpcodeManager()->EmuToEQ(app->GetOpcode()),
o->EmuToEQ(app->GetOpcode()) == 0 ? app->GetProtocolOpcode() : o->EmuToEQ(app->GetOpcode()),
app->Size(),
(LogSys.IsLogEnabled(Logs::Detail, Logs::PacketClientServer) ? DumpPacketToString(app) : "")
);
@@ -792,7 +793,10 @@ void Clientlist::ProcessOPMailCommand(Client *c, std::string command_string, boo
case CommandJoin:
if (!command_directed) {
//Append saved channels to params
parameters = parameters + ", " + database.CurrentPlayerChannels(c->GetName());
const auto saved_channels = database.CurrentPlayerChannels(c->GetName());
if (!saved_channels.empty()) {
parameters += fmt::format(", {}", Strings::Join(saved_channels, ", "));
}
parameters = RemoveDuplicateChannels(parameters);
}
c->JoinChannels(parameters, command_directed);
@@ -872,7 +876,7 @@ void Clientlist::ProcessOPMailCommand(Client *c, std::string command_string, boo
break;
case CommandGetBody:
database.SendBody(c, atoi(parameters.c_str()));
database.SendBody(c, Strings::ToInt(parameters.c_str()));
break;
case CommandMailTo:
@@ -887,7 +891,7 @@ void Clientlist::ProcessOPMailCommand(Client *c, std::string command_string, boo
case CommandSelectMailBox:
{
std::string::size_type NumStart = parameters.find_first_of("0123456789");
c->ChangeMailBox(atoi(parameters.substr(NumStart).c_str()));
c->ChangeMailBox(Strings::ToInt(parameters.substr(NumStart).c_str()));
break;
}
case CommandSetMailForwarding:
@@ -1249,7 +1253,7 @@ void Client::ProcessChannelList(std::string Input) {
std::string ChannelName = Input;
if (isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
ChatChannel *RequiredChannel = ChannelList->FindChannel(ChannelName);
@@ -1410,7 +1414,7 @@ void Client::SendChannelMessageByNumber(std::string Message) {
if (MessageStart == std::string::npos)
return;
int ChannelNumber = atoi(Message.substr(0, MessageStart).c_str());
int ChannelNumber = Strings::ToInt(Message.substr(0, MessageStart).c_str());
if ((ChannelNumber < 1) || (ChannelNumber > MAX_JOINED_CHANNELS)) {
@@ -1653,7 +1657,7 @@ void Client::SetChannelPassword(std::string ChannelPassword) {
std::string ChannelName = ChannelPassword.substr(ChannelStart);
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
std::string Message;
@@ -1718,7 +1722,7 @@ void Client::SetChannelOwner(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
LogInfo("Set owner of channel [[{}]] to [[{}]]", ChannelName.c_str(), NewOwner.c_str());
@@ -1764,7 +1768,7 @@ void Client::OPList(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
ChatChannel *RequiredChannel = ChannelList->FindChannel(ChannelName);
@@ -1807,7 +1811,7 @@ void Client::ChannelInvite(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
LogInfo("[[{}]] invites [[{}]] to channel [[{}]]", GetName().c_str(), Invitee.c_str(), ChannelName.c_str());
@@ -1877,7 +1881,7 @@ void Client::ChannelModerate(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
ChatChannel *RequiredChannel = ChannelList->FindChannel(ChannelName);
@@ -1935,7 +1939,7 @@ void Client::ChannelGrantModerator(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
LogInfo("[[{}]] gives [[{}]] moderator rights to channel [[{}]]", GetName().c_str(), Moderator.c_str(), ChannelName.c_str());
@@ -2016,7 +2020,7 @@ void Client::ChannelGrantVoice(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
LogInfo("[[{}]] gives [[{}]] voice to channel [[{}]]", GetName().c_str(), Voicee.c_str(), ChannelName.c_str());
@@ -2104,7 +2108,7 @@ void Client::ChannelKick(std::string CommandString) {
std::string ChannelName = CapitaliseName(CommandString.substr(ChannelStart));
if ((ChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = ChannelSlotName(atoi(ChannelName.c_str()));
ChannelName = ChannelSlotName(Strings::ToInt(ChannelName.c_str()));
LogInfo("[[{}]] kicks [[{}]] from channel [[{}]]", GetName().c_str(), Kickee.c_str(), ChannelName.c_str());
+23 -20
View File
@@ -84,10 +84,10 @@ void UCSDatabase::GetAccountStatus(Client *client)
auto row = results.begin();
client->SetAccountStatus(atoi(row[0]));
client->SetHideMe(atoi(row[1]) != 0);
client->SetKarma(atoi(row[2]));
client->SetRevoked((atoi(row[3]) == 1 ? true : false));
client->SetAccountStatus(Strings::ToInt(row[0]));
client->SetHideMe(Strings::ToInt(row[1]) != 0);
client->SetKarma(Strings::ToInt(row[2]));
client->SetRevoked((Strings::ToInt(row[3]) == 1 ? true : false));
LogDebug(
"Set account status to [{}], hideme to [{}] and karma to [{}] for [{}]",
@@ -119,9 +119,9 @@ int UCSDatabase::FindAccount(const char *characterName, Client *client)
}
auto row = results.begin();
client->AddCharacter(atoi(row[0]), characterName, atoi(row[2]));
client->AddCharacter(Strings::ToInt(row[0]), characterName, Strings::ToInt(row[2]));
int accountID = atoi(row[1]);
int accountID = Strings::ToInt(row[1]);
LogInfo("Account ID for [{}] is [{}]", characterName, accountID);
@@ -137,7 +137,7 @@ int UCSDatabase::FindAccount(const char *characterName, Client *client)
}
for (auto row = results.begin(); row != results.end(); ++row)
client->AddCharacter(atoi(row[0]), row[1], atoi(row[2]));
client->AddCharacter(Strings::ToInt(row[0]), row[1], Strings::ToInt(row[2]));
return accountID;
}
@@ -197,7 +197,7 @@ int UCSDatabase::FindCharacter(const char *characterName)
auto row = results.begin();
int characterID = atoi(row[0]);
int characterID = Strings::ToInt(row[0]);
return characterID;
}
@@ -225,7 +225,9 @@ bool UCSDatabase::GetVariable(const char *varname, char *varvalue, uint16 varval
bool UCSDatabase::LoadChatChannels()
{
LoadFilteredNamesFromDB();
if (!RuleB(Chat, ChannelsIgnoreNameFilter)) {
LoadFilteredNamesFromDB();
}
LoadReservedNamesFromDB();
LogInfo("Loading chat channels from the database");
@@ -242,7 +244,7 @@ bool UCSDatabase::LoadChatChannels()
auto channel_min_status = row[3];
if (!ChannelList->FindChannel(channel_name)) {
ChannelList->CreateChannel(channel_name, channel_owner, channel_password, true, atoi(channel_min_status), false);
ChannelList->CreateChannel(channel_name, channel_owner, channel_password, true, Strings::ToInt(channel_min_status), false);
}
}
return true;
@@ -334,16 +336,17 @@ void UCSDatabase::DeleteChatChannel(const std::string& channel_name)
LogInfo("Deleting channel [{}] from the database.", channel_name);
}
std::string UCSDatabase::CurrentPlayerChannels(const std::string& player_name) {
int current_player_channel_count = CurrentPlayerChannelCount(player_name);
if (current_player_channel_count == 0) {
return "";
std::vector<std::string> UCSDatabase::CurrentPlayerChannels(const std::string& player_name) {
auto rows = ChatchannelsRepository::GetWhere(*this, fmt::format("`owner` = '{}'", Strings::Escape(player_name)));
if (rows.empty()) {
return {};
}
const auto rquery = fmt::format("SELECT GROUP_CONCAT(`name` SEPARATOR ', ') FROM chatchannels WHERE `owner` = '{}'; ", Strings::Escape(player_name));
auto results = QueryDatabase(rquery);
auto row = results.begin();
std::string channels = row[0];
LogDebug("Player [{}] has the following permanent channels saved to the database: [{}].", player_name, channels);
std::vector<std::string> channels = {};
channels.reserve(rows.size());
for (auto &e: rows) {
channels.emplace_back(e.name);
}
LogDebug("Player [{}] has the following [{}] permanent channels saved to the database: [{}].", player_name, rows.size(), Strings::Join(channels, ", "));
return channels;
}
@@ -740,7 +743,7 @@ void UCSDatabase::GetFriendsAndIgnore(const int& charID, std::vector<std::string
for (auto row = results.begin(); row != results.end(); ++row) {
std::string name = row[1];
if (atoi(row[0]) == 0) {
if (Strings::ToInt(row[0]) == 0) {
ignorees.push_back(name);
LogInfo("Added Ignoree from DB [{}]", name.c_str());
continue;
+2 -3
View File
@@ -30,12 +30,11 @@
#include "../common/database.h"
#include "clientlist.h"
#include "chatchannel.h"
#include "../common/shareddb.h"
#include <string>
#include <vector>
#include <map>
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, nullptr, 10)
class UCSDatabase : public Database {
public:
@@ -51,7 +50,7 @@ public:
void SaveChatChannel(const std::string& channel_name, const std::string& channel_owner, const std::string& channel_password, const uint16& min_status);
void DeleteChatChannel(const std::string& channel_name);
int CurrentPlayerChannelCount(const std::string& player_name);
std::string CurrentPlayerChannels(const std::string& player_name);
std::vector<std::string> CurrentPlayerChannels(const std::string& player_name);
void GetAccountStatus(Client *c);
void SetChannelPassword(const std::string& channel_name, const std::string& password);
void SetChannelOwner(const std::string& channel_name, const std::string& owner);
+10 -4
View File
@@ -37,9 +37,10 @@
#include "../common/net/tcp_server.h"
#include "../common/net/servertalk_client_connection.h"
#include "../common/discord_manager.h"
#include "../common/discord/discord_manager.h"
#include "../common/path_manager.h"
#include "../common/zone_store.h"
#include "../common/events/player_event_logs.h"
ChatChannelList *ChannelList;
Clientlist *g_Clientlist;
@@ -49,6 +50,7 @@ WorldServer *worldserver = nullptr;
DiscordManager discord_manager;
PathManager path;
ZoneStore zone_store;
PlayerEventLogs player_event_logs;
const ucsconfig *Config;
@@ -93,7 +95,7 @@ void CatchSignal(int sig_num) {
}
}
void DiscordQueueListener() {
void PlayerEventQueueListener() {
while (caught_loop == 0) {
discord_manager.ProcessMessageQueue();
Sleep(100);
@@ -112,7 +114,7 @@ int main() {
Timer ChannelListProcessTimer(60000);
Timer ClientConnectionPruneTimer(60000);
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
Timer keepalive(INTERSERVER_TIMER); // does auto-reconnect
LogInfo("Starting EQEmu Universal Chat Server");
@@ -177,7 +179,7 @@ int main() {
std::signal(SIGKILL, CatchSignal);
std::signal(SIGSEGV, CatchSignal);
std::thread(DiscordQueueListener).detach();
std::thread(PlayerEventQueueListener).detach();
worldserver = new WorldServer;
@@ -186,6 +188,10 @@ int main() {
// crash_test.detach();
auto loop_fn = [&](EQ::Timer* t) {
if (keepalive.Check()) {
keepalive.Start();
database.ping();
}
Timer::SetCurrentTime();
+14 -1
View File
@@ -26,7 +26,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "clientlist.h"
#include "ucsconfig.h"
#include "database.h"
#include "../common/discord_manager.h"
#include "../common/discord/discord_manager.h"
#include "../common/events/player_event_logs.h"
#include <iostream>
#include <string.h>
@@ -76,6 +77,18 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
}
case ServerOP_ReloadLogs: {
LogSys.LoadLogDatabaseSettings();
player_event_logs.ReloadSettings();
break;
}
case ServerOP_PlayerEvent: {
auto n = PlayerEvent::PlayerEventContainer{};
auto s = (ServerSendPlayerEvent_Struct*) pack->pBuffer;
EQ::Util::MemoryStreamReader ss(s->cereal_data, s->cereal_size);
cereal::BinaryInputArchive archive(ss);
archive(n);
discord_manager.QueuePlayerEventMessage(n);
break;
}
case ServerOP_DiscordWebhookMessage: {
+6 -6
View File
@@ -507,11 +507,11 @@ void MainFrame::SaveActivity(wxCommandEvent& event)
ourAct.optional = mActivityOptional->GetValue();
getStr = mActID->GetValue();
ourAct.activityId = atoi(getStr.mb_str());
ourAct.activityId = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mActStep->GetValue();
ourAct.step = atoi(getStr.mb_str());
ourAct.step = Strings::ToInt(getStr.mb_str());
getStr.Clear();
int type = mActType->GetSelection();
@@ -530,17 +530,17 @@ void MainFrame::SaveActivity(wxCommandEvent& event)
}
getStr = mActDeliver->GetValue();
ourAct.deliverToNpc = atoi(getStr.mb_str());
ourAct.deliverToNpc = Strings::ToInt(getStr.mb_str());
getStr.Clear();
ourAct.goalmethod = mActMethod->GetSelection();
getStr = mActGoalID->GetValue();
ourAct.goalid = atoi(getStr.mb_str());
ourAct.goalid = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mActGoalCount->GetValue();
ourAct.goalcount = atoi(getStr.mb_str());
ourAct.goalcount = Strings::ToInt(getStr.mb_str());
getStr.Clear();
if(ourAct.activityId == openedActivity.activityid && ourAct.id == openedActivity.id){
@@ -645,4 +645,4 @@ void MainFrame::ContextMenuActivityList()
PopupMenu(mMenu);
delete mMenu;
}
}
+27 -27
View File
@@ -76,7 +76,7 @@ bool MainFrame::LoadItems(){
while ((row = mysql_fetch_row(res)) != NULL){
eqitem newIT;
strcpy(newIT.name, row[0]);
newIT.id = atoi(row[1]);
newIT.id = Strings::ToInt(row[1]);
itemList.push_back(newIT);
itemsLoaded++;
}
@@ -127,7 +127,7 @@ bool MainFrame::LoadZones()
eqtask_zones newZ;
strcpy(newZ.name, row[0]);
newZ.id = atoi(row[1]);
newZ.id = Strings::ToInt(row[1]);
taskZoneList.push_back(newZ);
int * zoneId = new int;
@@ -168,7 +168,7 @@ bool MainFrame::LoadTasks()
res = mysql_use_result(mMysql);
while ((row = mysql_fetch_row(res)) != NULL){
eqtask newT;
newT.id = atoi(row[0]);
newT.id = Strings::ToInt(row[0]);
//This isn't all that safe
//Working under the assumption that:
@@ -185,15 +185,15 @@ bool MainFrame::LoadTasks()
if(newT.id > highestIndex)
highestIndex = newT.id;
newT.rewardid = atoi(row[4]);
newT.cashreward = atoi(row[5]);
newT.xpreward = atoi(row[6]);
newT.rewardmethod = atoi(row[7]);
newT.startzone = atoi(row[8]);
newT.duration = atoi(row[9]);
newT.level_min = atoi(row[10]);
newT.level_max = atoi(row[11]);
newT.repeatable = atoi(row[12]) ? true : false;
newT.rewardid = Strings::ToInt(row[4]);
newT.cashreward = Strings::ToInt(row[5]);
newT.xpreward = Strings::ToInt(row[6]);
newT.rewardmethod = Strings::ToInt(row[7]);
newT.startzone = Strings::ToInt(row[8]);
newT.duration = Strings::ToInt(row[9]);
newT.level_min = Strings::ToInt(row[10]);
newT.level_max = Strings::ToInt(row[11]);
newT.repeatable = Strings::ToInt(row[12]) ? true : false;
taskList.push_back(newT);
@@ -225,8 +225,8 @@ bool MainFrame::LoadGoals()
res = mysql_use_result(mMysql);
while ((row = mysql_fetch_row(res)) != NULL){
eqtask_goallist newGL;
newGL.id = atoi(row[0]);
newGL.value = atoi(row[1]);
newGL.id = Strings::ToInt(row[0]);
newGL.value = Strings::ToInt(row[1]);
goalTaskList.push_back(newGL);
goalsLoaded++;
@@ -258,19 +258,19 @@ bool MainFrame::LoadActivities() {
while ((row = mysql_fetch_row(res)) != NULL) {
eqtask_activities newAL;
newAL.id = atoi(row[0]);
newAL.activityId = atoi(row[1]);
newAL.step = atoi(row[2]);
newAL.activityType = atoi(row[3]);
newAL.id = Strings::ToInt(row[0]);
newAL.activityId = Strings::ToInt(row[1]);
newAL.step = Strings::ToInt(row[2]);
newAL.activityType = Strings::ToInt(row[3]);
strcpy(newAL.text1, row[4]);
strcpy(newAL.text2, row[5]);
strcpy(newAL.text3, row[6]);
newAL.goalid = atoi(row[7]);
newAL.goalmethod = atoi(row[8]);
newAL.goalcount = atoi(row[9]);
newAL.deliverToNpc = atoi(row[10]);
newAL.zoneid = atoi(row[11]);
newAL.optional = atoi(row[12]) ? true : false;
newAL.goalid = Strings::ToInt(row[7]);
newAL.goalmethod = Strings::ToInt(row[8]);
newAL.goalcount = Strings::ToInt(row[9]);
newAL.deliverToNpc = Strings::ToInt(row[10]);
newAL.zoneid = Strings::ToInt(row[11]);
newAL.optional = Strings::ToInt(row[12]) ? true : false;
taskActivitiesList.push_back(newAL);
activitiesLoaded++;
@@ -301,8 +301,8 @@ bool MainFrame::LoadProximity()
while ((row = mysql_fetch_row(res)) != NULL){
eqtask_proximity newPR;
newPR.zoneid = atoi(row[0]);
newPR.exploreid = atoi(row[1]);
newPR.zoneid = Strings::ToInt(row[0]);
newPR.exploreid = Strings::ToInt(row[1]);
newPR.minx = atof(row[2]);
newPR.maxx = atof(row[3]);
newPR.miny = atof(row[4]);
@@ -438,4 +438,4 @@ wxString MainFrame::MakeStringSQLSafe(const char * c)
ret.Printf("%s", c);
ret.Replace("\'", "\\\'");
return ret;
}
}
+2 -2
View File
@@ -276,7 +276,7 @@ void MainFrame::SaveProximity(wxCommandEvent& event)
inStr.Clear();
inStr = mProxId->GetValue();
toSave.exploreid = atoi(inStr.mb_str());
toSave.exploreid = Strings::ToInt(inStr.mb_str());
inStr.Clear();
inStr = mProxMinx->GetValue();
@@ -465,4 +465,4 @@ void MainFrame::ContextMenuProximity()
PopupMenu(mMenu);
delete mMenu;
}
}
+8 -8
View File
@@ -195,7 +195,7 @@ void MainFrame::OnRewardButton(wxCommandEvent& event)
{
wxString ridStr = mRewardID->GetValue();
int rtype = mRewardMethod->GetCurrentSelection();
int rid = atoi(ridStr.mb_str());
int rid = Strings::ToInt(ridStr.mb_str());
ShowRewardChange(rtype,rid);
}
@@ -224,15 +224,15 @@ void MainFrame::SaveTask(wxCommandEvent& event)
getStr.Clear();
getStr = mTaskMinLvl->GetValue();
ourTask.level_min = atoi(getStr.mb_str());
ourTask.level_min = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mTaskMaxLvl->GetValue();
ourTask.level_max = atoi(getStr.mb_str());
ourTask.level_max = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mTaskDuration->GetValue();
ourTask.duration = atoi(getStr.mb_str());
ourTask.duration = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mRewardName->GetValue();
@@ -240,15 +240,15 @@ void MainFrame::SaveTask(wxCommandEvent& event)
getStr.Clear();
getStr = mRewardID->GetValue();
ourTask.rewardid = atoi(getStr.mb_str());
ourTask.rewardid = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mRewardCash->GetValue();
ourTask.cashreward = atoi(getStr.mb_str());
ourTask.cashreward = Strings::ToInt(getStr.mb_str());
getStr.Clear();
getStr = mRewardXP->GetValue();
ourTask.xpreward = atoi(getStr.mb_str());
ourTask.xpreward = Strings::ToInt(getStr.mb_str());
getStr.Clear();
int * i = (int*)mStartZone->GetClientData(mStartZone->GetSelection());
@@ -325,4 +325,4 @@ void MainFrame::ContextMenuTaskList()
PopupMenu(mMenu);
delete mMenu;
}
}
+54 -54
View File
@@ -19,8 +19,8 @@ Fear Pathing generation utility.
bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &db_paths, list<PathNode*> &end_points) {
char query[512];
sprintf(query,
sprintf(query,
"SELECT x,y,z,gridid FROM grid_entries,zone "
"WHERE zone.zoneidnumber=zoneid AND short_name='%s' "
"ORDER BY gridid,number", zone);
@@ -28,21 +28,21 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
printf("Unable to query: %s\n", mysql_error(m));
return(false);
}
MYSQL_RES *res = mysql_store_result(m);
if(res == NULL) {
printf("Unable to store res: %s\n", mysql_error(m));
return(false);
}
MYSQL_ROW row;
PathNode *cur = NULL, *last = NULL, *first = NULL;
PathGraph *g = NULL;
int cur_g = -1,last_g = -1;
// int lid = 0;
while((row = mysql_fetch_row(res))) {
last = cur;
cur = new PathNode;
@@ -50,7 +50,7 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
cur->x = atof(row[0]);
cur->y = atof(row[1]);
cur->z = atof(row[2]);
cur_g = atoi(row[3]);
cur_g = Strings::ToInt(row[3]);
if(cur_g != last_g) {
if(g != NULL) {
//if we have a first and last node for this path
@@ -70,15 +70,15 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
last_g = cur_g;
last = NULL;
}
g->nodes.push_back(cur);
#ifdef LINK_PATH_ENDPOINTS
//this is a begining point
if(last == NULL)
end_points.push_back(cur);
#endif
if(last != NULL) {
#ifdef SPLIT_INVALID_PATHS
if(CheckLOS(map, last, cur)) {
@@ -93,7 +93,7 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
#endif
}
}
//handle the last active path
if(g != NULL) {
if(first != NULL && cur->Dist2(first) < ENDPOINT_CONNECT_MAX_DISTANCE*ENDPOINT_CONNECT_MAX_DISTANCE) {
@@ -102,7 +102,7 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
}
db_paths.push_back(g);
}
mysql_free_result(res);
return(true);
}
@@ -110,25 +110,25 @@ bool load_paths_from_db(MYSQL *m, Map *map, const char *zone, list<PathGraph*> &
bool load_spawns_from_db(MYSQL *m, const char *zone, list<PathNode*> &db_spawns) {
char query[512];
sprintf(query,
sprintf(query,
"SELECT x,y,z FROM spawn2 "
"WHERE zone='%s'", zone);
if(mysql_query(m, query) != 0) {
printf("Unable to query: %s\n", mysql_error(m));
return(false);
}
MYSQL_RES *res = mysql_store_result(m);
if(res == NULL) {
printf("Unable to store res: %s\n", mysql_error(m));
return(false);
}
MYSQL_ROW row;
PathNode *cur = NULL;
while((row = mysql_fetch_row(res))) {
cur = new PathNode;
cur->x = atof(row[0]);
@@ -136,34 +136,34 @@ bool load_spawns_from_db(MYSQL *m, const char *zone, list<PathNode*> &db_spawns)
cur->z = atof(row[2]);
db_spawns.push_back(cur);
}
mysql_free_result(res);
return(true);
}
bool load_doors_from_db(MYSQL *m, const char *zone, list<PathNode*> &db_spawns) {
char query[512];
sprintf(query,
sprintf(query,
"SELECT pos_x,pos_y,pos_z FROM doors "
"WHERE zone='%s'", zone);
if(mysql_query(m, query) != 0) {
printf("Unable to query: %s\n", mysql_error(m));
return(false);
}
MYSQL_RES *res = mysql_store_result(m);
if(res == NULL) {
printf("Unable to store res: %s\n", mysql_error(m));
return(false);
}
MYSQL_ROW row;
PathNode *cur = NULL;
while((row = mysql_fetch_row(res))) {
cur = new PathNode;
cur->x = atof(row[0]);
@@ -173,54 +173,54 @@ bool load_doors_from_db(MYSQL *m, const char *zone, list<PathNode*> &db_spawns)
//doors, not the edge of them which I assume these points are
db_spawns.push_back(cur);
}
mysql_free_result(res);
return(true);
}
bool load_hints_from_db(MYSQL *m, const char *zone, list<PathNode*> &db_spawns) {
char query[512];
sprintf(query,
sprintf(query,
"SELECT x,y,z,forced,disjoint FROM fear_hints "
"WHERE zone='%s'", zone);
if(mysql_query(m, query) != 0) {
printf("Unable to query: %s\n", mysql_error(m));
return(false);
}
MYSQL_RES *res = mysql_store_result(m);
if(res == NULL) {
printf("Unable to store res: %s\n", mysql_error(m));
return(false);
}
MYSQL_ROW row;
PathNode *cur = NULL;
while((row = mysql_fetch_row(res))) {
cur = new PathNode;
cur->x = atof(row[0]);
cur->y = atof(row[1]);
cur->z = atof(row[2]);
cur->forced = atoi(row[3])?true:false;
cur->disjoint = atoi(row[4])?true:false;
cur->forced = Strings::ToInt(row[3])?true:false;
cur->disjoint = Strings::ToInt(row[4])?true:false;
db_spawns.push_back(cur);
}
mysql_free_result(res);
return(true);
}
bool load_settings_from_db(MYSQL *m, const char *zone) {
char query[512];
sprintf(query,
sprintf(query,
"SELECT use_doors, min_fix_z, max_fear_distance, image_scale, split_invalid_paths,"
" link_path_endpoints, end_distance, split_long_min, split_long_step, same_dist, node_combine_dist,"
" grid_combine_dist, close_all_los, cross_count, cross_min_length, cross_max_z_diff, cross_combine_dist,"
@@ -231,46 +231,46 @@ bool load_settings_from_db(MYSQL *m, const char *zone) {
// printf("Unable to query: %s\n", mysql_error(m));
return(false);
}
MYSQL_RES *res = mysql_store_result(m);
if(res == NULL) {
// printf("Unable to store res: %s\n", mysql_error(m));
return(false);
}
MYSQL_ROW row;
int r = 0;
if((row = mysql_fetch_row(res))) {
INCLUDE_DOORS = atoi(row[r++])?true:false;
INCLUDE_DOORS = Strings::ToInt(row[r++])?true:false;
MIN_FIX_Z = atof(row[r++]);
FEAR_MAXIMUM_DISTANCE = atof(row[r++]);
IMAGE_SCALE = atoi(row[r++]);
SPLIT_INVALID_PATHS = atoi(row[r++])?true:false;
LINK_PATH_ENDPOINTS = atoi(row[r++])?true:false;
IMAGE_SCALE = Strings::ToInt(row[r++]);
SPLIT_INVALID_PATHS = Strings::ToInt(row[r++])?true:false;
LINK_PATH_ENDPOINTS = Strings::ToInt(row[r++])?true:false;
ENDPOINT_CONNECT_MAX_DISTANCE = atof(row[r++]);
SPLIT_LINE_LENGTH = atof(row[r++]);
SPLIT_LINE_INTERVAL = atof(row[r++]);
CLOSE_ENOUGH = atof(row[r++]);
CLOSE_ENOUGH_COMBINE = atof(row[r++]);
MERGE_MIN_SECOND_DIST = atof(row[r++]);
COMBINE_CHECK_ALL_LOS = atoi(row[r++])?true:false;
CROSS_REDUCE_COUNT = atoi(row[r++]);
COMBINE_CHECK_ALL_LOS = Strings::ToInt(row[r++])?true:false;
CROSS_REDUCE_COUNT = Strings::ToInt(row[r++]);
CROSS_MIN_LENGTH = atof(row[r++]);
CROSS_MAX_Z_DIFF = atof(row[r++]);
CLOSE_ENOUGH_CROSS = atof(row[r++]);
SPAWN_MIN_SECOND_DIST = atof(row[r++]);
MAX_LINK_SPAWN_DIST = atof(row[r++]);
int sc = atoi(row[r++]);
int sc = Strings::ToInt(row[r++]);
SPAWN_LINK_TWICE = sc >= 2?true:false;
SPAWN_LINK_THRICE = sc >= 3?true:false;
mysql_free_result(res);
return(true);
}
mysql_free_result(res);
return(false);
}
+4 -4
View File
@@ -1118,7 +1118,7 @@ void QTBuilder::AddPlaceable(FileLoader *fileloader, char *ZoneFileName, bool Li
if((ch==EOF)||(ch=='\n')) {
IniBuffer[StrIndex] = '\0';
if(State == ReadingModelNumbers) {
ModelNumber = atoi(IniBuffer);
ModelNumber = Strings::ToInt(IniBuffer);
if((ModelNumber >= 0) && (ModelNumber < fileloader->model_data.model_count))
{
fileloader->model_data.models[ModelNumber]->IncludeInMap = true;
@@ -1146,7 +1146,7 @@ void QTBuilder::AddPlaceable(FileLoader *fileloader, char *ZoneFileName, bool Li
}
}
else {
ModelNumber = atoi(IniBuffer);
ModelNumber = Strings::ToInt(IniBuffer);
if((ModelNumber >= 0) && (ModelNumber < fileloader->model_data.model_count))
{
fileloader->model_data.models[ModelNumber]->IncludeInMap = true;
@@ -1323,7 +1323,7 @@ void QTBuilder::AddPlaceableV4(FileLoader *fileloader, char *ZoneFileName, bool
Group = true;
strcpy(IniBuffer, IniBuffer+1);
}
ModelNumber = atoi(IniBuffer);
ModelNumber = Strings::ToInt(IniBuffer);
if(!Group)
{
if((ModelNumber >= 0) && (ModelNumber < fileloader->model_data.model_count))
@@ -1369,7 +1369,7 @@ void QTBuilder::AddPlaceableV4(FileLoader *fileloader, char *ZoneFileName, bool
Group = true;
strcpy(IniBuffer, IniBuffer+1);
}
ModelNumber = atoi(IniBuffer);
ModelNumber = Strings::ToInt(IniBuffer);
if(!Group)
{
if((ModelNumber >= 0) && (ModelNumber < fileloader->model_data.model_count))
+1 -1
View File
@@ -278,7 +278,7 @@ int DATLoader::Open(char *base_path, char *zone_name, Archive *archive) {
if(Token == "*QUADSPERTILE")
{
Token = GetToken(ZonBuffer, ZonPosition);
QuadsPerTile = atoi(Token.c_str());
QuadsPerTile = Strings::ToInt(Token.c_str());
#ifdef DEBUGDAT
printf("Set QuadsPerTile to %i\n", QuadsPerTile);
#endif
+1 -1
View File
@@ -97,7 +97,7 @@ FRAG_CONSTRUCTOR(Data15) {
plac->scale[1] = hdr->scale[1];
plac->scale[2] = hdr->scale[1];
plac->model = atoi((const char*)&wld->sHash[-(int)hdr->ref]);
plac->model = Strings::ToInt((const char*)&wld->sHash[-(int)hdr->ref]);
pl = new Placeable *[wld->model_data.plac_count + 1];
memcpy(pl, wld->model_data.placeable, sizeof(Placeable *) * wld->model_data.plac_count);
+52 -52
View File
@@ -20,41 +20,41 @@ void usage() {
}
int main(int argc, char *argv[]) {
const char *outfile;
if(argc != 3)
usage();
int charid = atoi(argv[1]);
int charid = Strings::ToInt(argv[1]);
if(charid == 0)
usage();
outfile = argv[2];
char *query = new char[1024];
char host[200], user[200], passwd[200], database[200];
int32 port=0;
bool compression = false;
bool items[6] = {false, false, false, false, false, false};
if(!DBcore::ReadDBINI(host, user, passwd, database, port, compression, items)) {
exit(1);
}
if (!items[0] || !items[1] || !items[2] || !items[3])
{
printf ("Incomplete DB.INI file.\n");
exit (1);
}
MYSQL m;
mysql_init(&m);
if(!mysql_real_connect(&m, host, user, passwd, database, 0, NULL, 0)) {
printf("Unable to connect 1: %s.\n", mysql_error(&m));
return(1);
}
CharHeader header;
char *ppbuffer;
char *eppbuffer;
@@ -62,13 +62,13 @@ int main(int argc, char *argv[]) {
InventoryEntry *inventory;
InventoryEntry *sharedbank;
QuestGlobalEntry *qglobals;*/
sprintf(query, "SELECT name,profile,extprofile,x,y,z,zonename,zoneid FROM character_ WHERE id=%d", charid);
if(mysql_query(&m, query) != 0) {
printf("Unable to query.\n");
return(1);
}
MYSQL_RES *res = mysql_use_result(&m);
if(res == NULL) {
printf("Unable to use character_ res.\n");
@@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
}
unsigned long* lengths;
lengths = mysql_fetch_lengths(res);
header.char_magic = CHAR_MAGIC;
strcpy(header.name, row[0]);
header.profile_length = lengths[1];
@@ -91,15 +91,15 @@ int main(int argc, char *argv[]) {
header.y = atof(row[4]);
header.z = atof(row[5]);
strcpy(header.zone_name, row[6]);
header.zone_id = atoi(row[7]);
header.zone_id = Strings::ToInt(row[7]);
//copy in blobs
ppbuffer = new char[header.profile_length];
eppbuffer = new char[header.extprofile_length];
memcpy(ppbuffer, row[1], header.profile_length);
memcpy(eppbuffer, row[2], header.extprofile_length);
mysql_free_result(res);
//query faction
sprintf(query, "SELECT faction_id,current_value FROM faction_values WHERE char_id=%d", charid);
if(mysql_query(&m, query) != 0) {
@@ -114,12 +114,12 @@ int main(int argc, char *argv[]) {
vector<FactionValueRecord> fr;
while((row = mysql_fetch_row(res))) {
FactionValueRecord r;
r.faction_id = atoi(row[0]);
r.current_value = atoi(row[1]);
r.faction_id = Strings::ToInt(row[0]);
r.current_value = Strings::ToInt(row[1]);
fr.push_back(r);
}
mysql_free_result(res);
//query inventory
sprintf(query, "SELECT slotid,itemid,charges,color,augslot1,augslot2,augslot3,augslot4,augslot5,instnodrop FROM inventory WHERE charid=%d", charid);
if(mysql_query(&m, query) != 0) {
@@ -134,19 +134,19 @@ int main(int argc, char *argv[]) {
vector<InventoryEntry> inv;
while((row = mysql_fetch_row(res))) {
InventoryEntry r;
r.slotid = atoi(row[0]);
r.itemid = atoi(row[1]);
r.charges = atoi(row[2]);
r.colors = atoi(row[3]);
r.augs[0] = atoi(row[4]);
r.augs[1] = atoi(row[5]);
r.augs[2] = atoi(row[6]);
r.augs[3] = atoi(row[7]);
r.augs[4] = atoi(row[8]);
r.slotid = Strings::ToInt(row[0]);
r.itemid = Strings::ToInt(row[1]);
r.charges = Strings::ToInt(row[2]);
r.colors = Strings::ToInt(row[3]);
r.augs[0] = Strings::ToInt(row[4]);
r.augs[1] = Strings::ToInt(row[5]);
r.augs[2] = Strings::ToInt(row[6]);
r.augs[3] = Strings::ToInt(row[7]);
r.augs[4] = Strings::ToInt(row[8]);
inv.push_back(r);
}
mysql_free_result(res);
//query shared bank
sprintf(query, "SELECT slotid,itemid,charges,augslot1,augslot2,augslot3,augslot4,augslot5 FROM sharedbank,character_ WHERE sharedbank.acctid = character_.account_id AND character_.id=%d", charid);
if(mysql_query(&m, query) != 0) {
@@ -161,18 +161,18 @@ int main(int argc, char *argv[]) {
vector<InventoryEntry> sb;
while((row = mysql_fetch_row(res))) {
InventoryEntry r;
r.slotid = atoi(row[0]);
r.itemid = atoi(row[1]);
r.charges = atoi(row[2]);
r.augs[0] = atoi(row[3]);
r.augs[1] = atoi(row[4]);
r.augs[2] = atoi(row[5]);
r.augs[3] = atoi(row[6]);
r.augs[4] = atoi(row[7]);
r.slotid = Strings::ToInt(row[0]);
r.itemid = Strings::ToInt(row[1]);
r.charges = Strings::ToInt(row[2]);
r.augs[0] = Strings::ToInt(row[3]);
r.augs[1] = Strings::ToInt(row[4]);
r.augs[2] = Strings::ToInt(row[5]);
r.augs[3] = Strings::ToInt(row[6]);
r.augs[4] = Strings::ToInt(row[7]);
sb.push_back(r);
}
mysql_free_result(res);
//query quest_globals
sprintf(query, "SELECT npcid,zoneid,name,value,expdate FROM quest_globals WHERE charid=%d", charid);
if(mysql_query(&m, query) != 0) {
@@ -187,37 +187,37 @@ int main(int argc, char *argv[]) {
vector<QuestGlobalEntry> qg;
while((row = mysql_fetch_row(res))) {
QuestGlobalEntry r;
r.npcid = atoi(row[0]);
r.zoneid = atoi(row[1]);
r.npcid = Strings::ToInt(row[0]);
r.zoneid = Strings::ToInt(row[1]);
strcpy(r.name, row[2]);
strcpy(r.value, row[3]);
r.expdate = atoi(row[4]);
r.expdate = Strings::ToInt(row[4]);
qg.push_back(r);
}
mysql_free_result(res);
mysql_close(&m);
FILE *outf = fopen(outfile, "wb");
if(outf == NULL) {
printf("Unable to open output file %s\n", outfile);
return(1);
}
//fill in our counters
header.faction_value_count = fr.size();
header.inventory_count = inv.size();
header.sharedbank_count = sb.size();
header.quest_globals_count = qg.size();
//write header
fwrite(&header, 1, sizeof(header), outf);
//write out pp and epp
fwrite(ppbuffer, 1, header.profile_length, outf);
fwrite(eppbuffer, 1, header.extprofile_length, outf);
//write out our variable length segments
vector<FactionValueRecord>::iterator curfr, endfr;
curfr = fr.begin();
@@ -226,7 +226,7 @@ int main(int argc, char *argv[]) {
FactionValueRecord &r = *curfr;
fwrite(&r, 1, sizeof(FactionValueRecord), outf);
}
vector<InventoryEntry>::iterator curi, endi;
curi = inv.begin();
endi = inv.end();
@@ -234,14 +234,14 @@ int main(int argc, char *argv[]) {
InventoryEntry &i = *curi;
fwrite(&i, 1, sizeof(InventoryEntry), outf);
}
curi = sb.begin();
endi = sb.end();
for(; curi != endi; curi++) {
InventoryEntry &i = *curi;
fwrite(&i, 1, sizeof(InventoryEntry), outf);
}
vector<QuestGlobalEntry>::iterator curqg, endqg;
curqg = qg.begin();
endqg = qg.end();
@@ -249,9 +249,9 @@ int main(int argc, char *argv[]) {
QuestGlobalEntry &r = *curqg;
fwrite(&r, 1, sizeof(QuestGlobalEntry), outf);
}
fclose(outf);
return(0);
}
+24 -24
View File
@@ -15,42 +15,42 @@ void usage() {
}
int main(int argc, char *argv[]) {
const char *infile;
if(argc != 3)
usage();
int accountid = atoi(argv[1]);
int accountid = Strings::ToInt(argv[1]);
if(accountid == 0)
usage();
infile = argv[2];
char *query = new char[1024000];
char *cursor;
char host[200], user[200], passwd[200], database[200];
int32 port=0;
bool compression = false;
bool items[6] = {false, false, false, false, false, false};
if(!DBcore::ReadDBINI(host, user, passwd, database, port, compression, items)) {
exit(1);
}
if (!items[0] || !items[1] || !items[2] || !items[3])
{
printf ("Incomplete DB.INI file.\n");
exit (1);
}
MYSQL m;
mysql_init(&m);
if(!mysql_real_connect(&m, host, user, passwd, database, 0, NULL, 0)) {
printf("Unable to connect 1: %s.\n", mysql_error(&m));
return(1);
}
CharHeader header;
char *ppbuffer;
char *eppbuffer;
@@ -58,25 +58,25 @@ int main(int argc, char *argv[]) {
InventoryEntry *inventory;
InventoryEntry *sharedbank;
QuestGlobalEntry *qglobals;
FILE *inf = fopen(infile, "rb");
if(inf == NULL) {
printf("Unable to open infile %s\n", infile);
return(1);
}
if(fread(&header, sizeof(header), 1, inf) != 1) {
printf("Error reading header.\n");
return(1);
}
ppbuffer = new char[header.profile_length];
eppbuffer = new char[header.extprofile_length];
factions = new FactionValueRecord[header.faction_value_count];
inventory = new InventoryEntry[header.inventory_count];
sharedbank = new InventoryEntry[header.sharedbank_count];
qglobals = new QuestGlobalEntry[header.quest_globals_count];
//read all the shit in
if(fread(ppbuffer, header.profile_length, 1, inf) != 1) {
printf("Error reading pp.\n");
@@ -102,9 +102,9 @@ int main(int argc, char *argv[]) {
printf("Error reading quest globals.\n");
return(1);
}
fclose(inf);
cursor = query;
cursor += sprintf(cursor, "INSERT INTO character_ "
"(account_id,name,profile,extprofile,x,y,z,zonename,zoneid)"
@@ -119,7 +119,7 @@ int main(int argc, char *argv[]) {
}
int charid = mysql_insert_id(&m);
uint32 r;
//faction
for(r = 0; r < header.faction_value_count; r++) {
sprintf(query, "INSERT INTO faction_values (char_id,faction_id,current_value)"
@@ -129,13 +129,13 @@ int main(int argc, char *argv[]) {
return(1);
}
}
//inventory
for(r = 0; r < header.inventory_count; r++) {
sprintf(query, "INSERT INTO inventory (charid,slotid,itemid,charges,color,augslot1,augslot2,augslot3,augslot4,augslot5,instnodrop)"
" VALUES(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", charid,
inventory[r].slotid, inventory[r].itemid, inventory[r].charges, inventory[r].colors,
inventory[r].augs[0], inventory[r].augs[1], inventory[r].augs[2], inventory[r].augs[3],
inventory[r].augs[0], inventory[r].augs[1], inventory[r].augs[2], inventory[r].augs[3],
inventory[r].augs[4], inventory[r].instnodrop
);
if(mysql_query(&m, query) != 0) {
@@ -143,7 +143,7 @@ int main(int argc, char *argv[]) {
return(1);
}
}
//shared bank
//this is far from perfect since this is per-account, works great with empty shard bank...
for(r = 0; r < header.sharedbank_count; r++) {
@@ -158,7 +158,7 @@ int main(int argc, char *argv[]) {
// return(1);
}
}
//quest globals
for(r = 0; r < header.quest_globals_count; r++) {
cursor = query;
@@ -168,17 +168,17 @@ int main(int argc, char *argv[]) {
cursor += sprintf(cursor, "','");
cursor += mysql_real_escape_string(&m, cursor, (const char *) qglobals[r].value, strlen(qglobals[r].value));
sprintf(cursor, "',%d)", qglobals[r].expdate);
if(mysql_query(&m, query) != 0) {
printf("Unable to insert quest global: %s\n", mysql_error(&m));
return(1);
}
}
mysql_close(&m);
printf("Successfully imported %s as character id %d\n", header.name, charid);
return(0);
}
@@ -226,7 +226,7 @@ bool atobool(char* iBool) {
return true;
if (!strcasecmp(iBool, "n"))
return false;
if (atoi(iBool))
if (Strings::ToInt(iBool))
return true;
return false;
}
@@ -328,4 +328,4 @@ int FloatToEQH(float d)
float EQHtoFloat(int d)
{
return(360.0f - float((d * 360) >> 11));
}
}

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