Also supports reducing lockout duration
Add Expedition::AddLockoutDuration
Add Client::AddExpeditionLockoutDuration
Some expeditions require adding to existing lockout durations
during progression. These add the specified seconds to individual
member lockout timers instead of setting a static duration based on
internal expedition lockout like UpdateLockoutDuration.
Add Group and Raid method DoesAnyMemberHaveExpeditionLockout
This is required by some expeditions that perform a manual check for
custom dialogue (Ikkinz group expeditions)
This implements the new behavior from live's September 16, 2020
(test server's September 8, 2020) patch
Expeditions can be created even when the client's group or raid
exceeds the expedition's max player requirement. Members are added
until the max player count is reached and the rest are ignored.
Raid members are added ordered by their raid group number with
ungrouped members having the lowest priority
Rename expedition request method ValidateMembers to CanMembersJoin
Change some expedition messages to System color (live changes)
On live, new expedition leaders are only notified if made leader from
the /dzmakeleader command (or from ui). This rule makes it so the new
leader is always messaged on a leader change for cases where previous
leader goes offline or quits
Only choose an online member as new leader on leader changes
Keep leader online status updated in zone expedition caches
Currently this will also trigger a leader change if the leader goes
linkdead. On live the character retains leadership while linkdead
and a new one is only chosen once kicked offline
Remove logging unsanitized input
Make unsigned comparison not compare < 0
Cleanup some FormatName and string usage. Some of these strings could
probably be moved instead
Remove unnecessary expedition lookup in a world message handler
Add static expedition methods to add or remove character lockouts
Add CreateLockout static helper to ExpeditionLockoutTimer
Refactor existing character lockout removal to allow removal of lockouts
for offline characters (was only used by #dz lockouts remove command)
Fix #dz list member count
Remove extra cross zone message server opcode and struct. Existing
function already exists for normal messages
Group CZClientMessageString struct with other CZ structs
Some live expeditions update a lockout's duration during progression
The current AddLockout method replaces lockout timers. This updates the
expiration of an existing lockout by modifying the original duration
Only members are updated and not the internal expedition timer by
default. This is so new members receive the original duration like live
Add SetLootEventByNPCTypeID and SetLootEventBySpawnID quest apis
These associate events with npcs or entities inside the dz to prevent
them from being looted by characters that didn't receive the event
lockout from the current expedition.
This fixes an exploit that allowed a player that already had a lockout
from another expedition being added to loot after the event is complete
Instead of allowing all previous members to bypass a replay timer
conflict, only allow if expedition uuid of the lockout matches
This fixes an exploit for expeditions that add delayed replay timers.
Members could be part of an expedition on creation and then quit to form
another expedition. They could then always be re-invited to the original
expedition even with a conflicting replay timer lockout.
Breaking change to the current API
has_replay_timer column removed from expedition_details table
This argument is unnecessary and just creates confusion. Expedition
replay timers use a hardcoded name precisely for this purpose and
those lockouts are already being checked on creation requests.
Ignore expired state of replay timers when assigning to new members
This fixes a regression from a previous change that stopped assigning
expired lockouts to new members. Only expired event timers should be
ignored for new members. Replay Timers should always be added with a
a fresh lockout
Live requires characters that quit an expedition to zone out before
being re-added. This is probably to avoid exploiting max player
requirements by constantly swapping players in and out
Delete pending lockouts of members on expedition creation
Delete pending lockouts when all members removed from expedition
This fixes an edge case where members could incorrectly be assigned
pending lockouts that were never cleared from the database (from a
server crash or other situation) after entering another dz.
This optimizes character status requests by only sending a single
bulk request to world for characters in all expeditions instead of
sending a separate request for each expedition on zone startup
This optimizes caching all expeditions by loading dynamic zone data and
expedition members in bulk instead of for each expedition separately.
This reduces the number of queries from 1+2n to 3 total.
Expedition members are now joined in the initial query since empty
expeditions aren't cached anyway. Optional internal lockouts for all
cached expeditions are loaded in a single bulk query afterwards.
Dynamic Zone data is also loaded as a single bulk query afterwards to
simplify processing and keep dz database logic separated. It might be
worth investigating if joining dz data in the initial expeditions load
query is worth refactoring for.
This fixes an edge case with client invites sometimes failing because
an expired lockout hasn't been removed from client yet
Clients no longer receive expired lockouts from expeditions when joining
Since world now tracks empty expeditions it can determine when to
shutdown dynamic zone instances when the rule is enabled rather than
letting zones do it.
Zones are no longer able to delete expeditions. World now tracks empty
expeditions in cache and only deletes them when it detects an
expedition's dynamic zone instance has no more clients inside.
This fixes an exploit where lockouts couldn't be applied to expeditions
after all members were removed because zones were deleting the expedition
immediately. Clients still inside the dz were able to complete events
before being kicked from the instance while not having an expedition.
Expeditions are no longer purged from database in the world purge
instance timer to avoid a possible race with this new system
This implements a small cache in world to track expedition states.
This fixes expired expeditions being left in zone caches unless the
expedition's dz instance was running to detect it (or unless an
expedition was deleted via a client using /kickplayers). This was also
leaving clients in a ghost expedition that no longer actually existed
Not all expeditions with a replay timer lockout add it to newly
added members automatically
This adds the Expedition::SetReplayLockoutOnMemberJoin(bool) method
to the quest api so it can be disabled
Checking the cache on member removal here isn't reliable due to race
with cross zone message
If a zone removes a member at the same time as another zone, neither zone
can know if the expedition will be empty via cache unless it processes the
world message from the other zone's member removal first.
Clears client expedition info immediately if removed inside dynamic zone
Live clears expedition info from clients removed inside a dz on the same
timer used for removals, even if the client zones before it triggers.
This is problematic to mimic and not worth the effort
Compass updates get data from the expedition cache so it needs to be
cached first.
Currently this doesn't affect anything because compass isn't sent to
CreateExpedition and has to be set post-creation. In the future this
will make the order of client messages more live accurate though