From 638ab27439b0a7fdca7e741bc9cdb91a60a478f0 Mon Sep 17 00:00:00 2001 From: Dennis Westermann Date: Tue, 18 Aug 2026 14:33:35 +0200 Subject: [PATCH 1/2] feat(presentation): Pausemenue und ein Riegel fuer modale Oberflaechen (#105, #102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paket 21.8, das Beta-Tor: bisher kam ein Spieler aus einer laufenden Runde nicht heraus, und wer ueber das Matchende ins Hauptmenue zurueckging, sah das Cockpit ueber dem Menue stehen. DER RIEGEL IST DIE UI-WURZEL, KEIN KATALOG. SetGameplayLayerActive schaltet jetzt das GameObject, auf das der Szenengenerator ohnehin alle In-Match- Komponenten legt, statt zweier namentlich genannter. Damit ist jede kuenftige HUD-Komponente automatisch abgedeckt, ohne je genannt zu werden — die Sorge im dortigen Docstring, ein Katalog verrotte mit der naechsten Komponente, ist damit strukturell beantwortet statt bestaetigt. Das Kamera-Rig bleibt ein eigener Schalter, es liegt auf der Main Camera und nicht auf der Wurzel. FUER DEN PAUSEZUSTAND EIN FLAG, denn dort bleibt die Wurzel an. ModalSurfaceLink publiziert pro Frame 'ein modales Fenster besitzt die Eingabe' — ausdruecklich nicht 'das Match laeuft nicht', die drei Zustaende bleiben getrennt. Kein Latch mit Gedaechtnis: ein haengendes true waere ein Eingabe-Deadlock, deshalb setzt OnDisable zurueck. Drei Fehler aus dem Audit fallen damit mit: - Der Klick auf 'Hauptmenue' selektierte eine Einheit HINTER dem Panel und erzeugte damit selbst die Auswahl, die danach ueber dem Menue stand - Ein armierter Bau-Ghost ueberlebte den Menuewechsel und wanderte in die naechste Runde - Die P-Pause hatte keinerlei Eingabe-Riegel: Hotkeys und Harvester-Eskorte feuerten in den gestoppten Kernel 'Einstellungen' ist bewusst nur ein Hinweis auf das Hauptmenue statt einer zweiten, driftenden Maske: die Bestandsmaske haengt fest im Menue-Screen samt Key Art. DebugHud unangetastet; nachgesehen und verhaltensgleich (siehe #107). Umsetzung durch den Kimi-K3-Worker. Co-Authored-By: Claude Opus 5 --- Assets/Tests/PlayMode/MainMenuTests.cs | 30 +- .../Editor/BootstrapSceneGenerator.cs | 47 +++- .../Scripts/Gameplay/UI/ModalSurfaceLink.cs | 46 ++++ .../Gameplay/UI/ModalSurfaceLink.cs.meta | 2 + .../Presentation/UI/MainMenuController.cs | 105 ++++--- .../Scripts/Presentation/UI/MatchFrameHud.cs | 119 ++++---- .../Scripts/Presentation/UI/PauseMenuHud.cs | 258 ++++++++++++++++++ .../Presentation/UI/PauseMenuHud.cs.meta | 2 + .../Scripts/Presentation/UI/RtsDeviceInput.cs | 90 ++++-- .../sprint-21/01-kimi-hud-state-audit.md | 54 ++++ .../v8.6.0/sprint-21/02-kimi-version-hud.md | 42 +++ .../sprint-21/03-kimi-buildzone-overlay.md | 42 +++ .../v8.6.0/sprint-21/04-kimi-anchor-rule.md | 42 +++ .../sprint-21/05-kimi-pause-and-gate.md | 58 ++++ 14 files changed, 808 insertions(+), 129 deletions(-) create mode 100644 Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs create mode 100644 Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs.meta create mode 100644 Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs create mode 100644 Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs.meta create mode 100644 reports/v8.6.0/sprint-21/01-kimi-hud-state-audit.md create mode 100644 reports/v8.6.0/sprint-21/02-kimi-version-hud.md create mode 100644 reports/v8.6.0/sprint-21/03-kimi-buildzone-overlay.md create mode 100644 reports/v8.6.0/sprint-21/04-kimi-anchor-rule.md create mode 100644 reports/v8.6.0/sprint-21/05-kimi-pause-and-gate.md diff --git a/Assets/Tests/PlayMode/MainMenuTests.cs b/Assets/Tests/PlayMode/MainMenuTests.cs index 1c710b1..c957e7a 100644 --- a/Assets/Tests/PlayMode/MainMenuTests.cs +++ b/Assets/Tests/PlayMode/MainMenuTests.cs @@ -26,10 +26,12 @@ namespace Nova.PlayMode.Tests /// rank-4 assemblies, and quality/scripts/run_gate_check.py:183-188 forbids /// any test assembly from referencing one — Nova.Presentation.Tests was /// dissolved for exactly that reason in 5cdb0ce. The menu's contract with - /// those three components (it switches two of them off while it is up and - /// back on when the match starts) is still worth a test, so they are found - /// by type name. A name that no longer resolves fails loudly here; the - /// alternative was not testing the behaviour at all. + /// those components (it switches the camera rig off while it is up, and + /// the whole gameplay HUD ROOT with it — the one GameObject every + /// in-match HUD component, DebugHud included, lives on) is still worth a + /// test, so they are found by type name. A name that no longer resolves + /// fails loudly here; the alternative was not testing the behaviour at + /// all. /// /// /// Run headless-with-graphics, never with -quit (same lane as @@ -135,9 +137,14 @@ public IEnumerator BootstrapScene_OpensInTheMainMenuWithNoMatchRunning() "this scene with no 'no match yet' guard: its LateUpdate reads scroll wheel, MMB, " + "Z/X and the screen-edge pan every frame, so a pointer resting near an edge would " + "pan the camera away from the HQ before the match even starts."); - Assert.IsFalse(DebugHudBehaviour().enabled, - "the debug HUD must be silent while the menu is up: its always-on status bar draws " + - "BEFORE its own F3 visibility check, so it would sit on top of the key art"); + Behaviour debugHud = DebugHudBehaviour(); + Assert.IsFalse(debugHud.gameObject.activeInHierarchy, + "the gameplay HUD root must be OFF while the menu is up: the menu switches the one " + + "GameObject every in-match HUD component lives on (MainMenuController.SetGameplayLayerActive), " + + "so the whole cockpit — including the debug HUD's always-on status bar, which draws " + + "BEFORE its own F3 visibility check — stays silent instead of sitting on the key art. " + + "The check goes through activeInHierarchy because the switch is the root's SetActive, " + + "not a per-component enabled toggle."); } // ------------------------------------------------------------------ @@ -213,11 +220,12 @@ public IEnumerator NewGame_StartsTheMatchHidesTheOverlayAndWakesTheCockpit() Assert.IsTrue(CameraRig().enabled, "the RTS camera must take over as the match starts; it was switched off only for " + "as long as the menu was up"); - Assert.IsTrue(DebugHudBehaviour().enabled, - "the status bar belongs to the cockpit and must come back with the match"); + Assert.IsTrue(DebugHudBehaviour().gameObject.activeInHierarchy, + "the gameplay HUD root must come back with the match — the status bar and the whole " + + "cockpit ride on the one root object the menu switches"); Assert.IsFalse(MenuController().enabled, - "the menu switches itself off after starting: this sprint has no pause menu and no " + - "restart, so there is deliberately no way back into it"); + "the menu switches itself off after starting; the way back in is a match-end or " + + "pause-menu button (ReturnToMenu re-enables it), not the start click itself"); uint tickAtStart = runner.Session.CurrentTick; yield return new WaitForSeconds(2f); diff --git a/Assets/_Project/Editor/BootstrapSceneGenerator.cs b/Assets/_Project/Editor/BootstrapSceneGenerator.cs index d153788..2a6a961 100644 --- a/Assets/_Project/Editor/BootstrapSceneGenerator.cs +++ b/Assets/_Project/Editor/BootstrapSceneGenerator.cs @@ -307,11 +307,17 @@ private static void EnsureGlutrinneMapAsset() /// /// Input sampling, the world-space HUD markers (selection, rally - /// flags, placement ghost), the build bar, the command card and the + /// flags, placement ghost), the build bar, the command card, the + /// match frame (result/network panels), the pause menu and the /// read-only debug overlay. The build bar and the command card are /// additionally wired INTO the input component: clicks landing on a /// HUD rect belong to the HUD and must not start a world selection - /// drag, place a building or resolve an order pick behind it. + /// drag, place a building or resolve an order pick behind it. The + /// pause menu is wired into the input's counterpart direction: it + /// reads the gesture-cancel stamp so ESC peels one layer at a time. + /// Everything lands on ONE GameObject so the main menu can silence + /// the whole cockpit with a single root switch — a component added + /// here is covered by that switch from the day it lands. /// private static GameObject CreateUiObject(MatchRunner runner, Camera camera) { @@ -375,6 +381,13 @@ private static GameObject CreateUiObject(MatchRunner runner, Camera camera) // _menu is wired in CreateMainMenuObject — the menu object does // not exist yet at this point in the generation order. + PauseMenuHud pauseMenu = uiObject.AddComponent(); + WireReference(pauseMenu, "_runner", runner); + WireReference(pauseMenu, "_matchFrame", frame); + WireReference(pauseMenu, "_input", input); + // _menu is wired in CreateMainMenuObject — same ordering reason + // as the match frame above. + DebugHud hud = uiObject.AddComponent(); WireReference(hud, "_runner", runner); WireReference(hud, "_input", input); @@ -389,15 +402,17 @@ private static GameObject CreateUiObject(MatchRunner runner, Camera camera) /// CreateMatchObject) and MainMenuController starts the match from /// "Neues Spiel". /// - /// The camera rig and the debug HUD are wired INTO the menu because - /// they are the only two components in this scene without a "no match - /// yet" guard: the rig would edge-pan and zoom while the player moves - /// the pointer over the menu, and the HUD's always-on status bar draws - /// before its own visibility check. The menu switches both off while - /// it is up. On the receiving side the rig is typed as Behaviour - /// (Nova.Presentation.UI may not reference Nova.Presentation), which - /// WireReference handles — it assigns object references, not typed - /// fields. + /// TWO things are wired INTO the menu because they are the scene's + /// only parts without a "no match yet" guard: the camera rig (it + /// would edge-pan and zoom while the player moves the pointer over + /// the menu) and the gameplay HUD ROOT — this one GameObject carries + /// every in-match HUD component, so the menu silences the whole + /// cockpit (including the debug HUD's always-on status bar, which + /// draws before its own visibility check) with a single root switch + /// that can never rot the way a component catalogue would. On the + /// receiving side the rig is typed as Behaviour (Nova.Presentation.UI + /// may not reference Nova.Presentation), which WireReference handles + /// — it assigns object references, not typed fields. /// /// private static void CreateMainMenuObject( @@ -430,7 +445,7 @@ private static void CreateMainMenuObject( WireReference(menu, "_bootstrap", runner.GetComponent()); WireReference(menu, "_music", music); WireReference(menu, "_cameraRig", camera.GetComponent()); - WireReference(menu, "_debugHud", uiObject.GetComponent()); + WireReference(menu, "_gameplayHudRoot", uiObject); WireReference(menu, "_keyArt", MenuAssetSetup.LoadRequired(MenuAssetSetup.KeyArtPath)); WireReference(menu, "_titleFont", @@ -438,12 +453,18 @@ private static void CreateMainMenuObject( WireReference(menu, "_bodyFont", MenuAssetSetup.LoadRequired(MenuAssetSetup.BodyFontPath)); - // The match frame's "Hauptmenü" button calls back into this menu. + // The match frame's "Hauptmenü" and the pause menu's "Zum + // Hauptmenü"/"Spiel beenden" call back into this menu. MatchFrameHud frame = uiObject.GetComponent(); if (frame != null) { WireReference(frame, "_menu", menu); } + PauseMenuHud pauseMenu = uiObject.GetComponent(); + if (pauseMenu != null) + { + WireReference(pauseMenu, "_menu", menu); + } CreateIngameMusicObject(runner, menu, musicGroup); } diff --git a/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs b/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs new file mode 100644 index 0000000..39f1c87 --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs @@ -0,0 +1,46 @@ +namespace Nova.Gameplay +{ + /// + /// Read-only modal-surface channel between the HUD layer + /// (Nova.Presentation.UI) and anyone who must know whether a modal panel + /// currently owns the player's input. Same pattern as + /// : a static in Nova.Gameplay both + /// Presentation assemblies can see, no new assembly edge. + /// + /// The semantics are exactly "a modal surface owns the input this frame" + /// — the pause menu, the match-result screen, a network status panel — + /// and deliberately NOT "the match is not running": a paused match and a + /// match without any modal are different states, and consumers that need + /// the clock read MatchRunner.IsRunning instead. + /// + /// + /// ONE writer: the component that draws the modal panels publishes once + /// per frame (today PauseMenuHud, which aggregates MatchFrameHud's + /// result/network panels). The value is a per-frame verdict, never a + /// latch with memory — a stuck true would deadlock every world + /// gesture for the rest of the session, so the writer's OnDisable calls + /// (the UI root switch-off on the way to the main + /// menu is the case that must never leave a stale true behind). + /// The reader is RtsDeviceInput, which suspends world gestures and + /// re-publishes through so the camera's + /// edge-pan strip stops too without gaining a reader of its own. + /// + /// + public static class ModalSurfaceLink + { + /// The last published verdict: a modal surface owns the input this frame. + public static bool Open { get; private set; } + + /// Publishes this frame's verdict. Called by the modal-drawing component every frame. + public static void Publish(bool open) + { + Open = open; + } + + /// Clears the verdict (writer disabled, play-mode transitions, domain-reload-off safety). + public static void Reset() + { + Open = false; + } + } +} diff --git a/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs.meta b/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs.meta new file mode 100644 index 0000000..d4e98b7 --- /dev/null +++ b/Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 593d941e459240a1ac57d96f8b4168ed \ No newline at end of file diff --git a/Assets/_Project/Scripts/Presentation/UI/MainMenuController.cs b/Assets/_Project/Scripts/Presentation/UI/MainMenuController.cs index 404486f..f290a69 100644 --- a/Assets/_Project/Scripts/Presentation/UI/MainMenuController.cs +++ b/Assets/_Project/Scripts/Presentation/UI/MainMenuController.cs @@ -17,9 +17,11 @@ namespace Nova.Presentation.UI /// scene-flow layer — bought for nothing. /// is off (the scene generator /// writes it), so the scene loads into an idle host: the kernel is not - /// running, every HUD component checks for a running match and draws - /// nothing, and "Neues Spiel" calls the idempotent - /// and hides this overlay. + /// running, and Start() switches the whole gameplay HUD root off in one + /// call before the first frame + /// draws. "Neues Spiel" calls the idempotent + /// , switches the root back + /// on and hides this overlay. /// /// /// UI TOOLKIT, NOT uGUI, and built in C# rather than from UXML. uGUI would @@ -65,8 +67,11 @@ public sealed partial class MainMenuController : MonoBehaviour "The scene generator wires the concrete component.")] [SerializeField] private Behaviour _cameraRig; - [Tooltip("Debug HUD. Its status bar draws before its own visibility check, so it would sit on the key art.")] - [SerializeField] private DebugHud _debugHud; + [Tooltip("The UI root GameObject the scene generator puts EVERY in-match HUD component on " + + "(input, markers, build bar, command card, fog, minimap, health bars, match frame, " + + "pause menu, debug HUD). Switched as ONE object, so a HUD added to the root later is " + + "covered without ever being named here — a component catalogue would rot with the next one.")] + [SerializeField] private GameObject _gameplayHudRoot; [Header("Content (scene generator)")] [SerializeField] private Texture2D _keyArt; @@ -131,9 +136,10 @@ public sealed partial class MainMenuController : MonoBehaviour /// /// True while the menu overlay owns the screen (initial state, and - /// after MatchFrameHud's "Hauptmenü"). Read by the input component to - /// suspend world gestures while the menu is up — a click on a menu - /// button must never also select or order in the world behind it. + /// after the match frame's "Hauptmenü" or the pause menu's "Zum + /// Hauptmenü"). Read by the input component to suspend world gestures + /// while the menu is up — a click on a menu button must never also + /// select or order in the world behind it. /// public bool IsMenuVisible { get; private set; } @@ -143,6 +149,14 @@ private void Awake() if (_music == null) _music = GetComponent(); if (_bootstrap == null) _bootstrap = FindAnyObjectByType(); if (_views == null) _views = FindAnyObjectByType(); + if (_gameplayHudRoot == null) + { + // Self-heal for scenes generated before the root switch + // existed: the root is by definition the GameObject the input + // component lives on (BootstrapSceneGenerator.CreateUiObject). + RtsDeviceInput input = FindAnyObjectByType(); + if (input != null) _gameplayHudRoot = input.gameObject; + } } private void Start() @@ -199,11 +213,12 @@ private void LogMissingWiring() "[MainMenuController] No camera rig wired — the RTS camera keeps reading edge pan and " + "scroll wheel while the menu is up, so the match will open on a drifted camera."); } - if (_debugHud == null) + if (_gameplayHudRoot == null) { Debug.LogError( - "[MainMenuController] No DebugHud wired — its always-on status bar will draw on top of " + - "the main menu."); + "[MainMenuController] No gameplay HUD root wired (and none found via RtsDeviceInput) — " + + "the cockpit will keep drawing over the menu. Re-run " + + "Tools/Project Nova/Create Bootstrap Scene."); } } @@ -714,22 +729,30 @@ private void StartMatch() if (_music != null) _music.FadeOutAndStop(); if (_screen != null) _screen.style.display = DisplayStyle.None; - // Nothing left to drive — until a match ends: MatchFrameHud's - // "Hauptmenü" button re-enters through ReturnToMenu below. + // Nothing left to drive — until a match ends or is abandoned: + // MatchFrameHud's "Hauptmenü" and the pause menu's "Zum + // Hauptmenü" re-enter through ReturnToMenu below. enabled = false; } /// - /// The way back from a finished match (MatchFrameHud's "Hauptmenü" - /// button): pause the host, hide the cockpit layer, bring the menu - /// screen and its music back. The match state itself is left for the - /// NEXT "Neues Spiel", which restarts it via - /// — the menu does not - /// demolish what it may never need again. + /// The way back from a finished or abandoned match (MatchFrameHud's + /// "Hauptmenü" button, the pause menu's "Zum Hauptmenü"): pause the + /// host, hide the cockpit layer, bring the menu screen and its music + /// back. The match state itself is left for the NEXT "Neues Spiel", + /// which restarts it via — + /// the menu does not demolish what it may never need again. /// public void ReturnToMenu() { - if (_bootstrap != null && _bootstrap.Runner != null && _bootstrap.Runner.IsRunning) + // A relay kernel cannot pause independently of its peer + // (PauseMatch logs an error and refuses) — and with the pause + // menu, "leave a RUNNING relay match" is now a reachable path, + // so the refusal must not be triggered on purpose. The relay + // match keeps ticking behind the menu until the next start + // restarts it, exactly as a locally paused match does. + if (_bootstrap != null && _bootstrap.Runner != null + && _bootstrap.Runner.IsRunning && !_bootstrap.Runner.IsRelayMatch) { _bootstrap.Runner.PauseMatch(); } @@ -753,7 +776,12 @@ public void ReturnToMenu() enabled = true; } - private void Quit() + /// + /// Quits the application after flushing any unsaved settings. Public + /// so the pause menu's "Spiel beenden" runs the exact same exit as + /// this menu's "Beenden" — one quit path, no copy. + /// + public void Quit() { FlushSettings(); #if UNITY_EDITOR @@ -766,24 +794,35 @@ private void Quit() } /// - /// Silences (or restores) the two scene components that do NOT guard - /// themselves against "no match yet". The list is short on purpose: - /// every other HUD component already returns early without a running - /// match, and a catalogue of every HUD in the scene would rot with - /// the next one added. + /// Silences (or restores) everything that must not run while the menu + /// owns the screen. TWO switches, by construction: /// - /// The camera rig has no guard at all — its LateUpdate reads - /// scroll wheel, MMB, Z/X, arrow keys and the screen-edge pan every - /// frame. Awake has already applied the start framing, so a disabled - /// rig sits exactly where the match wants it. - /// The debug HUD draws its always-on status bar BEFORE its own - /// visibility check, so its text would sit on top of the key art. + /// The camera rig — a plain component toggle. It lives on "Main + /// Camera", not on the HUD root, and has no "no match yet" guard: its + /// LateUpdate reads scroll wheel, MMB, Z/X, arrow keys and the + /// screen-edge pan every frame. Awake has already applied the start + /// framing, so a disabled rig sits exactly where the match wants + /// it. + /// The gameplay HUD ROOT — the one GameObject the scene + /// generator puts every in-match HUD component on. Switching the root + /// instead of a component list is what keeps this method correct + /// forever: a catalogue would rot with the next HUD added, while + /// whatever the generator places on the root is covered from the day + /// it lands, without ever being named here. Deactivation IS the + /// gate — OnGUI, Update and the hit-tests of every child die with + /// it, including the debug HUD whose always-on status bar would + /// otherwise sit on the key art (behaviour identical to the old + /// per-component toggle; the F3 state survives SetActive). /// + /// The in-match PAUSE menu is a different case and is deliberately + /// NOT this switch: it keeps the root on (the world stays visible + /// under the panel) and gates only the input, through + /// ModalSurfaceLink — see PauseMenuHud. /// private void SetGameplayLayerActive(bool active) { if (_cameraRig != null) _cameraRig.enabled = active; - if (_debugHud != null) _debugHud.enabled = active; + if (_gameplayHudRoot != null) _gameplayHudRoot.SetActive(active); } // --- settings persistence ---------------------------------------- diff --git a/Assets/_Project/Scripts/Presentation/UI/MatchFrameHud.cs b/Assets/_Project/Scripts/Presentation/UI/MatchFrameHud.cs index 9e06c5c..ea4afbc 100644 --- a/Assets/_Project/Scripts/Presentation/UI/MatchFrameHud.cs +++ b/Assets/_Project/Scripts/Presentation/UI/MatchFrameHud.cs @@ -9,22 +9,32 @@ namespace Nova.Presentation.UI { /// - /// The match frame (sprint 09 §6): the two modal panels that close a - /// round — the RESULT screen once latches an - /// outcome ("Sieg" / "Niederlage" / "Unentschieden" with the decided-tick - /// timestamp), and the PAUSE overlay while the kernel clock is stopped - /// (a paused match and a broken one used to look identical). Both offer - /// "Neue Runde" and/or "Hauptmenü", so quitting the application is no - /// longer the only way out of a finished round. + /// The match frame (sprint 09 §6): the modal panels that close a round — + /// the RESULT screen once latches an outcome + /// ("Sieg" / "Niederlage" / "Unentschieden" with the decided-tick + /// timestamp), and the NETWORK status panels for a relay match that + /// ended or stalls. Both offer a way out ("Neue Runde" and/or + /// "Hauptmenü"), so quitting the application is no longer the only exit + /// from a finished round. The PAUSE surface no longer lives here: since + /// sprint 21.8 it is (ESC/P), which also owns + /// the kernel clock. /// /// "Neue Runde" runs (the sim /// side is rebuilt wholesale) and then resets the presentation side: /// views via , the camera through /// — the rig owns /// the reset itself because Nova.Presentation.UI may not reference - /// Nova.Presentation (same rank). The selection clears itself on the - /// ingress rebind (RtsDeviceInput.EnsureDispatcher), and the fog overlay - /// plus minimap self-heal through their fog-instance guards. + /// Nova.Presentation (same rank). The selection and any armed gesture + /// clear themselves on the ingress rebind (RtsDeviceInput.EnsureDispatcher), + /// and the fog overlay plus minimap self-heal through their fog-instance + /// guards. + /// + /// + /// reports once per frame whether one of these + /// panels is up; PauseMenuHud aggregates it into + /// , the channel that tells the input + /// component "a modal owns every click" — a click on "Hauptmenü" must + /// never fall through the panel and select a unit behind it. /// /// /// READ-ONLY toward the simulation: this panel polls the victory system's @@ -48,6 +58,21 @@ public sealed class MatchFrameHud : MonoBehaviour private GUIStyle _bodyStyle; private GUIStyle _buttonStyle; + // The panel state, derived once per frame in Update: OnGUI draws from + // it (possibly several passes per frame) and PauseMenuHud reads + // ModalOpen for the ModalSurfaceLink publish — one derivation, no + // drift between "is a panel up" and "which panel is drawn". + private VictorySystem _panelVictory; + private string _panelNetworkReason; + private int _panelStalledSlot; + + /// + /// True while one of this component's modal panels (result or + /// network status) is up. Computed once per frame in Update; + /// PauseMenuHud aggregates it into . + /// + public bool ModalOpen { get; private set; } + private void Awake() { if (_runner == null) _runner = FindAnyObjectByType(); @@ -56,20 +81,42 @@ private void Awake() if (_views == null) _views = FindAnyObjectByType(); } - private void OnGUI() + private void Update() { - if (_runner == null || _bootstrap == null) return; - if (_menu != null && _menu.IsMenuVisible) return; + ModalOpen = ComputeModalState(); + } + + /// + /// The modal verdict and the panel payload behind it. "Modal" means + /// the decided-result screen, a relay end reason or a stalled relay + /// handshake — the paused-with-victory-pending state is deliberately + /// absent: it belongs to the pause menu now. + /// + private bool ComputeModalState() + { + _panelVictory = null; + _panelNetworkReason = null; + _panelStalledSlot = -1; + if (_runner == null || _bootstrap == null) return false; + if (_menu != null && _menu.IsMenuVisible) return false; bool isMatchReady = _bootstrap.IsMatchReady; - VictorySystem victory = isMatchReady ? _runner.Victory : null; - string networkEndReason = isMatchReady + _panelVictory = isMatchReady ? _runner.Victory : null; + _panelNetworkReason = isMatchReady ? _runner.RelayEndReason : _bootstrap.NetworkStatusReason; - int stalledOnSlot = isMatchReady && _runner.IsRelayMatch && _runner.RelayCommandsAllowed + _panelStalledSlot = isMatchReady && _runner.IsRelayMatch && _runner.RelayCommandsAllowed ? _bootstrap.NetworkStalledOnSlot : -1; - if (victory == null && string.IsNullOrEmpty(networkEndReason) && stalledOnSlot < 0) return; + + return (_panelVictory != null && _panelVictory.IsDecided) + || !string.IsNullOrEmpty(_panelNetworkReason) + || _panelStalledSlot >= 0; + } + + private void OnGUI() + { + if (!ModalOpen) return; EnsureStyles(); @@ -77,23 +124,19 @@ private void OnGUI() Matrix4x4 previousMatrix = GUI.matrix; GUI.matrix = Matrix4x4.Scale(new Vector3(scale, scale, 1f)); - if (victory != null && victory.IsDecided) + if (_panelVictory != null && _panelVictory.IsDecided) { - DrawResultPanel(victory); + DrawResultPanel(_panelVictory); } - else if (!string.IsNullOrEmpty(networkEndReason)) + else if (!string.IsNullOrEmpty(_panelNetworkReason)) { - DrawNetworkStatusPanel("NETZWERKFEHLER", networkEndReason); + DrawNetworkStatusPanel("NETZWERKFEHLER", _panelNetworkReason); } - else if (stalledOnSlot >= 0) + else if (_panelStalledSlot >= 0) { DrawNetworkStatusPanel( "VERBINDUNG", - $"Warte auf Spieler {stalledOnSlot + 1} … {_bootstrap.NetworkStallSeconds:0.0}s"); - } - else if (victory != null && !_runner.IsRunning) - { - DrawPausePanel(); + $"Warte auf Spieler {_panelStalledSlot + 1} … {_bootstrap.NetworkStallSeconds:0.0}s"); } GUI.matrix = previousMatrix; @@ -154,28 +197,6 @@ private void DrawResultPanel(VictorySystem victory) GUILayout.EndArea(); } - private void DrawPausePanel() - { - Rect rect = CenteredRect(150f); - GUI.Box(rect, GUIContent.none, HudChrome.OpaquePanelStyle); - GUILayout.BeginArea(rect); - GUILayout.Space(HudChrome.OpaquePanelStyle.padding.top); - GUILayout.Label("PAUSE", _headlineStyle); - GUILayout.Label("Die Simulation steht — P oder der Knopf setzt fort.", _bodyStyle); - GUILayout.Space(10f); - if (GUILayout.Button("Fortsetzen (P)", _buttonStyle, GUILayout.Height(30f))) - { - AudioServiceLocator.Play2D(SoundEventId.UI_Click); - _runner.StartMatch(); - } - if (GUILayout.Button("Hauptmenü", _buttonStyle, GUILayout.Height(26f))) - { - AudioServiceLocator.Play2D(SoundEventId.UI_Click); - ReturnToMenu(); - } - GUILayout.EndArea(); - } - /// /// The full round reset: sim side via the bootstrap, view side via /// the view manager, camera via the link channel (see the class diff --git a/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs b/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs new file mode 100644 index 0000000..4a40537 --- /dev/null +++ b/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs @@ -0,0 +1,258 @@ +// Graybox throwaway. Legacy Input + OnGUI. Does NOT satisfy G2/G4 UI criteria +// (see docs/production/MVPRecoveryPlan.md). Replaced when the new Input System and the real UI land. +using UnityEngine; +using Nova.Gameplay; +using Nova.Gameplay.Audio; +using Nova.Gameplay.Match; + +namespace Nova.Presentation.UI +{ + /// + /// The in-match pause menu (#105): ESC or P opens it OVER the live world + /// — the HUD root stays on, so the frozen match remains visible behind + /// the panel — and stops the kernel clock via + /// . "Fortsetzen" (or ESC/P again) + /// resumes what the menu itself paused, "Zum Hauptmenü" leaves through + /// , "Spiel beenden" through + /// . Relay matches cannot pause + /// (the runner refuses it), so there the menu opens without stopping the + /// clock and says so. + /// + /// ESC PEELS ONE LAYER PER PRESS: an armed placement ghost or order pick + /// owns the key first (RtsDeviceInput runs at -200 and stamps + /// when it cancels + /// one); the menu opens only on the next press. P is not a cancel key and + /// opens the menu directly — the input component disarms any armed + /// gesture the moment the modal gate engages. + /// + /// + /// SINGLE WRITER of : every frame this + /// component publishes whether ANY modal surface owns the input — this + /// menu or 's terminal panels (result / + /// network), which outrank the menu: the menu refuses to open over them + /// and closes itself if one appears underneath. RtsDeviceInput reads the + /// verdict and suspends world gestures while it is up. The publish is + /// per-frame, never latched, and resets the + /// channel — the UI root switch-off on the way to the main menu must + /// never leave a stale "open" behind, or the next match would deadlock + /// every click. + /// + /// + /// READ-ONLY toward the simulation: the only state this component + /// touches is the kernel clock (pause/resume); it never submits a + /// command. Settings are deliberately NOT a second mask here — they live + /// in the main menu, and the panel says so instead of drifting a copy. + /// + /// + [DisallowMultipleComponent] + public sealed class PauseMenuHud : MonoBehaviour + { + [Header("Wiring (scene generator)")] + [SerializeField] private MatchRunner _runner; + [SerializeField] private MainMenuController _menu; + [Tooltip("Its result/network panels are the terminal modals: the pause menu never stacks on top of them.")] + [SerializeField] private MatchFrameHud _matchFrame; + [Tooltip("Read for the ESC layer-peel: an armed gesture cancels first, the menu opens on the next press.")] + [SerializeField] private RtsDeviceInput _input; + + [Header("Presentation")] + [SerializeField] private float _uiScale = 1.5f; + [SerializeField] private float _panelWidth = 340f; + + private bool _menuOpen; + private bool _pausedByMenu; + + private GUIStyle _headlineStyle; + private GUIStyle _bodyStyle; + private GUIStyle _buttonStyle; + + /// True while the pause menu panel is up (read-only, for observers and tests). + public bool IsPauseMenuOpen => _menuOpen; + + private void Awake() + { + if (_runner == null) _runner = FindAnyObjectByType(); + if (_menu == null) _menu = FindAnyObjectByType(); + if (_matchFrame == null) _matchFrame = FindAnyObjectByType(); + if (_input == null) _input = FindAnyObjectByType(); + } + + private void OnDisable() + { + // The channel must never outlive its writer: this component sits + // on the UI root, and the root is switched OFF on the way to the + // main menu — exactly the transition where a latched "open" would + // deadlock the next match's input. Drop the local state with it, + // so a re-enabled component (next match start) starts clean. + _menuOpen = false; + _pausedByMenu = false; + ModalSurfaceLink.Reset(); + } + + private void Update() + { + if (_menu != null && _menu.IsMenuVisible) + { + // The main menu owns the screen and the UI root should + // already be off (this Update would not run). Hand-built + // scenes without the root switch still get a clean state: + // ReturnToMenu keeps the match paused, so nothing resumes here. + _menuOpen = false; + _pausedByMenu = false; + } + else + { + HandleToggleInput(); + if (_menuOpen && _matchFrame != null && _matchFrame.ModalOpen) + { + // A terminal panel (result / network) appeared under the + // open menu — it outranks the pause menu and takes over. + CloseMenu(playClick: false); + } + } + + ModalSurfaceLink.Publish(_menuOpen || (_matchFrame != null && _matchFrame.ModalOpen)); + } + + private void HandleToggleInput() + { + bool escape = Input.GetKeyDown(KeyCode.Escape); + bool pause = Input.GetKeyDown(KeyCode.P); + if (!escape && !pause) return; + + if (_menuOpen) + { + CloseMenu(playClick: true); + return; + } + + // ESC peels one layer at a time: RtsDeviceInput ran earlier this + // frame (execution order -200) and stamped the press if it + // cancelled an armed placement ghost or order pick — that press + // belongs to the gesture, not to the menu. P never cancels a + // gesture, so it needs no such check. + if (escape && !pause + && _input != null && _input.LastGestureCancelFrame == Time.frameCount) + { + return; + } + + // The terminal modals (result / network panels) own the screen; + // the pause menu does not stack on top of them. + if (_matchFrame != null && _matchFrame.ModalOpen) return; + + OpenMenu(); + } + + private void OpenMenu() + { + _menuOpen = true; + _pausedByMenu = false; + // Only a running LOCAL match is paused (a relay kernel cannot + // pause independently of its peer — PauseMatch would log an + // error, so it is not even called). The menu itself stays fully + // usable in a relay match; it just does not stop the clock. + if (_runner != null && !_runner.IsRelayMatch && _runner.IsRunning) + { + _pausedByMenu = _runner.PauseMatch(); + } + AudioServiceLocator.Play2D(SoundEventId.UI_Click); + } + + /// Closes the menu and resumes the clock if — and only if — this menu paused it. + private void CloseMenu(bool playClick) + { + _menuOpen = false; + if (_pausedByMenu) + { + _pausedByMenu = false; + if (_runner != null && !_runner.IsRunning) + { + _runner.StartMatch(); + } + } + if (playClick) AudioServiceLocator.Play2D(SoundEventId.UI_Click); + } + + private void OnGUI() + { + if (!_menuOpen) return; + + EnsureStyles(); + + float scale = Mathf.Max(1f, _uiScale); + Matrix4x4 previousMatrix = GUI.matrix; + GUI.matrix = Matrix4x4.Scale(new Vector3(scale, scale, 1f)); + + Rect rect = CenteredRect(250f); + GUI.Box(rect, GUIContent.none, HudChrome.OpaquePanelStyle); + GUILayout.BeginArea(rect); + GUILayout.Space(HudChrome.OpaquePanelStyle.padding.top); + GUILayout.Label("PAUSE", _headlineStyle); + GUILayout.Label( + _runner != null && _runner.IsRelayMatch + ? "Netzpartie — die Simulation läuft im Hintergrund weiter." + : "Die Simulation steht — ESC setzt fort.", + _bodyStyle); + GUILayout.Space(10f); + if (GUILayout.Button("Fortsetzen (ESC)", _buttonStyle, GUILayout.Height(34f))) + { + CloseMenu(playClick: true); + } + if (GUILayout.Button("Zum Hauptmenü", _buttonStyle, GUILayout.Height(30f))) + { + AudioServiceLocator.Play2D(SoundEventId.UI_Click); + // No resume: the menu leaves the match for good, and + // ReturnToMenu keeps it paused for the next "Neues Spiel". + _menuOpen = false; + _pausedByMenu = false; + if (_menu != null) _menu.ReturnToMenu(); + } + if (GUILayout.Button("Spiel beenden", _buttonStyle, GUILayout.Height(30f))) + { + AudioServiceLocator.Play2D(SoundEventId.UI_Click); + if (_menu != null) _menu.Quit(); + } + GUILayout.Space(6f); + GUILayout.Label("Einstellungen (Ton, Bild, Auflösung) gibt es im Hauptmenü.", _bodyStyle); + GUILayout.EndArea(); + + GUI.matrix = previousMatrix; + } + + private Rect CenteredRect(float height) + { + float scale = Mathf.Max(1f, _uiScale); + float x = (Screen.width / scale - _panelWidth) * 0.5f; + float y = (Screen.height / scale - height) * 0.4f; + return new Rect(x, y, _panelWidth, height); + } + + private void EnsureStyles() + { + if (_headlineStyle == null) + { + _headlineStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 22, + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleCenter, + wordWrap = true + }; + } + if (_bodyStyle == null) + { + _bodyStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 12, + alignment = TextAnchor.MiddleCenter, + wordWrap = true + }; + } + if (_buttonStyle == null) + { + _buttonStyle = new GUIStyle(GUI.skin.button) { fontSize = 14 }; + } + } + } +} diff --git a/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs.meta b/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs.meta new file mode 100644 index 0000000..3f498eb --- /dev/null +++ b/Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4839e6caa28240839b51760036ea05f0 \ No newline at end of file diff --git a/Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs b/Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs index 51b9443..dbb3642 100644 --- a/Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs +++ b/Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs @@ -69,6 +69,21 @@ namespace Nova.Presentation.UI /// the Builder actually walks into reach. /// /// + /// MODAL GATE (sprint 21.8): while + /// — published once per frame by PauseMenuHud, which aggregates every + /// modal surface (pause menu, result and network panels) — this + /// component's Update suspends ALL world gestures: no selection, no + /// orders, no hotkeys, no harvester escort into a stopped kernel, and no + /// click falling through a panel onto the unit behind it. The camera's + /// edge-pan strip is covered by re-publishing "pointer over HUD" + /// () instead of growing a second reader. + /// Any armed gesture (placement ghost, order pick) is disarmed when the + /// gate engages, so a modal never inherits one — and the ingress rebind + /// clears them too, so an armed ghost never survives into the next + /// match (#102). Pause/resume itself moved out of here: ESC/P and the + /// pause menu live in . + /// + /// /// World mapping (identical to UnitViewManager / FlowFieldDebugView / /// RtsCameraController): sim X -> Unity x, sim Y -> Unity z, ground /// plane at y = (0). Cell (gx, gy) covers the @@ -228,6 +243,16 @@ private enum PendingOrder /// public bool BuildZoneOverlayPinned => _buildZoneOverlayPinned; + /// + /// The frame () ESC last cancelled an + /// armed gesture here (placement ghost or order pick). PauseMenuHud + /// reads it to peel exactly one layer per press: this component runs + /// at -200, so its consumption is already stamped when the menu's + /// Update looks at the same ESC press — the gesture cancels first, + /// the menu opens on the NEXT press. + /// + public int LastGestureCancelFrame { get; private set; } = -1; + /// Definition the armed placement ghost currently carries. public ushort PlacementDefId => _placementDefId; @@ -419,7 +444,7 @@ private void Awake() _legend = "LMB click/drag select | RMB move — with an own producer building selected: set its rally point | S stop | " + "A attack enemy under cursor (else plain move; armed units auto-acquire visible in-range enemies, D-087) | " + - "H harvest nearest field | R return cargo | P pause/resume (local match only) | " + + "H harvest nearest field | R return cargo | ESC/P pause menu (clock stops in local matches only)\n" + "O build zone overlay on/off (shows on its own while a placement ghost is armed)\n" + "Build (build bar below or hotkey — a ghost follows the cursor; LMB place | RMB/ESC cancel): " + $"B {_buildingDefId} | Shift+B {_altBuildingDefId} | C {_storageDefId} | V {_vehicleFactoryDefId} | " + @@ -437,6 +462,26 @@ private void Update() if (!EnsureDispatcher()) return; if (_menu != null && _menu.IsMenuVisible) return; // the overlay owns every click + if (ModalSurfaceLink.Open) + { + // A modal surface (pause menu, result or network panel) owns + // the input: no selection, no orders, no hotkeys, no escort + // moves into a stopped kernel — and no click falling through + // the panel onto the world behind it. "Pointer over HUD" is + // published so the camera's edge-pan strip stops too, without + // a second reader. An in-flight drag or armed gesture dies + // here instead of resolving behind the panel. + HudPointerLink.Publish(true); + _dragActive = false; + if (_placementMode || _pendingOrder != PendingOrder.None) + { + _placementMode = false; + _pendingOrder = PendingOrder.None; + _lastCommandStatus = "Gesture cancelled — a modal surface owns the input"; + } + return; + } + Vector2 mouse = Input.mousePosition; UpdatePlacementHover(mouse); HandleBuildZoneOverlayToggle(); @@ -481,6 +526,13 @@ private bool EnsureDispatcher() // ClearSelection also drops the selected field (21.2): a rebinding // means a fresh match, and its ids belong to the old one. _selection.ClearSelection(); + // Armed gestures are input state tied to the OLD match's world: + // an armed placement ghost or order pick must never survive the + // ingress rebind into the next round (#102 — the ghost used to + // stay armed through "Hauptmenü" → "Neues Spiel"). + _placementMode = false; + _pendingOrder = PendingOrder.None; + _dragActive = false; return true; } @@ -541,8 +593,12 @@ private void HandleBuildZoneOverlayToggle() /// private void HandlePlacementModeInput(Vector2 mouse, bool shift) { - if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) + bool escape = Input.GetKeyDown(KeyCode.Escape); + if (escape || Input.GetMouseButtonDown(1)) { + // Stamp the ESC consumption: the pause menu peels one layer + // per press and must not open on this same press. + if (escape) LastGestureCancelFrame = Time.frameCount; _placementMode = false; _lastCommandStatus = "Placement cancelled"; return; @@ -935,26 +991,11 @@ private void HandleOrders(Vector2 mouse) if (Input.GetKeyDown(KeyCode.R)) OrderReturnCargo(); - // Pause/resume toggles the kernel clock only — simulation state is - // untouched, so this needs no command. StartMatch after PauseMatch - // simply restarts the tick pump. - if (Input.GetKeyDown(KeyCode.P)) - { - if (_runner.IsRelayMatch) - { - _lastCommandStatus = "Pause/resume is unavailable in a relay match"; - } - else if (_runner.IsRunning) - { - _runner.PauseMatch(); - _lastCommandStatus = "Match paused (P resumes)"; - } - else - { - _runner.StartMatch(); - _lastCommandStatus = "Match resumed"; - } - } + // Pause/resume no longer lives here: ESC/P and the pause menu + // belong to PauseMenuHud, which pauses the kernel clock directly + // (no command involved). While its modal is up, the gate in + // Update keeps every hotkey above from firing into the stopped + // kernel. // Control groups 1-9 (sprint 09 §7): Ctrl/Cmd+Digit stores the // current selection, the bare digit recalls it. @@ -1150,8 +1191,11 @@ private bool IsPointerOverHud(Vector2 mouse) /// private void HandleOrderPickInput(Vector2 mouse) { - if (Input.GetKeyDown(KeyCode.Escape) || Input.GetMouseButtonDown(1)) + bool escape = Input.GetKeyDown(KeyCode.Escape); + if (escape || Input.GetMouseButtonDown(1)) { + // Same one-layer-per-press contract as the placement cancel. + if (escape) LastGestureCancelFrame = Time.frameCount; _pendingOrder = PendingOrder.None; _lastCommandStatus = "Order pick cancelled"; return; diff --git a/reports/v8.6.0/sprint-21/01-kimi-hud-state-audit.md b/reports/v8.6.0/sprint-21/01-kimi-hud-state-audit.md new file mode 100644 index 0000000..90f69f3 --- /dev/null +++ b/reports/v8.6.0/sprint-21/01-kimi-hud-state-audit.md @@ -0,0 +1,54 @@ +--- +Bericht: HUD-Zustandsaudit (Paket 21.8, #102 / #105 / #103) +Worker: Kimi K3 (cc-Backend, read-only), 2026-08-18 +Auftraggeber: Orchestrator +--- + +> **Hinweis zur Vollständigkeit:** Die Abschnitte 1 (Inventar) und 2 (Klassen- +> einteilung) fehlen — sie wurden beim Einsammeln der Worker-Ausgabe +> abgeschnitten (`| tail -30` beim Dispatch, Fehler des Orchestrators, nicht des +> Workers). Erhalten sind die Abschnitte 3 bis 5 samt Verdikt; sie tragen die +> Befunde, auf denen Paket 21.8 gebaut wird. + + +## 3. Klasse (b): Warum geht es heute gut, und wann kippt es? + +- **`PlacementGhostView`** — Heute gut, weil der Welt-Space-Ghost hinter dem opaken Menü-Hintergrund unsichtbar ist. Kippt zweifach: (i) ein Pausemenü, das die Welt (abgedunkelt) sichtbar lässt, zeigt den scharfen Ghost mitten im Modalzustand — der Armiert-Zustand `_placementMode` (RtsDeviceInput.cs:164) überlebt `ReturnToMenu` ungelöscht, weil nur die *Auswahl* beim Ingress-Rebind geräumt wird (RtsDeviceInput.cs:468); (ii) derselbe Überlebensweg trägt einen armierten Ghost sogar in die **nächste** Runde („Neues Spiel" → `RestartMatch`). Das ist die #102-Annahme in Reinform: der Riegel ist Eingabezustand, nicht Oberflächenzustand. +- **`ConstructionSiteMarkerView`** — Heute gut, weil Welt-Space (verdeckt) und der Puls (`Time.time`, :69) unsichtbar vor sich hin läuft. Kippt beim selben Szenario wie der Ghost (sichtbare Welt unter Pausemenü); bis dahin nur vergeudete Reads. Kein `IsRunning`-Riegel — unter P-Pause pulsiert es weiter, was heute harmlos ist. +- **`FogOfWarOverlayView`** — Heute gut, weil verdeckt und der Repaint an `fog.LastRecomputeTick` hängt: pausierter Kernel → kein neuer Tick → null Arbeit. Die Fog-Instanz-Wache (:96) heilt den Restart selbst. Kippt nur bei transparentem/ Welt zeigendem Overlay — und selbst dann wäre stehende Fog-Karte kosmetisch korrekt. +- **`CombatEffectController`** — Heute gut, weil Effekte unscaled ≤ 1,5 s leben und ohne Ticks keine neuen Events kommen. Kippt praktisch nicht; maximal spielt ein Todes-Sound in die Menü-Musik hinein, wenn `ReturnToMenu` exakt auf einen Kill fällt. +- **`GlutrinneBlockoutView`** — Heute gut, weil verdeckt und 0,5-s-Kadenz billig. Sein Docstring (:139-141) nennt das Menü sogar — deckt aber nur „noch keine Economy" ab, nicht „Economy überlebt pausiert": es stagt die Scherben hinter dem Menü weiter. Kippt nicht sichtbar; es ist die erste Komponente, deren Docstring die falsche Annahme bereits dokumentiert. +- **`FlowFieldDebugView`** — Heute gut, weil Gizmos nur in der Editor-Scene-View existieren. Kippt nie im Build. +- **`RtsDeviceInput` (OnGUI + Panel-Klicks)** — Heute gut, weil `Update` bei `IsMenuVisible` aussteigt und das Drag-Rechteck einen aktiven Drag braucht. Kippt an zwei Stellen: (i) Die modalen Panels von `MatchFrameHud` (Resultat, Pause) stehen **nicht** in `IsPointerOverHud` (RtsDeviceInput.cs:1102-1107 kennt nur Baukarte, Karte, Minimap) — ein Klick auf „Hauptmenü" läuft in `Update` zuerst durch `HandleSelection`/`SelectSingle` (:819, :1354) und **verändert die Auswahl hinter dem Panel**, bevor `OnGUI` den Button feuert. Der Ausstiegsklick selbst kann also die Auswahl erzeugen, die `CommandCardHud` dann über dem Menü zeichnet — #102 armiert sich teilweise selbst. (ii) **P-Pause hat gar keinen Riegel**: `IsMenuVisible` ist false, also laufen Selektion, sämtliche Hotkeys (S/A/H/R/Q/B/U…) und die Harvester-Eskorte (:634) in den Ingress des gestoppten Kernels weiter — Befehle stauen sich bis zum Resume. Genau hier bricht das geplante Pausemenü mit „derselben Anforderung" ein: für den Menü-Zustand existiert ein Signal, für den Pause-Zustand keines. + +## 4. Zustandssignale — was ist heute abfragbar? + +| Signal | Ort | Bedeutung | Lesbar ohne neue `MainMenuController`-Abhängigkeit? | +|---|---|---|---| +| `MainMenuController.IsMenuVisible` | MainMenuController.cs:138 | Menü-Oberfläche besitzt den Schirm | Nur innerhalb Nova.Presentation.UI (drei Komponenten verdrahtet bereits: RtsDeviceInput.cs:92, MatchFrameHud.cs:40, MusicDirector.cs:42). Für Nova.Presentation **unmöglich** — Rank-Gate, darum ist `_cameraRig` als `Behaviour` deklariert (:63-66). Sagt nichts über Pause. | +| `MatchBootstrap.IsMatchReady` | MatchBootstrap.cs:213 | „Match-Welt existiert" (Kernel + Systeme gebaut) | **Ja** — `MatchBootstrap` wird bereits aus Presentation.UI und Presentation.Maps referenziert. Bleibt bei Pause **true** — trennt „kein Match" von „pausiert", nicht „läuft" von „pausiert". | +| `MatchRunner.IsRunning` | MatchRunner.cs:157 (`Kernel != null && Kernel.IsRunning`) | Simulationsuhr läuft | **Ja** — bereits der häufigste Riegel. „Pausiert" und „kein Match" lesen beide false; die Unterscheidung liefert erst die Kombination mit `IsMatchReady` (bzw. `Entities != null`). | +| `Runner.PauseMatch()` / `StartMatch()` | MatchRunner.cs:314 / :296 | **Aktionen**, keine Signale | — | +| `_runner.Victory.IsDecided` | via MatchRunner | Matchende gelatcht | **Ja** (MatchFrameHud, MusicDirector, DebugHud lesen es bereits). | +| Abgeleitet: `IsMatchReady && !IsRunning` | MatchFrameHud.cs:94 macht genau das (via `victory != null`) | **„pausiert"** | **Ja** — der dritte Zustand ist heute schon ohne neues Signal ableitbar. | +| `HudPointerLink.PointerOverHud` | HudPointerLink.cs:24 | Zeiger über HUD (pro Frame publiziert) | **Ja** — statischer Kanal in Nova.Gameplay, von beiden Presentation-Assemblies lesbar, **der etablierte Präzedenzfall** für Signale ohne neue Assembly-Kante (mit `MinimapCameraLink`, MinimapCameraLink.cs:26). | +| `_runner.Entities/Economy/FogOfWar != null` | überall | „Welt existiert" | Ja — aber das ist exakt die gebrochene #102-Annahme: **„Welt existiert" ≠ „Match ist aktive Oberfläche"**. | + +Fazit: „kein Match" vs. „pausiert" ist über `IsMatchReady` + `IsRunning` sauber trennbar; „Oberfläche gehört einem Modal" (Menü, Pause, Resultat) existiert als Signal nur fürs Hauptmenü (`IsMenuVisible`) und ist rank-bedignt nicht überall lesbar. + +## 5. Empfehlung: ein einziger Riegel — und ja, die Wurzel statt des Flags + +**Die gemeinsame UI-Wurzel existiert bereits** und ist der bessere Riegel: der Szenengenerator legt **alle** In-Match-HUD-Komponenten auf **ein** GameObject „UI" (BootstrapSceneGenerator.cs:317: RtsDeviceInput, SelectionMarkerView, RallyFlagView, PlacementGhostView, ConstructionSiteMarkerView, BuildMenuHud, CommandCardHud, FogOfWarOverlayView, MinimapHud, HealthBarHud, MatchFrameHud, DebugHud). Damit: + +1. **Sichtbarkeit: `SetGameplayLayerActive` (MainMenuController.cs:783) schaltet die Wurzel** (`_gameplayHudRoot.SetActive(active)`) statt einer Komponentenliste. Setzer: weiterhin allein `MainMenuController`. Leser: **niemand** — die Deaktivierung *ist* der Riegel; OnGUI, LateUpdate und Hit-Tests der Kinder sterben mit. Das ist die einzige Lösung, die die berechtigte Sorge des Docstrings (:770-773) strukturell beantwortet: ein Katalog verrottet, eine Wurzel nicht — eine neue HUD-Komponente landet ohnehin im Generator auf diesem Objekt und ist ab dann abgedeckt, **ohne je namentlich genannt zu werden**. Der Kamera-Rig bleibt separater Toggle (er liegt auf „Main Camera", :101, nicht auf der Wurzel). Musik braucht nichts (`MusicDirector` ist bereits Klasse (a)), `UnityAudioService` bleibt passiv — Restklänge verklingen, das ist korrekt so. +2. **Eingabe im dritten Zustand (Pausemenü):** Die Wurzel deckt Menü und Matchende-mit-Menü ab; das Pausemenü will die Wurzel aber typischerweise **an** lassen (Welt/HUD darunter sichtbar) und nur die Weltgesten sperren. Dafür **ein** Flag mit der Semantik „eine modale Oberfläche besitzt die Eingabe" — *nicht* „Match läuft nicht". Konkret nach dem HudPointerLink-Vorbild: ein statischer Kanal in Nova.Gameplay (z. B. `ModalSurfaceLink.Open`), der **pro Frame publiziert** wird (kein Latch mit Gedächtnis — ein hängengebliebenes `true` wäre ein Eingabe-Deadlock). Setzer: genau eine Stelle — die Komponente, die modale Panels zeichnet, heute `MatchFrameHud` (Resultat + Pause), morgen das Pausemenü; sie muss außerhalb der UI-Wurzel leben, damit sie im Menü-Zustand überhaupt publizieren kann (im Menü ist die Wurzel ohnehin aus — niemand liest). Leser: `RtsDeviceInput.Update` (ergänzt `IsMenuVisible` an :424 und behandelt Klicks wie HUD-Klicks — damit sterben auch die Klickdurchfälle auf „Hauptmenü"/„Fortsetzen") und **gratis** die Kamera: `RtsDeviceInput` publiziert bei offenem Modal einfach `HudPointerLink.Publish(true)` — der bestehende Kanal deckt den Rand-Pan ohne neuen Leser ab. Pause und „kein Match" bleiben dabei sauber getrennt: das Flag sagt „Modal offen", die Match-Zustände liest weiterhin, wer sie braucht, aus `IsMatchReady`/`IsRunning`. +3. **DebugHud — Absprache nötig (Einheitenstrang):** `DebugHud` liegt auf derselben Wurzel (:370). `DebugHud.cs` selbst muss **nicht** geändert werden — `_visible` und F3-Zustand überleben `SetActive`, das Verhalten ist identisch zum heutigen `_debugHud.enabled`-Toggle. Aber der Kontrollfluss über die fremde Komponente ändert sich (benannter Einzel-Toggle → Wurzel), und der Wurzel-Ansatz nimmt die Option, DebugHud künftig *über* dem Menü zu zeigen (Diagnose am Menü), ohne die Komponente umzuhängen. Das gehört in die Absprache, bevor `SetGameplayLayerActive` umgestellt wird. + +Bewusst **nicht** empfohlen: jeder Komponente einen `IsMenuVisible`-/`IsRunning`-Check zu verpassen. Das ist der Katalog, der mit der nächsten Komponente verrottet — 21.2 hat gerade zwei neue (FieldCard, Scherben-Staging) geliefert. + +STATUS: DONE +- Klasse (c) = #102-Mechanismus: BuildMenuHud, CommandCardHud, MinimapHud prüfen nur „Welt existiert" (`Entities`/`Economy`/`FogOfWar != null`); ReturnToMenu pausiert nur, also zeichnen und **klicken** sie über dem Menü (IMGUI liegt immer über UI Toolkit); Minimap-Klicks stellen zusätzlich einen Kamera-Sprung ein, der beim Matchstart ausgeführt wird (MinimapCameraLink.cs:103). +- Klasse (b)-Kritikalste: RtsDeviceInput — die modalen Panels (Resultat/Pause) stehen nicht in `IsPointerOverHud` (RtsDeviceInput.cs:1102), der Klick auf „Hauptmenü" selektiert hinter dem Panel und armiert die Karte über dem Menü selbst; P-Pause hat gar keinen Riegel, alle Hotkeys und die Harvester-Eskorte feuern in den gestoppten Kernel. +- Empfehlung: die bereits existierende UI-Wurzel (BootstrapSceneGenerator.cs:317) als einziger Sichtbarkeits-Riegel statt Komponentenkatalog, plus **ein** pro Frame publiziertes „Modal offen"-Flag nach HudPointerLink-Vorbild für Eingaben im Pause-Zustand; DebugHud liegt auf derselben Wurzel — Verhalten bleibt gleich, aber der Kontrollfluss über die Einheitenstrang-Komponente ändert sich: Absprache erforderlich. + +[exited with code 0] diff --git a/reports/v8.6.0/sprint-21/02-kimi-version-hud.md b/reports/v8.6.0/sprint-21/02-kimi-version-hud.md new file mode 100644 index 0000000..c1b9e85 --- /dev/null +++ b/reports/v8.6.0/sprint-21/02-kimi-version-hud.md @@ -0,0 +1,42 @@ +--- +Bericht: 02-kimi-version-hud (Sprint 21) +Worker: Kimi K3 (cc-Backend, --mode rw), 2026-08-18 +Auftraggeber: Orchestrator +--- + +> Hinweis: Der Anfang der Worker-Ausgabe wurde beim Einsammeln abgeschnitten +> (`| tail -30` beim Dispatch, Fehler des Orchestrators). Erhalten sind die +> Entscheidungen, das Testergebnis und das Verdikt. + +| `Assets/Tests/PlayMode/MainMenuTests.cs` | **Reparatur nötig:** `MenuDocument()` nutzte `FindAnyObjectByType()` — mit zwei UIDocuments in der Szene wäre das mehrdeutig; findet jetzt per GameObject-Name „MainMenu" | + +### Getroffene Entscheidungen + +1. **Eigenes UIDocument auf eigenem GameObject** statt Einklinken ins Menü: `MainMenuController.BuildTree()` ruft `root.Clear()` auf und würde das Badge löschen; die IMGUI-Schicht fällt unter #102. Das Badge teilt sich nur die PanelSettings mit dem Menü. +2. **`sortOrder = 1` in `Awake`** (Menü bleibt 0) — zwingend, sonst läge das Badge *unter* dem Vollbild-Key-Art und wäre im Menü unsichtbar. +3. **Editor zeigt immer `dev (Editor)`**, auch wenn ein Stempel von einem früheren Packaging-Lauf im Arbeitsbaum liegt (`Application.isEditor`-Zweig): Eine Editor-Session ist nicht dieser Commit. +4. **Dateiinhalt ist `$COMMIT`** aus den Skripten — exakt `git rev-parse --short HEAD`, plus `-dirty` bei schmutzigem Baum, konsistent mit Info.plist- und Archiv-Stempel derselben Skripte. +5. **Fehlende Datei → `dev`, nie ein Log** (try/catch wie das bestehende `BuildInfo.Load`). +6. **Optik** am Menü orientiert: Rajdhani-Regular, Body-Farbe `(0.88, 0.91, 0.95)`, Opazität 0.55, 12 px, 10/8 px Rand; Werte als `[SerializeField]`-Defaults auf der Komponente („the generator wires, it does not tune"). + +### Nicht prüfbar (kein Unity hier) + +- **Kompilieren:** Alle benutzten Symbole gegen Bestandscode gegengeprüft (`Label(string)`-Ctor + Objekt-Initializer wie `MainMenuController.cs:312`, `FontDefinition.FromFont`, `style.display.value`, `FindObjectsByType(FindObjectsInactive)`-Overload wie `MainMenuTests.cs:152`). `UIDocument.sortOrder` (get/set) ist aus der Unity-Doku, nicht gegen Projektnutzung verifiziert, weil bisher niemand es benutzt. +- **Szene nicht regeneriert:** `Bootstrap.unity` enthält das Badge erst nach „Tools/Project Nova/Create Bootstrap Scene". Bis dahin schlägt der neue PlayMode-Test fehl — mit lauter Anleitung, wie es die bestehenden Tests bei veralteter Szene auch tun. +- **Packaging-Läufe** nicht ausgeführt (nur `bash -n`). +- **Rajdhani-Glyphe `·` (U+00B7)** nicht verifiziert — bei Fehlen greift der Theme-Font; Zeichen steht exakt so in der Vorgabe. +- **Visuelle Überlappung** mit Minimap/Build-Bar nicht gesehen (10/8 px Rand, gedämpft). + +### Befund außerhalb des Auftrags + +Es existiert bereits ein paralleler Mechanismus: `BuildCommitStamp` (Nova.Editor, `IPreprocessBuildWithReport`) stempelt `NovaBuildCommit.txt` bei **jedem** Player-Build, `BuildInfo.Commit` (Nova.Gameplay.Match) liest ihn (Lobby, D-094). Der Auftrag verlangte ausdrücklich `BuildInfo.txt` aus den Packaging-Skripten — so gebaut, Bestand unangetastet. Konsequenz, die ihr kennen solltet: Ein Build über die Unity-GUI (ohne Skripte) zeigt `dev`, obwohl `NovaBuildCommit.txt` frisch gestempelt wäre; und ein nach einem Packaging-Lauf im Arbeitsbaum liegender `BuildInfo.txt`-Stempel würde in einem späteren GUI-Build dessen alten Hash zeigen. Alternative wäre gewesen, das Badge auf `BuildInfo.Commit` lesen zu lassen — nicht der Auftrag, daher nur als Hinweis. + +STATUS: DONE +- VersionBadge als eigenes UIDocument/GameObject umgesetzt: immer sichtbar (Menü + Match), unten links, gedämpft, `PickingMode.Ignore`, String einmalig in `Start()` — Format Editor `v0.21.0 · dev (Editor)`, Build `v0.21.0 · ` aus `Resources/BuildInfo.txt`, fehlend → `dev` ohne Log. +- `bundleVersion` auf `0.21.0` gesetzt; beide Packaging-Skripte stempeln `BuildInfo.txt` vor dem Unity-Aufruf (`$COMMIT` inkl. `-dirty`); Datei + Meta sind git-ignoriert. +- `MainMenuTests.MenuDocument()` repariert (zwei UIDocuments machten `FindAnyObjectByType` mehrdeutig); neuer `VersionBadgeTests`-PlayMode-Test pinnt Format, Nicht-Klickbarkeit, Dokument-Unabhängigkeit und Sortierung. +- Nicht verifizierbar ohne Unity: Kompilieren, Szenen-Regeneration (Badge fehlt in `Bootstrap.unity`, bis der Generator läuft — neuer Test schlägt bis dahin bewusst laut fehl), `UIDocument.sortOrder`-Setter zur Laufzeit, Rajdhani-Glyphe `·`, optisches Ergebnis. +- Nebenbefund: Mit `BuildCommitStamp`→`NovaBuildCommit.txt`→`BuildInfo.Commit` (D-094) existiert ein zweiter, build-hook-basierter Stempelmechanismus; GUI-Builds ohne Skripte zeigen im Badge `dev`. +/Users/denniswestermann/.claude/skills/kimi/scripts/kimi-agent.sh: line 270: hen: command not found + +[exited with code 0] diff --git a/reports/v8.6.0/sprint-21/03-kimi-buildzone-overlay.md b/reports/v8.6.0/sprint-21/03-kimi-buildzone-overlay.md new file mode 100644 index 0000000..57826b7 --- /dev/null +++ b/reports/v8.6.0/sprint-21/03-kimi-buildzone-overlay.md @@ -0,0 +1,42 @@ +--- +Bericht: 03-kimi-buildzone-overlay (Sprint 21) +Worker: Kimi K3 (cc-Backend, --mode rw), 2026-08-18 +Auftraggeber: Orchestrator +--- + +> Hinweis: Der Anfang der Worker-Ausgabe wurde beim Einsammeln abgeschnitten +> (`| tail -30` beim Dispatch, Fehler des Orchestrators). Erhalten sind die +> Entscheidungen, das Testergebnis und das Verdikt. + +| `Assets/_Project/Scripts/Simulation/Construction/ConstructionSystem.cs` | **Minimal:** `IsInsideBuildInfluence` und `HasMinimumBuildingSpacing` von `private` auf `public`, plus Docstrings. Keine Verhaltensänderung — die Methodenkörper sind Byte-identisch. | +| `Assets/_Project/Scripts/Presentation/UI/RtsDeviceInput.cs` | O-Taste als Toggle (`BuildZoneOverlayPinned`, reiner View-State), Handler in `Update()` (greift auch während Platzierung/Pick-Modus), Hilfetext-Legende ergänzt. | +| `Assets/_Project/Editor/BootstrapSceneGenerator.cs` | Ein Block (7 Zeilen) in `CreateUiObject`, direkt hinter der `PlacementGhostView`-Verdrahtung — rebase-freundlich. | +| `Assets/Tests/EditMode/Simulation/BuildZoneOverlayQueryTests.cs` (+`.meta`) | **Neu.** Zwei Tests, die den Overlay-Vertrag pinnen. | + +### Getroffene Entscheidungen + +1. **Die Regel wird abgefragt, nicht nachgebaut.** Jeder Texel ist die Antwort von `ConstructionSystem.IsInsideBuildInfluence` bzw. `HasMinimumBuildingSpacing` für einen 3×3-Footprint-Ursprung auf dieser Zelle — exakt die beiden Reads, die `ValidatePlacement` selbst konsumiert. Kein Radius, keine Ankerliste im Overlay. Wenn D-108 die Ankerliste öffnet, folgt das Bild von allein. +2. **Drei Zustände:** ausserhalb der Zone = kein Tint; innerhalb + Abstand gewahrt = Grün (Alpha 26); innerhalb + Mindestabstand verletzt = Orange (Alpha 44). Genau die Unterscheidung „innerhalb und trotzdem gesperrt“, die der Testbericht vermisste. Terrain-Begehbarkeit und Feldabstände werden bewusst **nicht** gemalt (Feldabstand ist rollenabhängig — die Refinery invertiert ihn; der Ghost liefert das Vollverdikt am Cursor). +3. **Sichtbarkeit:** automatisch während `PlacementModeActive`, zusätzlich per **O** umschaltbar (O war frei: B/C/V/T/G/F/Y Gebäude, Q/U/N/E/D Einheiten, S/A/H/R/P Befehle, Z/X/Leertaste Kamera, F3–F5 Debug). Der Toggle sitzt in `Update()`, nicht in `HandleOrders`, damit er auch im Platzierungsmodus lebt. +4. **Performance:** Repaint-Kadenz 4 Hz nur solange sichtbar (Bauzustand ändert sich nur auf Tick-Events), Sofort-Repaint beim Einblenden; `FilterMode.Point`, damit Grün/Orange nicht zu einem bedeutungslosen Drittton verschwimmen. Höhe 0.05: über Fog (0.04), unter den Markern (0.06+). +5. **Kartenrand:** Ursprungszellen, deren Footprint die Karte verlassen würde, bleiben leer (Kartengeometrie über die öffentlichen Konstanten, nicht die Zonenregel). +6. **Teststrategie:** Der EditMode-Test pinnt nur die *Relation* (beide Reads sind notwendig für `Applied`; das Paar unterscheidet „draussen“ von „drin, aber gesperrt“) — nie Radiuswerte oder Ankerrollen, damit er D-108 unverändert übersteht. Verifiziert habe ich ihn über eine **transiente** Kopie in der .NET-Spiegel-Lane (kompiliert, 2/2 grün, danach entfernt — `tools/` ist im Enddiff unberührt). + +### Testergebnis + +**725/725 grün** (`dotnet test tools/Nova.SimRunner.Tests`), davon 0 Fehler, 0 übersprungen. Die „723“ aus dem Auftrag ist veraltet: die Baseline auf HEAD (9281341) zählt bereits **725** — die zwei Kapazitätstests aus 21.1/#92 kamen mit Merge #100 dazu. Gegenprobe auf jungfräulichem HEAD in einem temporären Worktree bestätigt: 725 vorher = 725 nachher, keine Regression. Der mitlaufende `PresentationSourceBoundaryTests`-Scan akzeptiert die neue View-Datei. + +### Nicht prüfbar + +- **Unity-Kompilierung** der Präsentations- und Editor-Dateien sowie der EditMode-Testdatei (kein Unity hier). Abgemildert: sämtliche verwendeten Symbole/Signatures sind aus funktionierenden Geschwisterdateien gespiegelt (`FogOfWarOverlayView`, `PlacementGhostView`, `ConstructionSystemTests`), asmdef-Referenzen reichen aus, und der Test wurde in der identischen .NET-Quell-Lane tatsächlich kompiliert und ausgeführt. +- **Optik** (Farbwerte, Höhe, Lesbarkeit im laufenden Spiel) — Werte sind SerializeField-Defaults und im Inspector nachjustierbar. +- `./.dotnet/dotnet` existiert im Worktree nicht (untracked SDK); verwendet wurde das gepinnte SDK **8.0.318** aus dem Haupt-Checkout — exakt die Version, die `global.json` verlangt. + +STATUS: DONE +- Overlay fragt ausschliesslich die beiden Sim-Reads ab (kein Regel-Nachbau); D-108-Ankeränderung erbt es gratis; ConstructionSystem-Diff ist reine Sichtbarkeit + Docstrings, Körper unverändert. +- Testgate grün: 725/725, Baseline-Vergleich auf sauberem HEAD bestätigt keine Regression („723“ im Auftrag war um die zwei 21.1-Tests veraltet). +- Zwei Zustände unterscheidbar gemalt (Grün = baubar, Orange = in der Zone, aber Mindestabstand verletzt); Sichtbarkeit: Platzierungsmodus + O-Toggle, Legende ergänzt, Szene mit einem 7-Zeilen-Block verdrahtet. +- Nicht verifizierbar blieben Unity-Kompilierung der UI-/EditMode-Dateien und das visuelle Ergebnis — beides oben transparent gemacht. +/Users/denniswestermann/.claude/skills/kimi/scripts/kimi-agent.sh: line 270: hen: command not found + +[exited with code 0] diff --git a/reports/v8.6.0/sprint-21/04-kimi-anchor-rule.md b/reports/v8.6.0/sprint-21/04-kimi-anchor-rule.md new file mode 100644 index 0000000..f8d8468 --- /dev/null +++ b/reports/v8.6.0/sprint-21/04-kimi-anchor-rule.md @@ -0,0 +1,42 @@ +--- +Bericht: 04-kimi-anchor-rule (Sprint 21) +Worker: Kimi K3 (cc-Backend, --mode rw), 2026-08-18 +Auftraggeber: Orchestrator +--- + +> Hinweis: Der Anfang der Worker-Ausgabe wurde beim Einsammeln abgeschnitten +> (`| tail -30` beim Dispatch, Fehler des Orchestrators). Erhalten sind die +> Entscheidungen, das Testergebnis und das Verdikt. + +2. **`Assets/Tests/EditMode/Simulation/ConstructionSystemTests.cs`** — neuer Test `ValidatePlacement_EveryCompletedBuildingExtendsTheZone_ItsSiteDoesNot`. +3. **`tools/Nova.SimRunner.Tests/ConstructionSystemTests.cs`** — derselbe neue Test (gespiegelte .NET-Lane). + +**Neue Regel in einem Satz:** Jedes eigene, lebende, fertiggestellte Gebäude ist ein Bauanker und schiebt die Bauzone um seinen eigenen Radius (Footprint-Distanz ≤ 8) weiter — Baustellen niemals. + +## Testergebnisse + +- **Vor der Änderung (Baseline, via `git stash` hergestellt):** 725/725 grün. +- **Nach der Änderung:** **726/726 grün** — keine roten Tests, die Liste ist leer. Es gab also nichts einzuordnen (keine Baseline-Bewegung, kein echter Fehler). +- **Diskriminierungsnachweis:** Der neue Test wurde einmal gegen die *alte* Produktionsregel laufen gelassen (Produktionsdatei allein gestasht, Tests drin gelassen) und schlägt dort exakt fehl: `Expected: Applied / But was: RejectedInvalidTarget` — er pinnt also genau die Regeländerung, nichts Beliebiges. + +## Einordnung einzelner erwarteter, aber ausgebliebener Rottöne + +- **`CanonicalAiOutcomeTests`** (pinnt Tick 2726 / `0x10B83E94F86F2E55`): **blieb grün.** Die kanonische KI-Partie versucht nie eine Platzierung, deren Validierungsausgang unter der neuen Regel kippt — der gepinnte Ausgang bewegt sich nicht. Die im Auftrag erwartete Bewegung trat nicht ein; ein Baseline-Neusetzungs-PR ist nach dieser Suite nicht nötig. +- **`RulesHash64`: hat sich NICHT bewegt.** Der Hash wird in `MatchFingerprint.ComputeRulesHash64` ausschließlich aus numerischen Regelkonstanten gebaut (u. a. `BuildInfluenceRadiusCells`); die Anker-Rollenliste war nie ein gehashtes Feld. Da `Simulation/Replays/` für mich eingefroren ist, habe ich keine Revision angefasst. Falls die Regelidentität die Ankerregel künftig abbilden soll, braucht es eine `RulesRevisionV4` mit neuem Hash-Feld — das ist eine Entscheidung außerhalb meines Schreibbereichs und ich melde sie hiermit zurück. +- **`BuildZoneCapacityTests`** (pinnt 15 Kraftwerke): grün — der Scan ist auf die HQ-Startzone begrenzt und Power war bereits Ankerrolle; identische Platzierungsmenge. +- **Bestehende Tests angepasst:** keiner. Kein bestehender Test schrieb die alte Dreierliste fest (der Einfluss-Test `..._AtDistanceEight` pinnt nur own/living/completed/Distanz-8 sowie Feind/Tot/Baustelle — alles weiterhin wahr). Die Dreierliste stand nur in den Docstrings. Neu hinzugekommen ist ein Verhaltenstest (Kategorie „echte Verhaltensannahme", kein Hash-Pin). + +## Was ich nicht prüfen konnte + +- Die Unity-EditMode-Lane läuft in dieser Umgebung nicht (kein Unity); die gespiegelte Datei wurde textidentisch synchronisiert — Unity-CI muss sie bestätigen. +- Der `IsActiveSite`-Guard in `IsInsideBuildInfluence` ist strukturell defensiv: `_buildings` enthält im Normalfluss nur fertige Placements (`CompleteSite` deaktiviert die Baustelle vor dem Anlegen des Placements), die Prüfung kann derzeit nicht feuern — sie dokumentiert die Regel explizit, wie beauftragt. +- Ob der Auftraggeber `RulesHash64` trotz unveränderter Konstanten bewegt haben will (s. o.) — das erfordert einen Eingriff in eingefrorenen Bereich. + +STATUS: DONE +- Regel umgesetzt: jedes eigene, lebende, fertiggestellte Gebäude ist Bauanker; Baustellen explizit ausgeschlossen (`IsActiveSite`); Docstrings auf den geltenden Stand. +- 726/726 Tests grün (Baseline vorher 725/725); null rote Tests — die erwartete Baseline-/Pin-Bewegung trat nicht ein (KI-Ausgang und RulesHash64 unverändert, da konstantenbasiert gehasht). +- Neuer Test `ValidatePlacement_EveryCompletedBuildingExtendsTheZone_ItsSiteDoesNot` in beiden Lanes; gegen die alte Regel nachweislich rot (Applied vs. RejectedInvalidTarget). +- Keine Baseline-, Pin-, CHANGELOG-, docs- oder Frozen-Area-Datei angefasst; Rückfrage an den Orchestrator: RulesHash64-Revision (V4) für die Ankerregel gewünscht? +/Users/denniswestermann/.claude/skills/kimi/scripts/kimi-agent.sh: line 270: hen: command not found + +[exited with code 0] diff --git a/reports/v8.6.0/sprint-21/05-kimi-pause-and-gate.md b/reports/v8.6.0/sprint-21/05-kimi-pause-and-gate.md new file mode 100644 index 0000000..bb0b95a --- /dev/null +++ b/reports/v8.6.0/sprint-21/05-kimi-pause-and-gate.md @@ -0,0 +1,58 @@ +--- +Bericht: 05-kimi-pause-and-gate (Sprint 21) +Worker: Kimi K3 (cc-Backend, --mode rw), 2026-08-18 +Auftraggeber: Orchestrator +--- + +> Hinweis: Der Anfang der Worker-Ausgabe wurde beim Einsammeln abgeschnitten +> (`| tail -30` beim Dispatch, Fehler des Orchestrators). Erhalten sind die +> Entscheidungen, das Testergebnis und das Verdikt. + +# Bericht — Paket 21.8: Pausemenü (#105) und der Eingabe-Riegel (#102) + +## Dateiliste + +| Datei | Änderung | +|---|---| +| `Assets/_Project/Scripts/Gameplay/UI/ModalSurfaceLink.cs` (+ `.meta`) | **Neu.** Statischer Kanal nach `HudPointerLink`-Vorbild: `Open` / `Publish(bool)` / `Reset()`. Semantik: „eine modale Oberfläche besitzt die Eingabe" — ausdrücklich nicht „Match läuft nicht". Pro Frame publiziert, kein Latch. | +| `Assets/_Project/Scripts/Presentation/UI/PauseMenuHud.cs` (+ `.meta`) | **Neu.** Das Pausemenü: ESC/P öffnet und schließt, hält lokale Matches an (`MatchRunner.PauseMatch`, Relay wird gar nicht erst aufgerufen) und setzt nur fort, was es selbst angehalten hat. Einträge: **Fortsetzen**, **Zum Hauptmenü** (`MainMenuController.ReturnToMenu`), **Spiel beenden** (`MainMenuController.Quit`, jetzt `public`). **Einziger Setzer** von `ModalSurfaceLink` (aggregiert eigenen Zustand + `MatchFrameHud.ModalOpen`); `OnDisable` resettet den Kanal — die Wurzel-Abschaltung auf dem Weg ins Menü kann so nie ein hängendes `true` hinterlassen. Liegt auf der UI-Wurzel (Generator), die Welt bleibt darunter sichtbar. | +| `RtsDeviceInput.cs` | Modal-Gate in `Update` direkt hinter dem `IsMenuVisible`-Ausstieg; Gesture-Cleanup beim Ingress-Rebind; P-Block aus `HandleOrders` entfernt (Pause gehört jetzt PauseMenuHud); `LastGestureCancelFrame` für die ESC-Schichtung (Geste zuerst, Menü beim nächsten Druck — RtsDeviceInput läuft auf -200 zuerst); Legende aktualisiert. | +| `MatchFrameHud.cs` | `DrawPausePanel` entfernt (Pause-Oberfläche ist jetzt das Pausemenü; alle gestoppten-Kernel-Zustände haben weiterhin eine Oberfläche: Resultat, Netzwerk, Pausemenü). Neu: `ModalOpen`-Property, einmal pro Frame in `Update` via `ComputeModalState()` abgeleitet — exakt die bisherige OnGUI-Bedingung, Resultat + Netzwerk-Panels. OnGUI zeichnet aus dem einmal abgeleiteten Zustand. | +| `MainMenuController.cs` | `_debugHud`-Feld durch `_gameplayHudRoot` (GameObject) ersetzt; `SetGameplayLayerActive` schaltet jetzt **die Wurzel** plus separat das Kamera-Rig (liegt auf „Main Camera"). Awake-Fallback findet die Wurzel über `RtsDeviceInput` für Szenen aus before-root-Generationen. `Quit()` public. `ReturnToMenu` ruft `PauseMatch` nicht mehr bei Relay-Matches auf (der Weg „laufende Netzpartie verlassen" ist jetzt erreichbar; die Verweigerung würde sonst absichtlich einen Error loggen — Match tickt hinter dem Menü weiter bis zum nächsten Start, wie ein lokal pausiertes). | +| `BootstrapSceneGenerator.cs` | `CreateUiObject` legt `PauseMenuHud` auf die Wurzel und verdrahtet `_runner`/`_matchFrame`/`_input`; `CreateMainMenuObject` verdrahtet `_gameplayHudRoot` statt `_debugHud` und `pauseMenu._menu`. | +| `Assets/Tests/PlayMode/MainMenuTests.cs` | DebugHud-Assertions von `.enabled` auf `gameObject.activeInHierarchy` umgestellt (der Schalter ist jetzt die Wurzel, nicht die Komponente — alter Assert würde sonst fehlschlagen); veraltete „no pause menu"-Meldung korrigiert. | + +## Die drei Fehler aus Punkt 3 + +1. **Ausstiegsklick armiert #102 selbst:** Behoben durch das Gate, nicht durch eine Rect-Liste: `ModalSurfaceLink.Open` → `RtsDeviceInput.Update` steigt aus, bevor `HandleSelection`/`SelectSingle` laufen. Klicks auf „Hauptmenü"/„Fortsetzen" (Resultat-, Netzwerk-, Pause-Panel) selektieren nichts mehr hinter dem Panel; der Drag-State wird fallen gelassen. Der Kamera-Randscroll fällt gratis mit ab, weil das Gate `HudPointerLink.Publish(true)` publiziert. +2. **`_placementMode` überlebt den Menüwechsel:** Doppelt geräumt — (a) der Ingress-Rebind (`EnsureDispatcher`) löscht jetzt `_placementMode`, `_pendingOrder` und `_dragActive` zusammen mit der Auswahl, damit wandert kein Ghost in die nächste Runde; (b) das Gate disarmt armierte Gesten in dem Frame, in dem ein Modal aufgeht (mit Statusmeldung), damit kein Ghost armiert unter einem Panel schwebt. +3. **P-Taste ohne Riegel:** P/ESC sind aus `RtsDeviceInput` heraus in `PauseMenuHud` umgezogen. Pausiert heißt jetzt: Pausemenü offen → Kanal `true` → Selektion, sämtliche Hotkeys (S/A/H/R/Q/B/U…) und die Harvester-Eskorte feuern nicht mehr in den gestoppten Kernel. + +Dazu der strukturelle #102-Fix: `SetGameplayLayerActive(false)` schaltet die ganze Wurzel — BuildMenuHud, CommandCardHud und MinimapHud (Audit-Klasse (c)) können über dem Menü weder zeichnen noch klicken, ohne je namentlich katalogisiert worden zu sein. + +## „Einstellungen" — bewusst kein zweiter Dialog + +Die Einstellungsmaske des Hauptmenüs ist fest in dessen `_screen`-Baum gebaut (`ShowSettings` toggelt gegen das Haupt-Panel mit „Neues Spiel"; „Zurück" führt dorthin). Sie mitten im Match zu zeigen hieße: ganzer Menü-Screen inkl. Key Art über dem Spiel, `IsMenuVisible`-Semantik gebrochen — die Verrenkung, vor der der Auftrag warnt. Stattdessen: drei funktionierende Einträge plus ehrliche Hinweiszeile im Panel („Einstellungen (Ton, Bild, Auflösung) gibt es im Hauptmenü."). Ein Eintrag weniger, keine driftende Zweitmaske. + +## Testergebnis + +`dotnet test tools/Nova.SimRunner.Tests` (dotnet aus dem Haupt-Checkout; der Worktree hat kein `.dotnet`): **725/725 grün, 0 Fehler.** Der Auftrag nannte 723 — der Branch-Stand (9281341) trägt bereits zwei Tests mehr; meine Änderungen kompilieren ohnehin nicht in dieses Projekt hinein (es referenziert nur Core/Simulation/AI/Networking), die Oberfläche hat nichts bewegt. + +## Nicht prüfbar gewesen (ausdrücklich) + +- **Kein Unity-Lauf:** Keine Unity-Assembly kompiliert. Symbolnamen/Signaturen sind doppelt gegen die Bestandsdateien geprüft (`PauseMatch()`/`StartMatch()` liefern `bool` — wird genutzt bzw. ignoriert wie im Bestand; `HudChrome.OpaquePanelStyle` ist assembly-intern erreichbar), aber ein Tippfehler fiele hier nicht auf. +- **`Bootstrap.unity` ist NICHT regeneriert** (Maschinenausgabe, Unity nötig). Bis jemand `Tools/Project Nova/Create Bootstrap Scene` laufen lässt, enthält die committete Szene kein `PauseMenuHud` → kein Pausemenü und kein publizierter Riegel (Resultat-Panels zeichnen weiterhin, das Klickdurchfall-Problem bleibt in der alten Szene bestehen). Der Wurzel-Schalter heilt die alte Szene dagegen selbst (Awake-Fallback über `RtsDeviceInput`), sodass die angepassten `MainMenuTests` auch gegen die alte Szene korrekt sind. **Es gibt bewusst keinen neuen PlayMode-Test fürs Pausemenü** — er hinge an der regenerierten Szene und liefe hier auf ein falsches Rot. +- **PlayMode-Tests nicht ausgeführt** (brauchen Unity headless-with-graphics) — die Anpassung in `MainMenuTests.cs` ist nur am Mechanismus gespiegelt, nicht gelaufen. +- **Editor-Assembly** (`BootstrapSceneGenerator.cs`) ebenfalls unkompiliert geprüft. +- Reihenfolge-Annahme verifiziert am Bestand: `RtsDeviceInput` trägt `DefaultExecutionOrder(-200)`, läuft also vor `PauseMenuHud.Update` — die ESC-Schichtung baut darauf. Kanal-Latenz ist konstruktionsbedingt 1 Frame (wie HudPointerLink). +- `DebugHud.cs` unangetastet. Nachlese-Befund: nur `Awake`/`Update`/`OnGUI`, kein `Start`/`OnEnable`/`OnDisable` mit Seiteneffekten; `_visible` (F3) überlebt `SetActive` — der Wurzel-Schalter ist exakt verhaltensgleich zum alten `enabled`-Toggle. Nichts an den anderen Beitragenden zu melden. +- Kamera während des Pausemenüs: Pfeiltasten/Zoom/Rotation bleiben absichtlich bedienbar (Kernel steht, Karteninspektion im Pausezustand ist üblich); nur der Randscroll-Unfall ist gegaten. Falls unerwünscht, wäre das ein Folgepunkt. + +STATUS: DONE +- Eingabe-Riegel steht: `ModalSurfaceLink` (pro Frame, ein Setzer, OnDisable-Reset) gatet `RtsDeviceInput.Update` komplett — Selektion, Hotkeys und Harvester-Eskorte feuern nicht mehr in den gestoppten Kernel, und Klicks auf modale Panels selektieren nichts mehr dahinter (#102-Selbstarmierung tot). +- `_placementMode`/`_pendingOrder` überleben weder Modal-Öffnung noch Ingress-Rebind — der Bau-Ghost wandert nicht mehr ins Menü oder in die nächste Runde. +- Pausemenü (ESC/P) mit Fortsetzen / Zum Hauptmenü / Spiel beenden steht; „Einstellungen" ehrlich als Hinweis statt driftender Zweitmaske; `SetGameplayLayerActive` schaltet jetzt die UI-Wurzel (plus Kamera-Rig separat) — Cockpit liegt nicht mehr über dem Hauptmenü. +- Nicht prüfbar ohne Unity: Kompilierung der Unity-/Editor-Assemblies, PlayMode-Tests, und `Bootstrap.unity` muss regeneriert werden, sonst existieren Pausemenü und Riegel in der Szene schlicht nicht (Wurzel-Schalter heilt die alte Szene per Awake-Fallback). SimRunner: 725/725 grün. +/Users/denniswestermann/.claude/skills/kimi/scripts/kimi-agent.sh: line 270: hen: command not found + +[exited with code 127] From 01683756fa60ca197d2beebfe23bf44c86ed163a Mon Sep 17 00:00:00 2001 From: Dennis Westermann Date: Tue, 18 Aug 2026 14:45:26 +0200 Subject: [PATCH 2/2] chore(scene+tests): Szene fuer 21.8 neu erzeugen und die PlayMode-Lage nachziehen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bootstrap.unity neu erzeugt — deckt jetzt alle vier Generator-Aenderungen des Tages ab (21.2, Versionsanzeige, Baubereich-Overlay, Pausemenue). Geprueft: PauseMenuHud, VersionBadge und BuildZoneOverlayView sind in der Szene. Neuer PlayMode-Test PauseMenuTests pinnt die zwei Fallen, die heute wirklich zugeschnappt sind: dass das Pausemenue ueberhaupt in der committeten Szene landet (sie war einmal acht Tage stale, waehrend der Generator dreimal zog), und dass ModalSurfaceLink beim Weg ins Hauptmenue kein haengendes true hinterlaesst — das waere ein Eingabe-Deadlock ohne laufende Komponente, die ihn noch loesen koennte. FieldReservePickTests angepasst: er startet das Match direkt an MainMenuController vorbei, und seit dem Wurzel-Schalter ist RtsDeviceInput dabei inaktiv — kein Update, kein gebundener Dispatcher, Null-Referenz in jedem Pick-Pfad. Der Test schaltet die Wurzel jetzt selbst ein und behauptet vorher, dass sie aus ist, damit die Zeile ehrlich bleibt, falls der Schalter je woanders hinwandert. Das Produktverhalten ist richtig und bleibt ungeaendert; eine Null-Absicherung im Produktivcode haette echte Verdrahtungsfehler verschluckt. Nachweis: EditMode 605/605, PlayMode 12/13 — der eine rote ist NetworkPanel_ValidatesMasks..., auf main bereits rot (#110). Co-Authored-By: Claude Opus 5 --- .../Tests/PlayMode/FieldReservePickTests.cs | 25 +- Assets/Tests/PlayMode/PauseMenuTests.cs | 96 + Assets/Tests/PlayMode/PauseMenuTests.cs.meta | 2 + Assets/_Project/Scenes/Bootstrap.unity | 1544 +++++++++-------- 4 files changed, 916 insertions(+), 751 deletions(-) create mode 100644 Assets/Tests/PlayMode/PauseMenuTests.cs create mode 100644 Assets/Tests/PlayMode/PauseMenuTests.cs.meta diff --git a/Assets/Tests/PlayMode/FieldReservePickTests.cs b/Assets/Tests/PlayMode/FieldReservePickTests.cs index 1841222..f6b394c 100644 --- a/Assets/Tests/PlayMode/FieldReservePickTests.cs +++ b/Assets/Tests/PlayMode/FieldReservePickTests.cs @@ -33,13 +33,36 @@ public IEnumerator ClickOnStartField_SelectsTheField() bootstrap.StartGrayboxMatch(); Assert.IsTrue(bootstrap.IsMatchReady, "match did not start"); - // Two frames: let every Awake/Start and the first model rebuilds settle. + // Two frames: let every Awake/Start and the first model rebuilds + // settle. MainMenuController.Start is among them, and it is the + // one that matters below. yield return null; yield return null; MonoBehaviour input = FindByTypeName("RtsDeviceInput"); Assert.NotNull(input, "scene contains no RtsDeviceInput"); + // THE COCKPIT HAS TO BE SWITCHED ON, and this test has to do it + // itself. Since package 21.8 the whole HUD root is inactive while + // the main menu owns the screen (#102), and the thing that turns + // it back on is MainMenuController.StartMatch — which this test + // deliberately bypasses by driving MatchBootstrap directly. Left + // off, RtsDeviceInput never runs a single Update, never binds its + // dispatcher, and every pick path below dereferences null. + // + // The OFF assertion keeps this line honest: it must run AFTER the + // two frames above, because the switch-off happens in + // MainMenuController.Start, not during scene activation — asserted + // one frame earlier it reads the scene file's default and passes + // for the wrong reason. + Assert.IsFalse(input.gameObject.activeInHierarchy, + "the HUD root is expected to be off while the main menu owns the screen — if this " + + "fails, the menu/match switch moved and the SetActive below is papering over it"); + input.gameObject.SetActive(true); + + // One more frame so the freshly enabled input binds its dispatcher. + yield return null; + // The serialized scene predates the 21.2 field: a missing YAML // entry must materialise the C# default 2f — pin that assumption, // it is exactly the kind of silent zero a scene upgrade swallows. diff --git a/Assets/Tests/PlayMode/PauseMenuTests.cs b/Assets/Tests/PlayMode/PauseMenuTests.cs new file mode 100644 index 0000000..5b95b72 --- /dev/null +++ b/Assets/Tests/PlayMode/PauseMenuTests.cs @@ -0,0 +1,96 @@ +using System.Collections; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.TestTools; +using Nova.Gameplay; + +namespace Nova.PlayMode.Tests +{ + /// + /// The two traps of package 21.8, pinned where they actually bite. + /// + /// WHY THIS FILE NAMES THE TYPE AS A STRING: Nova.PlayMode.Tests + /// references Nova.Gameplay but NOT Nova.Presentation.UI, so + /// PauseMenuHud cannot be named as a type here — the same reason + /// MainMenuTests reaches for DebugHud that way. + /// ModalSurfaceLink IS reachable: it lives in Nova.Gameplay + /// precisely so both Presentation assemblies and this one can see it. + /// + /// + public sealed class PauseMenuTests + { + private const string ScenePath = "Assets/_Project/Scenes/Bootstrap.unity"; + private const string PauseMenuTypeName = "PauseMenuHud"; + private const string DebugHudTypeName = "DebugHud"; + + /// + /// The pause menu is IN THE SCENE, on the switched root, and the modal + /// channel is clean while the main menu owns the screen. + /// + /// THE SCENE IS THE POINT OF THIS TEST. Bootstrap.unity is machine + /// output that is committed, and it went stale once already: it sat + /// unchanged from 2026-08-08 while the generator moved three times, so + /// components wired only in the generator were simply absent from the + /// running game — code merged, CI green, nothing on screen. Without + /// this assertion the whole of 21.8 can ship and do nothing. + /// + /// + /// THE CLEAN CHANNEL IS THE SECOND POINT. ModalSurfaceLink is a + /// per-frame verdict published by the pause menu, and the way to the + /// main menu switches the HUD root — writer included — OFF. A writer + /// that stopped publishing while its last word was true would + /// leave every world gesture suspended for the rest of the session: + /// no selection, no orders, no camera edge-pan, and no component still + /// running that could ever clear it. That is why the writer resets in + /// OnDisable, and this is the assertion that keeps it there. + /// + /// + [UnityTest] + public IEnumerator PauseMenu_IsWiredOntoTheHudRootAndLeavesNoStaleModalFlag() + { + yield return SceneManager.LoadSceneAsync(ScenePath, LoadSceneMode.Single); + yield return null; + yield return null; + + Behaviour pauseMenu = RequireBehaviour(PauseMenuTypeName, + "the UI object carries no pause menu, so ESC does nothing and a player cannot leave " + + "a running match (#105). The scene is machine output — run " + + "Tools/Project Nova/Create Bootstrap Scene after any change to " + + "BootstrapSceneGenerator.CreateUiObject."); + + Behaviour debugHud = RequireBehaviour(DebugHudTypeName, + "the UI object carries no debug HUD"); + + Assert.AreSame(debugHud.gameObject, pauseMenu.gameObject, + "the pause menu must live on the same GameObject as the rest of the cockpit: that " + + "root IS the menu/match switch (MainMenuController.SetGameplayLayerActive). A pause " + + "menu beside it would keep drawing over the main menu — which is exactly the defect " + + "(#102) this package exists to end."); + + Assert.IsFalse(pauseMenu.gameObject.activeInHierarchy, + "the HUD root must be OFF while the main menu owns the screen"); + + Assert.IsFalse(ModalSurfaceLink.Open, + "no modal may be claimed while the main menu is up. This is the deadlock guard: the " + + "channel is a per-frame verdict whose only writer sits on the root that was just " + + "switched off, so a last word of 'true' would suspend every world gesture for the " + + "rest of the session with nothing left running to clear it."); + } + + private static Behaviour RequireBehaviour(string typeName, string message) + { + // FindObjectsInactive.Include is load-bearing: the menu switches + // the HUD root off, and everything on it counts as inactive. + Behaviour[] all = Object.FindObjectsByType(FindObjectsInactive.Include); + for (int i = 0; i < all.Length; i++) + { + if (all[i].GetType().Name == typeName) return all[i]; + } + + Assert.Fail($"{message} (looked for a component named '{typeName}'). If it was renamed, " + + "this file has to follow — it cannot reference the type."); + return null; + } + } +} diff --git a/Assets/Tests/PlayMode/PauseMenuTests.cs.meta b/Assets/Tests/PlayMode/PauseMenuTests.cs.meta new file mode 100644 index 0000000..127e9d8 --- /dev/null +++ b/Assets/Tests/PlayMode/PauseMenuTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f1b0f5732f82436683fa1006703b5a46 \ No newline at end of file diff --git a/Assets/_Project/Scenes/Bootstrap.unity b/Assets/_Project/Scenes/Bootstrap.unity index 761ae59..0806275 100644 --- a/Assets/_Project/Scenes/Bootstrap.unity +++ b/Assets/_Project/Scenes/Bootstrap.unity @@ -119,7 +119,7 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &318030897 +--- !u!1 &128460811 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -127,101 +127,120 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 318030902} - - component: {fileID: 318030899} - - component: {fileID: 318030898} - - component: {fileID: 318030901} - - component: {fileID: 318030900} + - component: {fileID: 128460815} + - component: {fileID: 128460813} + - component: {fileID: 128460812} + - component: {fileID: 128460814} m_Layer: 0 - m_Name: Match - m_TagString: Untagged + m_Name: Main Camera + m_TagString: MainCamera m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &318030898 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 318030897} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0543a6c6c2d8cbd976ba484a58c2ddc5, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.MatchBootstrap - AutoStart: 0 - _seed: 16032251723485610609 - _mapWidth: 128 - _mapHeight: 128 - _entityCapacity: 1024 - UseDefinitionStats: 1 ---- !u!114 &318030899 +--- !u!114 &128460812 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 318030897} + m_GameObject: {fileID: 128460811} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3b9301a799fe64f85afe9906dc15bc39, type: 3} + m_Script: {fileID: 11500000, guid: 7e207447d841f8c67cd26bb722acdaf5, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.MatchRunner - _seed: 12345 + m_EditorClassIdentifier: Nova.Presentation::Nova.Presentation.RtsCameraController _mapWidth: 128 _mapHeight: 128 - _maxUnits: 2048 ---- !u!114 &318030900 -MonoBehaviour: + _panSpeed: 18 + _panSpeedHeightScale: 3 + _edgePanEnabled: 1 + _edgePanMargin: 12 + _zoomSpeed: 60 + _minHeight: 12 + _maxHeight: 90 + _pitchDegrees: 55 + _rotationSpeed: 90 + _middleDragDegreesPerPixel: 0.35 + _startFocusX: 8 + _startFocusZ: 6 + _startHeight: 42 + _startYawDegrees: 45 +--- !u!20 &128460813 +Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 318030897} + m_GameObject: {fileID: 128460811} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: bad3b0760ec204c94bb15e3918bbc921, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.UnitViewManager - _matchRunner: {fileID: 318030899} - _unitPrefab: {fileID: 0} - _combatEffects: {fileID: 318030901} - _assetMappings: {fileID: 11400000, guid: 54dfdf235acc54eecbef61df13a6b356, type: 2} - _interpolationSpeed: 25 - _viewerTeamOverride: -1 - _unknownPlayerColor: {r: 0.62, g: 0.62, b: 0.62, a: 1} - _damagedColor: {r: 0.42, g: 0.05, b: 0.05, a: 1} - _healthTintFloor: 0.25 ---- !u!114 &318030901 -MonoBehaviour: + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!81 &128460814 +AudioListener: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 318030897} + m_GameObject: {fileID: 128460811} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4cba4e364582443899c3490f303f72f, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.CombatFeedback.CombatEffectController ---- !u!4 &318030902 +--- !u!4 &128460815 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 318030897} + m_GameObject: {fileID: 128460811} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0.5, y: 0, z: 0, w: 0.8660254} + m_LocalPosition: {x: 64, y: 60, z: -20} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &595700764 +--- !u!1 &214746646 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -229,217 +248,315 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 595700767} - - component: {fileID: 595700766} - - component: {fileID: 595700765} + - component: {fileID: 214746661} + - component: {fileID: 214746660} + - component: {fileID: 214746659} + - component: {fileID: 214746658} + - component: {fileID: 214746657} + - component: {fileID: 214746656} + - component: {fileID: 214746655} + - component: {fileID: 214746654} + - component: {fileID: 214746653} + - component: {fileID: 214746652} + - component: {fileID: 214746651} + - component: {fileID: 214746650} + - component: {fileID: 214746649} + - component: {fileID: 214746648} + - component: {fileID: 214746647} m_Layer: 0 - m_Name: VersionBadge + m_Name: UI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &595700765 +--- !u!114 &214746647 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 595700764} + m_GameObject: {fileID: 214746646} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b5291f1c2dd449aea7a5874cd8d818bb, type: 3} + m_Script: {fileID: 11500000, guid: 743caecd4c5e6831d67dc968613cbfc6, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.VersionBadge - _document: {fileID: 595700766} - _font: {fileID: 12800000, guid: f028379ddea954641b86d6e9d5be7473, type: 3} - _fontSize: 12 - _marginLeft: 10 - _marginBottom: 8 - _textColor: {r: 0.88, g: 0.91, b: 0.95, a: 1} - _opacity: 0.55 ---- !u!114 &595700766 + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.DebugHud + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _visible: 0 + _uiScale: 1.5 + _fontSize: 13 +--- !u!114 &214746648 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 595700764} + m_GameObject: {fileID: 214746646} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Script: {fileID: 11500000, guid: 4839e6caa28240839b51760036ea05f0, type: 3} m_Name: - m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument - m_PanelSettings: {fileID: 11400000, guid: db0593cf705514e1aa6af7b41cca6743, type: 2} - m_ParentUI: {fileID: 0} - sourceAsset: {fileID: 0} - m_SortingOrder: 0 - m_Position: 0 - m_WorldSpaceSizeMode: 1 - m_WorldSpaceWidth: 1920 - m_WorldSpaceHeight: 1080 - m_PivotReferenceSize: 0 - m_Pivot: 0 - m_WorldSpaceCollider: {fileID: 0} ---- !u!4 &595700767 -Transform: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.PauseMenuHud + _runner: {fileID: 2042920973} + _menu: {fileID: 1629940937} + _matchFrame: {fileID: 214746649} + _input: {fileID: 214746660} + _uiScale: 1.5 + _panelWidth: 340 +--- !u!114 &214746649 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 595700764} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &712913255 -GameObject: + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9a8f5ae5c96d7491494f6d2974f32f3b, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MatchFrameHud + _runner: {fileID: 2042920973} + _bootstrap: {fileID: 2042920972} + _menu: {fileID: 1629940937} + _views: {fileID: 2042920974} + _uiScale: 1.5 + _panelWidth: 340 +--- !u!114 &214746650 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 712913258} - - component: {fileID: 712913257} - - component: {fileID: 712913256} - m_Layer: 0 - m_Name: IngameMusic - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &712913256 + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3fbdd2dfe068b4dc0a6f71442dc18c31, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.HealthBarHud + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _uiScale: 1.5 + _barWidth: 26 + _barHeight: 4 + _unitHeightOffset: 1.6 + _buildingHeightOffset: 3.4 +--- !u!114 &214746651 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 712913255} + m_GameObject: {fileID: 214746646} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: cdcf36c4668804ae6a8c2889ba4c9d33, type: 3} + m_Script: {fileID: 11500000, guid: 885e2e9fac8724df08b326c82e983510, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MusicDirector - _source: {fileID: 712913257} - _runner: {fileID: 318030899} - _bootstrap: {fileID: 318030898} - _menu: {fileID: 766640420} - _playlist: - - {fileID: 8300000, guid: 3c291cb887cd427f8fe213d0cc97e7ba, type: 3} - - {fileID: 8300000, guid: 159885d03b3d4674a15ae77a1275fd85, type: 3} - - {fileID: 8300000, guid: 8605bd0c749044cbaaa4a64ec990b5b5, type: 3} - _fadeSeconds: 1.25 - _trackGapSeconds: 2 ---- !u!82 &712913257 -AudioSource: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MinimapHud + _runner: {fileID: 2042920973} + _buildMenu: {fileID: 214746654} + _uiScale: 1.5 + _mapSize: 168 + _margin: 8 + _terrainColor: {r: 0.72, g: 0.6, b: 0.42, a: 1} + _exploredBrightness: 0.45 + _unexploredBrightness: 0.15 + _unitDotSize: 3 + _buildingDotSize: 4.5 + _radarPingColor: {r: 1, g: 0.55, b: 0.1, a: 1} +--- !u!114 &214746652 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 712913255} + m_GameObject: {fileID: 214746646} m_Enabled: 1 - serializedVersion: 4 - OutputAudioMixerGroup: {fileID: -161172014317909320, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} - m_audioClip: {fileID: 0} - m_Resource: {fileID: 0} - m_PlayOnAwake: 1 - m_Volume: 1 - m_Pitch: 1 - Loop: 0 - Mute: 0 - Spatialize: 0 - SpatializePostEffects: 0 - Priority: 128 - DopplerLevel: 1 - MinDistance: 1 - MaxDistance: 500 - Pan2D: 0 - rolloffMode: 0 - BypassEffects: 0 - BypassListenerEffects: 0 - BypassReverbZones: 0 - rolloffCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - - serializedVersion: 3 - time: 1 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - panLevelCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - spreadCustomCurve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - reverbZoneMixCustomCurve: + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 956e9df8ef76b491abc04e94045ee0d7, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.FogOfWarOverlayView + _runner: {fileID: 2042920973} + _unexploredAlpha: 0.85 + _exploredAlpha: 0.45 + _overlayHeight: 0.04 +--- !u!114 &214746653 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 79cf751f533e746e993958254d4d427e, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.CommandCardHud + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _buildMenu: {fileID: 214746654} + _bootstrap: {fileID: 2042920972} + _uiScale: 1.5 + _panelWidth: 236 + _panelMargin: 8 +--- !u!114 &214746654 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 22628296e159b4d5a8e9c701b125cee0, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.BuildMenuHud + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _uiScale: 1.5 + _buttonWidth: 108 + _buttonHeight: 62 + _barMargin: 8 + _hintMinSeconds: 6 + _hintMaxSeconds: 90 +--- !u!114 &214746655 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a2b97178f25d64f78897be61bbbb70dd, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.ConstructionSiteMarkerView + _runner: {fileID: 2042920973} + _markerHeight: 0.07 + _buildingColor: {r: 0.35, g: 0.9, b: 0.55, a: 0.55} + _pausedColor: {r: 1, g: 0.62, b: 0.15, a: 1} + _pulseSpeed: 4 +--- !u!114 &214746656 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60b14ad0059d4ecbb3bb0f16e8f28aaf, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.BuildZoneOverlayView + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _buildableColor: serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 ---- !u!4 &712913258 + rgba: 442164806 + _spacingBlockedColor: + serializedVersion: 2 + rgba: 740857599 + _overlayHeight: 0.05 + _repaintIntervalSeconds: 0.25 +--- !u!114 &214746657 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2cef43f34213c4155a30156e42d58fa4, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.PlacementGhostView + _input: {fileID: 214746660} + _ghostHeight: 0.09 + _validColor: {r: 0.3, g: 1, b: 0.4, a: 1} + _invalidColor: {r: 1, g: 0.3, b: 0.25, a: 1} +--- !u!114 &214746658 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f602abebcfdbc4649af799cbeddc3fcc, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.RallyFlagView + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _markerHeight: 0.07 + _flagSize: 1 + _lineWidth: 0.18 + _rallyColor: {r: 1, g: 0.82, b: 0.25, a: 1} +--- !u!114 &214746659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bc78ab4760d9d417bb2865e8edf60d3d, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.SelectionMarkerView + _runner: {fileID: 2042920973} + _input: {fileID: 214746660} + _views: {fileID: 2042920974} + _markerHeight: 0.06 + _unitMarkerSize: 2.4 + _buildingMarkerMargin: 0.4 + _selectionColor: {r: 0.35, g: 1, b: 0.4, a: 1} +--- !u!114 &214746660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 214746646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 39a0624d641e60a06323d84ab3edc209, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.RtsDeviceInput + _runner: {fileID: 2042920973} + _camera: {fileID: 128460813} + _buildMenu: {fileID: 214746654} + _commandCard: {fileID: 214746653} + _minimap: {fileID: 0} + _menu: {fileID: 0} + _groundPlaneY: 0 + _dragThresholdPixels: 8 + _pickRadiusWorld: 1.5 + _fieldPickRadiusWorld: 2 + _buildingDefId: 5 + _altBuildingDefId: 7 + _unitDefId: 2 + _altUnitDefId: 12 + _storageDefId: 6 + _vehicleFactoryDefId: 8 + _researchLabDefId: 9 + _radarDefId: 10 + _defensePlatformDefId: 11 + _refineryDefId: 4 + _builderDefId: 1 + _antiArmorDefId: 13 + _scoutDefId: 14 + _lightTankDefId: 15 + _battleTankDefId: 16 + _artilleryDefId: 17 +--- !u!4 &214746661 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 712913255} + m_GameObject: {fileID: 214746646} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -448,7 +565,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &766640419 +--- !u!1 &526112586 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -456,83 +573,45 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 766640424} - - component: {fileID: 766640423} - - component: {fileID: 766640422} - - component: {fileID: 766640421} - - component: {fileID: 766640420} + - component: {fileID: 526112589} + - component: {fileID: 526112588} + - component: {fileID: 526112587} m_Layer: 0 - m_Name: MainMenu + m_Name: IngameMusic m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &766640420 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766640419} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e77b731ae61b8471192a9ee5a7727fdb, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MainMenuController - _document: {fileID: 766640423} - _bootstrap: {fileID: 318030898} - _music: {fileID: 766640421} - _cameraRig: {fileID: 1208129614} - _debugHud: {fileID: 1729466583} - _keyArt: {fileID: 2800000, guid: 0f0988a5c327e451a990f97269d3ceee, type: 3} - _titleFont: {fileID: 12800000, guid: b95db3c2c8b9045b683866f321683fad, type: 3} - _bodyFont: {fileID: 12800000, guid: f028379ddea954641b86d6e9d5be7473, type: 3} - _title: HASHKRIEG - _titleFontSize: 92 - _titleLetterSpacing: 14 - _titleRuleWidth: 420 - _contentPadding: 120 - _buttonFontSize: 30 - _buttonWidth: 340 - _buttonHeight: 56 - _fieldFontSize: 17 - _fieldLabelWidth: 190 - _settingsWidth: 680 - _settingsScrollHeight: 480 - _titleColor: {r: 0.92, g: 0.96, b: 1, a: 1} - _accentColor: {r: 0.35, g: 0.78, b: 0.92, a: 1} - _bodyColor: {r: 0.88, g: 0.91, b: 0.95, a: 1} - _panelFill: {r: 0.05, g: 0.06, b: 0.08, a: 0.82} - _panelEdge: {r: 0.55, g: 0.62, b: 0.72, a: 0.5} - _buttonFill: {r: 0.08, g: 0.1, b: 0.13, a: 0.85} - _buttonHoverFill: {r: 0.16, g: 0.26, b: 0.32, a: 0.92} - _scrimColor: {r: 0.02, g: 0.03, b: 0.05, a: 0.42} - _disabledTextColor: {r: 0.52, g: 0.55, b: 0.6, a: 1} - _disabledEdgeColor: {r: 0.34, g: 0.38, b: 0.44, a: 0.45} - _saveIntervalSeconds: 0.35 ---- !u!114 &766640421 +--- !u!114 &526112587 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766640419} + m_GameObject: {fileID: 526112586} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: bccc1231bdd82465fa987e6ad5bb61e2, type: 3} + m_Script: {fileID: 11500000, guid: cdcf36c4668804ae6a8c2889ba4c9d33, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MenuMusicPlayer - _source: {fileID: 766640422} - _clip: {fileID: 8300000, guid: 85a05f77cb9f94a3684e85a7325e0184, type: 3} - _fadeOutSeconds: 1.25 ---- !u!82 &766640422 + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MusicDirector + _source: {fileID: 526112588} + _runner: {fileID: 2042920973} + _bootstrap: {fileID: 2042920972} + _menu: {fileID: 1629940937} + _playlist: + - {fileID: 8300000, guid: 3c291cb887cd427f8fe213d0cc97e7ba, type: 3} + - {fileID: 8300000, guid: 159885d03b3d4674a15ae77a1275fd85, type: 3} + - {fileID: 8300000, guid: 8605bd0c749044cbaaa4a64ec990b5b5, type: 3} + _fadeSeconds: 1.25 + _trackGapSeconds: 2 +--- !u!82 &526112588 AudioSource: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766640419} + m_GameObject: {fileID: 526112586} m_Enabled: 1 serializedVersion: 4 OutputAudioMixerGroup: {fileID: -161172014317909320, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} @@ -623,36 +702,13 @@ AudioSource: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 ---- !u!114 &766640423 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766640419} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} - m_Name: - m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument - m_PanelSettings: {fileID: 11400000, guid: db0593cf705514e1aa6af7b41cca6743, type: 2} - m_ParentUI: {fileID: 0} - sourceAsset: {fileID: 0} - m_SortingOrder: 0 - m_Position: 0 - m_WorldSpaceSizeMode: 1 - m_WorldSpaceWidth: 1920 - m_WorldSpaceHeight: 1080 - m_PivotReferenceSize: 0 - m_Pivot: 0 - m_WorldSpaceCollider: {fileID: 0} ---- !u!4 &766640424 +--- !u!4 &526112589 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 766640419} + m_GameObject: {fileID: 526112586} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -661,7 +717,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &796025941 +--- !u!1 &802321239 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -669,9 +725,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 796025944} - - component: {fileID: 796025943} - - component: {fileID: 796025942} + - component: {fileID: 802321242} + - component: {fileID: 802321241} + - component: {fileID: 802321240} m_Layer: 0 m_Name: Audio m_TagString: Untagged @@ -679,25 +735,25 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &796025942 +--- !u!114 &802321240 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 796025941} + m_GameObject: {fileID: 802321239} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 209209a86486d4b3a8bed38f9ae33c50, type: 3} m_Name: m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.SfxSettingsBridge ---- !u!114 &796025943 +--- !u!114 &802321241 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 796025941} + m_GameObject: {fileID: 802321239} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5dc2508a98b444101ad6cef0e77cec67, type: 3} @@ -721,13 +777,13 @@ MonoBehaviour: _weaponsGroup: {fileID: -2573851237862643720, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} _unitsGroup: {fileID: -3201287591632689540, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} _uiGroup: {fileID: 2761139959417956413, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} ---- !u!4 &796025944 +--- !u!4 &802321242 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 796025941} + m_GameObject: {fileID: 802321239} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -736,7 +792,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1208129612 +--- !u!1 &954524122 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -744,162 +800,41 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1208129616} - - component: {fileID: 1208129613} - - component: {fileID: 1208129614} - - component: {fileID: 1208129615} + - component: {fileID: 954524124} + - component: {fileID: 954524123} m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera + m_Name: Map + m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!20 &1208129613 -Camera: +--- !u!114 &954524123 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1208129612} + m_GameObject: {fileID: 954524122} m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 2 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_Iso: 200 - m_ShutterSpeed: 0.005 - m_Aperture: 16 - m_FocusDistance: 10 - m_FocalLength: 50 - m_BladeCount: 5 - m_Curvature: {x: 2, y: 11} - m_BarrelClipping: 0.25 - m_Anamorphism: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!114 &1208129614 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1208129612} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7e207447d841f8c67cd26bb722acdaf5, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation::Nova.Presentation.RtsCameraController - _mapWidth: 128 - _mapHeight: 128 - _panSpeed: 18 - _panSpeedHeightScale: 3 - _edgePanEnabled: 1 - _edgePanMargin: 12 - _zoomSpeed: 60 - _minHeight: 12 - _maxHeight: 90 - _pitchDegrees: 55 - _rotationSpeed: 90 - _middleDragDegreesPerPixel: 0.35 - _startFocusX: 8 - _startFocusZ: 6 - _startHeight: 42 - _startYawDegrees: 45 ---- !u!81 &1208129615 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1208129612} - m_Enabled: 1 ---- !u!4 &1208129616 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1208129612} - serializedVersion: 2 - m_LocalRotation: {x: 0.5, y: 0, z: 0, w: 0.8660254} - m_LocalPosition: {x: 64, y: 60, z: -20} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1239032164 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1239032166} - - component: {fileID: 1239032165} - m_Layer: 0 - m_Name: Map - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1239032165 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1239032164} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9b36a2ce3f98b46249dd0de03a577164, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation::Nova.Presentation.Maps.GlutrinneBlockoutView - _bootstrap: {fileID: 318030898} - _groundRenderer: {fileID: 1688916558} - _sandColor: {r: 0.72, g: 0.6, b: 0.42, a: 1} - _crystalColor: {r: 0.2, g: 0.85, b: 0.9, a: 1} - _edgeColor: {r: 0.28, g: 0.24, b: 0.2, a: 1} - _rockColor: {r: 0.36, g: 0.31, b: 0.26, a: 1} - _groundTextureTiling: {x: 32, y: 32} ---- !u!4 &1239032166 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1239032164} + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b36a2ce3f98b46249dd0de03a577164, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Presentation::Nova.Presentation.Maps.GlutrinneBlockoutView + _bootstrap: {fileID: 2042920972} + _groundRenderer: {fileID: 1162144974} + _sandColor: {r: 0.72, g: 0.6, b: 0.42, a: 1} + _crystalColor: {r: 0.2, g: 0.85, b: 0.9, a: 1} + _edgeColor: {r: 0.28, g: 0.24, b: 0.2, a: 1} + _rockColor: {r: 0.36, g: 0.31, b: 0.26, a: 1} + _groundTextureTiling: {x: 32, y: 32} +--- !u!4 &954524124 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 954524122} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -908,7 +843,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1688916557 +--- !u!1 &1162144973 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -916,10 +851,10 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1688916561} - - component: {fileID: 1688916560} - - component: {fileID: 1688916559} - - component: {fileID: 1688916558} + - component: {fileID: 1162144977} + - component: {fileID: 1162144976} + - component: {fileID: 1162144975} + - component: {fileID: 1162144974} m_Layer: 0 m_Name: Ground m_TagString: Untagged @@ -927,13 +862,13 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 2147483647 m_IsActive: 1 ---- !u!23 &1688916558 +--- !u!23 &1162144974 MeshRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1688916557} + m_GameObject: {fileID: 1162144973} m_Enabled: 1 m_CastShadows: 1 m_ReceiveShadows: 1 @@ -976,13 +911,13 @@ MeshRenderer: m_SortingOrder: 0 m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!64 &1688916559 +--- !u!64 &1162144975 MeshCollider: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1688916557} + m_GameObject: {fileID: 1162144973} m_Material: {fileID: 0} m_IncludeLayers: serializedVersion: 2 @@ -998,21 +933,21 @@ MeshCollider: m_Convex: 0 m_CookingOptions: 30 m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} ---- !u!33 &1688916560 +--- !u!33 &1162144976 MeshFilter: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1688916557} + m_GameObject: {fileID: 1162144973} m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1688916561 +--- !u!4 &1162144977 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1688916557} + m_GameObject: {fileID: 1162144973} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 64, y: 0, z: 64} @@ -1021,7 +956,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1729466582 +--- !u!1 &1309622895 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1029,271 +964,375 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1729466595} - - component: {fileID: 1729466584} - - component: {fileID: 1729466594} - - component: {fileID: 1729466593} - - component: {fileID: 1729466592} - - component: {fileID: 1729466591} - - component: {fileID: 1729466586} - - component: {fileID: 1729466585} - - component: {fileID: 1729466590} - - component: {fileID: 1729466589} - - component: {fileID: 1729466588} - - component: {fileID: 1729466587} - - component: {fileID: 1729466583} + - component: {fileID: 1309622898} + - component: {fileID: 1309622897} + - component: {fileID: 1309622896} m_Layer: 0 - m_Name: UI + m_Name: VersionBadge m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &1729466583 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 743caecd4c5e6831d67dc968613cbfc6, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.DebugHud - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _visible: 0 - _uiScale: 1.5 - _fontSize: 13 ---- !u!114 &1729466584 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 39a0624d641e60a06323d84ab3edc209, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.RtsDeviceInput - _runner: {fileID: 318030899} - _camera: {fileID: 1208129613} - _buildMenu: {fileID: 1729466586} - _commandCard: {fileID: 1729466585} - _minimap: {fileID: 0} - _menu: {fileID: 0} - _groundPlaneY: 0 - _dragThresholdPixels: 8 - _pickRadiusWorld: 1.5 - _buildingDefId: 5 - _altBuildingDefId: 7 - _unitDefId: 2 - _altUnitDefId: 12 - _storageDefId: 6 - _vehicleFactoryDefId: 8 - _researchLabDefId: 9 - _radarDefId: 10 - _defensePlatformDefId: 11 - _refineryDefId: 4 - _builderDefId: 1 - _antiArmorDefId: 13 - _scoutDefId: 14 - _lightTankDefId: 15 - _battleTankDefId: 16 - _artilleryDefId: 17 ---- !u!114 &1729466585 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 79cf751f533e746e993958254d4d427e, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.CommandCardHud - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _buildMenu: {fileID: 1729466586} - _uiScale: 1.5 - _panelWidth: 236 - _panelMargin: 8 ---- !u!114 &1729466586 +--- !u!114 &1309622896 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1309622895} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 22628296e159b4d5a8e9c701b125cee0, type: 3} + m_Script: {fileID: 11500000, guid: b5291f1c2dd449aea7a5874cd8d818bb, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.BuildMenuHud - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _uiScale: 1.5 - _buttonWidth: 108 - _buttonHeight: 62 - _barMargin: 8 - _hintMinSeconds: 6 - _hintMaxSeconds: 90 ---- !u!114 &1729466587 + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.VersionBadge + _document: {fileID: 1309622897} + _font: {fileID: 12800000, guid: f028379ddea954641b86d6e9d5be7473, type: 3} + _fontSize: 12 + _marginLeft: 10 + _marginBottom: 8 + _textColor: {r: 0.88, g: 0.91, b: 0.95, a: 1} + _opacity: 0.55 +--- !u!114 &1309622897 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1309622895} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 9a8f5ae5c96d7491494f6d2974f32f3b, type: 3} + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MatchFrameHud - _runner: {fileID: 318030899} - _bootstrap: {fileID: 318030898} - _menu: {fileID: 766640420} - _views: {fileID: 318030900} - _uiScale: 1.5 - _panelWidth: 340 ---- !u!114 &1729466588 -MonoBehaviour: + m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument + m_PanelSettings: {fileID: 11400000, guid: db0593cf705514e1aa6af7b41cca6743, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 0} + m_SortingOrder: 0 + m_Position: 0 + m_WorldSpaceSizeMode: 1 + m_WorldSpaceWidth: 1920 + m_WorldSpaceHeight: 1080 + m_PivotReferenceSize: 0 + m_Pivot: 0 + m_WorldSpaceCollider: {fileID: 0} +--- !u!4 &1309622898 +Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3fbdd2dfe068b4dc0a6f71442dc18c31, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.HealthBarHud - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _uiScale: 1.5 - _barWidth: 26 - _barHeight: 4 - _unitHeightOffset: 1.6 - _buildingHeightOffset: 3.4 ---- !u!114 &1729466589 -MonoBehaviour: + m_GameObject: {fileID: 1309622895} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1521561486 +GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 885e2e9fac8724df08b326c82e983510, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MinimapHud - _runner: {fileID: 318030899} - _buildMenu: {fileID: 1729466586} - _uiScale: 1.5 - _mapSize: 168 - _margin: 8 - _terrainColor: {r: 0.72, g: 0.6, b: 0.42, a: 1} - _exploredBrightness: 0.45 - _unexploredBrightness: 0.15 - _unitDotSize: 3 - _buildingDotSize: 4.5 - _radarPingColor: {r: 1, g: 0.55, b: 0.1, a: 1} ---- !u!114 &1729466590 -MonoBehaviour: + serializedVersion: 6 + m_Component: + - component: {fileID: 1521561488} + - component: {fileID: 1521561487} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1521561487 +Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1521561486} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 956e9df8ef76b491abc04e94045ee0d7, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.FogOfWarOverlayView - _runner: {fileID: 318030899} - _unexploredAlpha: 0.85 - _exploredAlpha: 0.45 - _overlayHeight: 0.04 ---- !u!114 &1729466591 + serializedVersion: 13 + m_Type: 1 + m_Color: {r: 1, g: 0.87, b: 0.7, a: 1} + m_Intensity: 1.15 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.85 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShapeRadius: 0.025 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &1521561488 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1521561486} + serializedVersion: 2 + m_LocalRotation: {x: 0.12450414, y: -0.8617815, z: 0.25527132, w: 0.42031893} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1629940936 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1629940941} + - component: {fileID: 1629940940} + - component: {fileID: 1629940939} + - component: {fileID: 1629940938} + - component: {fileID: 1629940937} + m_Layer: 0 + m_Name: MainMenu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1629940937 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1629940936} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a2b97178f25d64f78897be61bbbb70dd, type: 3} + m_Script: {fileID: 11500000, guid: e77b731ae61b8471192a9ee5a7727fdb, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.ConstructionSiteMarkerView - _runner: {fileID: 318030899} - _markerHeight: 0.07 - _buildingColor: {r: 0.35, g: 0.9, b: 0.55, a: 0.55} - _pausedColor: {r: 1, g: 0.62, b: 0.15, a: 1} - _pulseSpeed: 4 ---- !u!114 &1729466592 + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MainMenuController + _document: {fileID: 1629940940} + _bootstrap: {fileID: 2042920972} + _music: {fileID: 1629940938} + _cameraRig: {fileID: 128460812} + _gameplayHudRoot: {fileID: 214746646} + _keyArt: {fileID: 2800000, guid: 0f0988a5c327e451a990f97269d3ceee, type: 3} + _titleFont: {fileID: 12800000, guid: b95db3c2c8b9045b683866f321683fad, type: 3} + _bodyFont: {fileID: 12800000, guid: f028379ddea954641b86d6e9d5be7473, type: 3} + _title: HASHKRIEG + _titleFontSize: 92 + _titleLetterSpacing: 14 + _titleRuleWidth: 420 + _contentPadding: 120 + _buttonFontSize: 30 + _buttonWidth: 340 + _buttonHeight: 56 + _fieldFontSize: 17 + _fieldLabelWidth: 190 + _settingsWidth: 680 + _settingsScrollHeight: 480 + _titleColor: {r: 0.92, g: 0.96, b: 1, a: 1} + _accentColor: {r: 0.35, g: 0.78, b: 0.92, a: 1} + _bodyColor: {r: 0.88, g: 0.91, b: 0.95, a: 1} + _panelFill: {r: 0.05, g: 0.06, b: 0.08, a: 0.82} + _panelEdge: {r: 0.55, g: 0.62, b: 0.72, a: 0.5} + _buttonFill: {r: 0.08, g: 0.1, b: 0.13, a: 0.85} + _buttonHoverFill: {r: 0.16, g: 0.26, b: 0.32, a: 0.92} + _scrimColor: {r: 0.02, g: 0.03, b: 0.05, a: 0.42} + _disabledTextColor: {r: 0.52, g: 0.55, b: 0.6, a: 1} + _disabledEdgeColor: {r: 0.34, g: 0.38, b: 0.44, a: 0.45} + _saveIntervalSeconds: 0.35 +--- !u!114 &1629940938 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1629940936} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 2cef43f34213c4155a30156e42d58fa4, type: 3} + m_Script: {fileID: 11500000, guid: bccc1231bdd82465fa987e6ad5bb61e2, type: 3} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.PlacementGhostView - _input: {fileID: 1729466584} - _ghostHeight: 0.09 - _validColor: {r: 0.3, g: 1, b: 0.4, a: 1} - _invalidColor: {r: 1, g: 0.3, b: 0.25, a: 1} ---- !u!114 &1729466593 -MonoBehaviour: + m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.MenuMusicPlayer + _source: {fileID: 1629940939} + _clip: {fileID: 8300000, guid: 85a05f77cb9f94a3684e85a7325e0184, type: 3} + _fadeOutSeconds: 1.25 +--- !u!82 &1629940939 +AudioSource: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1629940936} m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f602abebcfdbc4649af799cbeddc3fcc, type: 3} - m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.RallyFlagView - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _markerHeight: 0.07 - _flagSize: 1 - _lineWidth: 0.18 - _rallyColor: {r: 1, g: 0.82, b: 0.25, a: 1} ---- !u!114 &1729466594 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: -161172014317909320, guid: 7831b040d10e94eb9bddf12783bcee5e, type: 2} + m_audioClip: {fileID: 0} + m_Resource: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &1629940940 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1629940936} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: bc78ab4760d9d417bb2865e8edf60d3d, type: 3} + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} m_Name: - m_EditorClassIdentifier: Nova.Presentation.UI::Nova.Presentation.UI.SelectionMarkerView - _runner: {fileID: 318030899} - _input: {fileID: 1729466584} - _views: {fileID: 318030900} - _markerHeight: 0.06 - _unitMarkerSize: 2.4 - _buildingMarkerMargin: 0.4 - _selectionColor: {r: 0.35, g: 1, b: 0.4, a: 1} ---- !u!4 &1729466595 + m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument + m_PanelSettings: {fileID: 11400000, guid: db0593cf705514e1aa6af7b41cca6743, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 0} + m_SortingOrder: 0 + m_Position: 0 + m_WorldSpaceSizeMode: 1 + m_WorldSpaceWidth: 1920 + m_WorldSpaceHeight: 1080 + m_PivotReferenceSize: 0 + m_Pivot: 0 + m_WorldSpaceCollider: {fileID: 0} +--- !u!4 &1629940941 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1729466582} + m_GameObject: {fileID: 1629940936} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -1302,7 +1341,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &2086866621 +--- !u!1 &2042920971 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1310,89 +1349,94 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 2086866623} - - component: {fileID: 2086866622} + - component: {fileID: 2042920976} + - component: {fileID: 2042920973} + - component: {fileID: 2042920972} + - component: {fileID: 2042920975} + - component: {fileID: 2042920974} m_Layer: 0 - m_Name: Directional Light + m_Name: Match m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!108 &2086866622 -Light: +--- !u!114 &2042920972 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2086866621} + m_GameObject: {fileID: 2042920971} m_Enabled: 1 - serializedVersion: 13 - m_Type: 1 - m_Color: {r: 1, g: 0.87, b: 0.7, a: 1} - m_Intensity: 1.15 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.802082 - m_CookieSize2D: {x: 0.5, y: 0.5} - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 0.85 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ForceVisible: 0 - m_ShapeRadius: 0.025 - m_ShadowAngle: 0 - m_LightUnit: 1 - m_LuxAtDistance: 1 - m_EnableSpotReflector: 1 ---- !u!4 &2086866623 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0543a6c6c2d8cbd976ba484a58c2ddc5, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.MatchBootstrap + AutoStart: 0 + _seed: 16032251723485610609 + _mapWidth: 128 + _mapHeight: 128 + _entityCapacity: 1024 + UseDefinitionStats: 1 +--- !u!114 &2042920973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2042920971} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b9301a799fe64f85afe9906dc15bc39, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.MatchRunner + _seed: 12345 + _mapWidth: 128 + _mapHeight: 128 + _maxUnits: 2048 +--- !u!114 &2042920974 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2042920971} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bad3b0760ec204c94bb15e3918bbc921, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.Match.UnitViewManager + _matchRunner: {fileID: 2042920973} + _unitPrefab: {fileID: 0} + _combatEffects: {fileID: 2042920975} + _assetMappings: {fileID: 11400000, guid: 54dfdf235acc54eecbef61df13a6b356, type: 2} + _interpolationSpeed: 25 + _viewerTeamOverride: -1 + _unknownPlayerColor: {r: 0.62, g: 0.62, b: 0.62, a: 1} + _damagedColor: {r: 0.42, g: 0.05, b: 0.05, a: 1} + _healthTintFloor: 0.25 +--- !u!114 &2042920975 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2042920971} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4cba4e364582443899c3490f303f72f, type: 3} + m_Name: + m_EditorClassIdentifier: Nova.Gameplay::Nova.Gameplay.CombatFeedback.CombatEffectController +--- !u!4 &2042920976 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2086866621} + m_GameObject: {fileID: 2042920971} serializedVersion: 2 - m_LocalRotation: {x: 0.12450414, y: -0.8617815, z: 0.25527132, w: 0.42031893} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 @@ -1403,13 +1447,13 @@ Transform: SceneRoots: m_ObjectHideFlags: 0 m_Roots: - - {fileID: 1208129616} - - {fileID: 2086866623} - - {fileID: 1688916561} - - {fileID: 796025944} - - {fileID: 318030902} - - {fileID: 1239032166} - - {fileID: 1729466595} - - {fileID: 766640424} - - {fileID: 712913258} - - {fileID: 595700767} + - {fileID: 128460815} + - {fileID: 1521561488} + - {fileID: 1162144977} + - {fileID: 802321242} + - {fileID: 2042920976} + - {fileID: 954524124} + - {fileID: 214746661} + - {fileID: 1629940941} + - {fileID: 526112589} + - {fileID: 1309622898}