Files
link/tools/scaffolding/BridgeSweepProbe.cs
colby afc97c414e Phase 3: polled sweeps (vitals, house decay, economy)
BridgeSweeps runs three repeating Core-thread timers for the state that has no
EventSink. Cost measured in Phase 1 is why they can run on the main thread: a
full pass of all three is well under a millisecond at the seeded scale.

  - Vitals: online players only. Small and volatile; the sidecar diffs snapshots.
    Offline characters do not move, so they are served on demand as full profiles
    instead, not swept.
  - House decay: emits only on a level transition. A silent baseline on
    ServerStarted records every house's current stage, so a restart does not
    re-announce them. Payload carries from/to, coords, nested ban location,
    region, sign name, owner serial+account, and built/refreshed timestamps, all
    null-guarded.
  - Economy supply: periodic sum of every account's currency as a snapshot. The
    level; AccountGoldChange and the vendor events are the flow.

All three re-arm on `[bridge reload`; `[bridge sweepnow` runs one of each on
demand; `[bridge status` reports sweep counters. Sweeps skip emitting while the
sidecar is disconnected, since their state is perishable and re-emitted next
tick anyway (unlike events, which queue through an outage).

Verified on the seeded world with 8s intervals: baseline recorded 29 houses
silently, a probe bumped one Somewhat->Fairly, and the next sweep emitted exactly
one house.decay and none for the other 28. Economy emitted a supply snapshot per
interval. Vitals emitted nothing, correctly, since all seeded characters are
offline. Evidence in docs/PLAN.md §13.

Adds tools/scaffolding/BridgeSweepProbe.cs (never deployed) to force a decay
transition on demand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:59:21 -05:00

71 lines
2.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using Server.Multis;
namespace Server.Custom
{
/// <summary>
/// Forces a house-decay transition so the decay sweep's transition detection can be
/// observed without waiting out a real 1224 h IDOC stage.
///
/// After the bridge takes its silent baseline on ServerStarted, this bumps one condemned
/// seeded house one stage further with SetDynamicDecay. The next decay sweep should see the
/// level change and emit exactly one house.decay.
///
/// Test scaffolding. Never deployed. Only meaningful against the seeded world.
/// </summary>
public static class BridgeSweepProbe
{
public static void Initialize()
{
if (Config.Get("Bridge.SweepProbeOnStart", false))
EventSink.ServerStarted += () => Timer.DelayCall(TimeSpan.FromSeconds(6.0), Run);
}
private static void Run()
{
try
{
BaseHouse target = null;
DecayLevel current = DecayLevel.Ageless;
// Find a house already decaying (not Ageless/LikeNew), so a bump is a real move.
foreach (var h in BaseHouse.AllHouses)
{
if (h == null || h.Deleted)
continue;
var lvl = h.DecayLevel;
if (lvl == DecayLevel.Greatly || lvl == DecayLevel.Fairly || lvl == DecayLevel.Somewhat)
{
target = h;
current = lvl;
break;
}
}
if (target == null)
{
Console.WriteLine("[SweepProbe] no decaying house found to bump");
return;
}
var next = current + 1; // e.g. Somewhat -> Fairly -> Greatly -> IDOC
Console.WriteLine("[SweepProbe] bumping house 0x{0:X} from {1} to {2}",
target.Serial.Value, current, next);
target.SetDynamicDecay(next);
Console.WriteLine("[SweepProbe] done; the next decay sweep should emit house.decay");
}
catch (Exception ex)
{
Console.WriteLine("[SweepProbe] FAILED: " + ex);
}
}
}
}