debug console init
parent
213358a2ba
commit
ad29c9cd29
|
@ -0,0 +1,29 @@
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
internal sealed class CharIterator : Iterator<char>
|
||||||
|
{
|
||||||
|
public CharIterator(string str) : base(str.ToCharArray())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharIterator(char[] chars) : base(chars)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override char MoveNext()
|
||||||
|
{
|
||||||
|
char c = base.MoveNext();
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
Line++;
|
||||||
|
Column = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Column++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,21 +2,97 @@ using Godot;
|
||||||
|
|
||||||
namespace SupaLidlGame.Debug;
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
public partial class DebugConsole : Node
|
public sealed partial class DebugConsole : Control
|
||||||
{
|
{
|
||||||
public void SetProp(
|
private Node _context;
|
||||||
Utils.World world,
|
public Node Context
|
||||||
string entityName,
|
|
||||||
string property,
|
|
||||||
string value)
|
|
||||||
{
|
{
|
||||||
var ent = world.CurrentMap.Entities.GetNodeOrNull(entityName);
|
get => _context;
|
||||||
if (ent is not null)
|
private set
|
||||||
{
|
{
|
||||||
ent.Set(property, value);
|
if (value is not null)
|
||||||
|
{
|
||||||
|
_context = value;
|
||||||
|
if (_entry is not null)
|
||||||
|
{
|
||||||
|
_entry.PlaceholderText = "Enter Godot expression from " +
|
||||||
|
_context.GetPath();
|
||||||
|
GetParent<Window>().Title = "Supa Developer Console: " +
|
||||||
|
_context.GetPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Entry _entry;
|
||||||
|
|
||||||
|
private RichTextLabel _output;
|
||||||
|
|
||||||
|
private Node ctx => Context;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
_entry = GetNode<Entry>("%Entry");
|
||||||
|
_output = GetNode<RichTextLabel>("%Output");
|
||||||
|
Context = Utils.World.Instance;
|
||||||
|
|
||||||
|
_entry.ConsoleInput += (string input) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Execute(input);
|
||||||
|
}
|
||||||
|
catch (InterpreterException ex)
|
||||||
|
{
|
||||||
|
_output.Text += ex.Message + '\n';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PathType
|
||||||
|
{
|
||||||
|
Node,
|
||||||
|
Property
|
||||||
|
};
|
||||||
|
|
||||||
|
public Variant From(NodePath path)
|
||||||
|
{
|
||||||
|
CharIterator iterator = new(path);
|
||||||
|
Variant variant = Context ?? this;
|
||||||
|
foreach (var subpath in NodePathParser.ParseNodePath(iterator))
|
||||||
|
{
|
||||||
|
if (variant.VariantType == Variant.Type.Object)
|
||||||
|
{
|
||||||
|
if (variant.AsGodotObject() is Node n)
|
||||||
|
{
|
||||||
|
if (subpath.Type == NodePathTokenType.Node)
|
||||||
|
{
|
||||||
|
if (subpath.Path != "")
|
||||||
|
{
|
||||||
|
variant = n.GetNode(subpath.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variant = n.GetIndexed(subpath.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetProp(NodePath path, Variant value)
|
||||||
|
{
|
||||||
|
var node = GetNode(path.GetAsPropertyPath());
|
||||||
|
//var ent = CurrentMap.Entities.GetNodeOrNull(entityName);
|
||||||
|
//if (ent is not null)
|
||||||
|
//{
|
||||||
|
// ent.Set(property, value);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
public string CallMethod(
|
public string CallMethod(
|
||||||
Utils.World world,
|
Utils.World world,
|
||||||
string entityName,
|
string entityName,
|
||||||
|
@ -31,4 +107,54 @@ public partial class DebugConsole : Node
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Print(string text)
|
||||||
|
{
|
||||||
|
GD.Print(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(string str)
|
||||||
|
{
|
||||||
|
str = Sanitizer.Sanitize(str);
|
||||||
|
string inputMirror = $"[b]{Context.GetPath()}:[/b] {str}";
|
||||||
|
_output.Text += inputMirror + "\n";
|
||||||
|
var context = Context;
|
||||||
|
|
||||||
|
Godot.Expression exp = new();
|
||||||
|
|
||||||
|
string[] reserved = { "from", "set_context", "context" };
|
||||||
|
Godot.Collections.Array reservedMap = new();
|
||||||
|
reservedMap.Add(new Callable(this, MethodName.From));
|
||||||
|
reservedMap.Add(new Callable(this, MethodName.SetContext));
|
||||||
|
reservedMap.Add(Context);
|
||||||
|
|
||||||
|
var err = exp.Parse(str, reserved);
|
||||||
|
if (err != Error.Ok)
|
||||||
|
{
|
||||||
|
throw new InterpreterException(
|
||||||
|
"Error occurred while parsing Godot.Expression: \n" +
|
||||||
|
exp.GetErrorText(),
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant result = exp.Execute(reservedMap, context);
|
||||||
|
if (exp.HasExecuteFailed())
|
||||||
|
{
|
||||||
|
throw new InterpreterException(
|
||||||
|
"Error occurred while evaluating Godot.Expression: \n" +
|
||||||
|
exp.GetErrorText(),
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send result to output
|
||||||
|
if (result.VariantType != Variant.Type.Nil)
|
||||||
|
{
|
||||||
|
_output.Text += result + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetContext(Node node)
|
||||||
|
{
|
||||||
|
Context = node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
public partial class Entry : LineEdit
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void ConsoleInputEventHandler(string input);
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
GuiInput += OnGuiInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGuiInput(InputEvent @event)
|
||||||
|
{
|
||||||
|
if (@event is InputEventKey key)
|
||||||
|
{
|
||||||
|
if (key.KeyLabel == Key.Enter && !key.Pressed)
|
||||||
|
{
|
||||||
|
EmitSignal(SignalName.ConsoleInput, Text);
|
||||||
|
|
||||||
|
if (!key.CtrlPressed)
|
||||||
|
{
|
||||||
|
Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
protected List<T> _elements;
|
||||||
|
|
||||||
|
public Iterator(T[] elements)
|
||||||
|
{
|
||||||
|
_elements = new List<T>(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator(List<T> elements)
|
||||||
|
{
|
||||||
|
_elements = new List<T>(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetNext(int offset = 0)
|
||||||
|
{
|
||||||
|
if (Index + offset + 1 < _elements.Count)
|
||||||
|
{
|
||||||
|
return _elements[Index + offset + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual T MoveNext()
|
||||||
|
{
|
||||||
|
T next = GetNext();
|
||||||
|
Index++;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void MoveBack()
|
||||||
|
{
|
||||||
|
Index--;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
internal static class NodePathParser
|
||||||
|
{
|
||||||
|
internal static IEnumerable<NodePathToken> ParseNodePath(CharIterator iterator)
|
||||||
|
{
|
||||||
|
// Some/Node/Path:And:Property/More/Paths
|
||||||
|
// ->
|
||||||
|
// Some/Node/Path (Node)
|
||||||
|
// :And:Property (Property)
|
||||||
|
// More/Paths (Node)
|
||||||
|
|
||||||
|
NodePathTokenType curType = NodePathTokenType.Node;
|
||||||
|
string path = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char curChar = iterator.MoveNext();
|
||||||
|
|
||||||
|
if (curChar == ':')
|
||||||
|
{
|
||||||
|
// if we have been parsing a nodepath, yield a nodepath
|
||||||
|
if (curType == NodePathTokenType.Node)
|
||||||
|
{
|
||||||
|
if (path.Length > 0)
|
||||||
|
{
|
||||||
|
yield return new NodePathToken(path, curType);
|
||||||
|
path = "";
|
||||||
|
curType = NodePathTokenType.Property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path += curChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (curChar == '/')
|
||||||
|
{
|
||||||
|
// if we have been parsing property, yield a property
|
||||||
|
if (curType == NodePathTokenType.Property)
|
||||||
|
{
|
||||||
|
yield return new NodePathToken(path, curType);
|
||||||
|
path = "";
|
||||||
|
curType = NodePathTokenType.Node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path += curChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path += curChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reached the end
|
||||||
|
if (path.Length > 0)
|
||||||
|
{
|
||||||
|
yield return new NodePathToken(path, curType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public enum NodePathTokenType
|
||||||
|
{
|
||||||
|
Node,
|
||||||
|
Property
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct NodePathToken
|
||||||
|
{
|
||||||
|
public NodePath Path { get; set; }
|
||||||
|
|
||||||
|
public NodePathTokenType Type { get; set; }
|
||||||
|
|
||||||
|
public NodePathToken(NodePath path, NodePathTokenType type)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
using Godot;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
public static class Sanitizer
|
||||||
|
{
|
||||||
|
private static Regex _nonAlphanum = new("[^a-zA-Z0-9_]");
|
||||||
|
|
||||||
|
private static Regex _nonNodeName = new("[^a-zA-Z0-9_\\-\\/]");
|
||||||
|
|
||||||
|
private static string ScanString(CharIterator iterator)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.MoveNext();
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
char escape = iterator.MoveNext();
|
||||||
|
|
||||||
|
switch (escape)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
ret += '\n';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
ret += '\t';
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
throw new InterpreterException("Unexpected EOL",
|
||||||
|
iterator.Line, iterator.Column); default:
|
||||||
|
ret += escape;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
throw new InterpreterException("Unexpected EOL, expected '\"'",
|
||||||
|
iterator.Line, iterator.Column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ScanNodePath(CharIterator iterator)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.MoveNext();
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
return ScanString(iterator);
|
||||||
|
}
|
||||||
|
else if (_nonNodeName.IsMatch(c.ToString()))
|
||||||
|
{
|
||||||
|
iterator.MoveBack();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ScanUntilOrEOL(CharIterator iterator, char delim)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.GetNext();
|
||||||
|
if (c == delim)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ScanGlobalCommand(CharIterator iterator)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.MoveNext();
|
||||||
|
if (_nonAlphanum.IsMatch(c.ToString()))
|
||||||
|
{
|
||||||
|
iterator.MoveBack();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Sanitize(string input)
|
||||||
|
{
|
||||||
|
CharIterator iterator = new(input);
|
||||||
|
string ret = "";
|
||||||
|
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.MoveNext();
|
||||||
|
|
||||||
|
if (c == '$')
|
||||||
|
{
|
||||||
|
string nodePath = ScanNodePath(iterator);
|
||||||
|
ret += $"from.call(\"{nodePath}\")";
|
||||||
|
}
|
||||||
|
else if (c == '"')
|
||||||
|
{
|
||||||
|
string str = ScanString(iterator);
|
||||||
|
ret += $"\"{str}\"";
|
||||||
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
// \global -> global.call
|
||||||
|
string command = ScanGlobalCommand(iterator);
|
||||||
|
ret += $"{command}.call";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
public enum TokenType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Identifier,
|
||||||
|
String,
|
||||||
|
GodotExpression,
|
||||||
|
Command,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
|
||||||
|
public struct Token
|
||||||
|
{
|
||||||
|
public TokenType Type { get; set; }
|
||||||
|
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
public int Line { get; set; }
|
||||||
|
|
||||||
|
public int Column { get; set; }
|
||||||
|
|
||||||
|
public Token(TokenType type, string value, int line, int col)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Value = value;
|
||||||
|
Line = line;
|
||||||
|
Column = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CompareTypeValue(Token token)
|
||||||
|
{
|
||||||
|
return Type == token.Type && Value == token.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return base.Equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return base.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Token left, Token right) => left.Equals(right);
|
||||||
|
|
||||||
|
public static bool operator !=(Token left, Token right) => !left.Equals(right);
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Debug;
|
||||||
|
|
||||||
|
internal sealed class Tokenizer
|
||||||
|
{
|
||||||
|
private static readonly HashSet<char> WHITESPACE = new HashSet<char> { ' ', '\n' };
|
||||||
|
|
||||||
|
private static string ScanString(CharIterator iterator)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.MoveNext();
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
char escape = iterator.MoveNext();
|
||||||
|
|
||||||
|
switch (escape)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
ret += '\n';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
ret += '\t';
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
throw new InterpreterException("Unexpected EOL",
|
||||||
|
iterator.Line, iterator.Column);
|
||||||
|
default:
|
||||||
|
ret += escape;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
throw new InterpreterException("Unexpected EOL, expected '\"'",
|
||||||
|
iterator.Line, iterator.Column);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ScanNodePath(CharIterator iterator)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.GetNext();
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
ret += ScanString(iterator);
|
||||||
|
}
|
||||||
|
else if (WHITESPACE.Contains(c))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private static string ScanUntil(CharIterator iterator)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static string ScanExpression(CharIterator iterator)
|
||||||
|
{
|
||||||
|
int level = 0;
|
||||||
|
string exp = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.GetNext();
|
||||||
|
|
||||||
|
if (c == '(')
|
||||||
|
{
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
else if (c == ')')
|
||||||
|
{
|
||||||
|
level--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level < 0)
|
||||||
|
{
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp += c;
|
||||||
|
}
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ScanUntilOrEOL(CharIterator iterator, char delim)
|
||||||
|
{
|
||||||
|
string ret = "";
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char c = iterator.GetNext();
|
||||||
|
if (c == delim)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Token> Tokenize(CharIterator iterator)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.Print("hi");
|
||||||
|
while (iterator.GetNext() != '\0')
|
||||||
|
{
|
||||||
|
char curChar = iterator.MoveNext();
|
||||||
|
System.Diagnostics.Debug.Print(curChar.ToString());
|
||||||
|
|
||||||
|
int line = iterator.Line;
|
||||||
|
int col = iterator.Column;
|
||||||
|
|
||||||
|
if (WHITESPACE.Contains(curChar))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (curChar == '\\')
|
||||||
|
{
|
||||||
|
string command = ScanUntilOrEOL(iterator, ' ');
|
||||||
|
if (command == "")
|
||||||
|
{
|
||||||
|
throw new InterpreterException(
|
||||||
|
"Expected a command name",
|
||||||
|
iterator.Line,
|
||||||
|
iterator.Column);
|
||||||
|
}
|
||||||
|
yield return new Token(TokenType.Command,
|
||||||
|
command,
|
||||||
|
line,
|
||||||
|
col);
|
||||||
|
}
|
||||||
|
else if (curChar == '(')
|
||||||
|
{
|
||||||
|
string exp = ScanExpression(iterator);
|
||||||
|
yield return new Token(TokenType.GodotExpression,
|
||||||
|
exp,
|
||||||
|
line,
|
||||||
|
col);
|
||||||
|
}
|
||||||
|
else if (curChar == '"')
|
||||||
|
{
|
||||||
|
yield return new Token(TokenType.String,
|
||||||
|
ScanString(iterator),
|
||||||
|
line,
|
||||||
|
col);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// parse this as expression
|
||||||
|
string exp = ScanUntilOrEOL(iterator, ' ');
|
||||||
|
yield return new Token(TokenType.GodotExpression,
|
||||||
|
exp,
|
||||||
|
line,
|
||||||
|
col);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
else if (curChar == '$')
|
||||||
|
{
|
||||||
|
yield return new Token(TokenType.NodePath,
|
||||||
|
ScanNodePath(iterator),
|
||||||
|
line,
|
||||||
|
col);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
yield return new Token(TokenType.End, "",
|
||||||
|
iterator.Line, iterator.Column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace SupaLidlGame;
|
||||||
|
|
||||||
|
public class InterpreterException : System.Exception
|
||||||
|
{
|
||||||
|
public int Line { get; set; }
|
||||||
|
public int Column { get; set; }
|
||||||
|
|
||||||
|
public InterpreterException(string msg, int line, int column) : base(msg)
|
||||||
|
{
|
||||||
|
Line = line;
|
||||||
|
Column = column;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,28 +4,6 @@ namespace SupaLidlGame.Extensions;
|
||||||
|
|
||||||
public static class NodeExtensions
|
public static class NodeExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Iterates through each ancestor until it finds an ancestor of type
|
|
||||||
/// <c>T</c>
|
|
||||||
/// </summary>
|
|
||||||
[System.Obsolete]
|
|
||||||
public static T GetAncestorDeprecated<T>(this Node node) where T : Node
|
|
||||||
{
|
|
||||||
Node parent;
|
|
||||||
|
|
||||||
while ((parent = node.GetParent()) != null)
|
|
||||||
{
|
|
||||||
if (parent is T t)
|
|
||||||
{
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A version <c>GetNode</c> that returns null rather than cause an
|
/// A version <c>GetNode</c> that returns null rather than cause an
|
||||||
/// exception if the node is not found or is not the same type.
|
/// exception if the node is not found or is not the same type.
|
||||||
|
|
|
@ -29,6 +29,7 @@ stretch = true
|
||||||
stretch_shrink = 3
|
stretch_shrink = 3
|
||||||
|
|
||||||
[node name="UIViewport" type="SubViewport" parent="SubViewportContainer"]
|
[node name="UIViewport" type="SubViewport" parent="SubViewportContainer"]
|
||||||
|
disable_3d = true
|
||||||
transparent_bg = true
|
transparent_bg = true
|
||||||
handle_input_locally = false
|
handle_input_locally = false
|
||||||
size = Vector2i(640, 360)
|
size = Vector2i(640, 360)
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
[gd_scene format=3 uid="uid://be8bc4eivsg4s"]
|
[gd_scene load_steps=3 format=3 uid="uid://be8bc4eivsg4s"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Debug/DebugConsole.cs" id="1_3fw5a"]
|
||||||
|
[ext_resource type="Script" path="res://Debug/Entry.cs" id="2_kdlsh"]
|
||||||
|
|
||||||
[node name="DebugUI" type="Control"]
|
[node name="DebugUI" type="Control"]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
|
@ -8,11 +11,47 @@ anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
[node name="Window" type="Window" parent="."]
|
||||||
layout_mode = 1
|
disable_3d = true
|
||||||
anchors_preset = 12
|
gui_embed_subwindows = true
|
||||||
anchor_top = 1.0
|
title = "Supa Developer Console"
|
||||||
|
position = Vector2i(32, 32)
|
||||||
|
size = Vector2i(1280, 720)
|
||||||
|
always_on_top = true
|
||||||
|
|
||||||
|
[node name="DebugConsole" type="Control" parent="Window"]
|
||||||
|
layout_mode = 3
|
||||||
|
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 = 0
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_3fw5a")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="Window/DebugConsole"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Output" type="RichTextLabel" parent="Window/DebugConsole/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_font_sizes/normal_font_size = 24
|
||||||
|
theme_override_font_sizes/bold_font_size = 24
|
||||||
|
bbcode_enabled = true
|
||||||
|
text = "[b]/root/World:[/b] \\echo :CurrentPlayer:Health
|
||||||
|
100
|
||||||
|
"
|
||||||
|
scroll_following = true
|
||||||
|
|
||||||
|
[node name="Entry" type="LineEdit" parent="Window/DebugConsole/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
placeholder_text = "Enter a GDScript expression or \\command..."
|
||||||
|
draw_control_chars = true
|
||||||
|
script = ExtResource("2_kdlsh")
|
||||||
|
|
|
@ -23,8 +23,8 @@ 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"
|
||||||
DebugConsole="*res://Debug/DebugConsole.cs"
|
|
||||||
Panku="*res://addons/panku_console/console.tscn"
|
Panku="*res://addons/panku_console/console.tscn"
|
||||||
|
DebugUi="*res://UI/Debug/DebugUI.tscn"
|
||||||
|
|
||||||
[dialogue_manager]
|
[dialogue_manager]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue