ModernUO/Projects/UOContent
Kamron Batman 114dbba6e2
fix: a stop order silently cancelled a standing follow order (#2616)
## The bug

Pet is set to follow. It gets attacked and defends itself (the order flips to `Attack`), or the player tells it to `come`. The player then says `stop`. The pet quietly stops following and starts idle-wandering — the player has to re-issue the order to get it back.

`ResolveStop` clears `ControlTarget`, since the transient order that is ending owns it, and then resumes the standing order. Nothing restores a target, so the resumed `Follow` has none. `DoOrderFollow` checks for a target before anything else, finds none on the very next think, says "I have no one to follow" and cancels the order to `None`:

```
follow standing        order=Follow  target=set  persist=Follow  cur=0.2 => move=0.3
attacked (defends)     order=Attack  target=set  persist=Follow  cur=0.2 => move=0.3
stop issued            order=Follow  target=null persist=Follow  cur=0.2 => move=0.3
  next think           order=None    target=null persist=Follow  cur=0.4 => move=0.9
```

Two things go wrong at once:

- `PersistentOrder` still reads `Follow` while `ControlOrder` is `None`, so the pet never recovers on its own.
- The pace falls from the active clock to the passive one. A shard that tunes `SetMoveSpeed(active, passive)` sees a following pet drop from its active move speed to its passive one for no visible reason — which is how this surfaced.

Era-independent. Guard is unaffected: `DoOrderGuard` works off `ControlMaster`, not `ControlTarget`.

## The fix

A standing `Follow` does not always mean "follow the master" — a pet friend can point it elsewhere with `all follow me` / `*follow me` (0x163, 0x16C) or `*follow` plus a target pick. So `SetPersistentOrder` remembers the target the standing order was given, and `ResumePersistentOrder` restores it, falling back to the master only when that target is gone. The field is runtime-only, like `PersistentOrder` itself.

Doing this in `ResumePersistentOrder` rather than `ResolveStop` also covers the Friend/Unfriend/Transfer resumes, where `ControlTarget` points at a third party and the pet would otherwise have resumed its follow on *them*. It matches what `HandleInvalidControlTarget` already does before its own resume.

## Tests

`Stop_WhileAttacking_FallsBackToPersistentFollow` already existed and passed, because it asserted the resumed order without checking for a target or driving a think tick. Three tests added alongside it:

- `Stop_WhileAttacking_ResumedFollowTargetsTheMaster`
- `Stop_WhileAttacking_ResumedFollowKeepsAPetFriendAsItsTarget` — a friend's follow order is not hijacked back to the owner
- `Stop_WhileAttacking_ResumedFollowSurvivesTheNextThink` — the one that catches the cancellation

Each was confirmed to fail without the change (`Expected: Follow, Actual: None`; wrong target). Full suites green: 782 UOContent, 869 Server.
2026-09-07 08:51:10 -07:00
..
Accounting perf(login): run password hashing on a parked worker thread (#2566) 2026-08-09 00:13:34 -07:00
Assistants chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
Commands fix: Removes side effects from locked down items, decaying houses, bracelet of binding, and builds (#2608) 2026-09-06 09:39:00 -07:00
Compression feat: Implements new robust/pluggable backup/archive system. (#2388) 2026-03-22 19:51:20 -07:00
Configuration fix: Streamlines insurance. Insurance only executes when enabled. (#2550) 2026-07-26 09:47:49 -07:00
Console
Context Menus fix: Moves ContextMenu out of core, streamlines code, fixes bugs (#1873) 2024-07-20 21:33:23 -07:00
Engines fix: OPL revision hash collided on reordered and repeated properties (#2615) 2026-09-06 21:32:12 -07:00
Gumps fix: harden idle-sleep scheduling against bad config and misattributed saves (#2567) 2026-08-09 22:05:18 -07:00
Holiday Stuff perf: Migrate Veteran Reward gumps to DynamicGump/StaticGump (#2415) 2026-04-25 20:09:27 -07:00
Items fix: pet release never finished, summon master follows the pet, horse breeder and notoriety guards (#2613) 2026-09-06 16:12:29 -07:00
Migrations refactor: Changes BaseCreature to the SerializationGenerator (delta save requirement) (#2611) 2026-09-06 14:11:51 -07:00
Misc fix: pet release never finished, summon master follows the pet, horse breeder and notoriety guards (#2613) 2026-09-06 16:12:29 -07:00
Mobiles fix: a stop order silently cancelled a standing follow order (#2616) 2026-09-07 08:51:10 -07:00
Multis fix: Removes side effects from locked down items, decaying houses, bracelet of binding, and builds (#2608) 2026-09-06 09:39:00 -07:00
Network fix: Fixes tick count wrap-around in movement throttle, and eliminates more allocations in NetState (#2603) 2026-09-01 20:25:20 -07:00
Regions fix(regions): correct end Z coordinate assignment in InitRectangles (#2597) 2026-08-27 06:51:42 -07:00
Skills refactor: Changes BaseCreature to the SerializationGenerator (delta save requirement) (#2611) 2026-09-06 14:11:51 -07:00
Special Systems feat: Add zero-alloc interpolation handler to ValueStringBuilder, replace all StringBuilder usage (#2387) 2026-03-22 14:23:44 -07:00
Spells refactor: Changes BaseCreature to the SerializationGenerator (delta save requirement) (#2611) 2026-09-06 14:11:51 -07:00
Systems/JailSystem fix: pet release never finished, summon master follows the pet, horse breeder and notoriety guards (#2613) 2026-09-06 16:12:29 -07:00
Targets chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
Text fix: Bumps deps. Updates copyrights (#2353) 2026-03-05 19:36:54 -08:00
Utilities perf(login): run password hashing on a parked worker thread (#2566) 2026-08-09 00:13:34 -07:00
World Saves perf(messages): mechanical interpolation cleanups (#2436) 2026-05-03 18:26:49 -07:00
Module.cs
UOContent.csproj fix: Fixes dirty-tracking gaps in generated content: setters, sub-object owners, BaseVendor (#2609) 2026-09-06 09:43:44 -07:00