Nuke docs. Manual local testing just passes

This commit is contained in:
dam 2026-04-30 22:56:25 +03:00
parent 5422d0ba2d
commit 8bb1dc4e30
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB

View file

@ -1,159 +0,0 @@
# Combat Movement Rewrite Notes
This branch is intended to separate combat movement from generic interaction
movement before changing combat behavior. The immediate goal is to make the
current engine boundaries explicit, then replace the hidden coupling in small,
testable steps.
## Current Tick Order
The major update worker currently runs a tick in this order:
1. `PacketProcessor.processQueue()`
2. `GameWorld.Pulser.updateAll()`
3. `GameWorld.tickListeners`
4. `UpdateSequence.start()`
5. `UpdateSequence.run()`
6. `UpdateSequence.end()`
7. `GameWorld.pulse()`
8. `Managers.tick()`
`UpdateSequence.start()` ticks NPCs first, then players. Each entity tick runs
`scripts.preMovement()`, dispatches `TickEvent`, pulses skills, applies
`walkingQueue.update()`, runs `scripts.postMovement(...)`, processes timers, and
prepares update masks.
That means pulse code mutates movement state before the entity movement phase,
but the actual tile step is applied later by `WalkingQueue`.
## Current Combat Movement Coupling
`Properties` constructs one `CombatPulse` for every entity. `CombatPulse`
constructs a private `MovementPulse(entity, null)` during initialization and
later uses it as a pathing helper by replacing its destination in
`CombatPulse.setVictim(...)`.
During `CombatPulse.interactable()`, melee/range/magic swing handlers decide
whether the attacker can swing, should move and still interact, or cannot
interact. If movement is needed, `CombatPulse` calls the private movement
helper's `updatePath()`. That helper resets and repopulates the attacker's
`WalkingQueue`; `WalkingQueue.update()` applies the step later in the entity
tick.
NPC and player attack clicks do not go through normal approach scripts in the
common case. NPC attack interaction is registered as an instant listener, so it
starts `CombatPulse` directly.
## Known Failure Modes
- A melee attacker following a running victim responds too late and can lose
melee pressure.
- Mutual melee attackers can wait for the other actor to approach instead of
both moving to meet.
- `MovementPulse.checkAllowMovement()` contains an anti-loop rule that blocks a
mover from approaching a target that is already combat-pathing back to it.
- `MeleeSwingHandler.canSwing()` only permits moving interaction against a
moving victim when the victim is not targeting the attacker.
- Combat pathing currently reuses generic interaction movement logic, including
object/entity interaction shortcuts that are not necessarily valid combat
movement rules.
## Intended Boundary
Movement should remain an engine feature, not a `ScriptProcessor` feature.
Scripts may request actions and process content-specific results, but the
movement phase should own tile stepping, path queues, clipping, run/walk state,
and movement locks.
Combat should also remain an engine feature for targeting, swing timing, reach,
path pressure, and movement intent. Scripts should be reserved for attack
results and content effects such as damage application, sounds, graphics,
special effects, drops, and dialogue/interface side effects.
The rewrite should replace the private combat `MovementPulse` helper with a
combat movement planner that produces explicit movement intents. Those intents
should be resolved in a deterministic engine phase before `WalkingQueue` applies
steps.
## First Behavioral Targets
Pending tests live in `Server/src/test/kotlin/content/CombatMovementTests.kt`.
They are disabled until the combat movement engine exists so the main test suite
does not fail during the rewrite.
Initial targets:
- A PvP melee attacker mirrors a running victim and remains in melee reach.
- Mutual melee attackers approach instead of waiting indefinitely.
- Player versus moving NPC melee chase remains functional.
- Movement-locked attackers do not move, but may swing if already in range.
- Large target melee reach is measured against occupied border tiles.
## Suggested Implementation Sequence
1. [x] Extract a `CombatReach` utility from the swing handlers.
2. [x] Add a `CombatMovementPlanner` that can choose target border tiles and predict
one or two target movement steps from `WalkingQueue`.
3. [x] Add a combat movement intent phase that resolves step conflicts
deterministically.
4. [x] Remove the private `MovementPulse` from `CombatPulse`.
5. [x] Enable the pending tests one scenario at a time.
## Progress Log
- 2026-04-28: Extracted `CombatReach` in `core.game.node.entity.combat`.
Melee occupied-tile reach, halberd reach, generic center-distance reach,
NPC combat-distance overrides, and straight-line step validation now live
behind that utility. Existing swing handlers delegate to it, while
`MeleeSwingHandler.canMelee(...)` remains as a compatibility wrapper for
current callers. Added a focused regression in `CombatTests` for large-target
melee occupied-tile reach.
- 2026-04-28: Added a standalone `CombatMovementPlanner` that reads
`WalkingQueue` without mutating it, predicts the target's next one or two
movement locations using run state and run-disabled path points, and chooses
the closest valid border tile around the predicted occupied area. The planner
is not yet wired into `CombatPulse`; the next step is the deterministic combat
movement intent phase.
- 2026-04-29: Added `CombatMovementIntents`, an engine-side queue resolved from
`MajorUpdateWorker` after world tick listeners and before entity walking
queues update. Melee combat pulses now submit chase intents instead of using
the private generic `MovementPulse`; non-melee combat still uses the existing
path until the private movement helper is removed. Intent resolution orders
movers by entity index, paths to planner-selected border tiles, and reserves
each mover's projected occupied tiles for the current tick to keep first-step
conflicts deterministic.
- 2026-04-29: Removed the private generic `MovementPulse` from `CombatPulse`.
Combat pulses now submit combat movement intents directly whenever the swing
handler reports that the attacker cannot stand-still interact. Range and magic
still rely on their existing swing-distance checks to stop movement once they
are in range; the shared intent resolver owns the chase path.
- 2026-04-29: Enabled the first pending combat movement scenario:
`meleeAttackerShouldMirrorRunningVictimWhenRunEnabledAndKeepAttackPressure`.
The fixture now uses an open wilderness arena and explicitly enables
wilderness PvP for player versus player movement tests so combat pulses do not
stop at attackability checks before movement can be exercised.
- 2026-04-29: Enabled the remaining pending combat movement scenarios:
mutual melee approach, player versus moving melee NPC chase, movement-locked
in-range melee, and large-target occupied-tile melee reach. The focused
`content.CombatMovementTests` suite now runs all five scenarios with no
disabled tests.
- 2026-04-29: Fixed the remaining melee chase gap against running targets. A
melee attacker now submits chase pressure even while currently in melee range
if the target's queued movement would leave that range. Added a regression
covering the active pulse/intent handoff so a run-enabled player attacking a
running-away target stays adjacent after both walking queues advance.
- 2026-04-29: Fixed the live PvP run-click ordering gap. The previous pressure
check only happened inside the attacker's `CombatPulse`, so a victim's normal
map-click `MovementPulse` could be queued later in the same pulser batch; the
attacker then saw no target path and stood still while the victim's run path
was applied before walking queues advanced. `MajorUpdateWorker` now asks
`CombatMovementIntents` to collect active melee pressure after all pulses and
tick listeners, then resolves intents before entity walking queues step. Added
a regression that uses the real `WorldspaceWalk` packet path with both players
run-enabled and wielding dragon scimitars.
- 2026-04-30: Corrected combat intent movement so PvP melee chase respects the
attacker's own run state. The resolver now clamps target prediction to the
attacker's current walk/run capacity, treats zero run energy as walking, and
no longer forces `WalkingQueue.reset(true)` when the attacker has run toggled
off. If a moving target temporarily blocks an exact walking path, combat waits
for the next tick instead of stopping as unreachable.