Akkadius
We've added a CLI interface to the world process which can be handy for various things, such as showing build version, database schema, database version or other utility things like setting account status. This feature is built in such a way that makes it easier for the development team to also add other commands in the future
Added an internal single source of truth for where we maintain our database schema for different types of tables. These lists will be significant for things like export/import commands, future plans for multi-tenancy etc.
Player Tables
Content Tables
State Tables
Server Tables
Login Tables
CLI Interface Changes
Commands that used option flags are arguments are now proper arguments as shown in examples. This is reflected in the Loginserver CLI as well and the documentation has been changed to reflect
Old
./world database:set-account-status --name=* --status=*
New
./world database:set-account-status {name} {status}
./world database:set-account-status myaccount 255
[email protected]:~/server$ ./bin/world --help​> EQEmulator [WorldServer] CLI Menu​databasedatabase:schema Displays server database schemadatabase:set-account-status Sets account status by account namedatabase:version Shows database versionworldworld:version Shows server version
Fix for pets breaking mez during combat
Fix for bot classes having skills they should not
Added bot command itemuse
This command will cause spawned bots to report if they can use the item which you currently hold on your cursor
To use this command, simply pick up an item and type ^itemuse
All spawned bots will check their inventories based on the items 'Slots' property and report that it is usable by them (no report if not usable)
Each bot will give a report for each eligible slot
To give the item to any reporting bot, simply click the text link with their name in it
This will invoke the inventorygive
command using ^inventorygive byname botname
All rules governing use of the bot command inventorygive
apply
You may also use the optional argument ^itemuse empty
to have bots only report empty inventory slots that can use it
This command will affect a chain follow effect, starting with the bot owner
All spawned bots will be included in this follow order unless they have previously been issued a follow command
The chain processing will skip all bots with the manual_follow
flag set
This flag may be removed by issuing a ^follow reset
on the affected bot or bots
The flag is temporary and is reset upon camping or zoning
Added bot command applypoison
This will apply item type 42
poisons (rogue-crafted) to an owner's targeted rogue bot's weapon
Class and level restrictions are observed
The application chance is the same as that for rogue players attempting to apply poison
To apply, simply place the poison on your cursor and type ^applypoison
You will receive a success/fail message and the item will be consumed in both cases
This effect remains active during the time in zone - just like a player's poison application
Added rule Bots:AllowApplyPoisonCommand
to allow the command to be enabled or disabled per server admin's needs (default is true)
Added bot command applypotion
This will apply item type 21
potions to any bot targeted by its owner
Class, race and level restrictions are observed
Potion-type rogue poisons must be applied using this command
Casting time requirements are currently bypassed - expect a change in behavior at some point
To apply, simply place the potion on your cursor and type ^applypotion
You will receive a success/fail message and the item will be consumed in both cases
This effect is retained as a 'casted buff' and will remain until expired or removed
Added rule Bots:AllowApplyPotionCommand
to allow the command to be enabled or disabled per server admin's needs (default is true)
Added rule Bots:RestrictApplyPotionToRogue
to allow a restriction of applypotion
to rogue-only potions (i.e., poisons) (default is true)
Added bot owner option buffcounter
When enabled, any bot buff with a counter will display a marquee message indicating how many 'hits' remain
Note: Bot owner option deathmarquee
messages have been changed to red
in color.
​
Notes:
In order to get potion effects to work properly after zoning or camping, I had to borrow code from the client connection handler.
It's unknown whether this code helps in the case of bots recasting buffs upon zoning and spawning..but, I did notice the lack of rebuffing in many cases - will watch!
​
Changed this rule property from an enumerated value to a bitmask
Renamed rule to coincide with the property change
Works the same as World:ExpansionSettings
in regards to active expansions (defaults to 16383 - same as the world rule)
Added code to bot aa assignment to honor the per-expansion restrictions
This rule may be expanded in the future to other bot-related systems
Added command nudge
to facilitate npc placement and orientation
Command accepts up to 4 arguments (x,y,z,h) and may use any combination, in any order
Acceptable values are float-type for all parameters
Values are interpreted as offsets and not absolute values
Adjustments are 'set' by applying the command #fixnpc
This command is ideally suited for macro (hotkey) use
Real-time updates are broadcast to clients..but, there may be 'visible' glitches if you try to use the command too fast (limited by packet broadcast timer)
Examples of use:
#nudge x=1.00 y=-1.00 z=3.45 h=-11.38
#nudge x=2.33 z=-1.01
#nudge h=133.00 z=-12.34
Added the new event EVENT_COMBINE_VALIDATE
This event is processed as the very last step in a tradeskill combine process just before the actual combine action
Its use is automatic and criteria may be added to the global_player
file for whichever scripting api that you are using
The initial candidate for special validation is tradeskill recipe #10344 - "Clockwork Scout Module"
function event_combine_validate(e)if (e.recipe_id == 10344) thenif (e.validate_type:find("check_zone")) thenif (e.zone_id ~= 289 and e.zone_id ~= 290) thenreturn 1;endendend​return 0;end
For this recipe, the combine is only allowed in two zones, tipt
and vxed
The active recipe id will always be passed by integer as the variable recipe_id
In this case, the active validation_type
of check_zone
, the current zone id will be passed by integer as the variable zone_id
From there, a simple check against valid zones can be made
Invalid zones will return a non-zero value resulting in a failure to validate the combine..hence, cancelling it
Valid zones will return a zero value and allow the combine to occur normally
The validation types can be expanded
This initial implementation is to alleviate a current bug
Note: This change requires a quest update to capture the new global player files, or the changes may be added manually.
Added two new 'Owner Option' features:
altcombat
- enabled, bots aggro based on owner's attack state; disabled, pet-like behavior
autodefend
- enabled, bots defend owner on aggro; disabled, no action taken
Renamed bot command ^hold
to ^suspend
(same action and counter to ^release
)
Repurposed bot command ^hold
to override all attack actions
Reworked ^guard
to allow all 'normal' actions and for bots to return to their guard spots when idle
Bot command ^attack
should now work as intended - with noted exceptions above
Revamped bot command ^pull
:
Pulling bot will travel to entity, gain aggro, then return to home position
Aggro is attained through the use of the low-damage spell 'Throw Stone'
Pulling candidacy is currently determined by a 4-tier ranking system
Akkadius
Auto convert insecure world server admin passwords during the world authentication process
Add CLI support for updating world admin account world-admin:update --username=* --password=
*
Kinglykrab
Fixed Maximum Status value in entity_list.QueueClientsStatus.
Maximum Status of 250 was causing status levels 251 to 254 to be excluded from the queue.
Akkadius
There's a few weeks of solid work wrapped in this update, you can review the changes in this pull request if you wish
Database schema includes all new tables, to migrate see migration reference below
All new config file JSON format login.json
found in ./loginserver/login_util/login.json
Now has an embedded Web API on port 6000 by default, details can be found at Loginserver API​
Now has a rich embedded CLI interface, details found at Login CLI Interface​
Now uses Scrypt for encryption which you can learn more about here​
Now automatically updates weak encryption methods during client login to the latest encryption method (Scrypt) in use on the fly
Now properly supports string escaping in all database calls
Now no longer requires you to specify a Local LAN subnet in the config to detect LAN world servers and LAN player connections. The server now can intelligently detect RFC1918 local LAN subnets in the requests to properly mark both World Server connections and Player connections appropriately (Plug-N-Play)
A production and stage/testing server of the same long name / short name pair can now live together as long as one world is registered
Code is heavily cleaned up, many parts not perfect but far far improved
Many many bug fixes, stability improvements
Improvements made to world -> loginserver and loginserver -> world reconnects through keep-alive. If a world is disconnected it will properly picked up by world and vise versa. Which also allows the chance for the process to reconnect sooner because it knows it had a connection die instead of waiting for it to be told
Improvements made to world -> zone and zone -> world disconnects through keep-alive for example on Linux if world had been killed, it would not gracefully reconnect to all zone processes and vise versa
To migrate your Legacy login server, follow this guide Migrating your Legacy Loginserver​
The popular C++ library FMT is now powering most of our logging FMT Library​
Migrated thousands of log calls to use now simplified log aliases, the most recent up to date list can be found here
The main reason for these changes is that it simplifies the use of logging by developers, it also makes it far easier to create logging statements because we no longer need to look up printf codes to match variable types going into logging calls as our FMT library that we are using will detect the types at runtime
Using the category log aliases also heavily simplifies the amount of verbosity that goes into simply typing the log statements to begin with
We have *Detail* level aliases, but we are trying to keep from using detail in categorized logging, if you are using detail you probably either need to use another specialized category. The only time detail should ever really be used is if it is incredibly spammy to the rest of the logging in the same category
Log(Logs::General, Logs::ZoneServer, "Connecting to MySQL... ");Log(Logs::General, Logs::Error, "Failed to connect to database: Error: %s", errbuf);Log(Logs::Detail, Logs::Spells, "Bard song %d started: slot %d, target id %d", bardsong, bardsong_slot, bardsong_target_id);Log(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", hit.damage_done);
LogInfo("Connecting to MySQL... ");LogError("Failed to connect to database: Error: {}", errbuf);LogSpells("Bard song [{}] started: slot [{}], target id [{}]", bardsong, (int) bardsong_slot, bardsong_target_id);LogCombat("Final damage after all reductions: [{}]", hit.damage_done);
LogEmergencyLogAlertLogCriticalLogErrorLogWarningLogNoticeLogInfoLogDebugLogAALogAADetailLogAILogAIDetailLogAggroLogAggroDetailLogAttackLogAttackDetailLogPacketClientServerLogPacketClientServerDetailLogCombatLogCombatDetailLogCommandsLogCommandsDetailLogCrashLogCrashDetailLogDoorsLogDoorsDetailLogGuildsLogGuildsDetailLogInventoryLogInventoryDetailLogLauncherLogLauncherDetailLogNetcodeLogNetcodeDetailLogNormalLogNormalDetailLogObjectLogObjectDetailLogPathingLogPathingDetailLogQSServerLogQSServerDetailLogQuestsLogQuestsDetailLogRulesLogRulesDetailLogSkillsLogSkillsDetailLogSpawnsLogSpawnsDetailLogSpellsLogSpellsDetailLogTCPConnectionLogTCPConnectionDetailLogTasksLogTasksDetailLogTradeskillsLogTradeskillsDetailLogTradingLogTradingDetailLogTributeLogTributeDetailLogMySQLErrorLogMySQLErrorDetailLogMySQLQueryLogMySQLQueryDetailLogMercenariesLogMercenariesDetailLogQuestDebugLogQuestDebugDetailLogLoginserverLogLoginserverDetailLogClientLoginLogClientLoginDetailLogHeadlessClientLogHeadlessClientDetailLogHPUpdateLogHPUpdateDetailLogFixZLogFixZDetailLogFoodLogFoodDetailLogTrapsLogTrapsDetailLogNPCRoamBoxLogNPCRoamBoxDetailLogNPCScalingLogNPCScalingDetailLogMobAppearanceLogMobAppearanceDetailLogStatusLogStatusDetail
RFC5424 Log Categories have been introduced, they are meant to simplify the use of common logging scenarios that don't require specific categories
LogEmergencyLogAlertLogCriticalLogErrorLogWarningLogNoticeLogInfoLogDebug
When using any of these macros, logging output will append the process name before the message itself, thus deprecating process specific categories
[WorldServer] [Info] Purging expired data buckets[WorldServer] [Info] Loading zones[WorldServer] [Info] Clearing groups[WorldServer] [Info] Clearing raids[WorldServer] [Info] Clearing inventory snapshots[WorldServer] [Info] Loading items[WorldServer] [Info] Loading skill caps[WorldServer] [Info] Loading guilds[LoginServer] [Warning] Remote address was null, defaulting to stream address 127.0.0.1
Uleat
Added code to restore rule notes to their original values
Uleat
Added code to inject new rules into the 'default' ruleset and remove orphaned rules from all rulesets
New rules are only added using the 'default' ruleset - Other rulesets will need to be added manually or through in-game updates
Rule notes are now loaded into the system's hard-coded entries and will now propagate properly into database updates
Defunct rules will have their orphaned entries removed from the 'rule_values' table for the all rulesets
Uleat
Added code to inject new commands and remove orphaned commands from both command systems
New commands are added with their status ('access') set to the server default value - no aliases are defined
Defunct commands will have their orhpaned entries removed from the command settings table for each system
Akkadius
Implemented command #roambox set [move_delay]
Implemented command #roambox remove
$npc->SetSimpleRoamBox(box_size, [move_distance], [move_delay]);
NPC:SetSimpleRoamBox(box_size, [move_distance], [move_delay]);
Spawngroup data now hot reloads on #repop
Command #npceditmass now lists column options when one isn't properly specified
Implemented command #spawneditmass [search] [option] with options [respawn_time] currently implemented
Akkadius
Added bulk edit command #npceditmass [column-to-search] [column-search-value] [change-column] [change-value]
Modified #findzone to include clickable saylinks to both regular zone (if able) and private gmzone instances
Added command #findzone [expansion-number] expansion to show zones via expansion
Akkadius Optimizations to movement updates to eliminate ghosting possibilities in larger zones
Uleat
Added script `vcxproj_dependencies.py` a script to help determine conflicting project dependencies (alpha-stage)
Akkadius
Add #npcedit flymode [0 = ground, 1 = flying, 2 = levitate, 3 = water, 4 = floating]
Added "flymode" to npc_types database table
Akkadius/KLS
Optimizations to packet updates introduced back into the source post network code overhaul
Optimizations made to position update packets by sending updates far less frequently when not in line with zone:max_movement_update_range
Optimizations made to position updates in respect to the much higher resolution of navmesh path finding that we were using. We have cut down on the resolution of path finding / updating so that we reduce the CPU overhead of path*finding and subsequent client update packets that get generated this action
Optimization made by adjusting ZLIB compression rate that was accidentally set to a compression level of 4 a long time ago
Added #netstats admin command to troubleshoot connection issues in detail
Websocket server is now available in zone and is bound to the same UDP port that the zoneserver listens on
Currently implemented websocket API calls at the zone level
get_packet_statistics
get_opcode_list
get_npc_list_detail
get_door_list_detail
get_corpse_list_detail
get_object_list_detail
get_mob_list_detail
get_client_list_detail
get_zone_attributes
get_logsys_categories
set_logging_level
Example of a Typescript client: https://gist.github.com/Akkadius/52d12d0379f36cf81c51b3b7da13db37​
Library Changes
We now use git submodules for libraries / dependencies versus manually downloading to the dependencies folder and/or storing
said dependencies within our codebase itself
To update dependencies (Required for compiling)
git submodule init
git submodule update
Libraries now in submodules
[glm] https://github.com/g-truc/glm.git​
[flm] https://github.com/fmtlib/fmt.git​
[libuv] https://github.com/libuv/libuv.git​
[cereal] https://github.com/USCiLab/cereal.git​
[websocketpp] https://github.com/zaphoyd/websocketpp.git​
[recastnavigation] https://github.com/EQEmu/recastnavigation.git​
Uleat
Eliminated the database connection associated with class BotDatabase
All behaviors remain the same with the exception of the calling object
To invoke a BotDatabase function, use database.botdb
rather than botdb
Noudess
Pull request #802 New min/max personal faction per faction. Use of actual client mods for race/class/deity.
This PR involves major changes to your database and server operators quests
The clients recently exposed raw data included
Min/Max personal faction for each faction
Actual faction id the client uses for each faction
Actual mods that come into play when a PC cons an opponent that determine your overall con to that faction
The approach I took resulted in minimal change to the code base. I did alter the code to enforce the new validated min/max from the client. This min/max applies to personally earned faction. So if a faction has a min of 0 and a max of 2000, that means your personally earned value can never go below 0 or over 2000. The actual con, will, however often do so because of class/race/deity modifications. I also changed the con ranges, per Mackal's data that was proven to be accurate
Faction | Value |
Ally | 1100+ |
Warmly | 750 to 1099 |
Kindly | 500 to 749 |
Amiable | 100 to 499 |
Indifferent | 0 to 99 |
Apprehensive | -1 to -100 |
Dubious | -101 to -500 |
Threateningly | -501 to -750 |
Ready to Attack | -751 |
The above means that dubious is a much smaller range now. For that reason the scripts modify any custom faction base values to put them in the same range, hopefully as the creators of the custom factions intended.
Also to be noted as characters that have a faction between -501 and -700 wont be dubious anymore, they will be threateningly. This is expected with the new ranges, but might take players by surprise as the old ranges we used were more liberal but were incorrect.
The database is changed extensively, but really only content. We're translating faction_list
to use the clients ids. As such every place a faction_is is used, namely (see below) are being converted
faction_list
faction_list_mod
npc_faction (primary_faction field only)
npc_faction_entries (faction_id field only)
faction_values
Quests will also automatically be adjusted. This MUST be done after the PR sql and before starting the server. This is automated by eqemu_server.pl (or starting world)
Be assured, custom factions that you may have created, or obsolete or duplicate factions in our original faction_list, that you may have used, will be preserved. Anything that does not map directly is being moved to the 5000 range in faction_list and any references are corrected to point there.
A great example of this is Ebon Mask and Hall of the Ebon Mask. Many PEQ DB style servers have both of these. Some have used one, some the other. We map Ebon Mask to the clients Ebon mask and the Hall of the Ebon Mask gets moved to the 5000 range, and all its references are preserved. However, if you would like to make proper use of client mobs to Ebon mask, or other factions that have duplicitous entries, I recommend you manually move to using the correct one. In that way all of the new raw data mapped in from the client into faction_list_mod will get used instead of what your db had before these values were known.
In my experience converting 4 different server's data, there are only about 20 factions moved into the 5000 range.
This PR has only 1 new, permanent table faction_base_data, which is taken right from the client. The base field is left in case you want to mod your server, but we are very sure that the client doesn't use a base. It uses global mods to race or class for this as you'll see in the new faction_list_mod
The PR makes many backup tables, and two mapping tables that are used during the conversion process to fix quests. This table was hand created by analysis. This table serves no purpose after conversion except an audit trail if we see any issues.
I will release a new PR that will clean up all these backups and temporary tables in about a month.
Uleat
Both classes will now use the same stance standard
Pushed stance types up to EQEmu::constants
Uleat
This is a server-based tool for redacting any language that an admin deems as profanity (socially unacceptable within their community)
Five options are available under this command
list
shows the current list of banned words
clears
the current list of banned words
add
adds to the banned word list
del
deletes from the banned word list
reload
forces a reload of the banned word list
All actions are immediate and a world broadcast refreshes other active zones
The system is in stand-by when the list is empty..just add a word to the list to begin censorship
Redaction only occurs on genuine occurrences of any banned word
Banned words are replaced with a series of '' characters
Compounded words are ignored to avoid issues with allowed words containing a banned substring
If 'test' is banned, 'testing' will not be banned .. it must be added separately
Extreme care should be exercised when adding words to the banned list
Quest failures and limited social interactions may alienate players if they become inhibiting
System commands are allowed to be processed before redaction occurs in the 'say' channel
A longer list requires more clock cycles to process - so, try to keep them to the most offensible occurrences
Fix for bots ceasing combat when their 'follow me' mob dies
Bots will revert to their client leash owner (bot owner or client group leader) when their FollowID() mob is no longer valid
Combat will no longer be interrupted in these cases
Does not apply to bot owner death
​
Uleat
Fixes bots not moving on spawn/grouping issue
Report any issues with non movement-related behavior
Uleat
...and added per-client restriction of spell id max
Bumped server spellbook entry capacity to 720 spells
Server keeps all 'learned' spells as found
Access is limited by the clients' limitations of spellbook capacities and max spell ids
This is done to avoid losing spells by switching from newer clients to older ones
Existing behavior is kept in place for illegal access conditions
Each client is still restricted to its spellbook capacity (400, 480, 480, 720, 720, 720 - respectively)
Each client is restricted to its max supported spell id (9999, 15999, 23000, 28000, 45000, 45000 respectively)
Please report any abnormal behavior so it may be addressed
Removed server-side checksum of player profile..wasted calculation since it's performed again in all translators
Uleat
Akkadius
[Command] Extended #goto via #goto [playername]
This will work cross zone, cross instance, in zone etc.
It works on top of the original #goto (target) and #goto x y z
[Command] Implemented server side #who
Searches can be filtered by
Account Name
Base Class Name
Guild Name
IP
Player Name
Race Name
Zone Short Name
Features a clickable (Goto) saylink that will bring you directly to a player regardless of
whether or not they are in an instance
[Command] Implemented: #gmzone [zone_short_name] [zone_version=0] [identifier=gmzone]
Zones to a private GM instance
Fix issue where NPC's clip into the world and the client interprets them at coordinates 0,0,0
This issue would show itself when NPC's would bunch up by a zone-in
Uleat
Server honors expansions that alter bank size and power source, general9 and general10 slots
Server honors gm flag behaviors for the active inventory slots of each client
Uleat
of 'World:ExpansionSettings' and 'World:UseClientBasedExpansionSettings' fields.
These fields are no longer allowed to be changed during server runtime through the command system
Major synchronization issues between server and clients result when these fields are altered in-game
It is not recommended to update these fields via sql queries while the server is in operation
Failure to observe these warnings will result in abhorant behavior and loss of items
Modify these fields during server operation at your own risk!
Akkadius
Global base scaling data has been updated in new database binary revision
Akkadius
Logging: Added new logging category MobAppearance
DevTools Proximity show of NPC now shows a "Path finding" circle around the proximity nodes to more clearly display
Scaling Global base scaling data now refreshes from the database on #repop
Commands Implemented command #killallnpcs [npc_name] for testing, leave blank for all attackable NPC's
Textures that have been changed with #wearchange / #wc or any wearchange quest script call will now stick for new clients entering a zone
Weapon models for NPCs changed using wearchange will stick as well during combat and when new clients enter the zone
The above changes allow for customization of a zone and NPC's without needing static data configured on npc_types table data and allows for much more customization options
$client->SetPrimaryWeaponOrnamentation(uint32 model_id);$client->SetSecondaryWeaponOrnamentation(uint32 model_id);
client:SetPrimaryWeaponOrnamentation(uint32 model_id);client:SetSecondaryWeaponOrnamentation(uint32 model_id);
Both of these API calls persist an ornamentation to the weapon in the inventory table and will load both in character select and cross zone
​