From 11596690cd1d013750caba2f264695a886202d28 Mon Sep 17 00:00:00 2001 From: Nikolay Petrov Date: Fri, 3 Oct 2025 02:09:44 +0500 Subject: [PATCH] [code] refactor Debug module --- Content/Blueprints/BP_MainCharacter.ts | 26 +- Content/Blueprints/BP_MainCharacter.uasset | 4 +- Content/Camera/Components/AC_Camera.ts | 63 +- Content/Camera/Components/AC_Camera.uasset | 4 +- .../Camera/Tests/FT_CameraInitialization.ts | 15 +- .../Tests/FT_CameraInitialization.uasset | 4 +- Content/Camera/Tests/FT_CameraLimits.ts | 15 +- Content/Camera/Tests/FT_CameraLimits.uasset | 4 +- Content/Camera/Tests/FT_CameraRotation.ts | 15 +- Content/Camera/Tests/FT_CameraRotation.uasset | 4 +- Content/Camera/Tests/FT_CameraSensitivity.ts | 15 +- .../Camera/Tests/FT_CameraSensitivity.uasset | 4 +- Content/Camera/Tests/FT_CameraSmoothing.ts | 15 +- .../Camera/Tests/FT_CameraSmoothing.uasset | 4 +- Content/Debug/Components/AC_DebugHUD.ts | 748 +++++------- Content/Debug/Components/AC_DebugHUD.uasset | 4 +- Content/Debug/Enums/E_DebugPageID.ts | 9 - Content/Debug/Enums/E_DebugPageID.uasset | 3 - Content/Debug/Enums/E_DebugUpdateFunction.ts | 9 - .../Debug/Enums/E_DebugUpdateFunction.uasset | 3 - Content/Debug/ManualTestingChecklist.md | 46 +- Content/Debug/Structs/S_DebugPage.ts | 8 +- Content/Debug/Structs/S_DebugPage.uasset | 4 +- Content/Debug/Structs/S_DebugSettings.ts | 12 - Content/Debug/Structs/S_DebugSettings.uasset | 3 - Content/Debug/TDD.md | 1052 ++++++++--------- Content/Debug/Tables/DT_DebugPages.ts | 55 - Content/Debug/Tables/DT_DebugPages.uasset | 3 - Content/Debug/Tests/FT_DebugNavigation.ts | 29 +- Content/Debug/Tests/FT_DebugNavigation.uasset | 4 +- .../Tests/FT_DebugPageContentGenerator.ts | 125 -- .../Tests/FT_DebugPageContentGenerator.uasset | 3 - Content/Debug/Tests/FT_DebugPageManagement.ts | 261 ++++ .../Debug/Tests/FT_DebugPageManagement.uasset | 3 + Content/Debug/Tests/FT_DebugSystem.ts | 47 +- Content/Debug/Tests/FT_DebugSystem.uasset | 4 +- Content/Input/Components/AC_InputDevice.ts | 53 +- .../Input/Components/AC_InputDevice.uasset | 4 +- .../Input/Tests/FT_InputDeviceDetection.ts | 10 +- .../Tests/FT_InputDeviceDetection.uasset | 4 +- Content/Levels/TestLevel.ts | 6 +- Content/Levels/TestLevel.umap | 4 +- Content/Movement/Components/AC_Movement.ts | 71 +- .../Movement/Components/AC_Movement.uasset | 4 +- Content/Movement/Tests/FT_BasicMovement.ts | 9 +- .../Movement/Tests/FT_BasicMovement.uasset | 4 +- Content/Movement/Tests/FT_DiagonalMovement.ts | 9 +- .../Movement/Tests/FT_DiagonalMovement.uasset | 4 +- 48 files changed, 1372 insertions(+), 1437 deletions(-) delete mode 100644 Content/Debug/Enums/E_DebugPageID.ts delete mode 100644 Content/Debug/Enums/E_DebugPageID.uasset delete mode 100644 Content/Debug/Enums/E_DebugUpdateFunction.ts delete mode 100644 Content/Debug/Enums/E_DebugUpdateFunction.uasset delete mode 100644 Content/Debug/Structs/S_DebugSettings.ts delete mode 100644 Content/Debug/Structs/S_DebugSettings.uasset delete mode 100644 Content/Debug/Tables/DT_DebugPages.ts delete mode 100644 Content/Debug/Tables/DT_DebugPages.uasset delete mode 100644 Content/Debug/Tests/FT_DebugPageContentGenerator.ts delete mode 100644 Content/Debug/Tests/FT_DebugPageContentGenerator.uasset create mode 100644 Content/Debug/Tests/FT_DebugPageManagement.ts create mode 100644 Content/Debug/Tests/FT_DebugPageManagement.uasset diff --git a/Content/Blueprints/BP_MainCharacter.ts b/Content/Blueprints/BP_MainCharacter.ts index 4b67a07..74d03f1 100644 --- a/Content/Blueprints/BP_MainCharacter.ts +++ b/Content/Blueprints/BP_MainCharacter.ts @@ -151,21 +151,23 @@ export class BP_MainCharacter extends Pawn { } this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent ); if (this.ShowDebugInfo) { this.DebugHUDComponent.InitializeDebugHUD( - this.MovementComponent, this.ToastSystemComponent, - this.InputDeviceComponent, - this.CameraComponent + this.InputDeviceComponent ); } - this.MovementComponent.InitializeMovementSystem(); + this.MovementComponent.InitializeMovementSystem(this.DebugHUDComponent); - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent + ); } /** @@ -176,10 +178,7 @@ export class BP_MainCharacter extends Pawn { this.DeltaTime = DeltaTime; if (this.ShowDebugInfo) { - this.DebugHUDComponent.UpdateHUD( - SystemLibrary.GetGameTimeInSeconds(), - DeltaTime - ); + this.DebugHUDComponent.UpdateHUD(SystemLibrary.GetGameTimeInSeconds()); this.ToastSystemComponent.UpdateToastSystem(); } @@ -197,7 +196,14 @@ export class BP_MainCharacter extends Pawn { this.CurrentMovementInput, DeltaTime ); + this.ApplyMovementAndRotation(); + + if (this.ShowDebugInfo) { + this.MovementComponent.UpdateDebugPage(); + this.InputDeviceComponent.UpdateDebugPage(); + this.CameraComponent.UpdateDebugPage(); + } } // ════════════════════════════════════════════════════════════════════════════════════════ diff --git a/Content/Blueprints/BP_MainCharacter.uasset b/Content/Blueprints/BP_MainCharacter.uasset index e024211..2160bf1 100644 --- a/Content/Blueprints/BP_MainCharacter.uasset +++ b/Content/Blueprints/BP_MainCharacter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd2a02d508f7f7bc9e8bcad821bddc6338eb61e99125dcc1944695094ac08c6a -size 347749 +oid sha256:e9ed74f8a01d3ef4dbf4b1ace40bd54ab969f3180515df86f9a975badb931d37 +size 358758 diff --git a/Content/Camera/Components/AC_Camera.ts b/Content/Camera/Components/AC_Camera.ts index f72412f..e650e39 100644 --- a/Content/Camera/Components/AC_Camera.ts +++ b/Content/Camera/Components/AC_Camera.ts @@ -2,6 +2,7 @@ import type { S_CameraSettings } from '#root/Camera/Structs/S_CameraSettings.ts'; import type { S_CameraState } from '#root/Camera/Structs/S_CameraState.ts'; +import type { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import type { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { ActorComponent } from '#root/UE/ActorComponent.ts'; import type { Float } from '#root/UE/Float.ts'; @@ -131,20 +132,48 @@ export class AC_Camera extends ActorComponent { * Initialize camera system with default settings * @category System Setup */ - public InitializeCameraSystem(InputDeviceRef: AC_InputDevice): void { + public InitializeCameraSystem( + InputDeviceRef: AC_InputDevice, + DebugComponentRef: AC_DebugHUD + ): void { this.InputDeviceComponent = InputDeviceRef; + this.DebugHUDComponent = DebugComponentRef; this.IsInitialized = true; - // Reset camera state - this.CameraState = { - CurrentPitch: 0.0, - CurrentYaw: 0.0, - TargetPitch: 0.0, - TargetYaw: 0.0, - LastInputDelta: new Vector(0, 0, 0), - InputMagnitude: 0.0, - }; + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + this.DebugHUDComponent.AddDebugPage( + this.DebugPageID, + 'Camera System', + 60 + ); + } + } + + /** + * Update debug HUD with current camera info + * @category Debug + */ + public UpdateDebugPage(): void { + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + if ( + this.DebugHUDComponent.ShouldUpdatePage( + this.DebugPageID, + SystemLibrary.GetGameTimeInSeconds() + ) + ) { + this.DebugHUDComponent.UpdatePageContent( + this.DebugPageID, + `Current Device: ${SystemLibrary.IsValid(this.InputDeviceComponent) ? this.InputDeviceComponent.GetCurrentInputDevice() : 'Input Device Component Not Found'}\n` + + `Sensitivity: ${SystemLibrary.IsValid(this.InputDeviceComponent) && this.InputDeviceComponent.IsGamepad() ? this.CameraSettings.GamepadSensitivity : this.CameraSettings.MouseSensitivity}\n` + + `Pitch: ${this.GetCameraRotation().Pitch}°\n` + + `Yaw: ${this.GetCameraRotation().Yaw}°\n` + + `Is Rotating: ${this.IsCameraRotating() ? 'Yes' : 'No'}\n` + + `Smoothing: ${this.CameraSettings.SmoothingSpeed}\n` + + `Invert Y: ${this.CameraSettings.InvertYAxis ? 'Yes' : 'No'}` + ); + } + } } // ════════════════════════════════════════════════════════════════════════════════════════ @@ -192,4 +221,18 @@ export class AC_Camera extends ActorComponent { * @category Components */ public InputDeviceComponent: AC_InputDevice | null = null; + + /** + * Reference to debug HUD component for displaying camera info + * Optional, used for debugging purposes + * @category Components + */ + public DebugHUDComponent: AC_DebugHUD | null = null; + + /** + * Debug page identifier for organizing debug output + * Used by debug HUD to categorize information + * @category Debug + */ + public readonly DebugPageID: string = 'CameraInfo'; } diff --git a/Content/Camera/Components/AC_Camera.uasset b/Content/Camera/Components/AC_Camera.uasset index a22f423..aba2909 100644 --- a/Content/Camera/Components/AC_Camera.uasset +++ b/Content/Camera/Components/AC_Camera.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:09d323185fbd52d11894461f7126e1e6bd50346f3c6cdc68cac49d83de42db9f -size 272426 +oid sha256:259cd56f0cb9f880238b39e3a5a2d4d5f70e4fd3d9f0b4242d0d7c5ed408ecf2 +size 364791 diff --git a/Content/Camera/Tests/FT_CameraInitialization.ts b/Content/Camera/Tests/FT_CameraInitialization.ts index 64f03ee..61244e2 100644 --- a/Content/Camera/Tests/FT_CameraInitialization.ts +++ b/Content/Camera/Tests/FT_CameraInitialization.ts @@ -1,6 +1,7 @@ // Camera/Tests/FT_CameraInitialization.ts import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -28,11 +29,15 @@ export class FT_CameraInitialization extends FunctionalTest { // Initialize dependencies this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent ); // Initialize camera system - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent + ); // Validate initialization if ( @@ -87,4 +92,10 @@ export class FT_CameraInitialization extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Camera/Tests/FT_CameraInitialization.uasset b/Content/Camera/Tests/FT_CameraInitialization.uasset index 0cd7778..e8951ea 100644 --- a/Content/Camera/Tests/FT_CameraInitialization.uasset +++ b/Content/Camera/Tests/FT_CameraInitialization.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a4eed0d3a3b80989b4e4de3f4707c80f316df9c759fee5848ec1dde90429d47 -size 113978 +oid sha256:60a5038b0b733393a0dd18f9eebfba6065f1511685e11422c31e81deb6bfc3ae +size 121517 diff --git a/Content/Camera/Tests/FT_CameraLimits.ts b/Content/Camera/Tests/FT_CameraLimits.ts index 2c6bbee..73071eb 100644 --- a/Content/Camera/Tests/FT_CameraLimits.ts +++ b/Content/Camera/Tests/FT_CameraLimits.ts @@ -1,6 +1,7 @@ // Camera/Tests/FT_CameraLimits.ts import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -30,9 +31,13 @@ export class FT_CameraLimits extends FunctionalTest { // Initialize system this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent + ); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent ); - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); // Test 1: Test upper pitch limit clamping const { PitchMin: pitchMin, PitchMax: pitchMax } = @@ -126,4 +131,10 @@ export class FT_CameraLimits extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Camera/Tests/FT_CameraLimits.uasset b/Content/Camera/Tests/FT_CameraLimits.uasset index 331b139..2fc5cc4 100644 --- a/Content/Camera/Tests/FT_CameraLimits.uasset +++ b/Content/Camera/Tests/FT_CameraLimits.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30aebdbcaaeb1f35d89c01009fae2a401fb8d1a833f39718be4768f8303fb955 -size 252875 +oid sha256:ba0ad97e2c48e8d1327fc654ba1fd3061f31f74c74fffb503287a1da8f469dc5 +size 257006 diff --git a/Content/Camera/Tests/FT_CameraRotation.ts b/Content/Camera/Tests/FT_CameraRotation.ts index bfbf218..e188556 100644 --- a/Content/Camera/Tests/FT_CameraRotation.ts +++ b/Content/Camera/Tests/FT_CameraRotation.ts @@ -1,6 +1,7 @@ // Camera/Tests/FT_CameraRotation.ts import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -30,9 +31,13 @@ export class FT_CameraRotation extends FunctionalTest { // Initialize system this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent + ); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent ); - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); // Test positive X input (should increase Yaw) this.CameraComponent.ProcessLookInput(new Vector(1.0, 0.0, 0.0), 0.016); @@ -120,4 +125,10 @@ export class FT_CameraRotation extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Camera/Tests/FT_CameraRotation.uasset b/Content/Camera/Tests/FT_CameraRotation.uasset index 7f46c84..a1bfad6 100644 --- a/Content/Camera/Tests/FT_CameraRotation.uasset +++ b/Content/Camera/Tests/FT_CameraRotation.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ca459c99ef879c1f98b6a6742abcc5fee9eaad7cdafb769b8e543cf5003609a9 -size 196870 +oid sha256:8da4fb5f381a721125c6b39b4ad9b9d82f1f686e89583c855d0f1d8366f69287 +size 200672 diff --git a/Content/Camera/Tests/FT_CameraSensitivity.ts b/Content/Camera/Tests/FT_CameraSensitivity.ts index 68cebbf..de0e513 100644 --- a/Content/Camera/Tests/FT_CameraSensitivity.ts +++ b/Content/Camera/Tests/FT_CameraSensitivity.ts @@ -1,6 +1,7 @@ // Camera/Tests/FT_CameraSensitivity.ts import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -29,9 +30,13 @@ export class FT_CameraSensitivity extends FunctionalTest { // Initialize system this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent + ); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent ); - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); // Test 1: Verify sensitivity settings are loaded correctly const { MouseSensitivity: mouseSens, GamepadSensitivity: gamepadSens } = @@ -100,4 +105,10 @@ export class FT_CameraSensitivity extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Camera/Tests/FT_CameraSensitivity.uasset b/Content/Camera/Tests/FT_CameraSensitivity.uasset index 058dc6a..bc1d0b6 100644 --- a/Content/Camera/Tests/FT_CameraSensitivity.uasset +++ b/Content/Camera/Tests/FT_CameraSensitivity.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad509efe2e7835d4917b9c04fcc881544682510db53fb27601db4009c034ba01 -size 133486 +oid sha256:cb3b9ddae534bad2337239d73f2c6aea06bf891e2f45225e3e25d2c93c26f407 +size 138168 diff --git a/Content/Camera/Tests/FT_CameraSmoothing.ts b/Content/Camera/Tests/FT_CameraSmoothing.ts index d083dda..43f40ec 100644 --- a/Content/Camera/Tests/FT_CameraSmoothing.ts +++ b/Content/Camera/Tests/FT_CameraSmoothing.ts @@ -1,6 +1,7 @@ // Camera/Tests/FT_CameraSmoothing.ts import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -29,9 +30,13 @@ export class FT_CameraSmoothing extends FunctionalTest { // Initialize system this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent + ); + this.CameraComponent.InitializeCameraSystem( + this.InputDeviceComponent, + this.DebugHUDComponent ); - this.CameraComponent.InitializeCameraSystem(this.InputDeviceComponent); // Test 1: Test smooth rotation behavior this.CameraComponent.ProcessLookInput(new Vector(5.0, 0.0, 0.0), 0.016); @@ -108,4 +113,10 @@ export class FT_CameraSmoothing extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Camera/Tests/FT_CameraSmoothing.uasset b/Content/Camera/Tests/FT_CameraSmoothing.uasset index 276fded..606911b 100644 --- a/Content/Camera/Tests/FT_CameraSmoothing.uasset +++ b/Content/Camera/Tests/FT_CameraSmoothing.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3e5102d6fdce5a4c861fcfbff23f1288f6b97231af2d3eab6c8bdb07fd646bb -size 126452 +oid sha256:78121838752b754c9cd6467469d79a6ad278e62b4cd721d97883ed3cf97a3995 +size 130590 diff --git a/Content/Debug/Components/AC_DebugHUD.ts b/Content/Debug/Components/AC_DebugHUD.ts index f12435a..abac009 100644 --- a/Content/Debug/Components/AC_DebugHUD.ts +++ b/Content/Debug/Components/AC_DebugHUD.ts @@ -1,22 +1,14 @@ // Debug/Components/AC_DebugHUD.ts -import type { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; -import { E_DebugUpdateFunction } from '#root/Debug/Enums/E_DebugUpdateFunction.ts'; import type { S_DebugPage } from '#root/Debug/Structs/S_DebugPage.ts'; -import type { S_DebugSettings } from '#root/Debug/Structs/S_DebugSettings.ts'; -import { DT_DebugPages } from '#root/Debug/Tables/DT_DebugPages.ts'; import { WBP_DebugHUD } from '#root/Debug/UI/WBP_DebugHUD.ts'; import type { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; -import type { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; import type { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { ActorComponent } from '#root/UE/ActorComponent.ts'; import { CreateWidget } from '#root/UE/CteateWidget.ts'; -import type { DataTable } from '#root/UE/DataTable.ts'; -import { DataTableFunctionLibrary } from '#root/UE/DataTableFunctionLibrary.ts'; import { ESlateVisibility } from '#root/UE/ESlateVisibility.ts'; import type { Float } from '#root/UE/Float.ts'; import type { Integer } from '#root/UE/Integer.ts'; -import { StringLibrary } from '#root/UE/StringLibrary.ts'; import { SystemLibrary } from '#root/UE/SystemLibrary.ts'; import type { Text } from '#root/UE/Text.ts'; import { UEArray } from '#root/UE/UEArray.ts'; @@ -33,81 +25,143 @@ export class AC_DebugHUD extends ActorComponent { // ════════════════════════════════════════════════════════════════════════════════════════ /** - * Check if debug HUD should be visible - * @returns True if system is initialized and mode is visible - * @category HUD Control - * @pure true - */ - private ShouldShowDebugHUD(): boolean { - const IsSystemReadyAndVisible = (modeIsVisible: boolean): boolean => - this.IsInitialized && modeIsVisible; - - return IsSystemReadyAndVisible( - this.DebugSettings.CurrentMode === ESlateVisibility.Visible - ); - } - - /** - * Check if debug HUD should update this frame + * Add or register a debug page in the system + * @param PageID - Unique identifier for the page + * @param Title - Display title for the page + * @param RefreshRate - How often this page should be updated (Hz), default 30 + * @param IsVisible - Whether the page is visible by default, default true * @example - * // Update every frame (UpdateFrequency = 0) - * ShouldUpdateDebugHUD(gameTime) // returns true - * // Update at 30Hz (UpdateFrequency = 30) - * ShouldUpdateDebugHUD(gameTime) // returns true every 1/30 seconds - * @param CurrentTime - Current game time in seconds - * @returns True if enough time has passed since last update - * @pure true - * @category HUD Control + * // In your component's BeginPlay: + * this.DebugHUDRef.AddDebugPage('MovementInfo', 'Movement Data', 30); + * @category Page Management */ - private ShouldUpdateDebugHUD(CurrentTime: Float = 0): boolean { - const IsFrequencyLimited = (updateFrequency: Float): boolean => - updateFrequency > 0; + public AddDebugPage( + PageID: string, + Title: Text, + RefreshRate: number = 30, + IsVisible: boolean = true + ): void { + const existingPageIndex = this.FindPageIndex(PageID); - const IsUpdateIntervalReached = ( - currentTime: Float, - updateFrequency: Float - ): boolean => currentTime - this.LastUpdateTime >= 1 / updateFrequency; + const pageData: S_DebugPage = { + PageID, + Title, + Content: '', + RefreshRate, + IsVisible, + LastUpdateTime: 0, + }; - if (IsFrequencyLimited(this.DebugSettings.UpdateFrequency)) { - return IsUpdateIntervalReached( - CurrentTime, - this.DebugSettings.UpdateFrequency - ); + if (existingPageIndex >= 0) { + this.DebugPages.SetArrayElem(existingPageIndex, { + ...pageData, + Content: this.DebugPages.Get(existingPageIndex).Content, + }); } else { - return true; // Update every frame + this.DebugPages.Add(pageData); } } /** - * Register or update a debug page in the system + * Update content of a specific debug page + * Call this from your component's Tick or custom update function + * @param PageId - Unique identifier of the page to update + * @param Content - New content text for the page * @example - * // Register movement constants page - * RegisterDebugPage({ - * PageID: E_DebugPageID.MovementInfo, - * Title: "Movement Constants", - * Content: "", - * IsVisible: true, - * UpdateFunction: E_DebugUpdateFunction.UpdateMovementPage - * }) - * @param PageData - Page configuration and content data + * // In your component's Tick: + * this.DebugHUDRef.UpdatePageContent( + * 'MovementInfo', + * `Speed: ${this.Speed}\nAcceleration: ${this.Acceleration}` + * ); * @category Page Management */ - private RegisterDebugPage(PageData: S_DebugPage): void { - let existingIndex: Integer = -1; + public UpdatePageContent(PageId: string, Content: Text): void { + const pageIndex = this.FindPageIndex(PageId); - this.DebugPages.forEach((page, index) => { - if (page.PageID === PageData.PageID) { - existingIndex = index; - return; + if (pageIndex >= 0) { + this.DebugPages.SetArrayElem(pageIndex, { + ...this.DebugPages.Get(pageIndex), + Content, + }); + } + } + + /** + * Check if page needs update based on its refresh rate + * Use this to control update frequency in your component + * @param PageID - Page identifier to check + * @param CurrentTime - Current game time + * @returns True if page should be updated + * @example + * // In your component's Tick: + * if (this.DebugHUDRef.ShouldUpdatePage('MovementInfo', currentTime)) { + * this.DebugHUDRef.UpdatePageContent('MovementInfo', this.GetDebugContent()); + * } + * @category Page Management + * @pure true + */ + public ShouldUpdatePage(PageID: string, CurrentTime: Float): boolean { + const pageIndex = this.FindPageIndex(PageID); + if (pageIndex >= 0) { + let page = this.DebugPages.Get(pageIndex); + + const IsTimeToUpdate = ( + currentTime: Float, + refreshRate: Float, + updateTime: Float + ): boolean => currentTime - updateTime >= 1 / refreshRate; + + const { RefreshRate: refreshRate, LastUpdateTime: updateTime } = page; + + if (IsTimeToUpdate(CurrentTime, refreshRate, updateTime)) { + page = { + ...page, + LastUpdateTime: CurrentTime, + }; + + this.DebugPages.SetArrayElem(pageIndex, page); + + return true; + } else { + return false; } - }); - - const IsPageExists = (): boolean => existingIndex >= 0; - - if (IsPageExists()) { - this.DebugPages.SetArrayElem(existingIndex, PageData); } else { - this.DebugPages.Add(PageData); + return false; + } + } + + /** + * Remove a debug page from the system + * @param pageId - Unique identifier of the page to remove + * @category Page Management + */ + public RemoveDebugPage(pageId: string): void { + const pageIndex = this.FindPageIndex(pageId); + + if (pageIndex >= 0) { + this.DebugPages.RemoveIndex(pageIndex); + + // Adjust current page index if needed + if (this.CurrentPageIndex >= this.GetVisiblePages().length) { + this.CurrentPageIndex = Math.max(0, this.GetVisiblePages().length - 1); + } + } + } + + /** + * Set visibility of a specific debug page + * @param pageId - Page identifier + * @param isVisible - Visibility state + * @category Page Management + */ + public SetPageVisibility(pageId: string, isVisible: boolean): void { + const pageIndex = this.FindPageIndex(pageId); + + if (pageIndex >= 0) { + this.DebugPages.SetArrayElem(pageIndex, { + ...this.DebugPages.Get(pageIndex), + IsVisible: isVisible, + }); } } @@ -117,41 +171,36 @@ export class AC_DebugHUD extends ActorComponent { * @category Page Management * @pure true */ - public GetVisiblePages(): UEArray { - const filteredPages: UEArray = new UEArray([]); + private GetVisiblePages(): UEArray { + const filteredArray: UEArray = new UEArray([]); this.DebugPages.forEach(page => { if (page.IsVisible) { - filteredPages.Add(page); + filteredArray.Add(page); } }); - return filteredPages; + return filteredArray; } /** * Get currently selected debug page - * @returns Object with page data and validity flag + * @returns Current page data or null if invalid * @category Page Management * @pure true */ - private GetCurrentPage(): - | { Page: S_DebugPage | null; IsFound: true } - | { Page: null; IsFound: false } { - const IsPageIndexInvalid = ( - length: Integer, - currentPageIndex: Integer - ): boolean => length === 0 || currentPageIndex >= length; + private GetCurrentPage(): { Page: S_DebugPage | null; IsFound: boolean } { + const IsCurrentPageValid = (length: Integer): boolean => + length === 0 || this.CurrentPageIndex >= length; - return IsPageIndexInvalid( - this.GetVisiblePages().length, - this.DebugSettings.CurrentPageIndex - ) - ? { Page: null, IsFound: false } - : { - Page: this.GetVisiblePages().Get(this.DebugSettings.CurrentPageIndex), - IsFound: true, - }; + if (!IsCurrentPageValid(this.GetVisiblePages().length)) { + return { + Page: this.GetVisiblePages().Get(this.CurrentPageIndex), + IsFound: true, + }; + } + + return { Page: null, IsFound: false }; } /** @@ -159,11 +208,14 @@ export class AC_DebugHUD extends ActorComponent { * @category Navigation */ public ToggleDebugHUD(): void { - this.DebugSettings.CurrentMode = - this.DebugSettings.CurrentMode === ESlateVisibility.Visible - ? ESlateVisibility.Hidden - : ESlateVisibility.Visible; - this.UpdateWidgetVisibility(); + if (SystemLibrary.IsValid(this.DebugWidget)) { + this.CurrentMode = + this.CurrentMode === ESlateVisibility.Visible + ? ESlateVisibility.Hidden + : ESlateVisibility.Visible; + + this.DebugWidget.SetVisibility(this.CurrentMode); + } } /** @@ -175,17 +227,13 @@ export class AC_DebugHUD extends ActorComponent { const length = this.GetVisiblePages().length; if (length > 1) { - const currentPage = this.DebugSettings.CurrentPageIndex; - - const isAtFirstPage = (): boolean => currentPage - 1 < 0; + const isAtFirstPage = (): boolean => this.CurrentPageIndex - 1 < 0; const getLastPageIndex = (): Integer => length - 1; - const getPreviousPageIndex = (): Integer => currentPage - 1; + const getPreviousPageIndex = (): Integer => this.CurrentPageIndex - 1; - this.DebugSettings.CurrentPageIndex = isAtFirstPage() + this.CurrentPageIndex = isAtFirstPage() ? getLastPageIndex() : getPreviousPageIndex(); - - this.UpdateCurrentPage(); } } @@ -197,16 +245,11 @@ export class AC_DebugHUD extends ActorComponent { public NextPage(): void { const length = this.GetVisiblePages().length; - const HasMultiplePages = (): boolean => length > 1; - const GetNextPageIndex = (currentPageIndex: Integer): Integer => - (currentPageIndex + 1) % length; + const GetNextPageIndex = (): Integer => + (this.CurrentPageIndex + 1) % length; - if (HasMultiplePages()) { - this.DebugSettings.CurrentPageIndex = GetNextPageIndex( - this.DebugSettings.CurrentPageIndex - ); - - this.UpdateCurrentPage(); + if (length > 1) { + this.CurrentPageIndex = GetNextPageIndex(); } } @@ -215,218 +258,145 @@ export class AC_DebugHUD extends ActorComponent { * @category Visual Debug */ public ToggleVisualDebug(): void { - this.DebugSettings.ShowVisualDebug = !this.DebugSettings.ShowVisualDebug; + this.ShowVisualDebug = !this.ShowVisualDebug; if (SystemLibrary.IsValid(this.ToastComponent)) { this.ToastComponent.ShowToast( - `Visual Debug ${this.DebugSettings.ShowVisualDebug ? 'Enabled' : 'Disabled'}` + `Visual Debug ${this.ShowVisualDebug ? 'Enabled' : 'Disabled'}` ); } } /** - * Update content of currently selected page - * Calls appropriate update function based on page type - * @category Page Updates + * Get comprehensive test data for debug system validation + * @returns Object containing initialization status, DataTable reference, and pages array + * @category Testing */ - private UpdateCurrentPage(): void { - let CurrentPage = this.GetCurrentPage().Page; + public GetTestData(): { + IsInitialized: boolean; + DebugPages: UEArray; + VisiblePagesLength: Integer; + CurrentPageIndex: Integer; + } { + return { + IsInitialized: this.IsInitialized, + DebugPages: this.DebugPages, + VisiblePagesLength: this.GetVisiblePages().length, + CurrentPageIndex: this.CurrentPageIndex, + }; + } - if (this.GetCurrentPage().IsFound && CurrentPage !== null) { - switch (CurrentPage.UpdateFunction) { - case E_DebugUpdateFunction.UpdateMovementPage: { - CurrentPage = this.UpdateMovementPage(CurrentPage); - break; - } - case E_DebugUpdateFunction.UpdateSurfacePage: { - CurrentPage = this.UpdateSurfacePage(CurrentPage); - break; - } - case E_DebugUpdateFunction.UpdatePerformancePage: { - CurrentPage = this.UpdatePerformancePage(CurrentPage); - break; - } - case E_DebugUpdateFunction.UpdateInputDevicePage: { - CurrentPage = this.UpdateInputDevicePage(CurrentPage); - break; - } - case E_DebugUpdateFunction.UpdateCameraPage: { - CurrentPage = this.UpdateCameraPage(CurrentPage); - break; + /** + * Initialize debug HUD system with movement component reference + * Sets up pages, creates widget, runs tests, and starts display + * @param ToastComponentRef - Reference to toast system for notifications + * @param InputDeviceComponentRef - Reference to input device component for device info + * @example + * // Initialize debug HUD in main character + * this.DebugHUDComponent.InitializeDebugHUD(this.MovementComponent); + * @category System Setup + */ + public InitializeDebugHUD( + ToastComponentRef: AC_ToastSystem | null, + InputDeviceComponentRef: AC_InputDevice | null + ): void { + this.ToastComponent = ToastComponentRef; + this.InputDeviceComponent = InputDeviceComponentRef; + + if (!this.IsInitialized) { + this.IsInitialized = true; + this.CreateDebugWidget(); + + if (SystemLibrary.IsValid(this.ToastComponent)) { + this.ToastComponent.ShowToast( + 'Debug HUD Initialized', + E_MessageType.Success + ); + } + } + } + + /** + * Find index of page by ID + * @param PageId - Page identifier to search for + * @returns Index of the page or -1 if not found + * @category Utility + */ + private FindPageIndex(PageId: string): Integer { + for (let i = 0; i < this.DebugPages.length; i++) { + if (this.DebugPages.Get(i).PageID === PageId) { + return i; + } + } + + return -1; + } + + /** + * Main update loop for debug HUD system + * @param CurrentTime - Current game time in seconds + * @category HUD Rendering + */ + public UpdateHUD(CurrentTime: Float): void { + if (this.IsInitialized && SystemLibrary.IsValid(this.DebugWidget)) { + this.FrameCounter++; + + const ShouldUpdateFPS = (currentTime: Float): boolean => + currentTime - this.LastUpdateTime >= 1; + + const UpdateFPSCounter = (currentTime: Float): Float => + this.FrameCounter / (currentTime - this.LastUpdateTime); + + if (ShouldUpdateFPS(CurrentTime)) { + this.FPS = UpdateFPSCounter(CurrentTime); + this.FrameCounter = 0; + this.LastUpdateTime = CurrentTime; + + if (this.ShouldShowDebugHUD()) { + this.UpdateWidgetDisplay(); } } - - this.DebugPages.SetArrayElem( - this.DebugSettings.CurrentPageIndex, - CurrentPage - ); - - this.UpdateWidgetPage(); } } /** - * Update movement constants page content - * @param Page - Page structure to update - * @returns Updated page with current movement data - * @category Page Updates + * Get navigation instructions based on input device + * @return Control hints text + * @category Widget Management + * @pure true */ - public UpdateMovementPage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.MovementComponent)) { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: - // Constants - `Max Speed: ${this.MovementComponent.MovementConstants.MaxSpeed}\n` + - `Acceleration: ${this.MovementComponent.MovementConstants.Acceleration}\n` + - `Friction: ${this.MovementComponent.MovementConstants.Friction}\n` + - `Gravity: ${this.MovementComponent.MovementConstants.Gravity}\n` + - `\n` + // Разделитель - // Current State - `Current Velocity: ${StringLibrary.ConvVectorToString(this.MovementComponent.CurrentVelocity)}\n` + - `Speed: ${this.MovementComponent.CurrentSpeed}\n` + - `Is Grounded: ${this.MovementComponent.IsGrounded}\n` + - `Surface Type: ${this.MovementComponent.CurrentSurface}\n` + - `Movement State: ${this.MovementComponent.MovementState}\n` + - `Input Magnitude: ${this.MovementComponent.InputMagnitude}`, - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } else { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: 'Movement Component Not Found', - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } - } - - /** - * Update surface classification page content - * @param Page - Page structure to update - * @returns Updated page with current surface angle thresholds - * @category Page Updates - */ - public UpdateSurfacePage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.MovementComponent)) { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: - `Walkable: ≤${this.MovementComponent.AngleThresholdsDegrees.Walkable}°\n` + - `Steep Slope: ${this.MovementComponent.AngleThresholdsDegrees.Walkable}°-${this.MovementComponent.AngleThresholdsDegrees.SteepSlope}°\n` + - `Wall: ${this.MovementComponent.AngleThresholdsDegrees.SteepSlope}°-${this.MovementComponent.AngleThresholdsDegrees.Wall}°\n` + - `Ceiling: >${this.MovementComponent.AngleThresholdsDegrees.Wall}°`, - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } else { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: 'Movement Component Not Found', - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } - } - - /** - * Update performance metrics page content - * @param Page - Page structure to update - * @returns Updated page with current performance data - * @category Page Updates - */ - public UpdatePerformancePage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.MovementComponent)) { - const IsUpdatingEveryFrame = (updateFrequency: Float): boolean => - updateFrequency <= 0; - - return { - PageID: Page.PageID, - Title: Page.Title, - Content: - `Frame: ${this.FrameCounter}\n` + - `FPS: ${this.FPS}\n` + - `Update Rate: ${IsUpdatingEveryFrame(this.DebugSettings.UpdateFrequency) ? 'Every Frame' : `${this.DebugSettings.UpdateFrequency} Hz`}\n` + - `ActivePages: ${this.GetVisiblePages().length}`, - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } else { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: 'Movement Component Not Found', - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } - } - - /** - * Update input device information page content - * @param Page - Page structure to update - * @returns Updated page with current input device data - * @category Page Updates - */ - public UpdateInputDevicePage(Page: S_DebugPage): S_DebugPage { + private GetControlHints(): Text { if (SystemLibrary.IsValid(this.InputDeviceComponent)) { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: - `Hardware Device Identifier: ${this.InputDeviceComponent.GetCurrentInputDevice()}` + - `Initialized: ${this.InputDeviceComponent.IsInitialized}` + - `Last Change: ${this.InputDeviceComponent.LastDeviceChangeTime}`, - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } else { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: 'Input Device Component Not Found', - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; + if (this.InputDeviceComponent.IsGamepad()) { + return 'LT+RT+Right/LT+RT+Left'; + } + } + + return 'PageUp/PageDown'; + } + + /** + * Update widget display with current page content + * @category Widget Management + */ + private UpdateWidgetDisplay(): void { + const { Page: currentPage, IsFound } = this.GetCurrentPage(); + + if (IsFound && SystemLibrary.IsValid(this.DebugWidget)) { + this.DebugWidget.SetHeaderText(currentPage!.Title); + this.DebugWidget.SetContentText(currentPage!.Content); + this.DebugWidget.SetNavigationText(this.GetNavigationText()); } } /** - * Update camera system information page content - * @param Page - Page structure to update - * @returns Updated page with current camera data - * @category Page Updates + * Generate navigation text showing current page position + * @returns Formatted navigation string + * @category Widget Control + * @pure true */ - public UpdateCameraPage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.CameraComponent)) { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: - `Current Device: ${SystemLibrary.IsValid(this.InputDeviceComponent) ? this.InputDeviceComponent.GetCurrentInputDevice() : 'Input Device Component Not Found'}\n` + - `Sensitivity: ${SystemLibrary.IsValid(this.InputDeviceComponent) && this.InputDeviceComponent.IsGamepad() ? this.CameraComponent.CameraSettings.GamepadSensitivity : this.CameraComponent.CameraSettings.MouseSensitivity}\n` + - `Pitch: ${this.CameraComponent.GetCameraRotation().Pitch}°\n` + - `Yaw: ${this.CameraComponent.GetCameraRotation().Yaw}°\n` + - `Is Rotating: ${this.CameraComponent.IsCameraRotating() ? 'Yes' : 'No'}\n` + - `Smoothing: ${this.CameraComponent.CameraSettings.SmoothingSpeed}\n` + - `Invert Y: ${this.CameraComponent.CameraSettings.InvertYAxis ? 'Yes' : 'No'}`, - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } else { - return { - PageID: Page.PageID, - Title: Page.Title, - Content: 'Camera Component Not Found', - IsVisible: Page.IsVisible, - UpdateFunction: Page.UpdateFunction, - }; - } + private GetNavigationText(): string { + return `Page ${this.CurrentPageIndex + 1}/${this.GetVisiblePages().length} | FPS: ${this.FPS} | ${this.GetControlHints()}`; } /** @@ -435,13 +405,16 @@ export class AC_DebugHUD extends ActorComponent { */ private CreateDebugWidget(): void { this.DebugWidget = CreateWidget(WBP_DebugHUD); - this.DebugWidget.MovementComponent = this.MovementComponent; if (SystemLibrary.IsValid(this.DebugWidget)) { this.DebugWidget.AddToViewport(); + this.UpdateWidgetVisibility(); } else { if (SystemLibrary.IsValid(this.ToastComponent)) { - this.ToastComponent.ShowToast('Failed to create debug widget'); + this.ToastComponent.ShowToast( + 'Failed to create debug widget', + E_MessageType.Error + ); } } } @@ -461,139 +434,22 @@ export class AC_DebugHUD extends ActorComponent { } /** - * Send current page data to debug widget for display - * @category Widget Communication + * Check if debug HUD should be visible + * @returns True if system is initialized and mode is visible + * @category HUD Control + * @pure true */ - private UpdateWidgetPage(): void { - if ( - this.GetCurrentPage().IsFound && - SystemLibrary.IsValid(this.DebugWidget) - ) { - const currentPage = this.GetCurrentPage().Page; - const visiblePages = this.GetVisiblePages(); - - this.DebugWidget.SetHeaderText(currentPage!.Title); - this.DebugWidget.SetContentText(currentPage!.Content); - this.DebugWidget.SetNavigationText( - `Page ${this.DebugSettings.CurrentPageIndex + 1}/${visiblePages.length} | ${this.GetControlHints()} - Navigate` - ); - } - } - - private GetControlHints(): Text { - if (SystemLibrary.IsValid(this.InputDeviceComponent)) { - if (this.InputDeviceComponent.IsGamepad()) { - return 'D-Pad Up/Down'; - } - } - - return 'PageUp/PageDown'; - } - - /** - * Main update loop for debug HUD system - * Called every frame from game loop - * @param CurrentTime - Current game time in seconds - * @param DeltaTime - Time since last frame in seconds - * @category HUD Rendering - */ - public UpdateHUD(CurrentTime: Float, DeltaTime: Float): void { - const IsReadyForUpdate = (shouldUpdateHUD: boolean): boolean => - this.IsInitialized && shouldUpdateHUD; - const IsValidDeltaTime = (deltaTime: Float): boolean => deltaTime > 0; - const CalculateFPS = (deltaTime: Float): Float => 1 / deltaTime; - - if (IsReadyForUpdate(this.ShouldUpdateDebugHUD(CurrentTime))) { - this.FrameCounter++; - this.FPS = IsValidDeltaTime(DeltaTime) ? CalculateFPS(DeltaTime) : 0; - this.LastUpdateTime = CurrentTime; - - if (this.ShouldShowDebugHUD()) { - this.UpdateCurrentPage(); - this.UpdateWidgetPage(); - } - } - } - - /** - * Register default debug pages (Movement, Surface, Performance) - * @category System Setup - */ - private RegisterDefaultPages(): void { - DataTableFunctionLibrary.GetDataTableRowNames(this.DebugDataTable).forEach( - arrayElement => { - this.DebugDataTable.GetDataTableRow(arrayElement, row => { - this.RegisterDebugPage(row); - }); - } + private ShouldShowDebugHUD(): boolean { + return ( + this.CurrentMode === ESlateVisibility.Visible && + this.GetVisiblePages().length > 0 ); } - /** - * Get comprehensive test data for debug system validation - * @returns Object containing initialization status, DataTable reference, and pages array - * @category Testing - */ - public GetTestData(): { - IsInitialized: boolean; - DebugDataTable: DataTable; - DebugPages: UEArray; - } { - return { - IsInitialized: this.IsInitialized, - DebugDataTable: this.DebugDataTable, - DebugPages: this.DebugPages, - }; - } - - /** - * Initialize debug HUD system with movement component reference - * Sets up pages, creates widget, runs tests, and starts display - * @param MovementComponentRef - Reference to movement component to debug - * @param ToastComponentRef - Reference to toast system for notifications - * @param InputDeviceComponentRef - Reference to input device component for device info - * @param CameraComponentRef - Reference to camera component for camera info - * @example - * // Initialize debug HUD in main character - * this.DebugHUDComponent.InitializeDebugHUD(this.MovementComponent); - * @category System Setup - */ - public InitializeDebugHUD( - MovementComponentRef: AC_Movement, - ToastComponentRef: AC_ToastSystem, - InputDeviceComponentRef: AC_InputDevice, - CameraComponentRef: AC_Camera - ): void { - this.MovementComponent = MovementComponentRef; - this.ToastComponent = ToastComponentRef; - this.InputDeviceComponent = InputDeviceComponentRef; - this.CameraComponent = CameraComponentRef; - this.IsInitialized = true; - this.FrameCounter = 0; - this.LastUpdateTime = 0; - this.FPS = 0; - this.RegisterDefaultPages(); - this.CreateDebugWidget(); - this.DebugSettings.CurrentPageIndex = 0; - this.UpdateWidgetVisibility(); - this.ToastComponent.ShowToast( - 'Debug HUD Initialized', - E_MessageType.Success - ); - this.UpdateCurrentPage(); - } - // ════════════════════════════════════════════════════════════════════════════════════════ // VARIABLES // ════════════════════════════════════════════════════════════════════════════════════════ - /** - * Reference to movement component being debugged - * Set during initialization, used for accessing movement data - * @category Components - */ - private MovementComponent: AC_Movement | null = null; - /** * Reference to toast system component for debug messaging * Set during initialization, used for displaying debug notifications @@ -609,25 +465,24 @@ export class AC_DebugHUD extends ActorComponent { public InputDeviceComponent: AC_InputDevice | null = null; /** - * Reference to camera component for camera-related debug info - * Set externally, used for displaying camera sensitivity and state - * @category Components - */ - public CameraComponent: AC_Camera | null = null; - - /** - * Debug system configuration settings - * Controls visibility, update frequency, and current page - * Instance editable for designer customization - * @category DebugConfig + * Current mode of the debug HUD (Visible, Hidden, Collapsed) + * @category Debug Config * @instanceEditable true */ - public DebugSettings: S_DebugSettings = { - CurrentMode: ESlateVisibility.Visible, - CurrentPageIndex: 0, - ShowVisualDebug: false, - UpdateFrequency: 0, - }; + public CurrentMode: ESlateVisibility = ESlateVisibility.Visible; + + /** + * Index of the currently displayed debug page + * @category Debug Config + */ + public CurrentPageIndex: Integer = 0; + + /** + * Visual debug rendering toggle (collision shapes, rays, etc.) + * @category Debug Config + * @instanceEditable true + */ + public ShowVisualDebug: boolean = true; /** * System initialization state flag @@ -670,11 +525,4 @@ export class AC_DebugHUD extends ActorComponent { * @category Page System */ private DebugPages: UEArray = new UEArray([]); - - /** - * DataTable reference for debug pages storage - * Contains structured page data with Name-based indexing for efficient lookup - * @category Page System - */ - private DebugDataTable: DataTable = DT_DebugPages; } diff --git a/Content/Debug/Components/AC_DebugHUD.uasset b/Content/Debug/Components/AC_DebugHUD.uasset index 86cc407..d6ef799 100644 --- a/Content/Debug/Components/AC_DebugHUD.uasset +++ b/Content/Debug/Components/AC_DebugHUD.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38ec7c9136f33e6b544c7fd4bc2b11f22e349b72f722bc0df3811e4ed9167fb2 -size 1051885 +oid sha256:d7a18ff591ef9cd37f05e1312b531b9cdff305332917961f489eeee2105e4152 +size 764802 diff --git a/Content/Debug/Enums/E_DebugPageID.ts b/Content/Debug/Enums/E_DebugPageID.ts deleted file mode 100644 index 86cb694..0000000 --- a/Content/Debug/Enums/E_DebugPageID.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Debug/Enums/E_DebugPageID.ts - -export enum E_DebugPageID { - MovementInfo = 'MovementInfo', - SurfaceInfo = 'SurfaceInfo', - PerformanceInfo = 'PerformanceInfo', - InputDeviceInfo = 'InputDeviceInfo', - CameraInfo = 'CameraInfo', -} diff --git a/Content/Debug/Enums/E_DebugPageID.uasset b/Content/Debug/Enums/E_DebugPageID.uasset deleted file mode 100644 index 16aecd1..0000000 --- a/Content/Debug/Enums/E_DebugPageID.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0f680337b58a38fce0bd8d37ed88a862ba353bc5d998861b4683b21f9bce449d -size 3279 diff --git a/Content/Debug/Enums/E_DebugUpdateFunction.ts b/Content/Debug/Enums/E_DebugUpdateFunction.ts deleted file mode 100644 index 946fdaf..0000000 --- a/Content/Debug/Enums/E_DebugUpdateFunction.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Debug/Enums/E_DebugUpdateFunction.ts - -export enum E_DebugUpdateFunction { - UpdateMovementPage = 'UpdateMovementPage', - UpdateSurfacePage = 'UpdateSurfacePage', - UpdatePerformancePage = 'UpdatePerformancePage', - UpdateInputDevicePage = 'UpdateInputDevicePage', - UpdateCameraPage = 'UpdateCameraPage', -} diff --git a/Content/Debug/Enums/E_DebugUpdateFunction.uasset b/Content/Debug/Enums/E_DebugUpdateFunction.uasset deleted file mode 100644 index d5b98c1..0000000 --- a/Content/Debug/Enums/E_DebugUpdateFunction.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:43ac12da7805825b92e83175a5bc08715c905fa44c4457dbf8196e38b206c5ed -size 3509 diff --git a/Content/Debug/ManualTestingChecklist.md b/Content/Debug/ManualTestingChecklist.md index 1e04b1f..e2efe96 100644 --- a/Content/Debug/ManualTestingChecklist.md +++ b/Content/Debug/ManualTestingChecklist.md @@ -5,7 +5,7 @@ ## Тестовая среена - **Персонаж:** BP_MainCharacter с ShowDebugInfo = true - **Клавиши:** PageUp/PageDown, Tab, Home -- **Требования:** MovementComponent и ToastSystemComponent инициализированы +- **Требования:** MovementComponent и InputDeviceComponentRef инициализированы --- @@ -23,57 +23,19 @@ --- -## 2. Содержимое страниц +## 2. Toggle функциональность -### 2.1 Movement Constants (Page 1) -- [ ] **Title:** "Movement Constants" -- [ ] **Content содержит:** - - Max Speed: 600 - - Acceleration: 2000 - - Friction: 8 - - Gravity: 980 - -### 2.2 Surface Classification (Page 2) -- [ ] **Title:** "Surface Classification" -- [ ] **Content содержит:** - - Walkable: ≤50° - - Steep Slope: 50°-85° - - Wall: 85°-95° - - Ceiling: >95° - -### 2.3 Performance Metrics (Page 3) -- [ ] **Title:** "Performance Metrics" -- [ ] **Content содержит:** - - Frame: [увеличивающийся счетчик] - - FPS: [текущий FPS] - - Update Rate: Every Frame - - ActivePages: 3 - ---- - -## 3. Toggle функциональность - -### 3.1 Debug HUD toggle +### 2.1 Debug HUD toggle - [ ] **Tab** скрывает/показывает весь debug HUD - [ ] **Visibility state** сохраняется при навигации -### 3.2 Visual Debug toggle +### 2.2 Visual Debug toggle - [ ] **Home** включает/выключает visual debug - [ ] **Toast notification** появляется: "Visual Debug Enabled/Disabled" --- -## 4. Обновление данных - -### 4.1 Real-time updates -- [ ] **Frame counter** увеличивается каждое обновление -- [ ] **FPS** отражает реальную производительность -- [ ] **Movement constants** соответствуют значениям из MovementComponent - ---- - ## Критерии прохождения -- [ ] Все 3 страницы отображаются корректно - [ ] Навигация работает в обе стороны - [ ] Toggle функции работают - [ ] Данные обновляются в реальном времени diff --git a/Content/Debug/Structs/S_DebugPage.ts b/Content/Debug/Structs/S_DebugPage.ts index c579dba..8bca320 100644 --- a/Content/Debug/Structs/S_DebugPage.ts +++ b/Content/Debug/Structs/S_DebugPage.ts @@ -1,13 +1,13 @@ // Debug/Structs/S_DebugPage.ts -import type { E_DebugPageID } from '#root/Debug/Enums/E_DebugPageID.js'; -import type { E_DebugUpdateFunction } from '#root/Debug/Enums/E_DebugUpdateFunction.js'; +import type { Float } from '#root/UE/Float.ts'; import type { Text } from '#root/UE/Text.ts'; export interface S_DebugPage { - PageID: E_DebugPageID; + PageID: string; Title: Text; Content: Text; + RefreshRate: Float; IsVisible: boolean; - UpdateFunction: E_DebugUpdateFunction; + LastUpdateTime: Float; } diff --git a/Content/Debug/Structs/S_DebugPage.uasset b/Content/Debug/Structs/S_DebugPage.uasset index 48edb7a..f13dd44 100644 --- a/Content/Debug/Structs/S_DebugPage.uasset +++ b/Content/Debug/Structs/S_DebugPage.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e22e97785d17d1670cec67ec24f4f9df99ea1f58b2a12cf5e92a01709b86b72 -size 8336 +oid sha256:6b0f38379acc6dd319285f5d14b6a7549b49d0113c662ca65d7c305c8bd1325a +size 8771 diff --git a/Content/Debug/Structs/S_DebugSettings.ts b/Content/Debug/Structs/S_DebugSettings.ts deleted file mode 100644 index 8eabc82..0000000 --- a/Content/Debug/Structs/S_DebugSettings.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Debug/Enums/S_DebugSettings.ts - -import type { ESlateVisibility } from '#root/UE/ESlateVisibility.ts'; -import type { Float } from '#root/UE/Float.ts'; -import type { Integer } from '#root/UE/Integer.ts'; - -export interface S_DebugSettings { - CurrentMode: ESlateVisibility; - CurrentPageIndex: Integer; - ShowVisualDebug: boolean; - UpdateFrequency: Float; -} diff --git a/Content/Debug/Structs/S_DebugSettings.uasset b/Content/Debug/Structs/S_DebugSettings.uasset deleted file mode 100644 index 24fcb44..0000000 --- a/Content/Debug/Structs/S_DebugSettings.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fa26fc4986f100489a5e3d98b52bd748b3528ced5ebebfc03fb76db0c9f4750b -size 7276 diff --git a/Content/Debug/TDD.md b/Content/Debug/TDD.md index 9013adc..5b12796 100644 --- a/Content/Debug/TDD.md +++ b/Content/Debug/TDD.md @@ -3,474 +3,537 @@ # Система Debug - Техническая Документация ## Обзор -Интегрированная система отладки для мониторинга производительности и параметров движения в реальном времени. Система обеспечивает многостраничный интерфейс с навигацией, автоматическим обновлением контента и визуальными инструментами отладки для разработчиков. +Система динамической отладки для мониторинга параметров компонентов в реальном времени. Компоненты самостоятельно регистрируют свои debug страницы и управляют их обновлением без централизованной конфигурации. ## Архитектурные принципы -- **Модульность:** Каждая страница отладки независима и может быть добавлена/удалена без влияния на систему -- **Производительность:** Контролируемая частота обновления для предотвращения падения FPS -- **Расширяемость:** Простое добавление новых страниц через DataTable конфигурацию -- **Интеграция:** Глубокая интеграция с Movement System и Toast notification system +- **Децентрализация:** Каждый компонент регистрирует и обновляет свои страницы независимо +- **Гибкость:** Страницы могут добавляться/удаляться в runtime без предварительной конфигурации +- **Производительность:** Индивидуальный контроль частоты обновления для каждой страницы +- **Простота:** Минимум кода для добавления debug информации в любой компонент ## Компоненты системы ### AC_DebugHUD (Core Component) **Ответственности:** -- Управление жизненным циклом debug страниц (регистрация, навигация, обновление) -- Контроль частоты обновления для оптимизации производительности -- Интеграция с Movement Component для получения данных в реальном времени -- Управление видимостью debug интерфейса и visual debug режима +- Регистрация debug страниц от любых компонентов +- Управление навигацией и отображением страниц +- Контроль видимости debug интерфейса +- Расчет FPS и управление обновлением UI -**Ключевые функции:** -- `InitializeDebugHUD()` - Инициализация с регистрацией страниц и созданием виджета -- `UpdateHUD()` - Основной цикл обновления, вызываемый каждый кадр -- `NextPage()` / `PreviousPage()` - Навигация между страницами с циклическим переходом -- `ToggleDebugHUD()` - Переключение видимости debug интерфейса -- `ToggleVisualDebug()` - Включение/выключение визуальной отладки +**Ключевые публичные функции:** + +#### Управление страницами +- **`AddDebugPage(PageID, Title, RefreshRate, IsVisible)`** + - Регистрирует новую debug страницу или обновляет существующую + - `PageID`: Уникальный идентификатор (string) + - `Title`: Заголовок страницы (Text) + - `RefreshRate`: Частота обновления в Hz (number, default 30) + - `IsVisible`: Видимость страницы (boolean, default true) + +- **`UpdatePageContent(PageID, Content)`** + - Обновляет содержимое страницы + - Вызывается из Tick компонента владельца страницы + - `Content`: Текстовое содержимое (Text) + +- **`ShouldUpdatePage(PageID, CurrentTime)`** + - Проверяет, нужно ли обновлять страницу согласно RefreshRate + - Возвращает `true` если прошло достаточно времени + - Автоматически обновляет LastUpdateTime при возврате `true` + +- **`RemoveDebugPage(PageID)`** + - Удаляет страницу из системы + - Автоматически корректирует CurrentPageIndex + +- **`SetPageVisibility(PageID, IsVisible)`** + - Управляет видимостью страницы без удаления + +#### Навигация +- **`ToggleDebugHUD()`** + - Переключает видимость всего debug интерфейса + +- **`NextPage()` / `PreviousPage()`** + - Навигация между видимыми страницами с циклическим переходом + +- **`ToggleVisualDebug()`** + - Включение/выключение визуальной отладки (debug draw) + +#### Система +- **`InitializeDebugHUD(ToastComponent, InputDeviceComponent)`** + - Инициализация системы с опциональными компонентами + - Создание виджета и подготовка к регистрации страниц + +- **`UpdateHUD(CurrentTime)`** + - Основной цикл обновления UI + - Расчет FPS и обновление отображения + - Вызывается из Tick главного персонажа + +**Ключевые приватные функции:** + +#### Утилиты поиска +- **`FindPageIndex(PageID)`** - Поиск индекса страницы по ID +- **`GetVisiblePages()`** - Получение только видимых страниц +- **`GetCurrentPage()`** - Получение активной страницы + +#### Валидация +- **`IsCurrentPageValid(visiblePagesCount)`** - Проверка валидности индекса +- **`IsTimeToUpdate(timeSinceLastUpdate, updateInterval)`** - Проверка времени обновления +- **`IsAtFirstPage()`** - Проверка, является ли текущая страница первой + +#### Производительность +- **`ShouldUpdateFPS(currentTime)`** - Проверка необходимости пересчета FPS +- **`UpdateFPSCounter(currentTime)`** - Расчет FPS на основе кадров + +#### Виджет управление +- **`GetControlHints()`** - Получение подсказок управления по типу устройства +- **`UpdateWidgetDisplay()`** - Обновление содержимого виджета +- **`GetNavigationText()`** - Генерация текста навигации +- **`CreateDebugWidget()`** - Создание экземпляра виджета +- **`UpdateWidgetVisibility()`** - Обновление видимости виджета +- **`ShouldShowDebugHUD()`** - Проверка условий отображения HUD ### WBP_DebugHUD (UI Widget) **Ответственности:** -- Отображение текущей debug информации в структурированном виде -- Управление тремя основными текстовыми элементами: заголовок, контент, навигация -- Автоматическое обновление отображения при изменении данных -- Интеграция с Movement Component для прямого доступа к данным +- Отображение debug информации в структурированном виде +- Управление тремя текстовыми секциями: заголовок, контент, навигация +- Автоматическое обновление при изменении данных **Ключевые функции:** - `SetHeaderText()` - Установка заголовка текущей страницы - `SetContentText()` - Обновление основного контента страницы -- `SetNavigationText()` - Отображение информации о навигации и текущей позиции +- `SetNavigationText()` - Отображение информации о навигации и FPS -### DT_DebugPages (DataTable Configuration) -**Ответственности:** -- Декларативное определение всех доступных debug страниц -- Конфигурация связи между страницами и функциями обновления -- Централизованное управление видимостью и метаданными страниц - -## Система страниц отладки - -### Типы страниц (E_DebugPageID) +### S_DebugPage (Data Structure) +**Поля:** ```typescript -enum E_DebugPageID { - MovementInfo = 'MovementInfo', // Константы движения - SurfaceInfo = 'SurfaceInfo', // Классификация поверхностей - PerformanceInfo = 'PerformanceInfo' // Метрики производительности -} -``` - -### Функции обновления (E_DebugUpdateFunction) -```typescript -enum E_DebugUpdateFunction { - UpdateMovementPage = 'UpdateMovementPage', // Обновление страницы движения - UpdateSurfacePage = 'UpdateSurfacePage', // Обновление страницы поверхностей - UpdatePerformancePage = 'UpdatePerformancePage' // Обновление страницы производительности -} -``` - -### Конфигурация страниц -```typescript -// Movement Constants Page { - PageID: E_DebugPageID.MovementInfo, - Title: 'Movement Constants', - Content: '', // Динамически обновляется - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateMovementPage -} - -// Surface Classification Page -{ - PageID: E_DebugPageID.SurfaceInfo, - Title: 'Surface Classification', - Content: '', // Динамически обновляется - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateSurfacePage -} - -// Performance Metrics Page -{ - PageID: E_DebugPageID.PerformanceInfo, - Title: 'Performance Metrics', - Content: '', // Динамически обновляется - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdatePerformancePage + PageID: string; // Уникальный идентификатор страницы + Title: Text; // Заголовок для отображения + Content: Text; // Текущее содержимое страницы + RefreshRate: Float; // Частота обновления (Hz) + IsVisible: boolean; // Флаг видимости + LastUpdateTime: Float; // Время последнего обновления } ``` -## Структуры данных +## Workflow использования + +### Регистрация debug страницы в компоненте -### S_DebugPage ```typescript -interface S_DebugPage { - PageID: E_DebugPageID; // Уникальный идентификатор страницы - Title: Text; // Заголовок для отображения - Content: Text; // Основное содержимое страницы - IsVisible: boolean; // Видимость в навигации - UpdateFunction: E_DebugUpdateFunction; // Функция обновления контента -} -``` +// Movement/Components/AC_Movement.ts -### S_DebugSettings -```typescript -interface S_DebugSettings { - CurrentMode: ESlateVisibility; // Текущий режим видимости (Visible/Hidden) - CurrentPageIndex: Integer; // Индекс активной страницы (0-based) - ShowVisualDebug: boolean; // Включение визуальной отладки - UpdateFrequency: Float; // Частота обновления в Герцах (0 = каждый кадр) -} -``` +export class AC_Movement extends ActorComponent { + private DebugHUDRef: AC_DebugHUD | null = null; -## Контент страниц - -### Movement Constants Page -``` -Max Speed: 600.0 -Acceleration: 2000.0 -Friction: 8.0 -Gravity: 980.0 -``` - -### Surface Classification Page -``` -Walkable: ≤50° -Steep Slope: 50°-85° -Wall: 85°-95° -Ceiling: >95° -``` - -### Performance Metrics Page -``` -Frame: 1247 -FPS: 60.2 -Update Rate: Every Frame | 30 Hz -ActivePages: 3 -``` - -## Система навигации - -### Циклическая навигация -```typescript -// Переход к следующей странице с возвратом в начало -NextPage(): void { - currentIndex = (currentIndex + 1) % visiblePagesLength -} - -// Переход к предыдущей странице с переходом в конец -PreviousPage(): void { - currentIndex = currentIndex - 1 < 0 ? - visiblePagesLength - 1 : - currentIndex - 1 -} -``` - -### Управление видимостью -- **Page Up/Page Down** - Навигация между страницами -- **F1** - Переключение видимости debug HUD -- **F2** - Переключение визуальной отладки - -### Индикация навигации -``` -Page 1/3 | PageUp/PageDown - Navigate -Page 2/3 | PageUp/PageDown - Navigate -Page 3/3 | PageUp/PageDown - Navigate -``` - -## Система обновления - -### Контроль частоты обновления -```typescript -// Проверка необходимости обновления -ShouldUpdateDebugHUD(CurrentTime: Float): boolean { - if (updateFrequency > 0) { - return currentTime - lastUpdateTime >= 1 / updateFrequency - } else { - return true // Обновление каждый кадр - } -} -``` - -### Режимы обновления -- **UpdateFrequency = 0:** Каждый кадр (максимальная отзывчивость) -- **UpdateFrequency = 30:** 30 раз в секунду (баланс производительности/отзывчивости) -- **UpdateFrequency = 10:** 10 раз в секунду (минимальное влияние на производительность) - -### Цикл обновления -```typescript -UpdateHUD(CurrentTime: Float, DeltaTime: Float): void { - if (ShouldUpdateDebugHUD(CurrentTime)) { - FrameCounter++ - FPS = 1 / DeltaTime - LastUpdateTime = CurrentTime + public BeginPlay(): void { + super.BeginPlay(); - if (ShouldShowDebugHUD()) { - UpdateCurrentPage() - UpdateWidgetPage() + // Получаем ссылку на DebugHUD + this.DebugHUDRef = this.GetOwner().FindComponentByClass(AC_DebugHUD); + + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + // Регистрируем страницы движения + this.DebugHUDRef.AddDebugPage( + 'MovementBasics', // Уникальный ID + 'Movement Info', // Заголовок + 30, // 30 Hz + true // Видимая + ); + + this.DebugHUDRef.AddDebugPage( + 'MovementPhysics', + 'Physics Details', + 60 // 60 Hz для высокочастотных данных + ); + } + } + + public TickComponent(DeltaTime: Float): void { + super.TickComponent(DeltaTime); + + // Обновляем свою логику + this.UpdateMovement(DeltaTime); + + // Обновляем debug страницы + this.UpdateDebugPages(); + } + + private UpdateDebugPages(): void { + if (!SystemLibrary.IsValid(this.DebugHUDRef)) return; + + const currentTime = this.GetWorld().GetTimeSeconds(); + + // Проверяем нужно ли обновлять страницу (учитывает RefreshRate) + if (this.DebugHUDRef.ShouldUpdatePage('MovementBasics', currentTime)) { + const content = [ + `Speed: ${this.Speed.toFixed(2)} cm/s`, + `Acceleration: ${this.Acceleration.toFixed(2)} cm/s²`, + `Is Grounded: ${this.IsGrounded ? 'Yes' : 'No'}` + ].join('\n'); + + this.DebugHUDRef.UpdatePageContent('MovementBasics', content); + } + + if (this.DebugHUDRef.ShouldUpdatePage('MovementPhysics', currentTime)) { + const content = [ + `Velocity: ${this.GetVelocity().Size().toFixed(2)} cm/s`, + `Mass: ${this.GetMass().toFixed(2)} kg`, + `Friction: ${this.GetFriction().toFixed(3)}` + ].join('\n'); + + this.DebugHUDRef.UpdatePageContent('MovementPhysics', content); } } } ``` -## Производительность +### Инициализация в главном персонаже + +```typescript +// Characters/BP_MainCharacter.ts + +export class BP_MainCharacter extends Character { + public DebugHUDComponent: AC_DebugHUD; + + public BeginPlay(): void { + super.BeginPlay(); + + // Инициализация DebugHUD (должна быть ПЕРВОЙ) + this.DebugHUDComponent.InitializeDebugHUD( + this.ToastSystemComponent, + this.InputDeviceComponent + ); + + // После этого все компоненты могут регистрировать свои страницы + } + + public Tick(DeltaTime: Float): void { + super.Tick(DeltaTime); + + const currentTime = this.GetGameTimeSinceCreation(); + + // Обновляем только UI, не контент страниц + this.DebugHUDComponent.UpdateHUD(currentTime); + } +} +``` + +### Динамическое управление страницами + +```typescript +// Добавление страницы в runtime +public EnableAdvancedDebug(): void { + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + this.DebugHUDRef.AddDebugPage( + 'AdvancedMetrics', + 'Advanced Metrics', + 120 // Очень высокая частота + ); + } +} + +// Удаление страницы +public DisableAdvancedDebug(): void { + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + this.DebugHUDRef.RemoveDebugPage('AdvancedMetrics'); + } +} + +// Скрытие/показ страницы без удаления +public TogglePhysicsDebug(): void { + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + this.showPhysics = !this.showPhysics; + this.DebugHUDRef.SetPageVisibility('MovementPhysics', this.showPhysics); + } +} +``` + +## Преимущества нового подхода + +### ✅ Децентрализация +- Каждый компонент управляет своими debug страницами +- Нет необходимости модифицировать централизованные DataTable или enum'ы +- Компонент владеет логикой генерации своего debug контента + +### ✅ Гибкость +- Страницы добавляются/удаляются динамически в runtime +- Легко менять выводимую информацию прямо в компоненте +- Условная регистрация страниц (например, только в Debug билдах) + +### ✅ Простота использования +```typescript +// Всего 3 шага: +// 1. Регистрация в BeginPlay +this.DebugHUD.AddDebugPage('MyPage', 'My Title', 30); + +// 2. Проверка в Tick +if (this.DebugHUD.ShouldUpdatePage('MyPage', currentTime)) { + // 3. Обновление контента + this.DebugHUD.UpdatePageContent('MyPage', this.GetDebugText()); +} +``` + +### ✅ Индивидуальный контроль производительности +- Каждая страница имеет свой RefreshRate +- Критичные данные: 60-120 Hz +- Обычные данные: 30 Hz +- Статичные данные: 15 Hz или меньше + +### ✅ Blueprint-совместимость +- Все параметры - простые типы (string, Text, number, boolean) +- Нет callback'ов или сложных структур данных +- Можно использовать как из C++/TypeScript, так и из Blueprint + +## Performance considerations ### Оптимизации -- **Контролируемая частота:** Программируемая частота обновления предотвращает избыточные расчеты -- **Ленивое обновление:** Обновление только видимых страниц -- **Кэширование FPS:** Расчет FPS только при обновлении -- **Условное отображение:** Пропуск обновления UI при скрытом HUD +- **Smart update timing:** `ShouldUpdatePage()` автоматически контролирует частоту +- **Single widget update:** UpdateHUD обновляет только текущую видимую страницу +- **Lazy evaluation:** Контент генерируется только когда страница видима и нужно обновление +- **FPS calculation:** Раз в секунду, не влияет на gameplay ### Benchmarks -- **Инициализация:** <0.5ms (создание виджета и регистрация страниц) -- **UpdateHUD (30Hz):** <0.1ms на обновление при включенном ограничении -- **UpdateHUD (каждый кадр):** <0.2ms на обновление без ограничений -- **Навигация:** <0.05ms на переключение страницы -- **Memory footprint:** ~1KB на debug HUD component +- **AddDebugPage:** <0.1ms (простое добавление в массив) +- **UpdatePageContent:** <0.05ms (обновление одного элемента массива) +- **ShouldUpdatePage:** <0.05ms (простая проверка времени) +- **UpdateHUD (widget refresh):** <0.2ms (обновление UI элементов) +- **Memory per page:** ~200 bytes (структура + strings) -### Performance considerations -- **String concatenation:** Минимизировано использование + для Text объектов -- **Widget updates:** Обновление UI только при изменении данных -- **Conditional rendering:** Полное отключение обновлений при скрытом HUD -- **Memory allocations:** Переиспользование текстовых буферов +### Best Practices для производительности + +```typescript +// ✅ Хорошо - контролируемое обновление +if (this.DebugHUD.ShouldUpdatePage('MyPage', currentTime)) { + this.DebugHUD.UpdatePageContent('MyPage', this.BuildContent()); +} + +// ✅ Хорошо - разная частота для разных данных +this.DebugHUD.AddDebugPage('CriticalData', 'Critical', 60); // Частое +this.DebugHUD.AddDebugPage('GeneralInfo', 'General', 30); // Обычное +this.DebugHUD.AddDebugPage('StaticData', 'Static', 5); // Редкое + +// ❌ Плохо - обновление без проверки частоты +this.DebugHUD.UpdatePageContent('MyPage', content); // Каждый кадр! + +// ❌ Плохо - слишком высокая частота для некритичных данных +this.DebugHUD.AddDebugPage('SlowData', 'Slow', 120); // Избыточно +``` ## Система тестирования ### FT_DebugSystem (Basic Functionality) **Покрывает:** - Успешность инициализации системы (`IsInitialized = true`) -- Соответствие количества страниц в DataTable и загруженных страниц -- Валидность компонентов Movement и DebugHUD -- Корректность загрузки конфигурации из DataTable +- Валидность компонента DebugHUD после инициализации +- Корректность создания виджета +- Базовую функциональность регистрации страниц + +**Тестовый сценарий:** +```typescript +1. Инициализация DebugHUD +2. Проверка IsInitialized == true +3. Проверка валидности компонента через SystemLibrary.IsValid() +``` ### FT_DebugNavigation (Navigation System) **Покрывает:** -- Корректность индексации при навигации (`CurrentPageIndex` в допустимых пределах) -- Циклическое поведение при достижении границ списка страниц -- Валидность состояния после операций `NextPage()` и `PreviousPage()` -- Устойчивость индексов при многократных переходах +- Корректность индексации при навигации +- Валидность CurrentPageIndex после NextPage/PreviousPage +- Циклическое поведение при достижении границ +- Устойчивость к многократным переходам -### FT_DebugPageContentGenerator (Content Generation) -**Покрывает:** -- Генерацию непустого контента для всех зарегистрированных страниц -- Корректность работы всех функций обновления (`UpdateMovementPage`, `UpdateSurfacePage`, `UpdatePerformancePage`) -- Обработку случаев отсутствия Movement Component -- Валидность сгенерированного контента - -### Test Coverage +**Тестовый сценарий:** ```typescript -// Тестируемые сценарии -TestScenarios = [ - 'Инициализация системы с корректными параметрами', - 'Навигация через все страницы в прямом направлении', - 'Навигация через все страницы в обратном направлении', - 'Генерация контента при наличии Movement Component', - 'Генерация контента при отсутствии Movement Component', - 'Переключение видимости debug HUD', - 'Переключение визуальной отладки', - 'Обновление с различными частотами', - 'Обработка пустого списка страниц', - 'Восстановление после ошибок' -] +1. Инициализация с проверкой начального состояния +2. NextPage() → проверка индекса в пределах [0, VisiblePages.length) +3. PreviousPage() → проверка индекса в пределах [0, VisiblePages.length) +4. Множественные переходы → индекс всегда валидный ``` -## Интеграция с системами - -### С Movement System +**Валидация состояния:** ```typescript -// Получение данных движения для отображения -UpdateMovementPage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.MovementComponent)) { - return { - ...Page, - Content: - `Max Speed: ${this.MovementComponent.MovementConstants.MaxSpeed}\n` + - `Acceleration: ${this.MovementComponent.MovementConstants.Acceleration}\n` + - `Friction: ${this.MovementComponent.MovementConstants.Friction}\n` + - `Gravity: ${this.MovementComponent.MovementConstants.Gravity}` +private IsStateValid(): boolean { + const { VisiblePagesLength, CurrentPageIndex } = this.DebugHUD.GetTestData(); + return ( + VisiblePagesLength > 0 && + CurrentPageIndex >= 0 && + CurrentPageIndex < VisiblePagesLength + ); +} +``` + +### FT_DebugPageManagement (NEW - Page Operations) +**Покрывает:** +- Динамическое добавление страниц через AddDebugPage +- Обновление контента через UpdatePageContent +- Проверку частоты обновления через ShouldUpdatePage +- Удаление страниц через RemoveDebugPage +- Управление видимостью через SetPageVisibility + +**Тестовый сценарий:** +```typescript +1. AddDebugPage('TestPage1', 'Test', 30) + → Проверка что страница добавлена (DebugPages.length == 1) + +2. UpdatePageContent('TestPage1', 'New Content') + → Проверка что контент обновился + +3. ShouldUpdatePage('TestPage1', time) + → Проверка что возвращает true при первом вызове + → Проверка что возвращает false сразу после + +4. AddDebugPage('TestPage2', 'Test2', 60) + → Проверка что страница добавлена (DebugPages.length == 2) + +5. SetPageVisibility('TestPage2', false) + → Проверка что VisiblePages.length == 1 + +6. RemoveDebugPage('TestPage1') + → Проверка что страница удалена (DebugPages.length == 1) + → Проверка что CurrentPageIndex корректно обновился +``` + +## Структура файлов + +``` +Content/ +├── Debug/ +│ ├── Components/ +│ │ └── AC_DebugHUD.ts # Main debug system component +│ ├── Structs/ +│ │ └── S_DebugPage.ts # Page data structure +│ ├── UI/ +│ │ └── WBP_DebugHUD.ts # Debug HUD widget +│ └── Tests/ +│ ├── FT_DebugSystem.ts # Basic functionality tests +│ ├── FT_DebugNavigation.ts # Navigation system tests +│ └── FT_DebugPageManagement.ts # Page operations tests (NEW) +├── Input/ +│ └── IMC_Default.ts # Input mapping integration +└── Characters/ + └── BP_MainCharacter.ts # Main integration point +``` + +## Примеры использования из разных компонентов + +### Camera Component Debug +```typescript +export class AC_Camera extends ActorComponent { + private DebugHUDRef: AC_DebugHUD | null = null; + + public BeginPlay(): void { + super.BeginPlay(); + + this.DebugHUDRef = this.GetOwner().FindComponentByClass(AC_DebugHUD); + + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + this.DebugHUDRef.AddDebugPage( + 'CameraInfo', + 'Camera State', + 30 + ); + } + } + + public TickComponent(DeltaTime: Float): void { + super.TickComponent(DeltaTime); + + if (!SystemLibrary.IsValid(this.DebugHUDRef)) return; + + const currentTime = this.GetWorld().GetTimeSeconds(); + + if (this.DebugHUDRef.ShouldUpdatePage('CameraInfo', currentTime)) { + const content = [ + `FOV: ${this.GetFOV().toFixed(1)}°`, + `Distance: ${this.GetCameraDistance().toFixed(2)} cm`, + `Pitch: ${this.GetPitch().toFixed(1)}°`, + `Yaw: ${this.GetYaw().toFixed(1)}°`, + `Target: ${this.GetTargetLocation().ToString()}` + ].join('\n'); + + this.DebugHUDRef.UpdatePageContent('CameraInfo', content); } } } ``` -### С Toast System +### Network Component Debug ```typescript -// Интеграция с уведомлениями -InitializeDebugHUD(MovementComponentRef, ToastComponentRef): void { - // ... инициализация ... - this.ToastComponent.ShowToast('Debug HUD Initialized', E_MessageType.Success) -} +export class AC_NetworkReplication extends ActorComponent { + private DebugHUDRef: AC_DebugHUD | null = null; -ToggleVisualDebug(): void { - // ... переключение ... - this.ToastComponent.ShowToast( - `Visual Debug ${this.DebugSettings.ShowVisualDebug ? 'Enabled' : 'Disabled'}` - ) -} -``` + public BeginPlay(): void { + super.BeginPlay(); + + this.DebugHUDRef = this.GetOwner().FindComponentByClass(AC_DebugHUD); + + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + // Регистрируем только в сетевой игре + if (this.GetWorld().IsNetMode()) { + this.DebugHUDRef.AddDebugPage( + 'NetworkStats', + 'Network Statistics', + 15 // Обновляем реже для сетевых данных + ); + } + } + } -### С Input System -```typescript -// Привязка клавиш через Enhanced Input -IMC_Default.mapKey(IA_NextDebugMode, 'PageDown') // Следующая страница -IMC_Default.mapKey(IA_PrevDebugMode, 'PageUp') // Предыдущая страница -IMC_Default.mapKey(IA_ToggleHUD, 'F1') // Переключение HUD -IMC_Default.mapKey(IA_ToggleVisualDebug, 'F2') // Visual debug -``` - -## API Reference - -### Публичные методы - -#### InitializeDebugHUD() -```typescript -InitializeDebugHUD(MovementComponentRef: AC_Movement, ToastComponentRef: AC_ToastSystem): void -``` -**Описание:** Инициализирует debug HUD систему с необходимыми компонентами -**Параметры:** -- `MovementComponentRef` - Ссылка на компонент движения для мониторинга -- `ToastComponentRef` - Ссылка на систему уведомлений - -**Когда вызывать:** EventBeginPlay в главном персонаже после инициализации dependencies -**Эффекты:** Создает debug widget, регистрирует страницы, показывает success уведомление - -#### UpdateHUD() -```typescript -UpdateHUD(CurrentTime: Float, DeltaTime: Float): void -``` -**Параметры:** -- `CurrentTime` - Текущее игровое время в секундах -- `DeltaTime` - Время с последнего кадра в секундах - -**Описание:** Основной цикл обновления debug информации -**Когда вызывать:** EventTick в главном персонаже -**Эффекты:** Обновляет счетчики, FPS, контент страниц - -#### ToggleDebugHUD() -```typescript -ToggleDebugHUD(): void -``` -**Описание:** Переключает видимость debug HUD между Visible и Hidden -**Эффекты:** Изменяет CurrentMode в DebugSettings, обновляет видимость виджета - -#### NextPage() / PreviousPage() -```typescript -NextPage(): void -PreviousPage(): void -``` -**Описание:** Навигация между debug страницами с циклическим переходом -**Требования:** Система должна быть инициализирована, наличие видимых страниц -**Эффекты:** Изменяет CurrentPageIndex, обновляет отображаемый контент - -#### ToggleVisualDebug() -```typescript -ToggleVisualDebug(): void -``` -**Описание:** Включает/выключает визуальную отладку (collision shapes, debug lines) -**Эффекты:** Изменяет ShowVisualDebug в DebugSettings, показывает toast уведомление - -### Публичные свойства - -#### DebugSettings (Instance Editable) -```typescript -DebugSettings: S_DebugSettings = { - CurrentMode: ESlateVisibility.Visible, // Режим видимости по умолчанию - CurrentPageIndex: 0, // Начальная страница - ShowVisualDebug: false, // Визуальная отладка отключена - UpdateFrequency: 0 // Обновление каждый кадр -} -``` - -#### ToastComponent (Public for Testing) -```typescript -ToastComponent: AC_ToastSystem | null = null -``` -**Описание:** Публичная ссылка на Toast System для использования в тестах -**Use case:** Доступ к toast функциональности из test случаев - -### Методы для тестирования - -#### GetVisiblePages() -```typescript -GetVisiblePages(): UEArray -``` -**Описание:** Возвращает массив всех видимых debug страниц -**Use case:** Валидация навигации и подсчет доступных страниц в тестах - -#### GetTestData() -```typescript -GetTestData(): { - IsInitialized: boolean, - DebugDataTable: DataTable, - DebugPages: UEArray -} -``` -**Описание:** Предоставляет доступ к внутреннему состоянию для тестирования -**Use case:** Валидация инициализации и внутреннего состояния в автотестах - -## Расширяемость - -### Добавление новой debug страницы -1. **Расширить E_DebugPageID enum:** -```typescript -enum E_DebugPageID { - // ... existing pages - NetworkInfo = 'NetworkInfo' // Новая страница сетевой информации -} -``` - -2. **Добавить функцию обновления в E_DebugUpdateFunction:** -```typescript -enum E_DebugUpdateFunction { - // ... existing functions - UpdateNetworkPage = 'UpdateNetworkPage' -} -``` - -3. **Реализовать функцию обновления в AC_DebugHUD:** -```typescript -UpdateNetworkPage(Page: S_DebugPage): S_DebugPage { - return { - ...Page, - Content: - `Ping: ${this.GetNetworkPing()}ms\n` + - `Packet Loss: ${this.GetPacketLoss()}%\n` + - `Bandwidth: ${this.GetBandwidth()} KB/s` + public TickComponent(DeltaTime: Float): void { + super.TickComponent(DeltaTime); + + if (!SystemLibrary.IsValid(this.DebugHUDRef)) return; + + const currentTime = this.GetWorld().GetTimeSeconds(); + + if (this.DebugHUDRef.ShouldUpdatePage('NetworkStats', currentTime)) { + const content = [ + `Ping: ${this.GetPing()}ms`, + `Packet Loss: ${this.GetPacketLoss().toFixed(2)}%`, + `Bandwidth: ${this.GetBandwidth().toFixed(1)} KB/s`, + `Connected: ${this.IsConnected() ? 'Yes' : 'No'}`, + `Players: ${this.GetPlayerCount()}` + ].join('\n'); + + this.DebugHUDRef.UpdatePageContent('NetworkStats', content); + } } } ``` -4. **Обновить switch в UpdateCurrentPage():** +### Conditional Debug Pages ```typescript -switch (CurrentPage.UpdateFunction) { - // ... existing cases - case E_DebugUpdateFunction.UpdateNetworkPage: { - CurrentPage = this.UpdateNetworkPage(CurrentPage) - break +export class AC_AdvancedSystem extends ActorComponent { + private DebugHUDRef: AC_DebugHUD | null = null; + private showDetailedDebug: boolean = false; + + public BeginPlay(): void { + super.BeginPlay(); + + this.DebugHUDRef = this.GetOwner().FindComponentByClass(AC_DebugHUD); + + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + // Базовая страница всегда + this.DebugHUDRef.AddDebugPage('BasicInfo', 'Basic Info', 30); + + // Детальная только в Debug билде + if (BUILD_DEBUG) { + this.DebugHUDRef.AddDebugPage( + 'DetailedInfo', + 'Detailed Debug', + 120, + false // Скрыта по умолчанию + ); + } + } } -} -``` -5. **Добавить конфигурацию в DT_DebugPages:** -```typescript -{ - Name: new Name('NetworkInfo'), - PageID: E_DebugPageID.NetworkInfo, - Title: 'Network Statistics', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateNetworkPage -} -``` - -### Пример расширенной страницы производительности: -```typescript -UpdateAdvancedPerformancePage(Page: S_DebugPage): S_DebugPage { - return { - ...Page, - Content: - `Frame: ${this.FrameCounter}\n` + - `FPS: ${this.FPS.toFixed(1)}\n` + - `Frame Time: ${(1000 / this.FPS).toFixed(2)}ms\n` + - `Memory: ${this.GetMemoryUsage()}MB\n` + - `Draw Calls: ${this.GetDrawCalls()}\n` + - `Triangles: ${this.GetTriangleCount()}\n` + - `Update Rate: ${this.GetUpdateRateDescription()}` + public ToggleDetailedDebug(): void { + this.showDetailedDebug = !this.showDetailedDebug; + + if (SystemLibrary.IsValid(this.DebugHUDRef)) { + this.DebugHUDRef.SetPageVisibility('DetailedInfo', this.showDetailedDebug); + } } } ``` @@ -478,180 +541,17 @@ UpdateAdvancedPerformancePage(Page: S_DebugPage): S_DebugPage { ## Известные ограничения ### Текущие ограничения -1. **Статическая конфигурация страниц** - Страницы определяются в design-time через DataTable +1. **Текстовый контент только** - Нет поддержки графиков, диаграмм, интерактивных элементов 2. **Фиксированный layout** - Трехсекционный layout (header, content, navigation) не настраивается -3. **Только текстовый контент** - Нет поддержки графиков, диаграмм, интерактивных элементов -4. **Однопоточное обновление** - Все страницы обновляются в main thread +3. **Линейная навигация** - Только последовательный переход между страницами +4. **Глобальный FPS** - Один FPS counter для всей системы -### Архитектурные ограничения -1. **Линейная навигация** - Только последовательный переход между страницами -2. **Глобальная частота обновления** - Одна частота для всех страниц -3. **Зависимость от MovementComponent** - Большинство страниц требует Movement System -4. **UI thread blocking** - Сложные вычисления в update функциях могут блокировать UI +### Архитектурные решения +1. **Компоненты управляют своими страницами** - Каждый компонент отвечает за регистрацию и обновление +2. **String-based PageID** - Простота использования в ущерб типобезопасности +3. **Tick-based updates** - Компоненты обновляют страницы в своем Tick +4. **No data caching** - Контент генерируется при каждом обновлении -### Performance ограничения -1. **String concatenation** - Каждое обновление создает новые строки -2. **No data caching** - Данные пересчитываются при каждом обновлении -3. **Synchronous updates** - Все обновления выполняются синхронно в main thread +## Миграция со старого подхода -## Планы развития (Stage 3+) - -### Краткосрочные улучшения -1. **Rich content support** - Поддержка графиков и визуальных элементов -2. **Configurable layouts** - Настраиваемые макеты для разных типов страниц -3. **Per-page update frequency** - Индивидуальная частота обновления для каждой страницы -4. **Data caching system** - Кэширование вычисляемых данных для оптимизации - -### Средне срочные цели -1. **Interactive debug controls** - Слайдеры, чекбоксы для runtime настройки параметров -2. **Debug command console** - Консоль для выполнения debug команд -3. **Export/Import settings** - Сохранение и загрузка debug конфигураций -4. **Multi-monitor support** - Отображение debug информации на втором мониторе - -### Долгосрочные цели -1. **Remote debug server** - Web-интерфейс для удаленной отладки -2. **Historical data tracking** - Сохранение и анализ исторических данных производительности -3. **AI-powered insights** - Автоматическое выявление проблем производительности -4. **Integration with profiling tools** - Связь с внешними профайлерами и аналитикой - -## Интеграционные точки - -### С Gameplay System -- **Game state monitoring:** Отслеживание состояния игровых объектов -- **Player statistics:** Мониторинг статистики игрока в реальном времени -- **Event logging:** Автоматическая запись важных игровых событий - -### С Rendering System -- **Draw call monitoring:** Отслеживание количества draw calls -- **Texture memory usage:** Мониторинг использования видеопамяти -- **Shader performance:** Анализ производительности шейдеров - -### С Audio System -- **Audio channel monitoring:** Отслеживание использования аудио каналов -- **3D audio debugging:** Визуализация 3D звуковых источников -- **Performance metrics:** Мониторинг производительности аудио подсистемы - -## Файловая структура - -``` -Content/ -├── Debug/ -│ ├── Components/ -│ │ └── AC_DebugHUD.ts # Core debug HUD logic -│ ├── Enums/ -│ │ ├── E_DebugPageID.ts # Page identifier enum -│ │ └── E_DebugUpdateFunction.ts # Update function enum -│ ├── Structs/ -│ │ ├── S_DebugPage.ts # Page data structure -│ │ └── S_DebugSettings.ts # Settings structure -│ ├── Tables/ -│ │ └── DT_DebugPages.ts # Page configuration DataTable -│ ├── UI/ -│ │ └── WBP_DebugHUD.ts # Debug HUD widget -│ └── Tests/ -│ ├── FT_DebugSystem.ts # Basic functionality tests -│ ├── FT_DebugNavigation.ts # Navigation system tests -│ └── FT_DebugPageContentGenerator.ts # Content generation tests -├── Input/ -│ └── IMC_Default.ts # Input mapping integration -└── Blueprints/ - └── BP_MainCharacter.ts # Main integration point -``` - -## Best Practices - -### Использование в коде -```typescript -// ✅ Хорошо - полная инициализация с зависимостями -this.DebugHUDComponent.InitializeDebugHUD( - this.MovementComponent, - this.ToastSystemComponent -) - -// ✅ Хорошо - проверка инициализации перед использованием -if (this.DebugHUDComponent.GetTestData().IsInitialized) { - this.DebugHUDComponent.UpdateHUD(gameTime, deltaTime) -} - -// ✅ Хорошо - контролируемая частота обновления для performance -this.DebugHUDComponent.DebugSettings.UpdateFrequency = 30 // 30 Hz - -// ❌ Плохо - обновление без проверки инициализации -this.DebugHUDComponent.UpdateHUD(gameTime, deltaTime) - -// ❌ Плохо - слишком высокая частота обновления -this.DebugHUDComponent.DebugSettings.UpdateFrequency = 120 // Избыточно - -// ❌ Плохо - навигация без видимых страниц -if (this.DebugHUDComponent.GetVisiblePages().length === 0) { - this.DebugHUDComponent.NextPage() // Может привести к ошибке -} -``` - -### Рекомендации по созданию страниц -```typescript -// ✅ Хорошо - проверка валидности компонентов -UpdateCustomPage(Page: S_DebugPage): S_DebugPage { - if (SystemLibrary.IsValid(this.RequiredComponent)) { - return { ...Page, Content: 'Valid data' } - } else { - return { ...Page, Content: 'Component Not Found' } - } -} - -// ✅ Хорошо - форматированный контент с единицами измерения -Content: `Temperature: ${temperature}°C\nPressure: ${pressure} kPa` - -// ✅ Хорошо - использование fallback значений -const fps = this.FPS > 0 ? this.FPS.toFixed(1) : 'N/A' - -// ❌ Плохо - отсутствие проверок валидности -UpdateBadPage(Page: S_DebugPage): S_DebugPage { - return { ...Page, Content: this.UndefinedComponent.SomeProperty } // Crash! -} -``` - -### Performance рекомендации -- **Используйте UpdateFrequency:** Установите разумную частоту обновления (10-30 Hz для большинства случаев) -- **Кэшируйте тяжелые вычисления:** Не пересчитывайте сложные метрики каждый кадр -- **Проверяйте видимость:** Обновляйте только видимые страницы -- **Ленивое форматирование:** Форматируйте строки только при изменении данных - -### Отладка debug системы -```typescript -// Проверка состояния системы -console.log('Debug HUD State:', this.DebugHUDComponent.GetTestData()) - -// Валидация навигации -console.log('Visible Pages:', this.DebugHUDComponent.GetVisiblePages().length) -console.log('Current Index:', this.DebugHUDComponent.DebugSettings.CurrentPageIndex) - -// Мониторинг производительности -console.log('Update Frequency:', this.DebugHUDComponent.DebugSettings.UpdateFrequency) -console.log('FPS Impact:', this.measureDebugOverhead()) -``` - -## Заключение - -Debug System представляет собой комплексную систему для мониторинга и отладки игровых систем в реальном времени. Система спроектирована с акцентом на расширяемость, производительность и удобство использования разработчиками. - -**Ключевые достижения:** -- ✅ Многостраничный интерфейс с интуитивной навигацией -- ✅ Контролируемая частота обновления для оптимизации производительности -- ✅ Глубокая интеграция с Movement System для реального мониторинга -- ✅ Comprehensive система тестирования (3 автотеста покрывающих core функциональность) -- ✅ Расширяемая архитектура через DataTable конфигурацию -- ✅ Toast уведомления для feedback разработчику - -**Готовность к production:** -- Все автотесты проходят успешно для основных сценариев использования -- Performance impact минимален при корректной настройке UpdateFrequency -- Система интегрирована с Enhanced Input для удобного управления -- Готова к добавлению новых страниц без изменения core логики -- Полная совместимость с существующими системами (Movement, Toast, Input) - -**Архитектурные преимущества:** -- Четкое разделение между data (S_DebugPage), presentation (WBP_DebugHUD) и logic (AC_DebugHUD) -- Декларативная конфигурация через DataTable устраняет hard-coding -- Модульная система позволяет легко добавлять/удалять страницы -- Event-driven архитектура с минимальными coupling между компонентами +### Было (DT_DebugPages + E_DebugUpdateFunction) diff --git a/Content/Debug/Tables/DT_DebugPages.ts b/Content/Debug/Tables/DT_DebugPages.ts deleted file mode 100644 index 5317c52..0000000 --- a/Content/Debug/Tables/DT_DebugPages.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Debug/Tables/DT_DebugPages.ts - -import { E_DebugPageID } from '#root/Debug/Enums/E_DebugPageID.ts'; -import { E_DebugUpdateFunction } from '#root/Debug/Enums/E_DebugUpdateFunction.ts'; -import type { S_DebugPage } from '#root/Debug/Structs/S_DebugPage.ts'; -import { DataTable } from '#root/UE/DataTable.ts'; -import { Name } from '#root/UE/Name.ts'; -import { UEArray } from '#root/UE/UEArray.ts'; - -export const DT_DebugPages = new DataTable( - null, - new Name('DT_DebugPages'), - new UEArray([ - { - Name: new Name('MovementInfo'), - PageID: E_DebugPageID.MovementInfo, - Title: 'Movement Constants', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateMovementPage, - }, - { - Name: new Name('SurfaceInfo'), - PageID: E_DebugPageID.SurfaceInfo, - Title: 'Surface Classification', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateSurfacePage, - }, - { - Name: new Name('PerformanceInfo'), - PageID: E_DebugPageID.PerformanceInfo, - Title: 'Performance Metrics', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdatePerformancePage, - }, - { - Name: new Name('InputDeviceInfo'), - PageID: E_DebugPageID.InputDeviceInfo, - Title: 'Input Device Info', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateInputDevicePage, - }, - { - Name: new Name('CameraInfo'), - PageID: E_DebugPageID.CameraInfo, - Title: 'Camera System', - Content: '', - IsVisible: true, - UpdateFunction: E_DebugUpdateFunction.UpdateCameraPage, - }, - ]) -); diff --git a/Content/Debug/Tables/DT_DebugPages.uasset b/Content/Debug/Tables/DT_DebugPages.uasset deleted file mode 100644 index 57b3742..0000000 --- a/Content/Debug/Tables/DT_DebugPages.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00c7597ae1e3d6ad847f2715e67327d5a462a62f36cefe8c2195e53d963f21fb -size 5021 diff --git a/Content/Debug/Tests/FT_DebugNavigation.ts b/Content/Debug/Tests/FT_DebugNavigation.ts index 6456767..38d186d 100644 --- a/Content/Debug/Tests/FT_DebugNavigation.ts +++ b/Content/Debug/Tests/FT_DebugNavigation.ts @@ -1,9 +1,7 @@ // Debug/Tests/FT_DebugNavigation.ts -import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; -import { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; import { FunctionalTest } from '#root/UE/FunctionalTest.ts'; @@ -28,10 +26,8 @@ export class FT_DebugNavigation extends FunctionalTest { */ EventStartTest(): void { this.DebugHUDComponent.InitializeDebugHUD( - this.MovementComponent, this.ToastSystemComponent, - this.InputDeviceComponent, - this.CameraComponent + this.InputDeviceComponent ); this.IfValid('Debug HUD: Navigation invalid initial state', () => { @@ -73,17 +69,12 @@ export class FT_DebugNavigation extends FunctionalTest { currentPage: Integer ): boolean => visiblePagesLength > 0 && currentPage >= visiblePagesLength; - const IsPageIndexNonNegative = (currentPage: Integer): boolean => - currentPage >= 0; - if ( !IsPageIndexOutOfBounds( - this.DebugHUDComponent.GetVisiblePages().length, - this.DebugHUDComponent.DebugSettings.CurrentPageIndex + this.DebugHUDComponent.GetTestData().VisiblePagesLength, + this.DebugHUDComponent.GetTestData().CurrentPageIndex ) && - IsPageIndexNonNegative( - this.DebugHUDComponent.DebugSettings.CurrentPageIndex - ) + this.DebugHUDComponent.GetTestData().CurrentPageIndex >= 0 ) { Out(); } else { @@ -95,12 +86,6 @@ export class FT_DebugNavigation extends FunctionalTest { // VARIABLES // ════════════════════════════════════════════════════════════════════════════════════════ - /** - * Movement system component - required for debug HUD initialization - * @category Components - */ - MovementComponent = new AC_Movement(); - /** * Debug HUD system - primary component under test * Tests page navigation state management @@ -119,10 +104,4 @@ export class FT_DebugNavigation extends FunctionalTest { * @category Components */ InputDeviceComponent = new AC_InputDevice(); - - /** - * Camera system component - included for completeness, not directly tested - * @category Components - */ - CameraComponent = new AC_Camera(); } diff --git a/Content/Debug/Tests/FT_DebugNavigation.uasset b/Content/Debug/Tests/FT_DebugNavigation.uasset index 516b416..4f02351 100644 --- a/Content/Debug/Tests/FT_DebugNavigation.uasset +++ b/Content/Debug/Tests/FT_DebugNavigation.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a95b4f35569732268f6abc2ca69ef8b6809a76b77be457fdcd08002780cb21da -size 114730 +oid sha256:d316fe79108783bdd9890de8afc69aa1f9a130d789da6bb5128d0cfe3c2457ad +size 94265 diff --git a/Content/Debug/Tests/FT_DebugPageContentGenerator.ts b/Content/Debug/Tests/FT_DebugPageContentGenerator.ts deleted file mode 100644 index 9d1778e..0000000 --- a/Content/Debug/Tests/FT_DebugPageContentGenerator.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Debug/Tests/FT_DebugPageContentGenerator.ts - -import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; -import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; -import { E_DebugPageID } from '#root/Debug/Enums/E_DebugPageID.ts'; -import { E_DebugUpdateFunction } from '#root/Debug/Enums/E_DebugUpdateFunction.ts'; -import type { S_DebugPage } from '#root/Debug/Structs/S_DebugPage.ts'; -import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; -import { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; -import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; -import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; -import { FunctionalTest } from '#root/UE/FunctionalTest.ts'; - -/** - * Functional Test: Debug HUD Page Content Generation - * Validates that all registered debug pages generate non-empty content - */ -export class FT_DebugPageContentGenerator extends FunctionalTest { - // ════════════════════════════════════════════════════════════════════════════════════════ - // GRAPHS - // ════════════════════════════════════════════════════════════════════════════════════════ - - // ──────────────────────────────────────────────────────────────────────────────────────── - // EventGraph - // ──────────────────────────────────────────────────────────────────────────────────────── - - /** - * Test entry point - validates content generation for all debug pages - * Iterates through all pages and tests their update functions - */ - EventStartTest(): void { - this.DebugHUDComponent.InitializeDebugHUD( - this.MovementComponent, - this.ToastSystemComponent, - this.InputDeviceComponent, - this.CameraComponent - ); - - this.DebugHUDComponent.GetTestData().DebugPages.forEach( - (arrayElement, arrayIndex) => { - this.UpdatedPage = arrayElement; - - switch (this.UpdatedPage.UpdateFunction) { - case E_DebugUpdateFunction.UpdateMovementPage: { - this.UpdatedPage = this.DebugHUDComponent.UpdateMovementPage( - this.UpdatedPage - ); - break; - } - - case E_DebugUpdateFunction.UpdateSurfacePage: { - this.UpdatedPage = this.DebugHUDComponent.UpdateSurfacePage( - this.UpdatedPage - ); - break; - } - - case E_DebugUpdateFunction.UpdatePerformancePage: { - this.UpdatedPage = this.DebugHUDComponent.UpdatePerformancePage( - this.UpdatedPage - ); - break; - } - } - - if (this.UpdatedPage.Content.length > 0) { - this.FinishTest(EFunctionalTestResult.Succeeded); - } else { - this.FinishTest( - EFunctionalTestResult.Failed, - `DebugHUD: Page ${arrayIndex + 1} content empty` - ); - } - } - ); - } - - // ════════════════════════════════════════════════════════════════════════════════════════ - // VARIABLES - // ════════════════════════════════════════════════════════════════════════════════════════ - - /** - * Movement system component - required for debug HUD initialization - * @category Components - */ - MovementComponent = new AC_Movement(); - - /** - * Debug HUD system - primary component under test - * Tests page content generation functionality - * @category Components - */ - DebugHUDComponent = new AC_DebugHUD(); - - /** - * Toast notification system - required for debug HUD initialization - * @category Components - */ - ToastSystemComponent = new AC_ToastSystem(); - - /** - * Input device detection system - used for input device debug page testing - * @category Components - */ - InputDeviceComponent = new AC_InputDevice(); - - /** - * Camera system component - included for completeness, not directly tested - * @category Components - */ - CameraComponent = new AC_Camera(); - - /** - * Working copy of debug page for content generation testing - * Updated during test execution for each page - * @category Test State - */ - UpdatedPage: S_DebugPage = { - PageID: E_DebugPageID.MovementInfo, - Title: '', - Content: '', - IsVisible: false, - UpdateFunction: E_DebugUpdateFunction.UpdateMovementPage, - }; -} diff --git a/Content/Debug/Tests/FT_DebugPageContentGenerator.uasset b/Content/Debug/Tests/FT_DebugPageContentGenerator.uasset deleted file mode 100644 index 056f4d5..0000000 --- a/Content/Debug/Tests/FT_DebugPageContentGenerator.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a733e2a8ebf7daca900269a694780d969b2895cd59714064d88a9ac95759ca99 -size 151574 diff --git a/Content/Debug/Tests/FT_DebugPageManagement.ts b/Content/Debug/Tests/FT_DebugPageManagement.ts new file mode 100644 index 0000000..8802bb7 --- /dev/null +++ b/Content/Debug/Tests/FT_DebugPageManagement.ts @@ -0,0 +1,261 @@ +// Debug/Tests/FT_DebugPageManagement.ts + +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; +import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; +import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; +import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; +import { FunctionalTest } from '#root/UE/FunctionalTest.ts'; +import { SystemLibrary } from '#root/UE/SystemLibrary.ts'; + +/** + * Functional Test: Debug Page Management + * Tests dynamic page registration, content updates, and lifecycle operations + */ +export class FT_DebugPageManagement extends FunctionalTest { + // ════════════════════════════════════════════════════════════════════════════════════════ + // GRAPHS + // ════════════════════════════════════════════════════════════════════════════════════════ + + // ──────────────────────────────────────────────────────────────────────────────────────── + // EventGraph + // ──────────────────────────────────────────────────────────────────────────────────────── + + /** + * Test entry point - validates all page management operations + * Tests: Add, Update, ShouldUpdate, Visibility, Remove + */ + EventStartTest(): void { + this.DebugHUDComponent.InitializeDebugHUD( + this.ToastSystemComponent, + this.InputDeviceComponent + ); + + this.DebugHUDComponent.AddDebugPage('TestPage1', 'Test Page 1', 30, true); + + const pageCount = this.DebugHUDComponent.GetTestData().DebugPages.length; + + if (pageCount === 1) { + const testContent = 'Test Content 123'; + + this.DebugHUDComponent.UpdatePageContent('TestPage1', testContent); + + const page = this.DebugHUDComponent.GetTestData().DebugPages.Get(0); + const contentMatches = page.Content === testContent; + + if (contentMatches) { + const currentTime = SystemLibrary.GetGameTimeInSeconds(); + + // First call should return true (no previous update) + const firstCall = this.DebugHUDComponent.ShouldUpdatePage( + 'TestPage1', + currentTime + ); + + // Immediate second call should return false (just updated) + const secondCall = this.DebugHUDComponent.ShouldUpdatePage( + 'TestPage1', + currentTime + ); + + if (firstCall && !secondCall) { + this.DebugHUDComponent.AddDebugPage( + 'TestPage2', + 'Test Page 2', + 60, + true + ); + + const pageCount = + this.DebugHUDComponent.GetTestData().DebugPages.length; + const visibleCount = + this.DebugHUDComponent.GetTestData().VisiblePagesLength; + + if (pageCount === 2 && visibleCount === 2) { + // Hide second page + this.DebugHUDComponent.SetPageVisibility('TestPage2', false); + + const totalCount = + this.DebugHUDComponent.GetTestData().DebugPages.length; + const visibleCount = + this.DebugHUDComponent.GetTestData().VisiblePagesLength; + + if (totalCount === 2 && visibleCount === 1) { + // Remove first page + this.DebugHUDComponent.RemoveDebugPage('TestPage1'); + + const totalCount = + this.DebugHUDComponent.GetTestData().DebugPages.length; + const currentIndex = + this.DebugHUDComponent.GetTestData().CurrentPageIndex; + + if (totalCount === 1 && currentIndex === 0) { + // Re-add page with same ID but different settings + this.DebugHUDComponent.AddDebugPage( + 'TestPage2', + 'Updated Title', + 120, + true + ); + + const totalCount = + this.DebugHUDComponent.GetTestData().DebugPages.length; + const visibleCount = + this.DebugHUDComponent.GetTestData().VisiblePagesLength; + const page = + this.DebugHUDComponent.GetTestData().DebugPages.Get(0); + const titleMatches = page.Title === 'Updated Title'; + const refreshRateMatches = page.RefreshRate === 120; + + if ( + totalCount === 1 && + visibleCount === 1 && + titleMatches && + refreshRateMatches + ) { + // Add pages with different refresh rates + this.DebugHUDComponent.AddDebugPage( + 'FastPage', + 'Fast Page', + 120, + true + ); + + this.DebugHUDComponent.AddDebugPage( + 'SlowPage', + 'Slow Page', + 10, + true + ); + + const currentTime = SystemLibrary.GetGameTimeInSeconds(); + + // Both should update on first call + const fastShouldUpdate = + this.DebugHUDComponent.ShouldUpdatePage( + 'FastPage', + currentTime + ); + const slowShouldUpdate = + this.DebugHUDComponent.ShouldUpdatePage( + 'SlowPage', + currentTime + ); + + // Wait for fast page interval (1/120 = 0.0083s) but not slow (1/10 = 0.1s) + const fastUpdateTime = currentTime + 0.01; + + const fastShouldUpdateAgain = + this.DebugHUDComponent.ShouldUpdatePage( + 'FastPage', + fastUpdateTime + ); + const slowShouldNotUpdate = + this.DebugHUDComponent.ShouldUpdatePage( + 'SlowPage', + fastUpdateTime + ); + + if ( + fastShouldUpdate && + slowShouldUpdate && + fastShouldUpdateAgain && + !slowShouldNotUpdate + ) { + // Try to update non-existent page (should not crash) + this.DebugHUDComponent.UpdatePageContent( + 'NonExistentPage', + 'Test' + ); + + // Try to remove non-existent page (should not crash) + this.DebugHUDComponent.RemoveDebugPage('NonExistentPage'); + + // Try to check non-existent page (should return false) + const currentTime = SystemLibrary.GetGameTimeInSeconds(); + const shouldUpdate = + this.DebugHUDComponent.ShouldUpdatePage( + 'NonExistentPage', + currentTime + ); + + if (!shouldUpdate) { + this.FinishTest(EFunctionalTestResult.Succeeded); + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + 'Test 9 Failed: ShouldUpdatePage returned true for non-existent page' + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 8 Failed: Refresh rates incorrect (fast1: ${fastShouldUpdate}, slow1: ${slowShouldUpdate}, fast2: ${fastShouldUpdateAgain}, slow2: ${slowShouldNotUpdate})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 7 Failed: Update registration incorrect (count: ${totalCount}, title: ${titleMatches}, rate: ${refreshRateMatches})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 6 Failed: Remove incorrect (count: ${totalCount}, index: ${currentIndex})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 5 Failed: Visibility incorrect (total: ${totalCount}, visible: ${visibleCount})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 4 Failed: Expected 2 pages (total: ${pageCount}, visible: ${visibleCount})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 3 Failed: ShouldUpdatePage timing incorrect (first: ${firstCall}, second: ${secondCall})` + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + 'Test 2 Failed: Content did not update correctly' + ); + } + } else { + this.FinishTest( + EFunctionalTestResult.Failed, + `Test 1 Failed: Expected 1 page, got ${pageCount}` + ); + } + } + + // ════════════════════════════════════════════════════════════════════════════════════════ + // VARIABLES + // ════════════════════════════════════════════════════════════════════════════════════════ + + /** + * Debug HUD system - primary component under test + * Tests all page management operations + * @category Components + */ + DebugHUDComponent = new AC_DebugHUD(); + + /** + * Toast notification system - required for debug HUD initialization + * @category Components + */ + ToastSystemComponent = new AC_ToastSystem(); + + /** + * Input device detection system - required for debug HUD initialization + * @category Components + */ + InputDeviceComponent = new AC_InputDevice(); +} diff --git a/Content/Debug/Tests/FT_DebugPageManagement.uasset b/Content/Debug/Tests/FT_DebugPageManagement.uasset new file mode 100644 index 0000000..7f221d0 --- /dev/null +++ b/Content/Debug/Tests/FT_DebugPageManagement.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ce33f7f74151311814fc56699cda0dae010b72b3c670b2a87b758ab9c4d412c +size 429493 diff --git a/Content/Debug/Tests/FT_DebugSystem.ts b/Content/Debug/Tests/FT_DebugSystem.ts index 0151243..1a78b1a 100644 --- a/Content/Debug/Tests/FT_DebugSystem.ts +++ b/Content/Debug/Tests/FT_DebugSystem.ts @@ -1,11 +1,8 @@ // Debug/Tests/FT_DebugSystem.ts -import { AC_Camera } from '#root/Camera/Components/AC_Camera.ts'; import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; -import { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; -import { DataTableFunctionLibrary } from '#root/UE/DataTableFunctionLibrary.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; import { FunctionalTest } from '#root/UE/FunctionalTest.ts'; import { SystemLibrary } from '#root/UE/SystemLibrary.ts'; @@ -29,41 +26,17 @@ export class FT_DebugSystem extends FunctionalTest { */ EventStartTest(): void { this.DebugHUDComponent.InitializeDebugHUD( - this.MovementComponent, this.ToastSystemComponent, - this.InputDeviceComponent, - this.CameraComponent + this.InputDeviceComponent ); if (this.DebugHUDComponent.GetTestData().IsInitialized) { - if ( - DataTableFunctionLibrary.GetDataTableRowNames( - this.DebugHUDComponent.GetTestData().DebugDataTable - ).length === this.DebugHUDComponent.GetTestData().DebugPages.length - ) { - if (SystemLibrary.IsValid(this.MovementComponent)) { - if (SystemLibrary.IsValid(this.DebugHUDComponent)) { - this.FinishTest(EFunctionalTestResult.Succeeded); - } else { - this.FinishTest( - EFunctionalTestResult.Failed, - 'DebugHUD component not valid' - ); - } - } else { - this.FinishTest( - EFunctionalTestResult.Failed, - 'Debug HUD: Movement component not valid' - ); - } + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + this.FinishTest(EFunctionalTestResult.Succeeded); } else { this.FinishTest( EFunctionalTestResult.Failed, - `Debug HUD: Expected ${this.DebugHUDComponent.GetTestData().DebugPages.length} pages, got ${ - DataTableFunctionLibrary.GetDataTableRowNames( - this.DebugHUDComponent.GetTestData().DebugDataTable - ).length - }` + 'DebugHUD component not valid' ); } } else { @@ -78,12 +51,6 @@ export class FT_DebugSystem extends FunctionalTest { // VARIABLES // ════════════════════════════════════════════════════════════════════════════════════════ - /** - * Movement system component - required for debug HUD initialization - * @category Components - */ - MovementComponent = new AC_Movement(); - /** * Debug HUD system - primary component under test * Tests basic system initialization and component validity @@ -102,10 +69,4 @@ export class FT_DebugSystem extends FunctionalTest { * @category Components */ InputDeviceComponent = new AC_InputDevice(); - - /** - * Camera system component - included for completeness, not directly tested - * @category Components - */ - CameraComponent = new AC_Camera(); } diff --git a/Content/Debug/Tests/FT_DebugSystem.uasset b/Content/Debug/Tests/FT_DebugSystem.uasset index 20f06f6..0084486 100644 --- a/Content/Debug/Tests/FT_DebugSystem.uasset +++ b/Content/Debug/Tests/FT_DebugSystem.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2624f24b482fa40c914637ba6ba9365a234ff3da584e7b2066e3db4fb05d9b2 -size 105674 +oid sha256:5aa91e08628007c679d44bfccadc987c7661891722e9d20b1712636186599627 +size 58816 diff --git a/Content/Input/Components/AC_InputDevice.ts b/Content/Input/Components/AC_InputDevice.ts index 29c911c..8aed077 100644 --- a/Content/Input/Components/AC_InputDevice.ts +++ b/Content/Input/Components/AC_InputDevice.ts @@ -1,5 +1,6 @@ // Input/Components/AC_InputDevice.ts +import type { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import type { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { ActorComponent } from '#root/UE/ActorComponent.ts'; import { EHardwareDevicePrimaryType } from '#root/UE/EHardwareDevicePrimaryType.ts'; @@ -52,14 +53,27 @@ export class AC_InputDevice extends ActorComponent { /** * Initialize device detection system with delegate registration * @param ToastComponentRef - Toast system for debug notifications + * @param DebugHUDComponentRef - Optional debug HUD for displaying device info * @category System Setup */ - public InitializeDeviceDetection(ToastComponentRef: AC_ToastSystem): void { + public InitializeDeviceDetection( + ToastComponentRef: AC_ToastSystem, + DebugHUDComponentRef: AC_DebugHUD + ): void { this.ToastComponent = ToastComponentRef; + this.DebugHUDComponent = DebugHUDComponentRef; this.RegisterHardwareDeviceDelegate(); this.DetectInitialDevice(); this.IsInitialized = true; + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + this.DebugHUDComponent.AddDebugPage( + this.DebugPageID, + 'Input Device Info', + 60 + ); + } + if (SystemLibrary.IsValid(this.ToastComponent)) { this.ToastComponent.ShowToast( `Device Detection Initialized: ${this.CurrentDevice}`, @@ -141,6 +155,28 @@ export class AC_InputDevice extends ActorComponent { return HasCooldownExpired(); } + /** + * Update debug HUD with current device info + * @category Debug + */ + public UpdateDebugPage(): void { + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + if ( + this.DebugHUDComponent.ShouldUpdatePage( + this.DebugPageID, + SystemLibrary.GetGameTimeInSeconds() + ) + ) { + this.DebugHUDComponent.UpdatePageContent( + this.DebugPageID, + `Hardware Device Identifier: ${this.GetCurrentInputDevice()}` + + `Initialized: ${this.IsInitialized}` + + `Last Change: ${this.LastDeviceChangeTime}` + ); + } + } + } + // ════════════════════════════════════════════════════════════════════════════════════════ // VARIABLES // ════════════════════════════════════════════════════════════════════════════════════════ @@ -151,6 +187,13 @@ export class AC_InputDevice extends ActorComponent { */ private ToastComponent: AC_ToastSystem | null = null; + /** + * Reference to debug HUD component for displaying camera info + * Optional, used for debugging purposes + * @category Components + */ + public DebugHUDComponent: AC_DebugHUD | null = null; + /** * Current active input device type * Updated by hardware device change events @@ -178,4 +221,12 @@ export class AC_InputDevice extends ActorComponent { * @instanceEditable true */ private DeviceChangeCooldown: Float = 0.3; + + /** + * Debug page identifier for organizing debug output + * Used by debug HUD to categorize information + * @category Debug + * @instanceEditable true + */ + public readonly DebugPageID: string = 'InputDeviceInfo'; } diff --git a/Content/Input/Components/AC_InputDevice.uasset b/Content/Input/Components/AC_InputDevice.uasset index be8f859..75fa7db 100644 --- a/Content/Input/Components/AC_InputDevice.uasset +++ b/Content/Input/Components/AC_InputDevice.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a2674517be558b852993ea485745d7a5132be1bcc68f952875ddbc0ba338950 -size 166704 +oid sha256:aac84b4bfad413610ddfcc4385d2963838de8ba4a1455b475aac03f51bec2163 +size 225040 diff --git a/Content/Input/Tests/FT_InputDeviceDetection.ts b/Content/Input/Tests/FT_InputDeviceDetection.ts index 55e2c4e..850d870 100644 --- a/Content/Input/Tests/FT_InputDeviceDetection.ts +++ b/Content/Input/Tests/FT_InputDeviceDetection.ts @@ -1,5 +1,6 @@ // Input/Tests/FT_InputDeviceDetection.ts +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts'; import { AC_ToastSystem } from '#root/Toasts/Components/AC_ToastSystem.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -28,7 +29,8 @@ export class FT_InputDeviceDetection extends FunctionalTest { // Initialize components this.ToastSystemComponent.InitializeToastSystem(); this.InputDeviceComponent.InitializeDeviceDetection( - this.ToastSystemComponent + this.ToastSystemComponent, + this.DebugHUDComponent ); this.TestInitialization(); this.TestDeviceQueries(); @@ -122,4 +124,10 @@ export class FT_InputDeviceDetection extends FunctionalTest { * @category Components */ private ToastSystemComponent = new AC_ToastSystem(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Input/Tests/FT_InputDeviceDetection.uasset b/Content/Input/Tests/FT_InputDeviceDetection.uasset index fa2ba5f..1056743 100644 --- a/Content/Input/Tests/FT_InputDeviceDetection.uasset +++ b/Content/Input/Tests/FT_InputDeviceDetection.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87d0332ed61dbbe88cff644607adb4373bd720ff133904bf9fed01d9c924ab91 -size 144696 +oid sha256:72fa7c9daa368a973b530ad4539135be1771eac770cc78f62925e0d25b9ceddd +size 146508 diff --git a/Content/Levels/TestLevel.ts b/Content/Levels/TestLevel.ts index db10c76..b7d4399 100644 --- a/Content/Levels/TestLevel.ts +++ b/Content/Levels/TestLevel.ts @@ -7,7 +7,7 @@ import { FT_CameraRotation } from '#root/Camera/Tests/FT_CameraRotation.ts'; import { FT_CameraSensitivity } from '#root/Camera/Tests/FT_CameraSensitivity.ts'; import { FT_CameraSmoothing } from '#root/Camera/Tests/FT_CameraSmoothing.ts'; import { FT_DebugNavigation } from '#root/Debug/Tests/FT_DebugNavigation.ts'; -import { FT_DebugPageContentGenerator } from '#root/Debug/Tests/FT_DebugPageContentGenerator.ts'; +import { FT_DebugPageManagement } from '#root/Debug/Tests/FT_DebugPageManagement.ts'; import { FT_DebugSystem } from '#root/Debug/Tests/FT_DebugSystem.ts'; import { FT_InputDeviceDetection } from '#root/Input/Tests/FT_InputDeviceDetection.ts'; import { FT_BasicMovement } from '#root/Movement/Tests/FT_BasicMovement.ts'; @@ -36,11 +36,10 @@ CameraSmoothingTest.EventStartTest(); // Debug Tests const DebugNavigationTest = new FT_DebugNavigation(); -const DebugPageContentGeneratorTest = new FT_DebugPageContentGenerator(); const DebugSystemTest = new FT_DebugSystem(); +const DebugPageManagementTest = new FT_DebugPageManagement(); DebugNavigationTest.EventStartTest(); -DebugPageContentGeneratorTest.EventStartTest(); DebugSystemTest.EventStartTest(); // Input Tests @@ -69,3 +68,4 @@ ToastsDurationHandlingTest.EventStartTest(); ToastsEdgeCasesTest.EventStartTest(); ToastsSystemInitializationTest.EventStartTest(); ToastsToastCreationTest.EventStartTest(); +DebugPageManagementTest.EventStartTest(); diff --git a/Content/Levels/TestLevel.umap b/Content/Levels/TestLevel.umap index 0ab07b4..99e7f77 100644 --- a/Content/Levels/TestLevel.umap +++ b/Content/Levels/TestLevel.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02f10e71ac92b36e4cbba0b7663cab29284009889ae53130eacc1a98204a93e0 -size 108689 +oid sha256:51558a36adc7515d2310a91c8c059d85368537f87667e168772ca2dd2f0c17d7 +size 107341 diff --git a/Content/Movement/Components/AC_Movement.ts b/Content/Movement/Components/AC_Movement.ts index ad653f4..88b75c1 100644 --- a/Content/Movement/Components/AC_Movement.ts +++ b/Content/Movement/Components/AC_Movement.ts @@ -1,5 +1,6 @@ // Movement/Components/AC_Movement.ts +import type { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { BFL_Vectors } from '#root/Math/Libraries/BFL_Vectors.ts'; import { E_MovementState } from '#root/Movement/Enums/E_MovementState.ts'; import { E_SurfaceType } from '#root/Movement/Enums/E_SurfaceType.ts'; @@ -9,6 +10,8 @@ import { ActorComponent } from '#root/UE/ActorComponent.ts'; import type { Float } from '#root/UE/Float.ts'; import { MathLibrary } from '#root/UE/MathLibrary.ts'; import { Rotator } from '#root/UE/Rotator.ts'; +import { StringLibrary } from '#root/UE/StringLibrary.ts'; +import { SystemLibrary } from '#root/UE/SystemLibrary.ts'; import { Vector } from '#root/UE/Vector.ts'; /** @@ -348,7 +351,10 @@ export class AC_Movement extends ActorComponent { * Converts degree thresholds to radians for runtime performance * @category System */ - public InitializeMovementSystem(): void { + public InitializeMovementSystem( + DebugHUDComponentRef: AC_DebugHUD | null + ): void { + this.DebugHUDComponent = DebugHUDComponentRef; this.IsInitialized = true; this.AngleThresholdsRads = { @@ -360,6 +366,55 @@ export class AC_Movement extends ActorComponent { ), Wall: MathLibrary.DegreesToRadians(this.AngleThresholdsDegrees.Wall), }; + + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + this.DebugHUDComponent.AddDebugPage( + this.DebugPageID, + 'Movement Info', + 60 + ); + } + } + + /** + * Update debug HUD with current movement info + * @category Debug + */ + public UpdateDebugPage(): void { + if (SystemLibrary.IsValid(this.DebugHUDComponent)) { + if ( + this.DebugHUDComponent.ShouldUpdatePage( + this.DebugPageID, + SystemLibrary.GetGameTimeInSeconds() + ) + ) { + this.DebugHUDComponent.UpdatePageContent( + this.DebugPageID, + // Constants + `Max Speed: ${this.MovementConstants.MaxSpeed}\n` + + `Acceleration: ${this.MovementConstants.Acceleration}\n` + + `Friction: ${this.MovementConstants.Friction}\n` + + `Gravity: ${this.MovementConstants.Gravity}\n` + + `Initialized: ${this.IsInitialized}\n` + + `\n` + + // Current State + `Current Velocity: ${StringLibrary.ConvVectorToString(this.CurrentVelocity)}\n` + + `Speed: ${this.CurrentSpeed}\n` + + `Is Grounded: ${this.IsGrounded}\n` + + `Surface Type: ${this.CurrentSurface}\n` + + `Movement State: ${this.MovementState}\n` + + `Input Magnitude: ${this.InputMagnitude}` + + `\n` + + // Rotation + `Current Yaw: ${this.CurrentRotation.yaw}\n` + + `Target Yaw: ${this.TargetRotation.yaw}\n°` + + `Rotation Delta: ${this.RotationDelta}\n°` + + `Is Rotating: ${this.IsCharacterRotating}\n` + + `Rotation Speed: ${this.RotationSpeed}\n°` + + `Min Speed: ${this.MinSpeedForRotation}` + ); + } + } } // ════════════════════════════════════════════════════════════════════════════════════════ @@ -409,6 +464,13 @@ export class AC_Movement extends ActorComponent { */ public IsInitialized = false; + /** + * Debug page identifier for organizing debug output + * Used by debug HUD to categorize information + * @category Debug + */ + public readonly DebugPageID: string = 'MovementInfo'; + /** * Current character velocity in world space * Updated every frame by movement calculations @@ -502,4 +564,11 @@ export class AC_Movement extends ActorComponent { * @category Character Rotation State */ public RotationDelta: Float = 0.0; + + /** + * Reference to debug HUD component for displaying camera info + * Optional, used for debugging purposes + * @category Components + */ + public DebugHUDComponent: AC_DebugHUD | null = null; } diff --git a/Content/Movement/Components/AC_Movement.uasset b/Content/Movement/Components/AC_Movement.uasset index afbd32f..0512e87 100644 --- a/Content/Movement/Components/AC_Movement.uasset +++ b/Content/Movement/Components/AC_Movement.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5c9971eb006daf9e4e9d94a6bffcc024c6e7615cacdcf5fae7598a00e371c4a -size 534988 +oid sha256:b0849d90e9a7bd3f6a9045199deef881451e77af9ac8dacad9c49ddd014d7eaa +size 640442 diff --git a/Content/Movement/Tests/FT_BasicMovement.ts b/Content/Movement/Tests/FT_BasicMovement.ts index aa23b27..519f158 100644 --- a/Content/Movement/Tests/FT_BasicMovement.ts +++ b/Content/Movement/Tests/FT_BasicMovement.ts @@ -1,5 +1,6 @@ // Movement/Tests/FT_BasicMovement.ts +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; import { E_MovementState } from '#root/Movement/Enums/E_MovementState.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; @@ -26,7 +27,7 @@ export class FT_BasicMovement extends FunctionalTest { */ EventStartTest(): void { // Initialize movement system - this.MovementComponent.InitializeMovementSystem(); + this.MovementComponent.InitializeMovementSystem(this.DebugHUDComponent); // Test 1: Initialization if (this.MovementComponent.IsInitialized) { @@ -125,4 +126,10 @@ export class FT_BasicMovement extends FunctionalTest { * @category Components */ private MovementComponent = new AC_Movement(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Movement/Tests/FT_BasicMovement.uasset b/Content/Movement/Tests/FT_BasicMovement.uasset index 7f3abed..3dd67b2 100644 --- a/Content/Movement/Tests/FT_BasicMovement.uasset +++ b/Content/Movement/Tests/FT_BasicMovement.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23561c3a3ee1b8a815efcc691b62c91e0aab438e792c47d9c2266d42a5c3526e -size 208643 +oid sha256:72e14d77f839c1db8ffe541729cb90910de680c45a76aca07f373c21fb743c3d +size 210334 diff --git a/Content/Movement/Tests/FT_DiagonalMovement.ts b/Content/Movement/Tests/FT_DiagonalMovement.ts index 1623373..b5d31c9 100644 --- a/Content/Movement/Tests/FT_DiagonalMovement.ts +++ b/Content/Movement/Tests/FT_DiagonalMovement.ts @@ -1,5 +1,6 @@ // Movement/Tests/FT_DiagonalMovement.ts +import { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts'; import { AC_Movement } from '#root/Movement/Components/AC_Movement.ts'; import { EFunctionalTestResult } from '#root/UE/EFunctionalTestResult.ts'; import { FunctionalTest } from '#root/UE/FunctionalTest.ts'; @@ -26,7 +27,7 @@ export class FT_DiagonalMovement extends FunctionalTest { */ EventStartTest(): void { // Initialize movement system - this.MovementComponent.InitializeMovementSystem(); + this.MovementComponent.InitializeMovementSystem(this.DebugHUDComponent); // Test 1: Cardinal movement (forward only) for (let i = 0; i < 100; i++) { @@ -94,4 +95,10 @@ export class FT_DiagonalMovement extends FunctionalTest { * @category Components */ private MovementComponent = new AC_Movement(); + + /** + * Debug HUD system - displays test status and parameters + * @category Components + */ + private DebugHUDComponent = new AC_DebugHUD(); } diff --git a/Content/Movement/Tests/FT_DiagonalMovement.uasset b/Content/Movement/Tests/FT_DiagonalMovement.uasset index d7dea1e..e1ae8f5 100644 --- a/Content/Movement/Tests/FT_DiagonalMovement.uasset +++ b/Content/Movement/Tests/FT_DiagonalMovement.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:468e000881430761e2f0bee7896ec89a888bf1428a5e3ae1797e2250df9798d5 -size 181961 +oid sha256:384c8c2fb25aeb24395c3b61f1894a6e2cb6a5b98a039e410e3499c1d4a377b3 +size 184511