Files
Project-M/Assets/_Project/Scripts/Client/Debug/DebugOverlay.cs
T
kronic b34945c2d2 LANTERN purge B3+B5: delete the cycle/core/win-lose spine + onboarding; save epoch v7
Deletes CyclePhaseSystem, GoalReachedSystem, CoreDamage/CoreRestore, ThreatDirector,
CoreIntegrity/GoalProgress/RunPhase/RunOutcome/ThreatState components,
CoreVisualFeedbackSystem, and the whole Client/Onboarding slice (+6 test files).

Keepers reworked: RunDirectorSystem (UpdateBefore attr + launch guard + goal/threat
bank removed; sole SaveRequest raiser now), CycleDirectorSpawnSystem (ledger/meta
host only), WaveSystem UNGATED (waves run wherever a WaveDirector is baked),
EnemyAISystem core-fallback stripped, AmbientAudioSystem reworked (bed + run cues;
no CycleState gate), MusicSystem RunInfo-only, HudSystem big trim (goal meter, core
bar, siege banner, terminal banner, outcome flash, onboarding hook all gone),
MetaShop/ClassPrep/AimReticle siege gates dropped, DebugOverlay/ops re-meant
(SpawnWave=force next wave, EndSiege=quiet arena; SetCalm/AdvanceGoal/SetHeat
retired, bytes reserved), TuningConfig Core knobs retired (ids 20-23 reserved),
StorageMath.DrainFraction deleted, HowToPlay copy rewritten.

Save epoch v7 (fresh epoch, operator-approved): SaveData drops goal/core/outcome +
conveyor/machine-IO fields; MinLoadableVersion=7; PendingSave/PendingStructure
trimmed; RollTerminalCampaignForward deleted; SaveStructureScan signature slimmed.

390 tests green; Play world-creation clean (player + waves live, no exceptions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 15:27:12 -07:00

148 lines
7.4 KiB
C#

#if UNITY_EDITOR
using ProjectM.Simulation;
using UnityEngine;
namespace ProjectM.Client
{
/// <summary>
/// EDITOR-ONLY in-game dev-tools overlay (IMGUI dev overlay). Buttons enqueue
/// <see cref="DebugCommandRequest"/> RPCs through <see cref="DebugCommandSendSystem"/>, so they drive the REAL
/// server-authoritative paths (and work over a live connection too, not just in-editor). Drop it on a
/// GameObject in the DevSandbox (or Game) scene. While open it forces the OS cursor visible
/// (<see cref="AimPresentation.ForceCursorVisible"/>) so its buttons stay clickable even while aiming.
/// Stripped from player builds (#if UNITY_EDITOR).
/// </summary>
public class DebugOverlay : MonoBehaviour
{
bool _open = true;
int _grantAmount = 50;
bool _tuningOpen;
Vector2 _scroll;
void OnDisable() => AimPresentation.ForceCursorVisible = false;
void OnGUI()
{
if (GUI.Button(new Rect(Screen.width - 96, 10, 86, 24), _open ? "DEV ▲" : "DEV ▼"))
_open = !_open;
AimPresentation.ForceCursorVisible = _open;
if (!_open)
return;
float panelH = Mathf.Min(760f, Screen.height - 50f);
GUILayout.BeginArea(new Rect(Screen.width - 232, 40, 222, panelH), GUI.skin.box);
GUILayout.Label("DEV TOOLS");
_scroll = GUILayout.BeginScrollView(_scroll);
GUILayout.Label("- World -");
if (GUILayout.Button("Force Next Wave")) DebugCommandSendSystem.SpawnWave();
if (GUILayout.Button("Stop Waves")) DebugCommandSendSystem.StopWaves();
if (GUILayout.Button("Clear Enemies")) DebugCommandSendSystem.ClearEnemies();
GUILayout.Space(6);
GUILayout.Label("- Resources -");
_grantAmount = IntField("Amount", _grantAmount);
GUILayout.BeginHorizontal();
if (GUILayout.Button("Aether")) DebugCommandSendSystem.GrantResource(ResourceId.Aether, _grantAmount);
if (GUILayout.Button("Ore")) DebugCommandSendSystem.GrantResource(ResourceId.Ore, _grantAmount);
if (GUILayout.Button("Bio")) DebugCommandSendSystem.GrantResource(ResourceId.Biomass, _grantAmount);
GUILayout.EndHorizontal();
if (GUILayout.Button("Grant Damage Upgrade")) DebugCommandSendSystem.GrantUpgrade();
GUILayout.Space(6);
GUILayout.Label("- Player -");
GUILayout.BeginHorizontal();
if (GUILayout.Button("Heal")) DebugCommandSendSystem.Heal();
if (GUILayout.Button("Kill")) DebugCommandSendSystem.Kill();
if (GUILayout.Button("God")) DebugCommandSendSystem.ToggleGod();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (GUILayout.Button("Go Base")) DebugCommandSendSystem.Teleport(RegionId.Base);
if (GUILayout.Button("Go Expedition")) DebugCommandSendSystem.Teleport(RegionId.Expedition);
GUILayout.EndHorizontal();
GUILayout.Space(6);
GUILayout.Label("- Class (F1/F2) -");
GUILayout.BeginHorizontal();
if (GUILayout.Button("Warrior")) DebugCommandSendSystem.SetWarrior();
if (GUILayout.Button("Ranger")) DebugCommandSendSystem.SetRanger();
GUILayout.EndHorizontal();
GUILayout.Space(6);
GUILayout.Label("- Telemetry (MC-0) -");
if (DevTelemetryReadout.HasData)
{
var t = DevTelemetryReadout.Latest;
GUILayout.Label($"tick {t.LastSampleTick} husks {t.LiveEnemyCount}");
GUILayout.Label($"dash neg {t.DashIFrameNegatedHits} / wasted {t.DashesWasted}");
GUILayout.Label($"whiff open {t.ChargerWhiffWindowsOpened} / punish {t.ChargerWhiffPunishesLanded}");
}
else
{
GUILayout.Label("(waiting for server telemetry...)");
}
GUILayout.Space(6);
_tuningOpen = GUILayout.Toggle(_tuningOpen, "- Tuning (MC-0) -");
if (_tuningOpen)
{
TuningRow("Dash dist", TuningKnob.DashDistance, 0.5f, "0.0");
TuningRow("Dash iframe t", TuningKnob.IFrameWindowTicks, 1f, "0");
TuningRow("Dash recover t", TuningKnob.RecoverTailTicks, 1f, "0");
TuningRow("Dash cd t", TuningKnob.DashCooldownTicks, 1f, "0");
TuningRow("Dash sharp", TuningKnob.DashSharpness, 25f, "0");
TuningRow("Chgr windup t", TuningKnob.ChargerWindupTicks, 1f, "0");
TuningRow("Chgr lunge spd", TuningKnob.ChargerLungeSpeed, 1f, "0.0");
TuningRow("Chgr lunge t", TuningKnob.ChargerLungeDurationTicks, 1f, "0");
TuningRow("Chgr stagger t", TuningKnob.ChargerWhiffStaggerTicks, 1f, "0");
TuningRow("Grunt windup t", TuningKnob.GruntWindupTicks, 1f, "0");
GUILayout.Space(4);
TuningRow("Melee dmg", TuningKnob.MeleeDamage, 1f, "0.0");
TuningRow("Melee range", TuningKnob.MeleeRange, 0.2f, "0.0");
TuningRow("Melee cone rad", TuningKnob.MeleeConeHalfAngleRad, 0.05f, "0.00");
TuningRow("Melee recover t", TuningKnob.MeleeRecoverTicks, 1f, "0");
TuningRow("Melee chain t", TuningKnob.MeleeChainGraceTicks, 1f, "0");
TuningRow("Melee move x", TuningKnob.MeleeSwingMoveScale, 0.05f, "0.00");
TuningRow("Melee knock spd", TuningKnob.MeleeKnockbackSpeed, 1f, "0.0");
TuningRow("Melee finish x", TuningKnob.MeleeFinisherMult, 0.1f, "0.0");
TuningRow("Melee combo len", TuningKnob.MeleeComboLength, 1f, "0");
GUILayout.Space(4);
TuningRow("Struct aggro w", TuningKnob.StructureAggroWeight, 0.1f, "0.00"); // EB-1: <1 prefers structures
}
GUILayout.EndScrollView();
GUILayout.EndArea();
}
static int IntField(string label, int value)
{
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(70));
string s = GUILayout.TextField(value.ToString(), GUILayout.Width(60));
GUILayout.EndHorizontal();
return int.TryParse(s, out var v) ? v : value;
}
// One live-tuning row: shows the current value (from the readout) + step buttons. A nudge fires the
// authoritative server RPC AND an optimistic local apply (so the tuner's own predicted dash uses it now).
static void TuningRow(string label, byte knob, float step, string fmt)
{
float cur = ProjectM.Simulation.TuningConfig.Get(TuningReadout.Current, knob);
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(92));
GUILayout.Label(cur.ToString(fmt), GUILayout.Width(40));
if (GUILayout.Button("-", GUILayout.Width(26))) Nudge(knob, cur - step);
if (GUILayout.Button("+", GUILayout.Width(26))) Nudge(knob, cur + step);
GUILayout.EndHorizontal();
}
static void Nudge(byte knob, float value)
{
DebugCommandSendSystem.SetTuning(knob, value); // authoritative (server applies + broadcasts; clamped)
TuningReadout.SetLocal(knob, value); // optimistic local (instant feel for the tuner; clamped)
}
}
}
#endif