feat: add in-game debug console UI
This commit is contained in:
@@ -56,6 +56,11 @@ jump={
|
|||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
toggle_console={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194332,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using Game.Features.Console.Application;
|
||||||
|
using Game.Features.Console.Contracts;
|
||||||
|
using Game.Features.Console.Infrastructure;
|
||||||
|
using Game.Godot;
|
||||||
|
using Game.Godot.Extensions;
|
||||||
|
using Game.Godot.Mappings;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Game.Features.Console.Godot;
|
||||||
|
|
||||||
|
public partial class ConsoleController : CanvasLayer
|
||||||
|
{
|
||||||
|
[Export] public LineEdit CommandInput;
|
||||||
|
[Export] public RichTextLabel OutputLog;
|
||||||
|
|
||||||
|
private CommandExecute _commandExecute = new(new CommandRegistry());
|
||||||
|
private MouseCapture.Memento _mouseMemento;
|
||||||
|
|
||||||
|
private void Toggle()
|
||||||
|
{
|
||||||
|
Visible = !Visible;
|
||||||
|
|
||||||
|
if (Visible)
|
||||||
|
{
|
||||||
|
GamePause.Pause();
|
||||||
|
_mouseMemento = MouseCapture.SaveCaptureMode();
|
||||||
|
CommandInput.GrabFocus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GamePause.Resume();
|
||||||
|
_mouseMemento.RestoreCaptureMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendLine(string line)
|
||||||
|
{
|
||||||
|
OutputLog.AppendText(line + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseCommandRegistry(ICommandRegistry registry)
|
||||||
|
{
|
||||||
|
_commandExecute = new CommandExecute(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInputSubmitted(string text)
|
||||||
|
{
|
||||||
|
CommandInput.Clear();
|
||||||
|
CommandInput.ReleaseFocus();
|
||||||
|
CommandInput.GrabFocus();
|
||||||
|
|
||||||
|
if (text.Length == 0) return;
|
||||||
|
|
||||||
|
AppendLine($"> {text}");
|
||||||
|
|
||||||
|
CommandResult result = _commandExecute.Execute(text);
|
||||||
|
if (result.ClearOutput)
|
||||||
|
{
|
||||||
|
OutputLog.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Message.Length > 0)
|
||||||
|
{
|
||||||
|
AppendLine(result.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
this.AssertRequiredExports();
|
||||||
|
Visible = false;
|
||||||
|
GamePause.SetIgnoresPause(this, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Input(InputEvent @event)
|
||||||
|
{
|
||||||
|
if (!@event.IsActionPressed(InputAction.ToggleConsole.ActionName())) return;
|
||||||
|
|
||||||
|
Toggle();
|
||||||
|
GetViewport().SetInputAsHandled();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ypsdpciag6r6
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bk0771dvonxh8"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ypsdpciag6r6" path="res://src/Features/Console/Godot/ConsoleController.cs" id="1_script"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_console"]
|
||||||
|
content_margin_left = 8.0
|
||||||
|
content_margin_top = 8.0
|
||||||
|
content_margin_right = 8.0
|
||||||
|
content_margin_bottom = 8.0
|
||||||
|
bg_color = Color(0, 0, 0, 0.85)
|
||||||
|
|
||||||
|
[sub_resource type="SystemFont" id="SystemFont_terminal"]
|
||||||
|
font_names = PackedStringArray("Consolas", "Cascadia Mono", "Courier New")
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_input"]
|
||||||
|
content_margin_left = 0.0
|
||||||
|
content_margin_top = 12.0
|
||||||
|
content_margin_right = 0.0
|
||||||
|
content_margin_bottom = 0.0
|
||||||
|
bg_color = Color(0, 0, 0, 0)
|
||||||
|
|
||||||
|
[node name="ConsoleController" type="CanvasLayer" unique_id=1711862908 node_paths=PackedStringArray("CommandInput", "OutputLog")]
|
||||||
|
layer = 100
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
CommandInput = NodePath("Panel/Container/InputRow/CommandInput")
|
||||||
|
OutputLog = NodePath("Panel/Container/OutputLog")
|
||||||
|
|
||||||
|
[node name="Panel" type="PanelContainer" parent="." unique_id=515760683]
|
||||||
|
anchors_preset = 10
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_bottom = 260.0
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_console")
|
||||||
|
|
||||||
|
[node name="Container" type="VBoxContainer" parent="Panel" unique_id=37696848]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 0
|
||||||
|
|
||||||
|
[node name="OutputLog" type="RichTextLabel" parent="Panel/Container" unique_id=1318894518]
|
||||||
|
custom_minimum_size = Vector2(0, 220)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_fonts/normal_font = SubResource("SystemFont_terminal")
|
||||||
|
theme_override_fonts/bold_font = SubResource("SystemFont_terminal")
|
||||||
|
theme_override_fonts/italics_font = SubResource("SystemFont_terminal")
|
||||||
|
theme_override_fonts/mono_font = SubResource("SystemFont_terminal")
|
||||||
|
scroll_following = true
|
||||||
|
|
||||||
|
[node name="InputRow" type="HBoxContainer" parent="Panel/Container" unique_id=1183500371]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 4
|
||||||
|
|
||||||
|
[node name="PromptMargin" type="MarginContainer" parent="Panel/Container/InputRow" unique_id=1356750045]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
|
||||||
|
[node name="PromptLabel" type="Label" parent="Panel/Container/InputRow/PromptMargin" unique_id=429447266]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_fonts/font = SubResource("SystemFont_terminal")
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="CommandInput" type="LineEdit" parent="Panel/Container/InputRow" unique_id=209466737]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_fonts/font = SubResource("SystemFont_terminal")
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_input")
|
||||||
|
theme_override_styles/read_only = SubResource("StyleBoxFlat_input")
|
||||||
|
theme_override_styles/focus = SubResource("StyleBoxFlat_input")
|
||||||
|
keep_editing_on_text_submit = true
|
||||||
|
caret_blink = true
|
||||||
|
|
||||||
|
[connection signal="text_submitted" from="Panel/Container/InputRow/CommandInput" to="." method="OnInputSubmitted"]
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
|
using Game.Features.Console.Application.Commands;
|
||||||
|
using Game.Features.Console.Godot;
|
||||||
|
using Game.Features.Console.Infrastructure;
|
||||||
using Game.Godot;
|
using Game.Godot;
|
||||||
|
using Game.Godot.Extensions;
|
||||||
using Game.Godot.Mappings;
|
using Game.Godot.Mappings;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
@@ -6,9 +10,24 @@ namespace Game.Godot.Bootstrap;
|
|||||||
|
|
||||||
public partial class GameBootstrap : Node
|
public partial class GameBootstrap : Node
|
||||||
{
|
{
|
||||||
|
[Export] public ConsoleController Console;
|
||||||
|
|
||||||
|
private void RegisterConsoleCommands()
|
||||||
|
{
|
||||||
|
CommandRegistry registry = new();
|
||||||
|
registry.Register(new HelpCommand(registry));
|
||||||
|
registry.Register(new EchoCommand());
|
||||||
|
registry.Register(new ClearCommand());
|
||||||
|
|
||||||
|
Console.UseCommandRegistry(registry);
|
||||||
|
}
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
|
this.AssertRequiredExports();
|
||||||
|
|
||||||
MouseCapture.Capture();
|
MouseCapture.Capture();
|
||||||
|
RegisterConsoleCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _UnhandledInput(InputEvent @event)
|
public override void _UnhandledInput(InputEvent @event)
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Game.Godot;
|
||||||
|
|
||||||
|
public static class GamePause
|
||||||
|
{
|
||||||
|
private static SceneTree Tree => (SceneTree)Engine.GetMainLoop();
|
||||||
|
|
||||||
|
public static bool IsPaused => Tree.Paused;
|
||||||
|
|
||||||
|
public static void Pause() => Tree.Paused = true;
|
||||||
|
|
||||||
|
public static void Resume() => Tree.Paused = false;
|
||||||
|
|
||||||
|
public static void Toggle()
|
||||||
|
{
|
||||||
|
if (IsPaused)
|
||||||
|
{
|
||||||
|
Resume();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetIgnoresPause(Node node, bool value) =>
|
||||||
|
node.ProcessMode = value ? Node.ProcessModeEnum.Always : Node.ProcessModeEnum.Inherit;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://i7fuhrb208r8
|
||||||
@@ -9,7 +9,8 @@ public enum InputAction
|
|||||||
MoveForward,
|
MoveForward,
|
||||||
MoveBack,
|
MoveBack,
|
||||||
Jump,
|
Jump,
|
||||||
Cancel
|
Cancel,
|
||||||
|
ToggleConsole
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InputActionExtensions
|
public static class InputActionExtensions
|
||||||
@@ -25,6 +26,7 @@ public static class InputActionExtensions
|
|||||||
InputAction.MoveBack => "move_back",
|
InputAction.MoveBack => "move_back",
|
||||||
InputAction.Jump => "jump",
|
InputAction.Jump => "jump",
|
||||||
InputAction.Cancel => "ui_cancel",
|
InputAction.Cancel => "ui_cancel",
|
||||||
|
InputAction.ToggleConsole => "toggle_console",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(action), action, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(action), action, null)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://curuqmbndymi6" path="res://src/Scenes/FloorCeilingHr42.tscn" id="2_1kpcd"]
|
[ext_resource type="PackedScene" uid="uid://curuqmbndymi6" path="res://src/Scenes/FloorCeilingHr42.tscn" id="2_1kpcd"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bka1dmgdi5btd" path="res://src/Features/Player/Godot/PlayerNode.tscn" id="2_mvtit"]
|
[ext_resource type="PackedScene" uid="uid://bka1dmgdi5btd" path="res://src/Features/Player/Godot/PlayerNode.tscn" id="2_mvtit"]
|
||||||
[ext_resource type="Script" uid="uid://drctu5y21ey2y" path="res://src/Godot/Bootstrap/GameBootstrap.cs" id="3_bootstrap"]
|
[ext_resource type="Script" uid="uid://drctu5y21ey2y" path="res://src/Godot/Bootstrap/GameBootstrap.cs" id="3_bootstrap"]
|
||||||
|
[ext_resource type="PackedScene" path="res://src/Features/Console/Godot/ConsoleController.tscn" id="4_console"]
|
||||||
|
|
||||||
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_epykj"]
|
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_epykj"]
|
||||||
panorama = ExtResource("1_g4n7o")
|
panorama = ExtResource("1_g4n7o")
|
||||||
@@ -16,8 +17,9 @@ background_mode = 2
|
|||||||
sky = SubResource("Sky_1kpcd")
|
sky = SubResource("Sky_1kpcd")
|
||||||
glow_enabled = true
|
glow_enabled = true
|
||||||
|
|
||||||
[node name="GameWorld" type="Node" unique_id=222644234]
|
[node name="GameWorld" type="Node" unique_id=222644234 node_paths=PackedStringArray("Console")]
|
||||||
script = ExtResource("3_bootstrap")
|
script = ExtResource("3_bootstrap")
|
||||||
|
Console = NodePath("Console")
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1669211403]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1669211403]
|
||||||
transform = Transform3D(-0.8660254, -0.43301278, 0.25, 0, 0.49999997, 0.86602545, -0.50000006, 0.75, -0.43301266, 0, 0, 0)
|
transform = Transform3D(-0.8660254, -0.43301278, 0.25, 0, 0.49999997, 0.86602545, -0.50000006, 0.75, -0.43301266, 0, 0, 0)
|
||||||
@@ -29,6 +31,8 @@ environment = SubResource("Environment_mvtit")
|
|||||||
[node name="Player" parent="." unique_id=26823676 instance=ExtResource("2_mvtit")]
|
[node name="Player" parent="." unique_id=26823676 instance=ExtResource("2_mvtit")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||||
|
|
||||||
|
[node name="Console" parent="." instance=ExtResource("4_console")]
|
||||||
|
|
||||||
[node name="Entities" type="Node3D" parent="." unique_id=851492709]
|
[node name="Entities" type="Node3D" parent="." unique_id=851492709]
|
||||||
|
|
||||||
[node name="floor_ceiling_hr_46" parent="Entities" unique_id=33949496 instance=ExtResource("2_1kpcd")]
|
[node name="floor_ceiling_hr_46" parent="Entities" unique_id=33949496 instance=ExtResource("2_1kpcd")]
|
||||||
|
|||||||
Reference in New Issue
Block a user