# InstancesNoDat: casts fail with TargetNotAcquired after the master unloads under an open copy

Observed on Aelrynth 2026-09-19 with +Buffy in a personal copy of Matron Hive South (6346), running DrakBot. Evidence is the ACE journal (`journalctl -u ace.service`) and the client log; timestamps are server local.

## Timeline

| Time | Event |
|---|---|
| 17:54:01 | `Aeshnidae.InstancesNoDat` hot-reloaded (new build). Log: "closed copy 1 of 6346, contents destroyed rather than saved, 162 physics registration(s) dropped" / "closed all 1 copy(ies)". The player inside was left in the **master** (shared) hive. |
| 17:54:17 | `/inst-send`: "copy 1 of 6346 opens as variant 'tier-0' for +Buffy", "+Buffy told to forget 581 object(s) of the master", "placed in copy 1 (moved from copy 0)". She fights in the copy for four minutes. |
| 17:58:27 | Weenie reload: "3000020 Creepy Canyons: reloaded (was not cached), 0 live object(s) refreshed across 12 loaded landblock(s)". |
| 17:58:40 | `/inst-reload-settings`: "settings re-read: 14 instanced dungeon(s), 1 copy(ies) still open". |
| **17:58:41** | **Every cast from the player is refused with WeenieError 0x042C `TargetNotAcquired`** (client log: `[use-done] err=0x042C` on each cast; the server does spawn the projectile - "Shockwave added to copy 1 of 6346" - but the targeted creature is never hit). The client still lists 42 hostiles; the bot targets a Gardener at 1.4 m repeatedly. No kills from here on. |
| 17:59:16 | The **master** 6346 re-initialises: ~40 lines of "Olthoi X spawned into the MASTER of 6346; 1 copy(ies) are open and none of them has it. Authored objects reach copies on /inst reload." This is five minutes after the last player left the master (17:54:17), i.e. ACE's empty-landblock unload followed by a reload. |
| 18:04 | `/instance` from inside still says: "You are in copy 1 of Matron Hive South (6346)… Dungeon Difficulty: Tier 10 (awakenings of whoever opened it)… Variant: tier-0". |

## What it looks like

ACE raises `TargetNotAcquired` in `Player.HandleActionCastTargetedSpell` / `HandleActionCastTargetedSpell` when `CurrentLandblock.GetObject(targetGuid)` (or the `GetObjectMaybeAssign` variant) returns null. From 17:58:41 the copy's creatures were no longer resolvable for the player although they were still in her client's object table and still attacking her. The master landblock going through its unload/reload cycle right then (empty since 17:54:17) is the one thing that changed in the world, so the working theory is: **a copy's object lookup still depends on its master landblock being loaded**, and the master unloading under an open copy broke the lookup (the copy's own physics cells stayed, its `Landblock`/object resolution did not).

Things worth checking in the mod:
1. Whether `ReloadAllCopies` / the copy's `Landblock` shares state with the master (`LandblockManager.GetLandblock(... )` on the master id, object dictionaries, `CurrentLandblock` of the player after `/inst-send`).
2. Keep the master loaded while any copy of it is open (touch its `LastActiveTime` on the copy's tick, or opt it out of the empty-landblock unload), **or** make the copy fully independent of the master.
3. `/inst-reload-settings` and the weenie reload at 17:58:27-40 happened seconds before; rule them out (neither logs anything about the copy, but they are the only other events).

## Also, from the same log

- **A mod reload drops players in copies into the shared master.** Better: on reload (or any time a player's copy ceases to exist), send them to their **lifestone** rather than leaving them standing in the shared dungeon at the same spot.
- The client keeps the copy's creatures after the server stops holding them, so the bot spins on phantoms. DrakBot side is fixed (a `TargetNotAcquired` now blacklists the target instead of benching the spell), but the server should also send the player the "forget these objects" it already knows how to send (it did at 17:54:17) when a copy is torn down.

## How to reproduce

Open a personal copy of an instanced dungeon, walk out of the master into it so the master is empty, wait five minutes for the master to unload, then cast at anything in the copy.


---

## Server-side response (2026-09-19 19:13, live and staging)

- **Lifestone:** already the rule for players. `InstanceWorld.Close(..., ejectPlayers: true)`
  recalls anyone inside to their lifestone; the 17:54:01 case placed Buffy in the master
  because she is *staff* ("reload, staff stay in the master" - admins author in the master).
  For a non-staff character a closed copy means the lifestone, never the shared dungeon.
- **Forget-objects on teardown:** `PlaceIn` already sends a delete for every object of the
  block being left when moving between copies (16:56); the reload/close path for staff goes
  through the same `PlaceIn` and so also forgets. Whether the *client* honours those deletes
  for creatures it is mid-attack on is DrakBot's side.
- **Master unloading under a copy** (the theory): the master is now kept active on every
  tick a copy of it exists (`KeepMasterLoadedWhileCopiesOpen`), so the unload/reload at
  17:59:16 cannot recur while someone is inside. Note the failure began at 17:58:41, 35 s
  *before* the master reload in the server log - either client clock skew, or the theory
  is incomplete. Also possible and now guarded: the copy itself queued into ACE's
  destruction queue (`AddToDestructionQueue` is one statement and may be inlined past the
  prefix); `PurgeDestructionQueue` takes copies back out after every tick.
- **Diagnostic:** `Landblock.GetObject` returning null inside a copy for a dynamic guid now
  logs, once a minute per guid: in master? in another copy? in the physics registry (and
  which cell)? how many objects the copy holds. The next occurrence will say what happened.
- Ruled out by reading: `inst-reload-settings` (17:58:40) rebuilds only the settings map;
  nothing in routing keys on it. The weenie reload (17:58:27) touched 0 live objects.

## 19:37-19:42 - the mechanism, caught

`inst-send Buffy` at 19:37:28 (another session) -> audit at 19:37:40 and 19:37:55:
"AUDIT +Buffy: cell 0x63460260 - physically in the master, listed in copy 1 <-- MISMATCH".
That is the fault: PlaceIn's in-place physics move left her PhysicsObj in the master's
cells while listing her in the copy, so her client's visible set was the master's
creatures and every cast at them failed on the copy's GetObject. At 19:41:56 the new
console `inst-tele <player> <landblock>` (a real ThreadSafeTeleport to the hub door's
landing spot; the routing hands out the copy like a portal would) put her in cleanly:
no mismatch, and the LOOKUP MISS diagnostic fired only for the two master creatures her
client still remembered from before the move. Suspect: `InstanceWorld.PlaceIn` (the
RemoveWorldObjectForPhysics / AddWorldObject / in-place teleport sequence) - not the
master unloading. Use inst-tele, not inst-send, until PlaceIn is fixed.

The 19:31 restart: the world log went silent for 15 min after a 19:13 inst-send (no
kills, no audit lines, copy gone by 19:30 without a close line) and the server was
restarted on suspicion of a stuck world thread. Unproven; the same 19:13 build is live
again since 19:41 (with inst-tele) and behaving.

## 20:16 - the lifestone rule, for staff too

`RecallWhenCopyIsLost` (on): a mod reload now ejects everyone inside a copy to their
lifestone, staff included, and anything still standing in an instanced landblock when the
new assembly starts is recalled too. Nobody is placed in the shared master or handed a copy
in place any more - both of which were the paths that left physics behind.

## 2026-09-20 00:20-01:15 - ghost monsters

Reports of "hundreds of ghost monsters" in copies: creatures the client draws (blank
appraisal - Value ???, Burden Unknown; casts and attacks fail; the player can get stuck
inside one, since the client collides with what it draws) that the server has nowhere.
LOOKUP MISS lines showed two kinds: the master's monsters, learned while the player's
physics passed through the master's cells on the way into a copy; and objects that exist
nowhere - dead creatures whose delete never reached the client.

In place now (InstancesNoDat):
- `KeepMasterLoadedWhileCopiesOpen` off (it kept 600 master monsters loaded to be seen).
- Arrival in a copy from outside: the client is told to forget every object of the master
  (`ForgetMaster`), immediately and again after 1.5 s and 3 s.
- A listed-here-physics-elsewhere mismatch is re-filed on the next position update
  (`ReenterPhysics`), both directions; before a physics rebuild the client's whole object
  table is wiped (`ForgetEverythingKnown`), because a new physics object cannot delete what
  the old one had sent.
- Every destroy inside a copy sends a delete to every player listed in that copy, before
  ACE's own tracking-based broadcast (`PreDestroy`), with a trace line per creature.
- The 15-second audit sweeps each player's known-object set against the block they are
  listed in: anything elsewhere or destroyed is deleted on the client (`SweepGhosts`,
  `DeleteByGuid` for objects that no longer exist).
- Console `inst-refresh <player>`: wipe and re-send; `inst-tele <player> <landblock>`.
- Recall with no lifestone goes to Holtburg square (Buffy landed in the Academy).

01:14-01:15 after a client restart and inst-tele: every kill's delete "sent to 1 player;
it knew 1 player itself"; no ghosts seen. The master hive shows creatures in mixed states
(listed in master, physics in a closed copy) - untouched, players never land there.

## 01:20-01:40 - the ghosts, understood

They were a fixed set, present on coming BACK into the dungeon after a short trip, never
accumulating, immune to every server-side delete, gone on a client restart. Mechanism:
the server's record of what a client has been shown lives on the player's physics
object, which is rebuilt on every teleport; the client, for a short trip, keeps the
landblock and every object in it. So on return the server thinks the client knows
nothing, sends the new copy, and never deletes the previous copy's creatures - which
died or were destroyed with the copy while nobody was there to be told. Solid,
unhittable, blank appraisal.

Fix: `ClientTable` - the mod records every guid a CreateObject goes out for, per client,
with the instance sequence it carried, and drops it on RemoveTrackedObject / logout. On
every arrival in a copy, anything recorded and not in that copy is deleted on the client
by that sequence (`DeleteByGuid(guid, seq)`), which is the delete the client honours.
Also part of `inst-refresh`. Belt and braces kept: TrackObject gate (a player in a copy is
never sent an object not in it), ObjectMaint gates, deletes on every destroy in a copy,
master forgotten on arrival x3, the 15 s sweep (tracking only, no sequence-less deletes).

01:37-01:40: 124 kills in copy 1 by smite, no ghosts. Round trip not yet exercised.

## 2026-09-20 12:55-13:45 - the second player in gets ghosts; still open

Five characters of one tester into Creepy Canyons, each from the hub, each its own
copy: the first clean, every later one with LOOKUP MISS storms (~1,900 in 40 min) for
objects that exist NOWHERE (not master, not any copy, not the registry), never logged
as added to or destroyed in any copy. Found and fixed on the way: an arrival from the
hub read as "from copy 1" (the hub is copy 1 of another landblock) and skipped the
master-forgets - now every arrival from a different landblock forgets the master and
purges the client table, immediately and at 1.5 s and 3 s (log confirms 66 objects x3
per arrival). The misses continued after that fix, so the master's monsters were not
the whole cause.

Instrumentation live 13:42: every LOOKUP MISS now names, per player in that copy, how
the client came to hold the guid - "HH:MM:SS <name> in <where> while the player was
listed in <copy/master>, physics cell <id>" - or "never sent by TrackObject" (which would
mean the client got it by a broadcast, not a create). Next tester pass answers it.

Suspects, in order: (1) the player's physics passing through the MASTER's cells during
the teleport (ACE resolves the destination cell with no ambient -> LScape's global
landblock = the master) and learning objects there that are then created/destroyed in
the master over time; (2) guid recycling - the client holding a guid from a destroyed
object and ignoring the later create/delete for its reuse; (3) something sending
creates for copy objects to the wrong copy's player (both TrackObject and ObjectMaint
are gated by landblock, so this would need a null CurrentLandblock at send time).

## 14:02 - two structural changes, not diagnostics

1. ACE's own `teleport_visibility_fix` server property set to 3 (was 0): on every
   teleport the server deletes every object the client knows before the new place is
   sent. ACE added it for exactly this class of client bug ("a DO and then a CO is the
   only thing that fixes this"). Whatever a client carries across a teleport - a closed
   copy, the master, another copy - is gone on arrival, by sequence, by the server that
   sent it. Live and staging (modifylong; persisted in the shard db).
2. `Player.Teleport` now runs with the destination COPY as the ambient (PreTeleport
   sets it once the routing has a copy, a finalizer restores). Teleport resolves the
   landing cell through LScape, which with no ambient is the master's physics
   landblock; so every entrant's physics landed in the master's cells first, saw its
   monsters, and was re-filed into the copy afterwards. Now it lands in the copy's cells
   and the master is neither loaded nor seen on the way in.
