diff --git a/GlitchyEditor/src/EditWindows/LogWindow.bf b/GlitchyEditor/src/EditWindows/LogWindow.bf index 31afbd0..c94e91e 100644 --- a/GlitchyEditor/src/EditWindows/LogWindow.bf +++ b/GlitchyEditor/src/EditWindows/LogWindow.bf @@ -259,7 +259,8 @@ class LogWindow : EditorWindow ImGui.TableNextColumn(); - if (ImGui.BeginChild("Message", .Zero, .None, .None)) + ImGui.BeginGroup(); + { // Timestamp ImGui.TextWrapped($"[{message.Timestamp:HH:mm:ss.fff}]"); @@ -310,7 +311,7 @@ class LogWindow : EditorWindow } } - ImGui.EndChild(); + ImGui.EndGroup(); if (ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(.Left)) { diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index 040bb5a..c7efea0 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -513,7 +513,7 @@ static class ScriptEngine } } - Log.ClientLogger.Error($"Mono Exception \"{exception.FullName}\": \"{exception.Message}\"{entityInfo}\nStackTrace:\n{exception.StackTrace}", exception); + Log.ClientLogger.Error($"Exception \"{exception.FullName}\": \"{exception.Message}\"{entityInfo}\nStackTrace:\n{exception.StackTrace}", exception); } // TODO: Wrap like the other classes diff --git a/GlitchyEngine/src/Scripting/MonoExceptionHelper.bf b/GlitchyEngine/src/Scripting/ScriptException.bf similarity index 89% rename from GlitchyEngine/src/Scripting/MonoExceptionHelper.bf rename to GlitchyEngine/src/Scripting/ScriptException.bf index 125ef8a..ce0b45d 100644 --- a/GlitchyEngine/src/Scripting/MonoExceptionHelper.bf +++ b/GlitchyEngine/src/Scripting/ScriptException.bf @@ -31,8 +31,8 @@ public class ScriptException public this(UUID entityId, StringView fullExceptionClassName, StringView message, StringView stackTrace) { String allocFullExceptionClassName = append String(fullExceptionClassName); - String allocMessage = append String(fullExceptionClassName); - String allocStackTrace = append String(fullExceptionClassName); + String allocMessage = append String(message); + String allocStackTrace = append String(stackTrace); _fullName = allocFullExceptionClassName; _message = allocMessage; diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index 31ee296..40945e8 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -224,6 +224,8 @@ static class ScriptGlue private function void SetEngineFunctions(EngineFunctions* engineFunctions); private static SetEngineFunctions _setEngineFunctions; + private static String _lastExceptionMessage = new .() ~ delete _; + public static void Init() { if (_setEngineFunctions == null) @@ -389,16 +391,29 @@ static class ScriptGlue public enum EngineResult : int32 { - Ok = 0, // Success, for boolean return value means True - False = 1, // Success, for boolean return value means False - Error = -1, - NotImplemented = -2, - ArgumentError = -3, + case Ok = 0; // Success, for boolean return value means True + case False = 1; // Success, for boolean return value means False + case Error = -1; + case NotImplemented = -2; + case ArgumentError = -3; // Entity Errors: - EntityNotFound = -4, // The entity doesn't exist or was deleted. - EntityDoesntHaveComponent = -5, // The entity has no component of type {typeof(T)} or it was deleted. - AssetNotFound = -6, // No asset exists for AssetHandle \"{assetId}\". + case EntityNotFound = -4; // The entity doesn't exist or was deleted. + case EntityDoesntHaveComponent = -5; // The entity has no component of type {typeof(T)} or it was deleted. + case AssetNotFound = -6; // No asset exists for AssetHandle \"{assetId}\". + + case CustomError = 1 << 31; + + public static EngineResult CustomError(int32 payload) + { + return CustomError | payload; + } + } + + [RegisterCall] + static char8* GetLastExceptionMessage() + { + return _lastExceptionMessage.Length == 0 ? null : _lastExceptionMessage.CStr(); } #region Log @@ -1492,6 +1507,11 @@ static class ScriptGlue asset }*/ + static void SetExceptionMessage(StringView message) + { + _lastExceptionMessage.Set(message); + } + static mixin GetAssetOrReturn(UUID assetId) where T : Asset { AssetHandle handle = .(assetId); @@ -1499,6 +1519,7 @@ static class ScriptGlue if (asset == null) { + SetExceptionMessage(scope $"Asset (Id: {assetId}) not found."); return EngineResult.AssetNotFound; } @@ -1511,6 +1532,7 @@ static class ScriptGlue if (asset == null) { + SetExceptionMessage(scope $"Asset (Handle: {assetHandle}) not found."); return EngineResult.AssetNotFound; } @@ -1552,7 +1574,26 @@ static class ScriptGlue { Material material = GetAssetOrReturn!(assetHandle); - material.[Friend]SetVariableRaw(StringView(variableName), elementType, rows, columns , arrayLength, Span((uint8*)rawData, dataLength)); + StringView variableNameView = StringView(variableName); + + if (material.[Friend]SetVariableRaw(variableNameView, elementType, rows, columns , arrayLength, Span((uint8*)rawData, dataLength)) case .Err(let error)) + { + switch (error) + { + case .VariableNotFound: + SetExceptionMessage(scope $"Material \"{material.Identifier}\" has no variable \"{variableNameView}\"."); + return .ArgumentError; + case .ElementTypeMismatch: + SetExceptionMessage(scope $"Variable \"{variableNameView}\" has incompatible element type."); + return .ArgumentError; + case .MatrixDimensionMismatch: + SetExceptionMessage(scope $"Variable \"{variableNameView}\" has incompatible matrix dimension type."); + return .ArgumentError; + case .ProvidedBufferTooShort: + SetExceptionMessage(scope $"The provided data buffer for variable \"{variableNameView}\" is not large enough."); + } + return .Error; + } return .Ok; } diff --git a/ScriptCore/Core/EngineResult.cs b/ScriptCore/Core/EngineResult.cs index c090c1c..51e36eb 100644 --- a/ScriptCore/Core/EngineResult.cs +++ b/ScriptCore/Core/EngineResult.cs @@ -17,24 +17,16 @@ internal enum EngineResult EntityNotFound = -4, // The entity doesn't exist or was deleted. EntityDoesntHaveComponent = -5, // The entity has no component of type {typeof(T)} or it was deleted. AssetNotFound = -6, // No asset exists for AssetHandle \"{assetId}\". + CustomError = 1 << 31 } public class EngineException(string message) : Exception(message); -public class EntityNotFoundException : Exception -{ - -} +public class EntityNotFoundException(string? message = null) : Exception(message); -public class ComponentNotFoundException : Exception -{ - -} +public class ComponentNotFoundException(string? message = null) : Exception(message); -public class AssetNotFoundException : Exception -{ - -} +public class AssetNotFoundException(string? message = null) : Exception(message); internal static class EngineErrors { @@ -43,22 +35,24 @@ internal static class EngineErrors if (result >= 0) return; + string engineMessage = ScriptGlue.GetLastExceptionMessage(); + switch (result) { case EngineResult.Error: - throw new EngineException($"Unspecified engine excepiton in {callerName}"); + throw new EngineException(engineMessage ?? $"Unspecified engine excepiton in {callerName}"); case EngineResult.NotImplemented: - throw new NotImplementedException($"Function {callerName} is not implemented in the engine."); + throw new NotImplementedException(engineMessage ?? $"Function {callerName} is not implemented in the engine."); case EngineResult.ArgumentError: - throw new ArgumentException($"An argument passed to {callerName} is invalid."); + throw new ArgumentException(engineMessage ?? $"An argument passed to {callerName} is invalid."); case EngineResult.EntityNotFound: - throw new EntityNotFoundException(); + throw new EntityNotFoundException(engineMessage); case EngineResult.EntityDoesntHaveComponent: - throw new ComponentNotFoundException(); + throw new ComponentNotFoundException(engineMessage); case EngineResult.AssetNotFound: - throw new AssetNotFoundException(); + throw new AssetNotFoundException(engineMessage); default: - throw new EngineException($"Unknown engine excepiton in {callerName}"); + throw new EngineException(engineMessage ?? $"Unknown engine excepiton in {callerName}"); } } } diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs index cc36cae..5dc0053 100644 --- a/ScriptCore/ScriptGlue.cs +++ b/ScriptCore/ScriptGlue.cs @@ -319,7 +319,7 @@ internal static unsafe partial class ScriptGlue struct ComponentFunctionPointers { public delegate* unmanaged[Cdecl] AddComponent; - public delegate* unmanaged[Cdecl] HasComponent; + public delegate* unmanaged[Cdecl] HasComponent; public delegate* unmanaged[Cdecl] RemoveComponent; } @@ -328,7 +328,7 @@ internal static unsafe partial class ScriptGlue [UnmanagedCallersOnly] public static void RegisterComponentType(byte* fullComponentTypeName, delegate* unmanaged[Cdecl] addComponent, - delegate* unmanaged[Cdecl] hasComponent, + delegate* unmanaged[Cdecl] hasComponent, delegate* unmanaged[Cdecl] removeComponent) { string? beefComponentTypeName = Marshal.PtrToStringUTF8((IntPtr)fullComponentTypeName); @@ -421,7 +421,9 @@ internal static unsafe partial class ScriptGlue public static bool Entity_HasComponent(UUID entityId, Type componentType) { - return ComponentTypeFunctions[componentType].HasComponent(entityId); + EngineResult returnValue = ComponentTypeFunctions[componentType].HasComponent(entityId); + EngineErrors.ThrowIfError(returnValue); + return returnValue == EngineResult.Ok; } public static void Entity_RemoveComponent(UUID entityId, Type componentType)