ModernUO/Projects/UOContent/Misc
Kamron Batman a2c232f4a8
fix: Removes side effects from locked down items, decaying houses, bracelet of binding, and builds (#2608)
## Why

Delta world saves (only changed entities re-serialized during the freeze) need two things from content: `Serialize` must be pure, and an unchanged entity must produce identical bytes on every save. An audit of the tree found the places that break this today. This PR fixes them and adds a diagnostic that measures byte stability in a running world over real time. No wire format changes, no version bumps.

## What

- **Guild**: `Serialize` ran the daily guildmaster recalculation (dictionary-order tie breaks, random picks, mutates another entity), war expiry, and the alliance leadership check on every save. That work now runs from `GuildMaintenanceTimer` (the former `WarTimer`, now started for both guild systems; the war and alliance checks are no-ops without the new guild system).
- **BaseHouse**: the `DecayLevel` getter wrote `LastRefreshed` and advanced the dynamic decay stage on every read, so any undecayable house changed its persisted bytes whenever a sign, gump, or `[Props` looked at it. It is now a pure read; `UpdateDecay()` on the decay tick advances the stage and refreshes a house that leaves the undecayable state.
- **Locked-down container contents decay through `DecayScheduler`** instead of a sweep inside `BaseHouse.Serialize`. `Item.CanDecay` now accepts a parent container whose new `Container.ContentsDecay` is true (locked down and not secure) when the content item is not itself locked down or secured; the `IsLockedDown`/`IsSecure` setters re-evaluate a container and its direct contents; `OnDecay` resolves the region from the world location. `BaseBoard`, `Aquarium` and `FishBowl` override `ContentsDecay` to false, matching the exclusions of the old sweep. Items already inside such containers are picked up at load, where every item re-evaluates its registration. The per-save O(all locked-down items) walk is gone; the work is now event driven.
- **BraceletOfBinding**: the `Bound` getter nulled its backing field for a deleted target; it now returns null for a missing or deleted target without writing.
- **`[SaveStability [delaySeconds=60] [sampleStride=1]`** (Administrator): hashes the serialized bytes of every entity in every registered entity persistence (`Persistence.EntityPersistences`, new), waits the delay in real time, hashes again, and reports per type how many records changed. Both passes are chunked under a 20 ms per-tick budget. Serializing twice inside one tick cannot see drift derived from `Core.Now`, which is frozen within a tick; the real-time wait is the point. On an idle shard the only legitimate churn is NPC movement and regeneration, so a static type with a high changed fraction is a serialization bug. `[SaveStability cancel` stops a run.

Engine additions: `Container.ContentsDecay` / `UpdateContentsDecayRegistration()`, the `CanDecay`/`OnDecay` change above, and diagnostic-facing `IGenericEntityPersistence.Name`, `EntityCount`, `EnumerateEntities()`, and `Persistence.EntityPersistences`.

## Behaviour notes

- Fealty recalculation now happens on the minute timer for both guild systems instead of at save time.
- A house that becomes decayable is refreshed on its next decay tick rather than at the exact moment of transition (at most one minute later).
- Contents of locked-down containers now decay on their own schedule (same `LastMoved + DecayTime` rule) instead of at the next world save after becoming due.

## Testing

- New tests: `GuildSerializePurityTests`, `HouseDecayPurityTests`, `SaveStabilityTests` (stable entities hash identically after the clock advances; a clock-stamped record is reported by type only after the clock advances; the snapshot covers Items, Mobiles and Guilds).
- `LockedDownContainerDecayTests` (Server.Tests): registration on drop, lock/secure/release transitions, excluded containers, nested containers, and decay on schedule through the scheduler.
- Full suites: Server.Tests 855 passed, UOContent.Tests 765 passed.
2026-09-06 09:39:00 -07:00
..
AccountPrompt.cs fix: Fixes console clobbering when prompted to add an owner account (#2133) 2025-02-26 18:43:20 -08:00
Animations.cs fix: Moves many EventSinks out of core. (#1783) 2024-05-21 10:02:30 -07:00
AOS.cs fix(ci): run test projects on CI; remove brittle OPL attribute tests (#2513) 2026-07-02 22:35:37 -07:00
AttackMessage.cs perf(messages): mechanical interpolation cleanups (#2436) 2026-05-03 18:26:49 -07:00
AutoRestart.cs fix: Fixes missing methods. Adds more admin gump world building (#1675) 2024-02-10 20:31:25 -08:00
Broadcasts.cs Fixes exiting/crash handling/ctrl+c (#237) 2020-09-12 00:05:38 -07:00
Cleanup.cs fix: Fixes structured logging (#1043) 2022-06-05 01:00:22 -07:00
ClientVerification.cs feat: Add zero-alloc interpolation handler to ValueStringBuilder, replace all StringBuilder usage (#2387) 2026-03-22 14:23:44 -07:00
CrashGuard.cs chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
DispellableAttribute.cs Formats UO Content (#201) 2020-08-27 18:30:38 -07:00
DispellableFieldAttribute.cs Formats UO Content (#201) 2020-08-27 18:30:38 -07:00
DoorGenerator.cs feat: Adds wall z-offset detection for doorgen (#2025) 2024-12-17 10:40:02 -08:00
Email.cs fix: Fixes spawn entry deserialization (#1693) 2024-03-03 08:45:16 -08:00
Emitter.cs Fixes brace style (#248) 2020-09-13 21:49:46 -07:00
FoodDecay.cs feat: Moves TcpServer to another thread. Rewrites Firewall (#1660) 2024-01-20 14:25:12 -08:00
Geometry.cs chore: Cleans up pattern checks. (#892) 2021-12-24 15:53:59 -08:00
Guild.cs fix: Removes side effects from locked down items, decaying houses, bracelet of binding, and builds (#2608) 2026-09-06 09:39:00 -07:00
HardwareInfo.cs fix: Fixes thread guard and cleans up incoming packet reader (#1641) 2023-12-19 17:04:09 -08:00
InhumanSpeech.cs feat: Replaces params array with params ReadOnlySpan (#2125) 2025-02-13 21:19:02 -08:00
Keywords.cs feat: T2A ping-pong mechanic and consider sins behaviour (#2356) 2026-03-10 23:10:27 -07:00
LanguageStatistics.cs fix: Adds command help, webpage, and fixes issues with other commands (#1669) 2024-02-10 00:19:19 -08:00
LightCycle.cs fix: Fixes buffs don't start/stop properly. Streamlines constructor and Add/Remove buffs. (#2082) 2025-01-24 18:20:23 -08:00
LoginStats.cs feat: Converts OnLogin to a coded generated event (#2070) 2025-01-17 15:21:45 -08:00
Loot.cs feat(throwing): wire SA loot flavor + Valkyrie's Glaive stealable (#2512) 2026-07-02 22:28:55 -07:00
LootPack.cs feat(throwing): wire SA loot flavor + Valkyrie's Glaive stealable (#2512) 2026-07-02 22:28:55 -07:00
MondainsLegacy.cs fix: Consolidates Color/Center html (#1762) 2024-05-07 23:56:32 -07:00
NameList.cs fix: Cleans up murder system (#1428) 2023-07-16 00:04:30 -07:00
NameVerification.cs fix: Fixes detecting consecutive exceptions in name validation (#2192) 2025-05-18 21:02:05 -07:00
Notoriety.cs fix: Eliminates double lookup with Contains->Remove (#2539) 2026-07-19 09:26:27 -07:00
PacketThrottles.cs chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
Paperdoll.cs fix(core): Converts remaining player packets (#374) 2020-12-30 16:09:51 -08:00
Poison.cs feat: Refactor Poison system, implement Darkglow & Parasitic effects (#2385) 2026-03-21 21:27:22 -07:00
PoisonKinds.cs feat: Refactor Poison system, implement Darkglow & Parasitic effects (#2385) 2026-03-21 21:27:22 -07:00
ProfanityProtection.cs fix: Fixes and optimizes NameVerification and ProfanityProtection (#2153) 2025-04-12 02:26:10 -07:00
ProfessionInfo.cs feat: Moves network related events to UOContent using code generation (#1945) 2024-09-06 16:57:10 -07:00
Profile.cs fix: Moves many EventSinks out of core. (#1783) 2024-05-21 10:02:30 -07:00
RaceDefinitions.cs fix: Updates races to properly support gargoyle equipment. (#744) 2021-08-29 00:43:55 -07:00
RegenRates.cs fix: Fixes poison field duration, cleans up skill calculations and poison calculations (#1582) 2023-11-04 12:32:54 -07:00
RenameRequests.cs fix: Fixes and optimizes NameVerification and ProfanityProtection (#2153) 2025-04-12 02:26:10 -07:00
ResourceInfo.cs fix: Codegens BOD rewards. (#1361) 2023-03-06 19:01:14 -08:00
ServerAccess.cs fix: Reverts GetAccount to use IAccount. Adds IAccount to serialization. (#1565) 2023-10-25 19:17:57 -07:00
ServerList.cs feat: Upgrades networking to use io_uring. (#2315) 2026-02-01 16:02:32 -08:00
ShardPoller.cs refactor: fold hand-written serializable property setters into field hooks (#2587) 2026-08-22 18:20:39 -07:00
ShrinkTable.cs chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
StaffInfo.cs fix: Codegens gifts. Unifies staff names. Thank you to the community! (#1766) 2024-05-08 20:44:00 -07:00
StaminaSystem.cs fix: Removes unnecessary dictionary removal guards (#2565) 2026-08-08 11:50:01 -07:00
Titles.cs feat: Adjusts fame and karma system with era gates for OSI accuracy (#2389) 2026-04-25 11:19:57 -07:00
ToggleItem.cs fix: Codegens house/vendors (#1767) 2024-05-08 22:45:59 -07:00
TreasureMapProtection.cs chore: Use var everywhere (#2294) 2025-12-27 16:47:28 -08:00
ValidationQueue.cs Fixes brace style (#248) 2020-09-13 21:49:46 -07:00
Weather.cs fix: Moves containers/bods/traps/etc to serialization generator (#2310) 2026-01-07 21:55:55 -08:00
WelcomeTimer.cs Removes UOAM vendors. (#241) 2020-09-12 11:56:52 -07:00