mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Handle exceptions from C# Scripts + Log window + EditorLogger
+ Renamed Platform/DX11/ImGui.bf to .../Dx11ImGui.bf for clarity + ImGuiExtension: ImageButtonEx thata takes a TextureViewBinding + EditorLogger that logs to the LogWindow + Current logger can now be changed + Info, Trace, Warning and Error Icons
This commit is contained in:
@@ -83,6 +83,22 @@ namespace Sandbox
|
|||||||
Log.Error("Camera not found.");
|
Log.Error("Camera not found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.Warning("Achtung.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SubVoid();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubVoid()
|
||||||
|
{
|
||||||
|
throw new Exception("Ouha!", new IndexOutOfRangeException("Bist du jecke2?!", new AccessViolationException("Haleluja")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -113,6 +129,9 @@ namespace Sandbox
|
|||||||
{
|
{
|
||||||
force.Y += JumpForce;
|
force.Y += JumpForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Input.IsKeyPressing(Key.N))
|
||||||
|
SubVoid();
|
||||||
|
|
||||||
_rigidBody.ApplyForceToCenter(force);
|
_rigidBody.ApplyForceToCenter(force);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -9,8 +9,8 @@
|
|||||||
AddressModeU = .Clamp,
|
AddressModeU = .Clamp,
|
||||||
AddressModeV = .Clamp,
|
AddressModeV = .Clamp,
|
||||||
AddressModeW = .Clamp,
|
AddressModeW = .Clamp,
|
||||||
MipMinLOD = -340282346638528859811704183484516925440,
|
MipMinLOD = -3.40282347e+38,
|
||||||
MipMaxLOD = 340282346638528859811704183484516925440,
|
MipMaxLOD = 3.40282347e+38,
|
||||||
MaxAnisotropy = 1,
|
MaxAnisotropy = 1,
|
||||||
BorderColor = {
|
BorderColor = {
|
||||||
R = 1,
|
R = 1,
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,367 @@
|
|||||||
|
using System;
|
||||||
|
using ImGui;
|
||||||
|
using System.Collections;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
using GlitchyEngine.World;
|
||||||
|
using GlitchLog;
|
||||||
|
using GlitchyEngine.Scripting;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.EditWindows;
|
||||||
|
|
||||||
|
enum MessageType
|
||||||
|
{
|
||||||
|
case None = 0;
|
||||||
|
case Trace = 1;
|
||||||
|
case Info = 2;
|
||||||
|
case Warning = 4;
|
||||||
|
case Error = 8;
|
||||||
|
|
||||||
|
public this(LogLevel level)
|
||||||
|
{
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case .Error:
|
||||||
|
this = Error;
|
||||||
|
case .Warning:
|
||||||
|
this = Warning;
|
||||||
|
case .Info:
|
||||||
|
this = Info;
|
||||||
|
case .Trace:
|
||||||
|
this = Trace;
|
||||||
|
default:
|
||||||
|
this = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageSource
|
||||||
|
{
|
||||||
|
public UUID? Entity = null;
|
||||||
|
public StringView? ScriptName = null;
|
||||||
|
public int? Line = null;
|
||||||
|
|
||||||
|
/// If true, the message is only meant for engine developers... so only me :(
|
||||||
|
public bool IsEngineMessage = false;
|
||||||
|
|
||||||
|
public MonoExceptionHelper Exception = null ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public String AdditionalData = null ~ delete _;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogMessage
|
||||||
|
{
|
||||||
|
private String _message ~ delete _;
|
||||||
|
|
||||||
|
public MessageType MessageType { get; private set; }
|
||||||
|
|
||||||
|
public DateTime Timestamp { get; private set; }
|
||||||
|
|
||||||
|
public MessageSource Source { get; private set; } ~ delete _;
|
||||||
|
|
||||||
|
public StringView Message => _message;
|
||||||
|
|
||||||
|
public this(DateTime timestamp, StringView message, MessageType logLevel, MessageSource ownSource)
|
||||||
|
{
|
||||||
|
Timestamp = timestamp;
|
||||||
|
_message = new String(message);
|
||||||
|
MessageType = logLevel;
|
||||||
|
Source = ownSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogWindow : EditorWindow
|
||||||
|
{
|
||||||
|
public const String s_WindowTitle = "Log";
|
||||||
|
|
||||||
|
private append List<LogMessage> _messages = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
|
||||||
|
public static SubTexture2D s_ErrorIcon;
|
||||||
|
public static SubTexture2D s_WarningIcon;
|
||||||
|
public static SubTexture2D s_InfoIcon;
|
||||||
|
public static SubTexture2D s_TraceIcon;
|
||||||
|
|
||||||
|
private bool _showGameMessages = true;
|
||||||
|
private bool _showEngineMessages = false;
|
||||||
|
private bool _autoScroll = true;
|
||||||
|
private bool _collapseMessages = true;
|
||||||
|
|
||||||
|
private MessageType _visibleMessageTypes = .Error | .Warning | .Info | .Trace;
|
||||||
|
|
||||||
|
protected override void InternalShow()
|
||||||
|
{
|
||||||
|
defer { ImGui.End(); }
|
||||||
|
if(!ImGui.Begin(s_WindowTitle, &_open, .MenuBar))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ShowMenuBar();
|
||||||
|
|
||||||
|
ShowMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMenuBar()
|
||||||
|
{
|
||||||
|
if(ImGui.BeginMenuBar())
|
||||||
|
{
|
||||||
|
if (ImGui.MenuItem("Clear"))
|
||||||
|
{
|
||||||
|
ClearLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginMenu("Filter"))
|
||||||
|
{
|
||||||
|
ImGui.Checkbox("Show game messages", &_showGameMessages);
|
||||||
|
ImGui.AttachTooltip("If checked, the log will show messages generated by the game (e.g. scripts).");
|
||||||
|
|
||||||
|
ImGui.Checkbox("Show engine messages", &_showEngineMessages);
|
||||||
|
ImGui.AttachTooltip("""
|
||||||
|
If checked, the log will show messages generated by the engine.
|
||||||
|
These messages are usually only necessary for engine debugging/development and don't provide practical information for game developers.
|
||||||
|
""");
|
||||||
|
|
||||||
|
ImGui.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Checkbox("Collapse", &_collapseMessages);
|
||||||
|
ImGui.AttachTooltip("If checked, identical messages will be collapsed into one.");
|
||||||
|
|
||||||
|
var col = ImGui.GetStyleColorVec4(.Button);
|
||||||
|
|
||||||
|
if (_visibleMessageTypes.HasFlag(.Trace))
|
||||||
|
ImGui.PushStyleColor(.Button, *col);
|
||||||
|
else
|
||||||
|
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
|
||||||
|
|
||||||
|
if (ImGui.ImageButtonEx(1, s_TraceIcon, .(14, 14), .Zero, .Ones, .(2, 2)))
|
||||||
|
_visibleMessageTypes ^= .Trace;
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
if (_visibleMessageTypes.HasFlag(.Info))
|
||||||
|
ImGui.PushStyleColor(.Button, *col);
|
||||||
|
else
|
||||||
|
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
|
||||||
|
|
||||||
|
if (ImGui.ImageButtonEx(2, s_InfoIcon, .(16, 16)))
|
||||||
|
_visibleMessageTypes ^= .Info;
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
if (_visibleMessageTypes.HasFlag(.Warning))
|
||||||
|
ImGui.PushStyleColor(.Button, *col);
|
||||||
|
else
|
||||||
|
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
|
||||||
|
|
||||||
|
if (ImGui.ImageButtonEx(3, s_WarningIcon, .(16, 16)))
|
||||||
|
_visibleMessageTypes ^= .Warning;
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
if (_visibleMessageTypes.HasFlag(.Error))
|
||||||
|
ImGui.PushStyleColor(.Button, *col);
|
||||||
|
else
|
||||||
|
ImGui.PushStyleColor(.Button, .(0, 0, 0, 0));
|
||||||
|
|
||||||
|
if (ImGui.ImageButtonEx(4, s_ErrorIcon, .(16, 16)))
|
||||||
|
_visibleMessageTypes ^= .Error;
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
ImGui.EndMenuBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMessages()
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTable("Messages", 3, .BordersInnerH | .SizingFixedFit))
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("", .WidthFixed);
|
||||||
|
ImGui.TableSetupColumn("", .WidthStretch);
|
||||||
|
ImGui.TableSetupColumn("", .WidthFixed);
|
||||||
|
|
||||||
|
//LogMessage lastMessage = null;
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
// Message ID for ImGui
|
||||||
|
int imGuiMessageId = 0;
|
||||||
|
|
||||||
|
for (let message in _messages)
|
||||||
|
{
|
||||||
|
if (!_visibleMessageTypes.HasFlag(message.MessageType))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((message.Source.IsEngineMessage && !_showEngineMessages) || (!message.Source.IsEngineMessage && !_showGameMessages))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*defer
|
||||||
|
{
|
||||||
|
lastMessage = message;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
LogMessage lastMessage = (message != _messages.Back) ? _messages[@message.Index + 1] : null;
|
||||||
|
|
||||||
|
if (_collapseMessages && lastMessage != null)
|
||||||
|
{
|
||||||
|
if (message.MessageType != lastMessage.MessageType)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (message.Message != lastMessage.Message)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (message.Source.Entity != lastMessage.Source.Entity)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// For exceptions the stack trace is basically the only relevant thing
|
||||||
|
if (message.Source.Exception?.StackTrace != lastMessage.Source.Exception?.StackTrace)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We collapse this message with the previous one:
|
||||||
|
// Increment counter and go to next message.
|
||||||
|
count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push current index as ID
|
||||||
|
ImGui.PushID((void*)++imGuiMessageId);
|
||||||
|
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableSetColumnIndex(0);
|
||||||
|
|
||||||
|
switch (message.MessageType)
|
||||||
|
{
|
||||||
|
case .Error:
|
||||||
|
ImGui.Image(s_ErrorIcon, ImGui.Vec2(32, 32));
|
||||||
|
ImGui.AttachTooltip("Error");
|
||||||
|
case .Warning:
|
||||||
|
ImGui.Image(s_WarningIcon, ImGui.Vec2(32, 32));
|
||||||
|
ImGui.AttachTooltip("Warning");
|
||||||
|
case .Info:
|
||||||
|
ImGui.Image(s_InfoIcon, ImGui.Vec2(32, 32));
|
||||||
|
ImGui.AttachTooltip("Info");
|
||||||
|
case .Trace:
|
||||||
|
ImGui.Image(s_TraceIcon, ImGui.Vec2(32, 32));
|
||||||
|
ImGui.AttachTooltip("Trace");
|
||||||
|
default:
|
||||||
|
ImGui.TextUnformatted("Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
// Timestamp
|
||||||
|
ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]");
|
||||||
|
|
||||||
|
if (message.Source.IsEngineMessage)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted("Engine");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show entity
|
||||||
|
if (message.Source?.Entity != null)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
Result<Entity> entity = Editor.Instance.CurrentScene.GetEntityByID(message.Source.Entity.Value);
|
||||||
|
|
||||||
|
if (entity case .Ok(let e))
|
||||||
|
{
|
||||||
|
ImGui.Text($"Entity: \"{e.Name}\" (ID: {message.Source.Entity})");
|
||||||
|
|
||||||
|
if (ImGui.IsItemClicked())
|
||||||
|
Editor.Instance.EntityHierarchyWindow.HighlightEntity(entity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.Text($"Entity: (ID: {message.Source.Entity})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Source.Exception != null)
|
||||||
|
{
|
||||||
|
if (ImGui.CollapsingHeader(message.Message.Ptr))
|
||||||
|
{
|
||||||
|
// Show the native to managed entry point only if we show engine messages
|
||||||
|
|
||||||
|
if (_showEngineMessages)
|
||||||
|
ImGui.TextUnformatted(message.Source.Exception.StackTrace);
|
||||||
|
else
|
||||||
|
ImGui.TextUnformatted(message.Source.Exception.CleanStackTrace);
|
||||||
|
|
||||||
|
ImGui.NewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(message.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dont show the counter if we only have one message.
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
// the message is not collapsible with the previous one.
|
||||||
|
// Print message count for last message and reset counter.
|
||||||
|
// This message will be printed normally.
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.Text($"{count}");
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_autoScroll)
|
||||||
|
{
|
||||||
|
if (ImGui.GetIO().MouseWheel > 0)
|
||||||
|
{
|
||||||
|
_autoScroll = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.SetScrollY(ImGui.GetScrollMaxY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ImGui.GetScrollMaxY() == ImGui.GetScrollY())
|
||||||
|
{
|
||||||
|
_autoScroll = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearLog()
|
||||||
|
{
|
||||||
|
ClearAndDeleteItems!(_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log(DateTime timestamp, LogLevel severity, StringView message, MessageSource source)
|
||||||
|
{
|
||||||
|
LogMessage logMessage = new LogMessage(timestamp, message, MessageType(severity), source);
|
||||||
|
_messages.Add(logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogException(DateTime timestamp, MonoExceptionHelper exception)
|
||||||
|
{
|
||||||
|
StringView firstLine = exception.StackTrace;
|
||||||
|
|
||||||
|
int firstInIndex = exception.StackTrace.IndexOf("\n");
|
||||||
|
|
||||||
|
if (firstInIndex != -1)
|
||||||
|
firstLine = firstLine.Substring(0, firstInIndex);
|
||||||
|
|
||||||
|
String message = scope .(128);
|
||||||
|
message.AppendF($"Exception: \"{exception.FullName}\" | Message: \"{exception.Message}\" {firstLine}\0");
|
||||||
|
|
||||||
|
// TODO: are mono exceptions never engine only?
|
||||||
|
LogMessage logMessage = new LogMessage(timestamp, message, .Error, new MessageSource(){Entity = exception.Instance, Exception = exception..AddRef(), IsEngineMessage = false});
|
||||||
|
_messages.Add(logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ namespace GlitchyEditor
|
|||||||
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
|
private ContentBrowserWindow _contentBrowserWindow ~ delete _;
|
||||||
private PropertiesWindow _propertiesWindow ~ delete _;
|
private PropertiesWindow _propertiesWindow ~ delete _;
|
||||||
private AssetViewer _assetViewer ~ delete _;
|
private AssetViewer _assetViewer ~ delete _;
|
||||||
|
private LogWindow _logWindow ~ delete _;
|
||||||
|
|
||||||
public Scene CurrentScene
|
public Scene CurrentScene
|
||||||
{
|
{
|
||||||
@@ -45,6 +46,7 @@ namespace GlitchyEditor
|
|||||||
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
|
public ContentBrowserWindow ContentBrowserWindow => _contentBrowserWindow;
|
||||||
public PropertiesWindow PropertiesWindow => _propertiesWindow;
|
public PropertiesWindow PropertiesWindow => _propertiesWindow;
|
||||||
public AssetViewer AssetViewer => _assetViewer;
|
public AssetViewer AssetViewer => _assetViewer;
|
||||||
|
public LogWindow LogWindow => _logWindow;
|
||||||
|
|
||||||
public EditorCamera* CurrentCamera { get; set; }
|
public EditorCamera* CurrentCamera { get; set; }
|
||||||
|
|
||||||
@@ -69,6 +71,11 @@ namespace GlitchyEditor
|
|||||||
InitWindows();
|
InitWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
s_Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitWindows()
|
private void InitWindows()
|
||||||
{
|
{
|
||||||
_sceneViewportWindow = new EditorViewportWindow(this);
|
_sceneViewportWindow = new EditorViewportWindow(this);
|
||||||
@@ -78,6 +85,7 @@ namespace GlitchyEditor
|
|||||||
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
|
_contentBrowserWindow = new ContentBrowserWindow((.)Application.Get().ContentManager);
|
||||||
_propertiesWindow = new PropertiesWindow(this);
|
_propertiesWindow = new PropertiesWindow(this);
|
||||||
_assetViewer = new AssetViewer((.)Application.Get().ContentManager);
|
_assetViewer = new AssetViewer((.)Application.Get().ContentManager);
|
||||||
|
_logWindow = new LogWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
@@ -89,6 +97,7 @@ namespace GlitchyEditor
|
|||||||
_contentBrowserWindow.Show();
|
_contentBrowserWindow.Show();
|
||||||
_propertiesWindow.Show();
|
_propertiesWindow.Show();
|
||||||
_assetViewer.Show();
|
_assetViewer.Show();
|
||||||
|
_logWindow.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ namespace GlitchyEditor
|
|||||||
public this(String[] args)
|
public this(String[] args)
|
||||||
{
|
{
|
||||||
PushLayer(new EditorLayer(args, _contentManager));
|
PushLayer(new EditorLayer(args, _contentManager));
|
||||||
|
|
||||||
|
Log.ClientLogger = new EditorLogger();
|
||||||
|
Log.EngineLogger = new EditorLogger() { IsEngineLogger = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IContentManager InitContentManager()
|
protected override IContentManager InitContentManager()
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ namespace GlitchyEditor
|
|||||||
public SubTexture2D Simulate ~ _.ReleaseRef();
|
public SubTexture2D Simulate ~ _.ReleaseRef();
|
||||||
public SubTexture2D Pause ~ _.ReleaseRef();
|
public SubTexture2D Pause ~ _.ReleaseRef();
|
||||||
public SubTexture2D SingleStep ~ _.ReleaseRef();
|
public SubTexture2D SingleStep ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Error ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Warning ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Info ~ _.ReleaseRef();
|
||||||
|
public SubTexture2D Trace ~ _.ReleaseRef();
|
||||||
|
|
||||||
public SamplerState SamplerState
|
public SamplerState SamplerState
|
||||||
{
|
{
|
||||||
@@ -41,6 +45,10 @@ namespace GlitchyEditor
|
|||||||
Simulate = GetNextGridTexture(ref pen, iconSize);
|
Simulate = GetNextGridTexture(ref pen, iconSize);
|
||||||
Pause = GetNextGridTexture(ref pen, iconSize);
|
Pause = GetNextGridTexture(ref pen, iconSize);
|
||||||
SingleStep = GetNextGridTexture(ref pen, iconSize);
|
SingleStep = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Error = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Warning = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Info = GetNextGridTexture(ref pen, iconSize);
|
||||||
|
Trace = GetNextGridTexture(ref pen, iconSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubTexture2D GetNextGridTexture(ref float2 pen, float2 iconSize)
|
private SubTexture2D GetNextGridTexture(ref float2 pen, float2 iconSize)
|
||||||
|
|||||||
@@ -171,6 +171,11 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
|
ContentBrowserWindow.s_FolderTexture = _editorIcons.Folder;
|
||||||
ContentBrowserWindow.s_FileTexture = _editorIcons.File;
|
ContentBrowserWindow.s_FileTexture = _editorIcons.File;
|
||||||
|
|
||||||
|
LogWindow.s_ErrorIcon = _editorIcons.Error;
|
||||||
|
LogWindow.s_WarningIcon = _editorIcons.Warning;
|
||||||
|
LogWindow.s_InfoIcon = _editorIcons.Info;
|
||||||
|
LogWindow.s_TraceIcon = _editorIcons.Trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitEditor()
|
private void InitEditor()
|
||||||
@@ -807,6 +812,9 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
if(ImGui.MenuItem(AssetViewer.s_WindowTitle))
|
if(ImGui.MenuItem(AssetViewer.s_WindowTitle))
|
||||||
_editor.AssetViewer.Open = true;
|
_editor.AssetViewer.Open = true;
|
||||||
|
|
||||||
|
if(ImGui.MenuItem(LogWindow.s_WindowTitle))
|
||||||
|
_editor.LogWindow.Open = true;
|
||||||
|
|
||||||
ImGui.EndMenu();
|
ImGui.EndMenu();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
using GlitchLog;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
namespace GlitchyEditor;
|
||||||
|
|
||||||
|
public class EditorLogger : Logger
|
||||||
|
{
|
||||||
|
// {l} = log level (first parameter)
|
||||||
|
// {t} = current date time (second parameter)
|
||||||
|
// {n} = logger name (third parameter)
|
||||||
|
// {m} = message
|
||||||
|
|
||||||
|
private String _name;
|
||||||
|
|
||||||
|
public override String Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set => _name = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEngineLogger {get; set;}
|
||||||
|
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
//Debug.Assert(Debug.IsDebuggerPresent, "The DebugLogger requires a debugger to be present.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG || GL_LOG_NOTRACE
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Trace(StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(.Trace, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG || GL_LOG_NOINFO
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Info(StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(.Info, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG || GL_LOG_NOWARNING
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Warning(StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(.Warning, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG || GL_LOG_NOERROR
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Error(StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(.Error, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG || GL_LOG_NOCRITICAL
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Critical(StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(.Critical, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GL_NOLOG
|
||||||
|
[SkipCall]
|
||||||
|
#endif
|
||||||
|
[Inline]
|
||||||
|
public override void Log(LogLevel level, StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
InternalLog(level, format, params args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
{
|
||||||
|
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
|
||||||
|
InternalLog(.Critical, failStr);
|
||||||
|
Internal.FatalError(failStr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AssertDebug(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
{
|
||||||
|
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
|
||||||
|
InternalLog(.Critical, failStr);
|
||||||
|
Internal.FatalError(failStr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InternalLog(LogLevel level, StringView format, params Object[] args)
|
||||||
|
{
|
||||||
|
if(_logLevel > level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DateTime timestamp = DateTime.Now;
|
||||||
|
|
||||||
|
String message = scope String(4096);
|
||||||
|
message.AppendF(format, params args);
|
||||||
|
|
||||||
|
Debug.Write($"[{timestamp:HH:mm:ss.fff}] ({_name})|{level.UpperString}: {message}");
|
||||||
|
|
||||||
|
if (Editor.Instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.Count > 0 && (var ex = args[^1] as MonoExceptionHelper))
|
||||||
|
{
|
||||||
|
Editor.Instance.LogWindow.LogException(timestamp, ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,9 +96,21 @@ namespace ImGui
|
|||||||
|
|
||||||
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
|
return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
|
public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
|
||||||
|
|
||||||
|
public static bool ImageButtonEx(uint32 id, SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec2 frame_padding = .Zero, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
|
||||||
|
{
|
||||||
|
if (uv0 != .Zero || uv1 != .Ones)
|
||||||
|
Runtime.NotImplemented();
|
||||||
|
|
||||||
|
float2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW;
|
||||||
|
|
||||||
|
return ImageButtonEx(id, subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static extern bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec2 frame_padding = .Zero, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones);
|
||||||
|
|
||||||
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
|
public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length);
|
||||||
|
|
||||||
public static void PushID(StringView id) => PushID(id.Ptr, id.Ptr + id.Length);
|
public static void PushID(StringView id) => PushID(id.Ptr, id.Ptr + id.Length);
|
||||||
|
|||||||
+12
@@ -34,6 +34,18 @@ namespace ImGui
|
|||||||
return pressed;
|
return pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static override bool ImageButtonEx(uint32 id, TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec2 frame_padding = .Zero, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones)
|
||||||
|
{
|
||||||
|
var view = textureViewBinding._nativeShaderResourceView..AddRef();
|
||||||
|
_resourceViews.Add(view);
|
||||||
|
|
||||||
|
bool pressed = ImGui.ImageButtonEx(id, view, size, uv0, uv1, frame_padding, bg_col, tint_col);
|
||||||
|
|
||||||
|
textureViewBinding.Release();
|
||||||
|
|
||||||
|
return pressed;
|
||||||
|
}
|
||||||
|
|
||||||
protected internal static override void CleanupFrame()
|
protected internal static override void CleanupFrame()
|
||||||
{
|
{
|
||||||
for(var view in _resourceViews)
|
for(var view in _resourceViews)
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
using Mono;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
|
||||||
|
public class MonoExceptionHelper : RefCounter
|
||||||
|
{
|
||||||
|
private String _fullName ~ delete _;
|
||||||
|
|
||||||
|
private String _message ~ delete _;
|
||||||
|
|
||||||
|
private String _stackTrace ~ delete _;
|
||||||
|
/// The clean stack trace only contains the Managed Stack (the full trace contains one line for the native-to-managed entry)
|
||||||
|
private StringView _cleanStackTrace;
|
||||||
|
|
||||||
|
private MonoExceptionHelper _innerException ~ _?.ReleaseRef();
|
||||||
|
|
||||||
|
public StringView FullName => _fullName;
|
||||||
|
public StringView Message => _message;
|
||||||
|
|
||||||
|
public StringView StackTrace => _stackTrace;
|
||||||
|
public StringView CleanStackTrace => _cleanStackTrace;
|
||||||
|
|
||||||
|
public MonoExceptionHelper InnerException => _innerException;
|
||||||
|
|
||||||
|
public UUID Instance { get; set; }
|
||||||
|
|
||||||
|
public this(MonoException* exception)
|
||||||
|
{
|
||||||
|
MonoObject* exObject = (MonoObject*)exception;
|
||||||
|
|
||||||
|
MonoClass* monoClass = Mono.mono_object_get_class(exObject);
|
||||||
|
|
||||||
|
StringView classNamespace = .(Mono.mono_class_get_namespace(monoClass));
|
||||||
|
StringView className = .(Mono.mono_class_get_name(monoClass));
|
||||||
|
_fullName = new $"{classNamespace}.{className}";
|
||||||
|
|
||||||
|
GetMessage(exObject, monoClass);
|
||||||
|
|
||||||
|
GetStackTrace(exception);
|
||||||
|
|
||||||
|
GetInnerException(exObject, monoClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetMessage(MonoObject* exceptionObject, MonoClass* monoClass)
|
||||||
|
{
|
||||||
|
var messageProperty = Mono.mono_class_get_property_from_name(monoClass, "Message");
|
||||||
|
|
||||||
|
MonoObject* message = Mono.mono_property_get_value(messageProperty, exceptionObject, null, null);
|
||||||
|
char8* exMessage = Mono.mono_string_to_utf8((.)message);
|
||||||
|
|
||||||
|
_message = new String(exMessage);
|
||||||
|
|
||||||
|
Mono.mono_free(exMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetStackTrace(MonoException* exception)
|
||||||
|
{
|
||||||
|
char8* stacktracePtr = Mono.mono_exception_get_managed_backtrace(exception);
|
||||||
|
_stackTrace = new String(stacktracePtr);
|
||||||
|
|
||||||
|
int entryIndex = _stackTrace.IndexOf("at (wrapper native-to-managed)");
|
||||||
|
|
||||||
|
if (entryIndex != -1)
|
||||||
|
_cleanStackTrace = _stackTrace.Substring(0, entryIndex);
|
||||||
|
else
|
||||||
|
_cleanStackTrace = _stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetInnerException(MonoObject* exceptionObject, MonoClass* monoClass)
|
||||||
|
{
|
||||||
|
MonoProperty* innerExceptionProperty = Mono.mono_class_get_property_from_name(monoClass, "InnerException");
|
||||||
|
|
||||||
|
MonoObject* innerException = Mono.mono_property_get_value(innerExceptionProperty, exceptionObject, null, null);
|
||||||
|
|
||||||
|
if (innerException != null)
|
||||||
|
_innerException = new MonoExceptionHelper((MonoException*)innerException);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -227,59 +227,40 @@ class ScriptClass : SharpClass
|
|||||||
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
|
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnCreate(MonoObject* instance)
|
public void OnCreate(MonoObject* instance, out MonoException* exception)
|
||||||
{
|
{
|
||||||
MonoException* exception = null;
|
exception = null;
|
||||||
|
|
||||||
if (_onCreate != null)
|
if (_onCreate != null)
|
||||||
_onCreate(instance, &exception);
|
_onCreate(instance, &exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnUpdate(MonoObject* instance, float deltaTime)
|
public void OnUpdate(MonoObject* instance, float deltaTime, out MonoException* exception)
|
||||||
{
|
{
|
||||||
MonoException* exception = null;
|
exception = null;
|
||||||
|
|
||||||
if (_onUpdate != null)
|
if (_onUpdate != null)
|
||||||
_onUpdate(instance, deltaTime, &exception);
|
_onUpdate(instance, deltaTime, &exception);
|
||||||
|
|
||||||
if (exception != null)
|
|
||||||
{
|
|
||||||
char8* str = Mono.mono_string_to_utf8(exception.Message);
|
|
||||||
|
|
||||||
Log.EngineLogger.Error($"Exception in \"{_fullName}.OnUpdate\". Message:\"{StringView(str)}\"");
|
|
||||||
|
|
||||||
Mono.mono_free(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnDestroy(MonoObject* instance)
|
public void OnDestroy(MonoObject* instance, out MonoException* exception)
|
||||||
{
|
{
|
||||||
MonoException* exception;
|
exception = null;
|
||||||
|
|
||||||
if (_onDestroy != null)
|
if (_onDestroy != null)
|
||||||
_onDestroy(instance, &exception);
|
_onDestroy(instance, &exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonoObject* CreateInstance(UUID uuid)
|
public MonoObject* CreateInstance(UUID uuid, out MonoException* exception)
|
||||||
{
|
{
|
||||||
MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
|
MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
|
||||||
|
|
||||||
// TODO: I think this is a bit dirty
|
|
||||||
// Invoke empty constructor to fill fields
|
// Invoke empty constructor to fill fields
|
||||||
Mono.mono_runtime_object_init(instance);
|
Mono.mono_runtime_object_init(instance);
|
||||||
|
|
||||||
// Invoke constructor with UUID
|
// Invoke constructor with UUID
|
||||||
#unwarn
|
#unwarn
|
||||||
ScriptEngine.[Friend]s_EngineObject.Invoke(ScriptEngine.[Friend]s_EngineObject._constructor, instance, &uuid);
|
ScriptEngine.[Friend]s_EngineObject.Invoke(ScriptEngine.[Friend]s_EngineObject._constructor, instance, out exception, &uuid);
|
||||||
|
|
||||||
//MonoException* exception = null;
|
|
||||||
//#unwarn
|
|
||||||
//ScriptEngine.[Friend]s_EntityRoot._constructor(instance, uuid, &exception);
|
|
||||||
//ScriptEngine.[Friend]s_EntityRoot.Invoke(_constructor, instance, &uuid);
|
|
||||||
|
|
||||||
/*MonoObject* exception = null;
|
|
||||||
#unwarn*/
|
|
||||||
//Mono.mono_runtime_invoke(_constructor, instance, (.)&uuid, &exception);
|
|
||||||
//Mono.mono_runtime_object_init(instance);
|
|
||||||
//MonoException* exception;
|
|
||||||
//_constructor(instance, uuid, &exception);
|
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@@ -312,12 +293,22 @@ class ScriptClass : SharpClass
|
|||||||
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, void** args = null)
|
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, void** args = null)
|
||||||
{
|
{
|
||||||
MonoObject* exception = null;
|
MonoObject* exception = null;
|
||||||
return Mono.mono_runtime_invoke(method, instance, args, &exception);
|
|
||||||
|
MonoObject* result = Mono.mono_runtime_invoke(method, instance, args, &exception);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException((MonoException*)exception);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, params void*[] args)
|
public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, out MonoException* exception, params void*[] args)
|
||||||
{
|
{
|
||||||
return Mono.mono_runtime_invoke(method, instance, args.Ptr, null);
|
exception = null;
|
||||||
|
|
||||||
|
MonoObject* result = Mono.mono_runtime_invoke(method, instance, args.Ptr, (.)&exception);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Invoke<T>(MonoMethod* method, MonoObject* instance, params void*[] args)
|
public T Invoke<T>(MonoMethod* method, MonoObject* instance, params void*[] args)
|
||||||
@@ -329,25 +320,17 @@ class ScriptClass : SharpClass
|
|||||||
public T GetFieldValue<T>(MonoObject* instance, MonoClassField* field)
|
public T GetFieldValue<T>(MonoObject* instance, MonoClassField* field)
|
||||||
{
|
{
|
||||||
T value = default;
|
T value = default;
|
||||||
Mono.Mono.mono_field_get_value(instance, field, &value);
|
Mono.mono_field_get_value(instance, field, &value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value)
|
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value)
|
||||||
{
|
{
|
||||||
/*if (typeof(T) == typeof(MonoObject*))
|
Mono.mono_field_set_value(instance, field, &value);
|
||||||
{
|
|
||||||
// TODO: MonoObject* is a pointer already, so we don't take the pointer
|
|
||||||
Mono.Mono.mono_field_set_value(instance, field, (void*)value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{*/
|
|
||||||
Mono.Mono.mono_field_set_value(instance, field, &value);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value) where T : struct*
|
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value) where T : struct*
|
||||||
{
|
{
|
||||||
Mono.Mono.mono_field_set_value(instance, field, value);
|
Mono.mono_field_set_value(instance, field, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,12 +209,14 @@ static class ScriptEngine
|
|||||||
if (scriptClass == null)
|
if (scriptClass == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
script.Instance = new ScriptInstance(scriptClass);
|
UUID entityId = entity.UUID;
|
||||||
|
|
||||||
|
script.Instance = new ScriptInstance(entityId, scriptClass);
|
||||||
script.Instance..ReleaseRef();
|
script.Instance..ReleaseRef();
|
||||||
|
|
||||||
_entityScriptInstances[entity.UUID] = script.Instance..AddRef();
|
_entityScriptInstances[entityId] = script.Instance..AddRef();
|
||||||
|
|
||||||
script.Instance.Instantiate(entity.UUID);
|
script.Instance.Instantiate(entityId);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -544,4 +546,27 @@ static class ScriptEngine
|
|||||||
|
|
||||||
return scriptClass;
|
return scriptClass;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
internal static void HandleMonoException(MonoException* exception, ScriptInstance sourceInstance = null)
|
||||||
|
{
|
||||||
|
MonoExceptionHelper wrappedException = new MonoExceptionHelper(exception);
|
||||||
|
|
||||||
|
String entityInfo = scope .();
|
||||||
|
|
||||||
|
if (sourceInstance != null)
|
||||||
|
{
|
||||||
|
wrappedException.Instance = sourceInstance.EntityId;
|
||||||
|
|
||||||
|
Result<Entity> sourceEntity = Context.GetEntityByID(sourceInstance.EntityId);
|
||||||
|
|
||||||
|
if (sourceEntity case .Ok(let e))
|
||||||
|
{
|
||||||
|
entityInfo.AppendF($" ({e.Name} | {sourceInstance.EntityId})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ClientLogger.Error($"Mono Exception \"{wrappedException.FullName}\": \"{wrappedException.Message}\"{entityInfo}\nStackTrace:\n{wrappedException.StackTrace}", wrappedException);
|
||||||
|
|
||||||
|
wrappedException.ReleaseRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using System;
|
|||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Scripting;
|
||||||
|
|
||||||
class ScriptInstance : RefCounter
|
class ScriptInstance : RefCounter
|
||||||
{
|
{
|
||||||
private ScriptClass _scriptClass;
|
private ScriptClass _scriptClass;
|
||||||
@@ -11,6 +13,8 @@ class ScriptInstance : RefCounter
|
|||||||
private MonoObject* _instance;
|
private MonoObject* _instance;
|
||||||
private uint32 _gcHandle;
|
private uint32 _gcHandle;
|
||||||
|
|
||||||
|
private UUID _entityId;
|
||||||
|
|
||||||
public ScriptClass ScriptClass => _scriptClass;
|
public ScriptClass ScriptClass => _scriptClass;
|
||||||
|
|
||||||
/// Gets whether or not the instance has ben initialized.
|
/// Gets whether or not the instance has ben initialized.
|
||||||
@@ -23,9 +27,13 @@ class ScriptInstance : RefCounter
|
|||||||
|
|
||||||
internal MonoObject* MonoInstance => _instance;
|
internal MonoObject* MonoInstance => _instance;
|
||||||
|
|
||||||
public this(ScriptClass scriptClass)
|
public UUID EntityId => _entityId;
|
||||||
|
|
||||||
|
public this(UUID entityId, ScriptClass scriptClass)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(scriptClass != null);
|
Log.EngineLogger.AssertDebug(scriptClass != null);
|
||||||
|
|
||||||
|
_entityId = entityId;
|
||||||
_scriptClass = scriptClass..AddRef();
|
_scriptClass = scriptClass..AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +41,7 @@ class ScriptInstance : RefCounter
|
|||||||
{
|
{
|
||||||
if (_instance != null)
|
if (_instance != null)
|
||||||
{
|
{
|
||||||
_scriptClass.OnDestroy(_instance);
|
InvokeOnDestroy();
|
||||||
Mono.mono_gchandle_free(_gcHandle);
|
Mono.mono_gchandle_free(_gcHandle);
|
||||||
}
|
}
|
||||||
_scriptClass?.ReleaseRef();
|
_scriptClass?.ReleaseRef();
|
||||||
@@ -41,24 +49,36 @@ class ScriptInstance : RefCounter
|
|||||||
|
|
||||||
public void Instantiate(UUID uuid)
|
public void Instantiate(UUID uuid)
|
||||||
{
|
{
|
||||||
_instance = _scriptClass.CreateInstance(uuid);
|
_instance = _scriptClass.CreateInstance(uuid, let exception);
|
||||||
_gcHandle = Mono.mono_gchandle_new(_instance, true);
|
_gcHandle = Mono.mono_gchandle_new(_instance, true);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeOnCreate()
|
public void InvokeOnCreate()
|
||||||
{
|
{
|
||||||
_scriptClass.OnCreate(_instance);
|
_scriptClass.OnCreate(_instance, let exception);
|
||||||
_isCreated = true;
|
_isCreated = true;
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeOnUpdate(float deltaTime)
|
public void InvokeOnUpdate(float deltaTime)
|
||||||
{
|
{
|
||||||
_scriptClass.OnUpdate(_instance, deltaTime);
|
_scriptClass.OnUpdate(_instance, deltaTime, let exception);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeOnDestroy()
|
public void InvokeOnDestroy()
|
||||||
{
|
{
|
||||||
_scriptClass.OnDestroy(_instance);
|
_scriptClass.OnDestroy(_instance, let exception);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetFieldValue<T>(ScriptField field)
|
public T GetFieldValue<T>(ScriptField field)
|
||||||
@@ -83,6 +103,9 @@ class ScriptInstance : RefCounter
|
|||||||
|
|
||||||
Mono.mono_property_set_value(entityProperty, componentInstance, (void**)&_instance, &exception);
|
Mono.mono_property_set_value(entityProperty, componentInstance, (void**)&_instance, &exception);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException((MonoException*)exception, this);
|
||||||
|
|
||||||
return componentInstance;
|
return componentInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,12 +232,25 @@ static class Mono
|
|||||||
|
|
||||||
[LinkName(.C)]
|
[LinkName(.C)]
|
||||||
public static extern MonoThread* mono_thread_current();
|
public static extern MonoThread* mono_thread_current();
|
||||||
|
|
||||||
|
#region Property
|
||||||
|
|
||||||
[LinkName(.C)]
|
[LinkName(.C)]
|
||||||
public static extern MonoProperty* mono_class_get_property_from_name(MonoClass *klass, char8* name);
|
public static extern MonoProperty* mono_class_get_property_from_name(MonoClass *klass, char8* name);
|
||||||
|
|
||||||
[LinkName(.C)]
|
[LinkName(.C)]
|
||||||
public static extern void mono_property_set_value(MonoProperty *prop, void *obj, void **@params, MonoObject **exc);
|
public static extern void mono_property_set_value(MonoProperty *prop, void *obj, void **@params, MonoObject **exc);
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
public static extern MonoObject* mono_property_get_value(MonoProperty *prop, void *obj, void** @params, MonoObject** exc);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
public static extern char8* mono_exception_get_managed_backtrace(MonoException* exc);
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
public static extern MonoClass* mono_object_get_class(MonoObject* obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MonoDomain;
|
struct MonoDomain;
|
||||||
|
|||||||
Reference in New Issue
Block a user