P35.9#8
Merged
Merged
Conversation
LogoutPlayer() ran inside a TransactionScope with no exception handling: on any DB failure the method exited without calling Disconnect/OnStopped, leaving _isInLogout=true with no recovery path and the character marked online permanently in the database. - Wrap LogoutPlayer() in try/catch/finally so Disconnect() and OnStopped() always execute; catch block ensures in-memory state (RemoveFromZone, SetSession) is cleaned up even when the transaction is rolled back. - Remove LogoutRequest(false) from Disconnect() — it incorrectly created a new logout timer after logout had already completed (timer was cleared before Task.Run). OnDisconnected already starts the timer for raw TCP disconnections. - Guard OnDisconnected against creating a logout timer when _isInLogout is already true to prevent a spurious second timer during session teardown. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NPCs that carry a Remote Armor Repairer or Energy Transferer now switch into a dedicated SupportAI state when any non-hostile NPC drops below 75% armor or energy. The most-needy ally (lowest %) is prioritized; the support NPC paths into module range with combat-style A* pathing, acquires a primary lock on the friend, and ticks support module activators that bypass the visibility set (same-faction friends are not visibility-tracked) by checking LOS directly through the zone. While in SupportAI, the NPC ignores enemies — combat module activators do not run and combat locks are dropped on Enter. AggressorAI's existing ShouldFlee branch still wins, so support NPCs flee to safety when their own armor or core gets low. AggressorAI re-acquires combat locks naturally on resume via CombatAI.UpdateHostiles after SupportAI pops. Friend discovery combines flock members with visible non-hostile SmartCreatures, covering both same-faction allies (Niani+Niani) and cross-faction allies (Niani+Cultist, both non-Syndicate per Npc.IsHostile). NPCs without remote support modules short-circuit on IsSupportCapable, so existing behavior is unchanged for them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three issues surfaced during in-zone testing:
1) Support modules fired on enemies during combat. CombatAI.Enter built
a ModuleActivator for every equipped module — the standard Visit
methods for RemoteArmorRepair/EnergyTransferer pick whatever is
locked, which in combat is the enemy. Filter both module types out
of CombatAI's activator list; SupportAI owns them.
2) NullReferenceException at the movement-start path and bot failing
to follow its lock target. Two compounding bugs:
- FindSupportPosition (worker thread) wrote `smartCreature.StopMoving()`
and `movement = null` directly to instance fields. When a second
worker started while the first's continuation had just populated
`nextMovement`, the AI tick could read the swapped pending
movement, then have it nulled by the worker before .Start ran.
- The repath trigger used `movement == null` so the AI tick
re-issued (and cancelled) the path search every frame until a
path materialized, which it never did.
Mirror CombatAI's trigger condition (target moved or periodic
timer), gate it with a pathPending flag like FleeAI uses, drop the
cross-thread mutations, add a defensive null check on the
Interlocked.Exchange result, and wrap FindSupportPosition in a
try/catch so worker exceptions don't fault the task.
3) Bot ran both repair and energy transfer regardless of need. Split
activators into repair/transfer lists and only tick the kind whose
corresponding stat on the current target is actually below the
support threshold.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
clouths
approved these changes
May 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.