-
Notifications
You must be signed in to change notification settings - Fork 0
Added Dev Console #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[gd_resource type="StyleBoxFlat" format=3 uid="uid://bs0wxlu2afue2"] | ||
|
||
[resource] | ||
bg_color = Color(0.164706, 0.180392, 0.203922, 1) | ||
corner_radius_top_left = 8 | ||
corner_radius_top_right = 8 | ||
corner_radius_bottom_right = 8 | ||
corner_radius_bottom_left = 8 | ||
expand_margin_left = 2.0 | ||
expand_margin_right = 2.0 | ||
shadow_color = Color(0.0784314, 0.0784314, 0.0784314, 1) | ||
shadow_offset = Vector2(1, 2) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://h368fwjarh3n"] | ||
|
||
[ext_resource type="StyleBox" uid="uid://bs0wxlu2afue2" path="res://assets/themes/box.tres" id="1_seonm"] | ||
|
||
[resource] | ||
LineEdit/font_sizes/font_size = 16 | ||
LineEdit/styles/focus = ExtResource("1_seonm") | ||
LineEdit/styles/normal = ExtResource("1_seonm") | ||
LineEdit/styles/read_only = ExtResource("1_seonm") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Linq; | ||
using ExtractIntoVoid.Managers; | ||
using Godot; | ||
|
||
public partial class ConsoleEnabledScene : Control { | ||
public override void _Input(InputEvent @event) | ||
{ | ||
base._Input(@event); | ||
if (@event is InputEventKey eKey && eKey.KeyLabel == Key.Quoteleft && eKey.IsReleased()) | ||
{ | ||
var consoles = GetChildren().OfType<DevConsole>(); | ||
if (consoles.Any()) | ||
{ | ||
var first = consoles.First(); | ||
|
||
first.Close(); | ||
} | ||
else | ||
{ | ||
AddChild(ConsoleManager.GetConsole()); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
using Godot; | ||
using System; | ||
using System.Linq; | ||
using ExtractIntoVoid.Managers; | ||
using System.Globalization; | ||
|
||
// ReSharper disable CheckNamespace | ||
// ReSharper disable MemberCanBePrivate.Global | ||
public partial class DevConsole : Window | ||
{ | ||
// Called when the node enters the scene tree for the first time. | ||
|
||
private TextEdit Output => GetNode<TextEdit>("./Control/Output"); | ||
private LineEdit Input => GetNode<LineEdit>("Control/InputArea/InputField"); | ||
|
||
public override void _Ready() | ||
{ | ||
CloseRequested += () => | ||
{ | ||
Close(); | ||
}; | ||
Open(); | ||
//ConsoleManager.Console = this; | ||
} | ||
// Called every frame. 'delta' is the elapsed time since the previous frame. | ||
public override void _Process(double delta) | ||
{ | ||
if (Visible && Output.Text != ConsoleManager.Contents) | ||
Output.Text = ConsoleManager.Contents; | ||
} | ||
private void OnInputSubmitted(string input) | ||
{ | ||
|
||
|
||
var split = input.Split(' '); | ||
var command = split.First(); | ||
var args = split.Skip(1).ToArray();//TakeLast(input.Split(' ').Length - 1).ToArray(); | ||
Input.Text = ""; | ||
Print("> " + input); | ||
|
||
HandleCommand(command, args); | ||
|
||
} | ||
public override void _Input(InputEvent @event) | ||
{ | ||
if (@event is InputEventKey eventKey && eventKey.Pressed && eventKey.Keycode == Key.Tab && Input.Text != "") | ||
{ | ||
var types = ConsoleManager.GetAll(); | ||
if (!types.Keys.Any(s => s.StartsWith(Input.Text))) | ||
{ | ||
return; | ||
} | ||
//Print(_cTypes.Keys.FirstOrDefault(s => s.StartsWith(Input.Text))); | ||
var suggestions = new PopupMenu() | ||
{ | ||
Size = new Vector2I(0, 0), | ||
Position = new Vector2I((int)Input.GetScreenPosition().X, (int)Input.GetScreenPosition().Y + 24) | ||
}; | ||
foreach (var item in types.Where(s => s.Key.StartsWith(Input.Text))) | ||
{ | ||
var context = new CommandContext(this, null); | ||
|
||
var value = ""; | ||
if (item.Value is CVar<string> cVarString) | ||
{ | ||
value += " " + cVarString.Get(context); | ||
} | ||
if (item.Value is CVar<bool> cVarBool) | ||
{ | ||
value += " " + cVarBool.Get(context); | ||
} | ||
if (item.Value is CVar<int> cVarInt) | ||
{ | ||
value += " " + cVarInt.Get(context); | ||
} | ||
if (item.Value is CVar<float> cVarFloat) | ||
{ | ||
value += " " + cVarFloat.Get(context); | ||
} | ||
suggestions.AddItem($"{item.Key}{value}"); | ||
} | ||
suggestions.IdPressed += delegate (long id) | ||
{ | ||
Input.Text = suggestions.GetItemText((int)id).Split(" ").First(); | ||
Input.CaretColumn = Input.Text.Length; | ||
}; | ||
suggestions.SetFocusedItem(0); | ||
Input.AddChild(suggestions); | ||
suggestions.Popup(); | ||
//_cTypes.Keys.Where(s => s.StartsWith(Input.Text)); | ||
} | ||
base._Input(@event); | ||
} | ||
|
||
public void Close() | ||
{ | ||
Visible = false; | ||
Godot.Input.MouseMode = ConsoleManager.CachedMouse; | ||
QueueFree(); | ||
} | ||
|
||
private void Open() | ||
{ | ||
ConsoleManager.CachedMouse = Godot.Input.MouseMode; | ||
Visible = true; | ||
Godot.Input.MouseMode = Godot.Input.MouseModeEnum.Visible; | ||
} | ||
public void HandleCommand(string inputCommand, string[] args) | ||
{ | ||
if (ConsoleManager.TryGet(inputCommand, out var command)) | ||
{ | ||
var context = new CommandContext(this, args); | ||
if (command is CFunc cFunc) | ||
{ | ||
cFunc.Call(context); | ||
} | ||
if (command is CVar<string> cVarString) | ||
{ | ||
if (args.Length == 0) | ||
{ | ||
Print(cVarString.Get(context)); | ||
}else { | ||
cVarString.Set(context, string.Join(" ", args)); | ||
} | ||
} | ||
if (command is CVar<bool> cVarBool) | ||
{ | ||
if (args.Length == 0) | ||
{ | ||
Print(cVarBool.Get(context)); | ||
}else { | ||
try { | ||
cVarBool.Set(context, Convert.ToBoolean(args[0])); | ||
|
||
} | ||
catch (FormatException) { | ||
Print($"Invalid input \"{args[0]}\", must be True or False"); | ||
} | ||
} | ||
} | ||
if (command is CVar<int> cVarInt) | ||
{ | ||
if (args.Length == 0) | ||
{ | ||
Print(cVarInt.Get(context)); | ||
}else { | ||
try { | ||
cVarInt.Set(context, Convert.ToInt32(args[0])); | ||
|
||
} | ||
catch (FormatException) { | ||
Print($"Invalid input \"{args[0]}\", must be an integer"); | ||
} | ||
} | ||
} | ||
if (command is CVar<float> cVarFloat) | ||
{ | ||
if (args.Length == 0) | ||
{ | ||
Print(cVarFloat.Get(context)); | ||
}else { | ||
try { | ||
cVarFloat.Set(context, float.Parse(args[0], CultureInfo.InvariantCulture)); | ||
|
||
} | ||
catch (FormatException) { | ||
Print($"Invalid input \"{args[0]}\", must be a float"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
public void Print(object what) | ||
{ | ||
ConsoleManager.Contents += what; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can simplify here by $"{what}\n"; |
||
ConsoleManager.Contents += '\n'; | ||
Output.ScrollVertical = Output.GetVScrollBar().MaxValue; | ||
|
||
} | ||
|
||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// o7 This is all legacy code from Origin Framework | ||
|
||
// ReSharper disable CheckNamespace | ||
// ReSharper disable MemberCanBePrivate.Global | ||
using System; | ||
using System.Collections.Generic; | ||
using Godot; | ||
using Serilog.Core; | ||
using Serilog.Events; | ||
|
||
namespace ExtractIntoVoid.Managers; | ||
|
||
public static class ConsoleManager | ||
{ | ||
public static string Contents = "* Extract Into Void Developer Console *\nPress TAB for autocomplete.\n'help' to see all commands.\n"; | ||
public static Godot.Input.MouseModeEnum CachedMouse = Godot.Input.MouseModeEnum.Visible; | ||
|
||
public static Node GetConsole() | ||
{ | ||
var console = SceneManager.GetPackedScene("DevConsole").Instantiate() as DevConsole; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please do additional checks if exists, if does not disable the console |
||
return console; | ||
} | ||
private static Dictionary<string, Command> _commands = new(); | ||
/// <summary> | ||
/// Registers a new Command. | ||
/// </summary> | ||
/// <param name="name">The name of the command</param> | ||
/// <param name="CFuncOrCVar">A CVar or CFunc Command</param> | ||
public static void Register(string name, Command CFuncOrCVar) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should have an unregister |
||
{ | ||
_commands.TryAdd(name, CFuncOrCVar); | ||
} | ||
public static bool TryGet(string name, out Command CFuncOrCVar) | ||
{ | ||
return _commands.TryGetValue(name, out CFuncOrCVar); | ||
} | ||
public static Dictionary<string, Command> GetAll() | ||
{ | ||
return new Dictionary<string, Command>(_commands); | ||
SlejmUr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
public abstract class Command | ||
{ | ||
public string Description = ""; | ||
|
||
} | ||
public class CommandContext | ||
{ | ||
public readonly DevConsole Console; | ||
public readonly Control Scene; | ||
public readonly string[] Args; | ||
|
||
public CommandContext(DevConsole console, string[] args) | ||
{ | ||
Console = console; | ||
Scene = console.GetParent() as Control; | ||
Args = args; | ||
} | ||
} | ||
public class CFunc : Command | ||
{ | ||
private Action<CommandContext> _function; | ||
public CFunc(string description, Action<CommandContext> function) | ||
{ | ||
Description = description; | ||
_function = function; | ||
} | ||
public void Call(CommandContext ctx) | ||
{ | ||
_function.Invoke(ctx); | ||
} | ||
|
||
} | ||
public class CVar<T> : Command | ||
{ | ||
private Func<CommandContext, T> _getter; | ||
private Action<CommandContext, T> _setter; | ||
public CVar(string description, Func<CommandContext, T> getter, Action<CommandContext, T> setter) | ||
{ | ||
Description = description; | ||
// Check at runtime if the type is one of the allowed types | ||
if (typeof(T) != typeof(int) && typeof(T) != typeof(float) && | ||
typeof(T) != typeof(bool) && typeof(T) != typeof(string)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should be able to use any number type. [interface exist for it] |
||
{ | ||
throw new InvalidOperationException("Invalid type. Only int, float, bool, and string are allowed."); | ||
} | ||
_getter = getter; | ||
_setter = setter; | ||
} | ||
public T Get(CommandContext ctx) | ||
{ | ||
return _getter.Invoke(ctx); | ||
} | ||
public void Set(CommandContext ctx, T value) | ||
{ | ||
_setter.Invoke(ctx, value); | ||
} | ||
|
||
} | ||
public class ConsoleSink : ILogEventSink | ||
{ | ||
|
||
public void Emit(LogEvent logEvent) | ||
{ | ||
ConsoleManager.Contents += logEvent.RenderMessage(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably export this to new func with type probably HandleVar(T varType, comman