debug console cleanup

godot-4.2
John Montagu, the 4th Earl of Sandvich 2023-09-29 11:32:15 -07:00
parent 166dc3664b
commit b542bbe01c
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
25 changed files with 497 additions and 42 deletions

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://dpxde42hku7e4"
path="res://.godot/imported/RobotoMono-Bold.ttf-5ef56699eefec9ae3f60998f926ed5e6.fontdata"
[deps]
source_file="res://Assets/Fonts/RobotoMono-Bold.ttf"
dest_files=["res://.godot/imported/RobotoMono-Bold.ttf-5ef56699eefec9ae3f60998f926ed5e6.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://634gg67hl134"
path="res://.godot/imported/RobotoMono-BoldItalic.ttf-2187145e1604e9580f88c665eb740135.fontdata"
[deps]
source_file="res://Assets/Fonts/RobotoMono-BoldItalic.ttf"
dest_files=["res://.godot/imported/RobotoMono-BoldItalic.ttf-2187145e1604e9580f88c665eb740135.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://dj0652yei7yiw"
path="res://.godot/imported/RobotoMono-Italic.ttf-989ab307e516d9cd034e27188c7b1633.fontdata"
[deps]
source_file="res://Assets/Fonts/RobotoMono-Italic.ttf"
dest_files=["res://.godot/imported/RobotoMono-Italic.ttf-989ab307e516d9cd034e27188c7b1633.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://br1ivkgagsm6e"
path="res://.godot/imported/RobotoMono-Regular.ttf-d60df72f1dd7eaf3651e080d6852d0c6.fontdata"
[deps]
source_file="res://Assets/Fonts/RobotoMono-Regular.ttf"
dest_files=["res://.godot/imported/RobotoMono-Regular.ttf-d60df72f1dd7eaf3651e080d6852d0c6.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://bm6pfkq3ihl5o"
path="res://.godot/imported/iosevka-bold.ttf-97aa97b299fedb67e54814ad33f00008.fontdata"
[deps]
source_file="res://Assets/Fonts/iosevka-bold.ttf"
dest_files=["res://.godot/imported/iosevka-bold.ttf-97aa97b299fedb67e54814ad33f00008.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://bc2ex8d8klivt"
path="res://.godot/imported/iosevka-medium.ttf-4b57839c72f99191e193eecde1f3b96c.fontdata"
[deps]
source_file="res://Assets/Fonts/iosevka-medium.ttf"
dest_files=["res://.godot/imported/iosevka-medium.ttf-4b57839c72f99191e193eecde1f3b96c.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Binary file not shown.

View File

@ -0,0 +1,33 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://c88b18xteq6b8"
path="res://.godot/imported/iosevka.ttf-42231c60126a7f0f1b381cf93906a3ed.fontdata"
[deps]
source_file="res://Assets/Fonts/iosevka.ttf"
dest_files=["res://.godot/imported/iosevka.ttf-42231c60126a7f0f1b381cf93906a3ed.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

View File

@ -2,6 +2,10 @@ namespace SupaLidlGame.Debug;
public class CharIterator : Iterator<char> public class CharIterator : Iterator<char>
{ {
public int Line { get; protected set; } = 1;
public int Column { get; protected set; } = 0;
public CharIterator(string str) : base(str.ToCharArray()) public CharIterator(string str) : base(str.ToCharArray())
{ {
@ -18,7 +22,7 @@ public class CharIterator : Iterator<char>
if (c == '\n') if (c == '\n')
{ {
Line++; Line++;
Column = 0; Column = 1;
} }
else else
{ {

View File

@ -18,6 +18,7 @@ public sealed partial class DebugConsole : Control
{ {
_entry.PlaceholderText = "Enter Godot expression from " + _entry.PlaceholderText = "Enter Godot expression from " +
_context.GetPath(); _context.GetPath();
_entry.SetContext(_context);
GetParent<Window>().Title = "Supa Developer Console: " + GetParent<Window>().Title = "Supa Developer Console: " +
_context.GetPath(); _context.GetPath();
} }
@ -27,6 +28,8 @@ public sealed partial class DebugConsole : Control
private Entry _entry; private Entry _entry;
public Entry Entry => _entry;
private RichTextLabel _output; private RichTextLabel _output;
private Node ctx => Context; private Node ctx => Context;
@ -45,16 +48,20 @@ public sealed partial class DebugConsole : Control
} }
catch (InterpreterException ex) catch (InterpreterException ex)
{ {
_output.Text += ex.Message + '\n'; _output.Text += ex.Message;
} if (!ex.Message.StartsWith("Error occurred while"))
};
}
enum PathType
{ {
Node, _output.Text += $" @{ex.Line}:{ex.Column}" + '\n';
Property _output.Text += input + '\n';
_output.Text += new string(' ', ex.Column - 1) + "^\n";
}
else
{
_output.Text += '\n';
}
}
}; };
}
public IEnumerable<NodePathToken> SplitPath(NodePath path) public IEnumerable<NodePathToken> SplitPath(NodePath path)
{ {
@ -67,6 +74,40 @@ public sealed partial class DebugConsole : Control
return Variant.From(path).AsNodePath(); return Variant.From(path).AsNodePath();
} }
public object GetNodeOrProperty(NodePath path)
{
var tokens = new List<NodePathToken>(SplitPath(path));
Node variant = Context ?? this;
for (int i = 0; i < tokens.Count; i++)
{
var subpath = tokens[i];
if (i == tokens.Count - 1)
{
if (subpath.Type == NodePathTokenType.Property)
{
return new PropertyPointer(variant, subpath.Path);
}
}
else
{
if (subpath.Type == NodePathTokenType.Node)
{
if (subpath.Path != "")
{
variant = variant.GetNode(subpath.Path);
}
}
else
{
variant = variant.GetIndexed(subpath.Path)
.AsGodotObject() as Node;
}
}
}
return variant;
}
public Variant From(NodePath path) public Variant From(NodePath path)
{ {
Variant variant = Context ?? this; Variant variant = Context ?? this;
@ -103,7 +144,6 @@ public sealed partial class DebugConsole : Control
for (int i = 0; i < tokens.Count; i++) for (int i = 0; i < tokens.Count; i++)
{ {
var subpath = tokens[i]; var subpath = tokens[i];
GD.Print(subpath);
if (i == tokens.Count - 1) if (i == tokens.Count - 1)
{ {
if (subpath.Type == NodePathTokenType.Property) if (subpath.Type == NodePathTokenType.Property)
@ -154,6 +194,11 @@ public sealed partial class DebugConsole : Control
GD.Print(text); GD.Print(text);
} }
public void Inspect(NodePath node)
{
}
public void Execute(string str) public void Execute(string str)
{ {
//str = Sanitizer.Sanitize(str); //str = Sanitizer.Sanitize(str);

View File

@ -1,4 +1,6 @@
using Godot; using Godot;
using GodotUtilities;
using System.Linq;
namespace SupaLidlGame.Debug; namespace SupaLidlGame.Debug;
@ -10,6 +12,9 @@ public partial class Entry : CodeEdit
public override void _Ready() public override void _Ready()
{ {
GuiInput += OnGuiInput; GuiInput += OnGuiInput;
AddStringDelimiter("\'", "\"", true);
AddStringDelimiter("'", "'", true);
} }
/* /*
@ -28,12 +33,12 @@ public partial class Entry : CodeEdit
public void OnGuiInput(InputEvent @event) public void OnGuiInput(InputEvent @event)
{ {
if (@event is InputEventKey key) if (@event is InputEventKey key && key.Pressed)
{ {
if (key.KeyLabel == Key.Enter) if (key.KeyLabel == Key.Enter)
{ {
AcceptEvent(); AcceptEvent();
if (!key.Pressed) if (key.Pressed)
{ {
EmitSignal(SignalName.ConsoleInput, Text); EmitSignal(SignalName.ConsoleInput, Text);
@ -45,4 +50,17 @@ public partial class Entry : CodeEdit
} }
} }
} }
public void SetContext(Node context)
{
var properties = context.GetPropertyList();
var propNames = properties.Select((prop) => prop["name"].ToString());
foreach (var prop in propNames)
{
AddCodeCompletionOption(
CodeCompletionKind.Member,
prop, prop);
}
UpdateCodeCompletionOptions(true);
}
} }

53
Debug/Inspector.cs 100644
View File

@ -0,0 +1,53 @@
using Godot;
using Godot.Collections;
using System.Linq;
namespace SupaLidlGame.Debug;
public partial class Inspector : Node
{
private Node _target;
private Array<Dictionary> _props;
private Dictionary<string, Label> _labels;
public Node Target
{
get => _target;
set
{
_target = value;
UpdateTarget();
}
}
public override void _Process(double delta)
{
foreach (var kv in _labels)
{
string propName = kv.Key;
var node = kv.Value;
node.Text = _target.Get(propName).ToString();
}
}
public void UpdateTarget()
{
foreach (var kv in _labels)
{
var node = kv.Value;
node.QueueFree();
}
_labels.Clear();
LoadAllProperties();
}
public void LoadAllProperties()
{
_props = _target.GetPropertyList();
foreach (var kv in _props)
{
}
}
}

View File

@ -4,10 +4,6 @@ namespace SupaLidlGame.Debug;
public class Iterator<T> where T : struct public class Iterator<T> where T : struct
{ {
public int Line { get; protected set; } = 1;
public int Column { get; protected set; } = 0;
public int Index { get; protected set; } = -1; public int Index { get; protected set; } = -1;
protected List<T> _elements; protected List<T> _elements;

View File

@ -0,0 +1,20 @@
using Godot;
namespace SupaLidlGame.Debug;
public struct PropertyPointer
{
public Node Node { get; set; }
public string Property { get; set; }
public PropertyPointer(Node node, string property)
{
Node = node;
Property = property;
}
public Variant Dereferenced => Node.Get(Property);
public void Set(Variant value) => Node.Set(Property, value);
}

View File

@ -12,23 +12,31 @@ public class LiteralExpression : Expression
Literal = literal; Literal = literal;
} }
public string EscapedLiteral()
{
return Literal.Value.Replace("\"", "\\\"")
.Replace("'", "\\'")
.Replace("\n", "\\n")
.Replace("\t", "\\t");
}
public override string Transpile() public override string Transpile()
{ {
var val = EscapedLiteral();
if (Literal.Type == TokenType.NodePath) if (Literal.Type == TokenType.NodePath)
{ {
var val = Regex.Escape(Literal.Value);
return $"from.call(\"{val}\")"; return $"from.call(\"{val}\")";
} }
else if (Literal.Type == TokenType.String) else if (Literal.Type == TokenType.String)
{ {
return $"\"{Literal.Value}\""; return $"\"{val}\"";
} }
return Literal.Value; return Literal.Value;
} }
public string TranspileNodePath() public string TranspileNodePath()
{ {
var val = Regex.Escape(Literal.Value); var val = EscapedLiteral();
return $"to_node_path.call(\"{val}\")"; return $"to_node_path.call(\"{val}\")";
} }
} }

View File

@ -0,0 +1,68 @@
using SupaLidlGame.Debug;
using Godot;
namespace SupaLidlGame.UI.Debug;
public partial class DebugUI : CanvasLayer
{
private bool _areWindowsVisible = false;
private Window _lastFocusedWindow = null;
public bool AreWindowsVisible
{
get => _areWindowsVisible;
set
{
_areWindowsVisible = value;
foreach (var node in GetChildren())
{
if (node is Window w)
{
w.Visible = value;
}
else if (node is Control c)
{
c.Visible = value;
}
}
}
}
//public override void _Ready()
//{
// AreWindowsVisible = false;
// ChildEnteredTree += (Node child) =>
// {
// if (child is Window w)
// {
// void setFocus()
// {
// _lastFocusedWindow = w;
// }
// w.FocusEntered += setFocus;
// }
// };
// _lastFocusedWindow = GetNode<Window>("%ConsoleWindow");
//}
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey key)
{
if (key.Keycode == Key.Quoteleft)
{
if (key.Pressed)
{
Toggle();
}
}
}
}
public void Toggle()
{
AreWindowsVisible = !AreWindowsVisible;
}
}

View File

@ -1,34 +1,33 @@
[gd_scene load_steps=3 format=3 uid="uid://be8bc4eivsg4s"] [gd_scene load_steps=4 format=3 uid="uid://be8bc4eivsg4s"]
[ext_resource type="Script" path="res://Debug/DebugConsole.cs" id="1_3fw5a"] [ext_resource type="Script" path="res://Debug/DebugConsole.cs" id="1_3fw5a"]
[ext_resource type="Script" path="res://UI/Debug/DebugUI.cs" id="1_b7eq2"]
[ext_resource type="Script" path="res://Debug/Entry.cs" id="2_kdlsh"] [ext_resource type="Script" path="res://Debug/Entry.cs" id="2_kdlsh"]
[node name="DebugUI" type="Control"] [node name="DebugUI" type="CanvasLayer"]
layout_mode = 3 process_mode = 3
anchors_preset = 15 script = ExtResource("1_b7eq2")
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Window" type="Window" parent="."] [node name="ConsoleWindow" type="Window" parent="."]
disable_3d = true unique_name_in_owner = true
gui_embed_subwindows = true handle_input_locally = false
title = "Supa Developer Console" title = "Supa Developer Console"
position = Vector2i(32, 32) position = Vector2i(32, 32)
size = Vector2i(1280, 720) size = Vector2i(1280, 720)
visible = false
always_on_top = true always_on_top = true
[node name="DebugConsole" type="Control" parent="Window"] [node name="DebugConsole" type="ColorRect" parent="ConsoleWindow"]
layout_mode = 3 unique_name_in_owner = true
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
color = Color(0.117647, 0.117647, 0.180392, 1)
script = ExtResource("1_3fw5a") script = ExtResource("1_3fw5a")
[node name="VBoxContainer" type="VBoxContainer" parent="Window/DebugConsole"] [node name="VBoxContainer" type="VBoxContainer" parent="ConsoleWindow/DebugConsole"]
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
@ -36,23 +35,21 @@ anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
[node name="Output" type="RichTextLabel" parent="Window/DebugConsole/VBoxContainer"] [node name="Output" type="RichTextLabel" parent="ConsoleWindow/DebugConsole/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
size_flags_vertical = 3 size_flags_vertical = 3
theme_override_font_sizes/normal_font_size = 24 theme_override_font_sizes/normal_font_size = 16
theme_override_font_sizes/bold_font_size = 24 theme_override_font_sizes/bold_font_size = 16
bbcode_enabled = true bbcode_enabled = true
text = "[b]/root/World:[/b] \\echo :CurrentPlayer:Health
100
"
scroll_following = true scroll_following = true
[node name="Entry" type="CodeEdit" parent="Window/DebugConsole/VBoxContainer"] [node name="Entry" type="CodeEdit" parent="ConsoleWindow/DebugConsole/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(0, 48) custom_minimum_size = Vector2(0, 36)
layout_mode = 2 layout_mode = 2
theme_override_font_sizes/font_size = 24 theme_override_colors/background_color = Color(0.0941176, 0.0941176, 0.145098, 1)
theme_override_font_sizes/font_size = 16
placeholder_text = "Enter a GDScript expression or \\command..." placeholder_text = "Enter a GDScript expression or \\command..."
draw_control_chars = true draw_control_chars = true
code_completion_enabled = true code_completion_enabled = true

View File

@ -0,0 +1,16 @@
[gd_resource type="Theme" load_steps=6 format=3 uid="uid://f403wogmdo7s"]
[ext_resource type="FontFile" uid="uid://dpxde42hku7e4" path="res://Assets/Fonts/RobotoMono-Bold.ttf" id="1_luw4j"]
[ext_resource type="FontFile" uid="uid://dj0652yei7yiw" path="res://Assets/Fonts/RobotoMono-Italic.ttf" id="2_eyrn1"]
[ext_resource type="FontFile" uid="uid://634gg67hl134" path="res://Assets/Fonts/RobotoMono-BoldItalic.ttf" id="3_cod6d"]
[ext_resource type="FontFile" uid="uid://br1ivkgagsm6e" path="res://Assets/Fonts/RobotoMono-Regular.ttf" id="4_5u55u"]
[sub_resource type="FontVariation" id="FontVariation_x2wu6"]
base_font = ExtResource("4_5u55u")
[resource]
default_font = SubResource("FontVariation_x2wu6")
/fonts/Bold = ExtResource("1_luw4j")
/fonts/Italic = ExtResource("2_eyrn1")
/fonts/Oblique = ExtResource("3_cod6d")
/fonts/Regular = ExtResource("4_5u55u")

View File

@ -23,7 +23,6 @@ EventBus="*res://Events/EventBus.cs"
BaseUI="*res://UI/Base.tscn" BaseUI="*res://UI/Base.tscn"
World="*res://Scenes/Level.tscn" World="*res://Scenes/Level.tscn"
AudioManager="*res://Audio/AudioManager.cs" AudioManager="*res://Audio/AudioManager.cs"
Panku="*res://addons/panku_console/console.tscn"
DebugUi="*res://UI/Debug/DebugUI.tscn" DebugUi="*res://UI/Debug/DebugUI.tscn"
[dialogue_manager] [dialogue_manager]