feat(bridge): ZLevels Remastered in hello (PLAN_REDESIGNS §14.3.6)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -2m7s

Stage 7 of the §14.3 integration plan (D374): hello's integrations gains
zLevels { loaded, version }, sent again when ZLevels loads or unloads,
and rg.world prints zLevels=. No level is read or sent; its XP boosts
are permissions a run already lends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-15 18:27:54 -05:00
parent 92915f7de6
commit 454ce53937
2 changed files with 30 additions and 5 deletions

View File

@@ -77,7 +77,8 @@ namespace Oxide.Plugins
/// <c>integrations.dangerousTreasures</c>; and Guarded Crate (§20.9, PLAN_REDESIGNS.md
/// §14.3.5): <c>gc.started</c>, <c>gc.ended</c> and <c>gc.failed</c>, <c>gc.place</c>,
/// <c>map.live</c>'s <c>guarded</c> rows, the tally's <c>guardedWon</c> and
/// <c>integrations.guardedCrate</c> with NpcSpawn beside it.
/// <c>integrations.guardedCrate</c> with NpcSpawn beside it; and ZLevels Remastered
/// (§20.10, PLAN_REDESIGNS.md §14.3.6): <c>integrations.zLevels</c>, and nothing more.
/// </para>
/// </summary>
private const int ProtocolVersion = 14;
@@ -5214,8 +5215,9 @@ namespace Oxide.Plugins
// Economics too: hello carries its starting balance, which the richest column needs;
// and Backpacks, whose sizes are what a Bigger backpack step offers; and TruePVE, which a
// zone step's PvP rules are refused without (§14.3.2); and Dynamic PVP (§14.3.3).
// Guarded Crate and NpcSpawn too: a placement is refused without either (D364).
if (IsZonePlugin(plugin) || IsRunicNpc(plugin) || IsEconomics(plugin) || IsBackpacks(plugin) || IsTruePve(plugin) || IsDynamicPvp(plugin) || IsDangerousTreasures(plugin) || IsGuardedCrate(plugin))
// Guarded Crate and NpcSpawn too: a placement is refused without either (D364). And
// ZLevels, which the servers page names (§14.3.6).
if (IsZonePlugin(plugin) || IsRunicNpc(plugin) || IsEconomics(plugin) || IsBackpacks(plugin) || IsTruePve(plugin) || IsDynamicPvp(plugin) || IsDangerousTreasures(plugin) || IsGuardedCrate(plugin) || IsZLevels(plugin))
NextTick(ResendHello);
// Dynamic PVP raises its creates as it opens its zones, which at a load are its
@@ -5258,7 +5260,7 @@ namespace Oxide.Plugins
if (plugin != null && plugin.Name == "BetterChat")
_titlesRegistered = false;
if (IsZonePlugin(plugin) || IsRunicNpc(plugin) || IsEconomics(plugin) || IsBackpacks(plugin) || IsTruePve(plugin) || IsDynamicPvp(plugin) || IsDangerousTreasures(plugin) || IsGuardedCrate(plugin))
if (IsZonePlugin(plugin) || IsRunicNpc(plugin) || IsEconomics(plugin) || IsBackpacks(plugin) || IsTruePve(plugin) || IsDynamicPvp(plugin) || IsDangerousTreasures(plugin) || IsGuardedCrate(plugin) || IsZLevels(plugin))
NextTick(ResendHello);
// Guarded Crate's Unload ended every event WITHOUT a hook.
@@ -10098,6 +10100,22 @@ namespace Oxide.Plugins
EmitFrame(frame);
}
// ---- ZLevels Remastered (PLAN_REDESIGNS §14.3.6, D369, D374) ----
//
// Hello says whether it is loaded, and that is all. No level is read or sent: the
// leaderboard does not change for it (D374). Its XP boosts are permissions, so an event
// lends one through `perm.lend` with no code of ours (§12).
private Plugin ZLevelsPlugin()
{
return plugins.Find("ZLevelsRemastered");
}
private bool IsZLevels(Plugin plugin)
{
return plugin != null && plugin != this && plugin.Name == "ZLevelsRemastered";
}
// ---- the zone's messages (D193) ----
//
// ZoneManager can say a zone's enter and leave messages itself, but only to chat unless its
@@ -11408,6 +11426,7 @@ namespace Oxide.Plugins
$"dangerousTreasures={(DangerousTreasuresPlugin() != null)} treasures={_treasures.Count} dtStarts={_dtStarts.Count} dtWarmingUp={DtWarmingUp()} " +
$"guardedCrate={(GuardedCratePlugin() != null)} npcSpawn={(NpcSpawnPlugin() != null)} guarded={_guardedCrates.Count} gcPlaces={_gcPlacements.Count} " +
$"gcEvents={(GuardedCrateEventNames() != null ? string.Join("|", GuardedCrateEventNames().ToArray()) : "none")} gcCommand={GuardedCrateCommand()} gcListReadable={_gcListReadable} " +
$"zLevels={(ZLevelsPlugin() != null ? ZLevelsPlugin().Version.ToString() : "absent")} " +
$"wipeId={(_wipeId ?? "none")} calls={_worldCalls.Count} consolePlugins={_consolePlugins} " +
$"credits={_vehicleCredit.Count} chinookCrates={_chinookCrates.Count} said={_worldEventsSaid} " +
$"worldEvents={(WorldEventsLive() ? "live" : $"quiet (ready={_worldReady} quitting={Rust.Application.isQuitting} loadingSave={Rust.Application.isLoadingSave})")}" + Environment.NewLine +
@@ -15022,7 +15041,9 @@ namespace Oxide.Plugins
// Protocol 14 (§14.3.4): whether a step may open a Dangerous Treasures event here.
{ "dangerousTreasures", IntegrationBody(DangerousTreasuresPlugin()) },
// Protocol 14 (§14.3.5): whether a step may place a guarded crate here, and which.
{ "guardedCrate", GuardedCrateBody() }
{ "guardedCrate", GuardedCrateBody() },
// Protocol 14 (§14.3.6): whether its XP boosts are here for a step to lend.
{ "zLevels", IntegrationBody(ZLevelsPlugin()) }
};
}