From b686b3bcd64494a869aba5cbe84bacd086a8cc56 Mon Sep 17 00:00:00 2001
From: Jhett Black <10942655+jhett12321@users.noreply.github.com>
Date: Thu, 23 Nov 2023 23:54:38 +0100
Subject: [PATCH 1/5] Update NWN.Core to 8193.35.21.
---
NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj | 2 +-
NWN.Anvil.Tests/NWN.Anvil.Tests.csproj | 2 +-
NWN.Anvil/NWN.Anvil.csproj | 2 +-
docs/NWN.Anvil.Samples.csproj | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj b/NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj
index 757ac1581..91d75bf9b 100644
--- a/NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj
+++ b/NWN.Anvil.TestRunner/NWN.Anvil.TestRunner.csproj
@@ -69,7 +69,7 @@
-
+
diff --git a/NWN.Anvil.Tests/NWN.Anvil.Tests.csproj b/NWN.Anvil.Tests/NWN.Anvil.Tests.csproj
index cab1c50be..8605ef181 100644
--- a/NWN.Anvil.Tests/NWN.Anvil.Tests.csproj
+++ b/NWN.Anvil.Tests/NWN.Anvil.Tests.csproj
@@ -42,7 +42,7 @@
-
+
diff --git a/NWN.Anvil/NWN.Anvil.csproj b/NWN.Anvil/NWN.Anvil.csproj
index 45c10d4ef..7d3873ae7 100644
--- a/NWN.Anvil/NWN.Anvil.csproj
+++ b/NWN.Anvil/NWN.Anvil.csproj
@@ -65,7 +65,7 @@
-
+
diff --git a/docs/NWN.Anvil.Samples.csproj b/docs/NWN.Anvil.Samples.csproj
index 50f1d0292..f7c68d25a 100644
--- a/docs/NWN.Anvil.Samples.csproj
+++ b/docs/NWN.Anvil.Samples.csproj
@@ -30,7 +30,7 @@
-
+
From 054348c5e4560e87db7d9875e0855b3748e1aca5 Mon Sep 17 00:00:00 2001
From: Jhett Black <10942655+jhett12321@users.noreply.github.com>
Date: Thu, 23 Nov 2023 23:55:18 +0100
Subject: [PATCH 2/5] Consolidate VirtualMachineFunctionHandler into AnvilCore.
Implement unmanaged handlers.
---
.../src/main/AnvilCore.FunctionHandlers.cs | 164 ++++++++++++++++++
NWN.Anvil/src/main/AnvilCore.cs | 75 ++------
.../Core/VirtualMachineFunctionHandler.cs | 107 ------------
.../Services/Services/AnvilServiceManager.cs | 1 -
4 files changed, 174 insertions(+), 173 deletions(-)
create mode 100644 NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
delete mode 100644 NWN.Anvil/src/main/Services/Core/VirtualMachineFunctionHandler.cs
diff --git a/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs b/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
new file mode 100644
index 000000000..a1b6f62b4
--- /dev/null
+++ b/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Anvil.API;
+using Anvil.Internal;
+using Anvil.Services;
+using NWN.Core;
+using NWN.Native.API;
+using Action = System.Action;
+
+namespace Anvil
+{
+ public sealed partial class AnvilCore : ICoreFunctionHandler
+ {
+ [Inject]
+ private static ScriptDispatchService? ScriptDispatchService { get; set; }
+
+ [Inject]
+ private static ServerUpdateLoopService? ServerUpdateLoopService { get; set; }
+
+ private static readonly Dictionary Closures = new Dictionary();
+ private static readonly Stack ScriptContexts = new Stack();
+
+ private static ulong nextEventId;
+ private static uint objectSelf;
+
+ uint ICoreFunctionHandler.ObjectSelf => objectSelf;
+
+ void ICoreFunctionHandler.ClosureActionDoCommand(uint obj, Action func)
+ {
+ if (VM.ClosureActionDoCommand(obj, nextEventId) != 0)
+ {
+ Closures.Add(nextEventId++, func);
+ }
+ }
+
+ void ICoreFunctionHandler.ClosureAssignCommand(uint obj, Action func)
+ {
+ if (VM.ClosureAssignCommand(obj, nextEventId) != 0)
+ {
+ Closures.Add(nextEventId++, func);
+ }
+ }
+
+ void ICoreFunctionHandler.ClosureDelayCommand(uint obj, float duration, Action func)
+ {
+ if (VM.ClosureDelayCommand(obj, duration, nextEventId) != 0)
+ {
+ Closures.Add(nextEventId++, func);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ private static void OnNWNXSignal(IntPtr signalPtr)
+ {
+ string signal = signalPtr.ReadNullTerminatedString();
+
+ switch (signal)
+ {
+ case "ON_NWNX_LOADED":
+ instance.Init();
+ break;
+ case "ON_MODULE_LOAD_FINISH":
+ instance.LoadAndStart();
+ break;
+ case "ON_DESTROY_SERVER":
+ Log.Info("Server is shutting down...");
+ instance.Unload();
+ break;
+ case "ON_DESTROY_SERVER_AFTER":
+ instance.Shutdown();
+ break;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ private static int OnRunScript(IntPtr scriptPtr, uint oidSelf)
+ {
+ string script = scriptPtr.ReadNullTerminatedString();
+ int retVal = 0;
+ objectSelf = oidSelf;
+ ScriptContexts.Push(oidSelf);
+
+ try
+ {
+ if (ScriptDispatchService != null)
+ {
+ retVal = (int)ScriptDispatchService.TryExecuteScript(script, oidSelf);
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "An exception occured while executing script {Script}", script);
+ }
+
+ ScriptContexts.Pop();
+ objectSelf = ScriptContexts.Count == 0 ? NWScript.OBJECT_INVALID : ScriptContexts.Peek();
+ return retVal;
+ }
+
+ [UnmanagedCallersOnly]
+ private static void OnClosure(ulong eid, uint oidSelf)
+ {
+ uint old = objectSelf;
+ objectSelf = oidSelf;
+
+ try
+ {
+ Closures[eid].Invoke();
+ }
+ catch (Exception e)
+ {
+ Log.Error(e);
+ }
+
+ Closures.Remove(eid);
+ objectSelf = old;
+ }
+
+ [UnmanagedCallersOnly]
+ private static void OnLoop(ulong _)
+ {
+ ServerUpdateLoopService?.Update();
+ }
+
+ [UnmanagedCallersOnly]
+ private static void OnAssertFail(IntPtr messagePtr, IntPtr nativeStackTracePtr)
+ {
+ string message = messagePtr.ReadNullTerminatedString();
+ string nativeStackTrace = nativeStackTracePtr.ReadNullTerminatedString();
+
+ StackTrace stackTrace = new StackTrace(true);
+ Log.Error("An assertion failure occurred in native code.\n" +
+ $"{message}{nativeStackTrace}\n" +
+ $"{stackTrace}");
+ }
+
+ [UnmanagedCallersOnly]
+ private static void OnServerCrash(int signal, IntPtr nativeStackTracePtr)
+ {
+ string stackTrace = nativeStackTracePtr.ReadNullTerminatedString();
+ Version serverVersion = NwServer.Instance.ServerVersion;
+
+ string error = signal switch
+ {
+ 4 => "Illegal instruction",
+ 6 => "Program aborted",
+ 8 => "Floating point exception",
+ 11 => "Segmentation fault",
+ _ => "Unknown error",
+ };
+
+ Log.Fatal("\n==============================================================\n" +
+ " Please file a bug at https://github.com/nwn-dotnet/Anvil/issues\n" +
+ $" {Assemblies.Anvil.GetName().Name} {AssemblyInfo.VersionInfo.InformationalVersion} has crashed. Fatal error: {error} ({signal})\n" +
+ $" Using: NWN {serverVersion}, NWN.Core {Assemblies.Core.GetName().Version}, NWN.Native {Assemblies.Native.GetName().Version}\n" +
+ "==============================================================\n" +
+ " Managed Backtrace:\n" +
+ $"{new StackTrace(true)}" +
+ $"{stackTrace}");
+ }
+ }
+}
diff --git a/NWN.Anvil/src/main/AnvilCore.cs b/NWN.Anvil/src/main/AnvilCore.cs
index 61ed33fd0..d41968308 100644
--- a/NWN.Anvil/src/main/AnvilCore.cs
+++ b/NWN.Anvil/src/main/AnvilCore.cs
@@ -1,5 +1,4 @@
using System;
-using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -17,15 +16,12 @@ namespace Anvil
/// Handles bootstrap and interop between %NWN, %NWN.Core and the %Anvil %API. The entry point of the implementing module should point to this class.
/// Until is called, all APIs are unavailable for usage.
///
- public sealed class AnvilCore
+ public sealed partial class AnvilCore
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static AnvilCore instance = null!;
- [Inject]
- private VirtualMachineFunctionHandler VirtualMachineFunctionHandler { get; init; } = null!;
-
private readonly IServiceManager serviceManager;
private AnvilCore(IServiceManager serviceManager)
@@ -53,22 +49,22 @@ private AnvilCore(IServiceManager serviceManager)
/// A custom service manager to use instead of the default . For advanced users only.
/// The init result code to return back to NWNX.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Init(IntPtr arg, int argLength, IServiceManager? serviceManager = default)
+ public static unsafe int Init(IntPtr arg, int argLength, IServiceManager? serviceManager = default)
{
serviceManager ??= new AnvilServiceManager();
instance = new AnvilCore(serviceManager);
- NWNCore.NativeEventHandles eventHandles = new NWNCore.NativeEventHandles
+ NWNCore.NativeEventHandlesUnmanaged eventHandles = new NWNCore.NativeEventHandlesUnmanaged
{
- Signal = instance.OnNWNXSignal,
- RunScript = instance.VirtualMachineFunctionHandler.OnRunScript,
- Closure = instance.VirtualMachineFunctionHandler.OnClosure,
- MainLoop = instance.VirtualMachineFunctionHandler.OnLoop,
- AssertFail = instance.OnAssertFail,
- CrashHandler = instance.OnServerCrash,
+ Signal = &OnNWNXSignal,
+ RunScript = &OnRunScript,
+ Closure = &OnClosure,
+ MainLoop = &OnLoop,
+ AssertFail = &OnAssertFail,
+ CrashHandler = &OnServerCrash,
};
- return NWNCore.Init(arg, argLength, instance.VirtualMachineFunctionHandler, eventHandles);
+ return NWNCore.Init(arg, argLength, instance, eventHandles);
}
///
@@ -137,57 +133,6 @@ private void LoadAndStart()
serviceManager.Start();
}
- private void OnNWNXSignal(string signal)
- {
- switch (signal)
- {
- case "ON_NWNX_LOADED":
- Init();
- break;
- case "ON_MODULE_LOAD_FINISH":
- LoadAndStart();
- break;
- case "ON_DESTROY_SERVER":
- Log.Info("Server is shutting down...");
- Unload();
- break;
- case "ON_DESTROY_SERVER_AFTER":
- Shutdown();
- break;
- }
- }
-
- private void OnAssertFail(string message, string nativeStackTrace)
- {
- StackTrace stackTrace = new StackTrace(true);
- Log.Error("An assertion failure occurred in native code.\n" +
- $"{message}{nativeStackTrace}\n" +
- $"{stackTrace}");
- }
-
- private void OnServerCrash(int signal, string stackTrace)
- {
- Version serverVersion = NwServer.Instance.ServerVersion;
-
- string error = signal switch
- {
- 4 => "Illegal instruction",
- 6 => "Program aborted",
- 8 => "Floating point exception",
- 11 => "Segmentation fault",
- _ => "Unknown error",
- };
-
- Log.Fatal("\n==============================================================\n" +
- " Please file a bug at https://github.com/nwn-dotnet/Anvil/issues\n" +
- $" {Assemblies.Anvil.GetName().Name} {AssemblyInfo.VersionInfo.InformationalVersion} has crashed. Fatal error: {error} ({signal})\n" +
- $" Using: NWN {serverVersion}, NWN.Core {Assemblies.Core.GetName().Version}, NWN.Native {Assemblies.Native.GetName().Version}\n" +
- "==============================================================\n" +
- " Managed Backtrace:\n" +
- $"{new StackTrace(true)}" +
- $"{stackTrace}");
- }
-
private void PrelinkNative()
{
if (!EnvironmentConfig.NativePrelinkEnabled)
diff --git a/NWN.Anvil/src/main/Services/Core/VirtualMachineFunctionHandler.cs b/NWN.Anvil/src/main/Services/Core/VirtualMachineFunctionHandler.cs
deleted file mode 100644
index 19e823aed..000000000
--- a/NWN.Anvil/src/main/Services/Core/VirtualMachineFunctionHandler.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using System;
-using System.Collections.Generic;
-using NLog;
-using NWN.Core;
-using Action = System.Action;
-
-namespace Anvil.Services
-{
- internal sealed class VirtualMachineFunctionHandler : ICoreService, ICoreFunctionHandler
- {
- private static readonly Logger Log = LogManager.GetCurrentClassLogger();
-
- [Inject]
- private static ScriptDispatchService? ScriptDispatchService { get; set; }
-
- [Inject]
- private static ServerUpdateLoopService? ServerUpdateLoopService { get; set; }
-
- private readonly Dictionary closures = new Dictionary();
- private readonly Stack scriptContexts = new Stack();
-
- private ulong nextEventId;
- private uint objectSelf;
-
- uint ICoreFunctionHandler.ObjectSelf => objectSelf;
-
- public void OnLoop(ulong _)
- {
- ServerUpdateLoopService?.Update();
- }
-
- void ICoreFunctionHandler.ClosureActionDoCommand(uint obj, Action func)
- {
- if (VM.ClosureActionDoCommand(obj, nextEventId) != 0)
- {
- closures.Add(nextEventId++, func);
- }
- }
-
- void ICoreFunctionHandler.ClosureAssignCommand(uint obj, Action func)
- {
- if (VM.ClosureAssignCommand(obj, nextEventId) != 0)
- {
- closures.Add(nextEventId++, func);
- }
- }
-
- void ICoreFunctionHandler.ClosureDelayCommand(uint obj, float duration, Action func)
- {
- if (VM.ClosureDelayCommand(obj, duration, nextEventId) != 0)
- {
- closures.Add(nextEventId++, func);
- }
- }
-
- void ICoreService.Init() {}
-
- void ICoreService.Load() {}
-
- void ICoreService.Shutdown() {}
-
- void ICoreService.Start() {}
-
- void ICoreService.Unload() {}
-
- internal void OnClosure(ulong eid, uint oidSelf)
- {
- uint old = objectSelf;
- objectSelf = oidSelf;
-
- try
- {
- closures[eid].Invoke();
- }
- catch (Exception e)
- {
- Log.Error(e);
- }
-
- closures.Remove(eid);
- objectSelf = old;
- }
-
- internal int OnRunScript(string script, uint oidSelf)
- {
- int retVal = 0;
- objectSelf = oidSelf;
- scriptContexts.Push(oidSelf);
-
- try
- {
- if (ScriptDispatchService != null)
- {
- retVal = (int)ScriptDispatchService.TryExecuteScript(script, oidSelf);
- }
- }
- catch (Exception e)
- {
- Log.Error(e, "An exception occured while executing script {Script}", script);
- }
-
- scriptContexts.Pop();
- objectSelf = scriptContexts.Count == 0 ? NWScript.OBJECT_INVALID : scriptContexts.Peek();
- return retVal;
- }
- }
-}
diff --git a/NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs b/NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs
index 346d06a18..e5634ddc5 100644
--- a/NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs
+++ b/NWN.Anvil/src/main/Services/Services/AnvilServiceManager.cs
@@ -227,7 +227,6 @@ private void InstallCoreContainer()
RegisterCoreService();
RegisterCoreService();
RegisterCoreService();
- RegisterCoreService();
RegisterCoreService();
RegisterCoreService();
RegisterCoreService();
From e54bed2d56258c5714f4b53ff0e73ac59b080f0d Mon Sep 17 00:00:00 2001
From: Jhett Black <10942655+jhett12321@users.noreply.github.com>
Date: Thu, 23 Nov 2023 23:55:43 +0100
Subject: [PATCH 3/5] Remove redundant try/catch.
---
.../ScriptDispatch/ScriptDispatchService.cs | 26 +++++--------------
1 file changed, 7 insertions(+), 19 deletions(-)
diff --git a/NWN.Anvil/src/main/Services/ScriptDispatch/ScriptDispatchService.cs b/NWN.Anvil/src/main/Services/ScriptDispatch/ScriptDispatchService.cs
index c0ec31a1a..6ef4c1b45 100644
--- a/NWN.Anvil/src/main/Services/ScriptDispatch/ScriptDispatchService.cs
+++ b/NWN.Anvil/src/main/Services/ScriptDispatch/ScriptDispatchService.cs
@@ -1,15 +1,11 @@
-using System;
using System.Collections.Generic;
using System.Linq;
-using NLog;
namespace Anvil.Services
{
[ServiceBinding(typeof(ScriptDispatchService))]
internal sealed class ScriptDispatchService
{
- private static readonly Logger Log = LogManager.GetCurrentClassLogger();
-
private readonly List dispatchers;
public ScriptDispatchService(IReadOnlyList dispatchers)
@@ -20,25 +16,17 @@ public ScriptDispatchService(IReadOnlyList dispatchers)
public ScriptHandleResult TryExecuteScript(string script, uint objectSelf)
{
- try
+ ScriptHandleResult result = ScriptHandleResult.NotHandled;
+ foreach (IScriptDispatcher dispatcher in dispatchers)
{
- ScriptHandleResult result = ScriptHandleResult.NotHandled;
- foreach (IScriptDispatcher dispatcher in dispatchers)
+ result = dispatcher.ExecuteScript(script, objectSelf);
+ if (result != ScriptHandleResult.NotHandled)
{
- result = dispatcher.ExecuteScript(script, objectSelf);
- if (result != ScriptHandleResult.NotHandled)
- {
- break;
- }
+ break;
}
-
- return result;
- }
- catch (Exception e)
- {
- Log.Error(e);
- return (int)ScriptHandleResult.Handled;
}
+
+ return result;
}
}
}
From 0a85fd78dfb1d663ea68d98c0fe64bbb4f580b5c Mon Sep 17 00:00:00 2001
From: Jhett Black <10942655+jhett12321@users.noreply.github.com>
Date: Thu, 23 Nov 2023 23:56:07 +0100
Subject: [PATCH 4/5] ServerUpdateLoop: Rename updateables -> updateItems.
---
.../Services/GameLoop/ServerUpdateLoopService.cs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/NWN.Anvil/src/main/Services/GameLoop/ServerUpdateLoopService.cs b/NWN.Anvil/src/main/Services/GameLoop/ServerUpdateLoopService.cs
index ee497799c..6904a8d76 100644
--- a/NWN.Anvil/src/main/Services/GameLoop/ServerUpdateLoopService.cs
+++ b/NWN.Anvil/src/main/Services/GameLoop/ServerUpdateLoopService.cs
@@ -11,25 +11,25 @@ internal sealed class ServerUpdateLoopService : IDisposable
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
- private IUpdateable[] updateables;
+ private IUpdateable[] updateItems;
- public ServerUpdateLoopService(IEnumerable updateables)
+ public ServerUpdateLoopService(IEnumerable updateItems)
{
- this.updateables = updateables.OrderBy(updateable => updateable.GetType().GetServicePriority()).ToArray();
+ this.updateItems = updateItems.OrderBy(updateable => updateable.GetType().GetServicePriority()).ToArray();
}
public void Dispose()
{
- updateables = Array.Empty();
+ updateItems = Array.Empty();
}
internal void Update()
{
- for (int i = 0; i < updateables.Length; i++)
+ for (int i = 0; i < updateItems.Length; i++)
{
try
{
- updateables[i].Update();
+ updateItems[i].Update();
}
catch (Exception e)
{
From 827ced9ef653be30aca241f65610bb4a20b67368 Mon Sep 17 00:00:00 2001
From: Jhett Black <10942655+jhett12321@users.noreply.github.com>
Date: Thu, 23 Nov 2023 23:56:37 +0100
Subject: [PATCH 5/5] Optimize OnRunScript calls.
---
NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs b/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
index a1b6f62b4..3acded81a 100644
--- a/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
+++ b/NWN.Anvil/src/main/AnvilCore.FunctionHandlers.cs
@@ -77,20 +77,18 @@ private static void OnNWNXSignal(IntPtr signalPtr)
[UnmanagedCallersOnly]
private static int OnRunScript(IntPtr scriptPtr, uint oidSelf)
{
+ int retVal;
string script = scriptPtr.ReadNullTerminatedString();
- int retVal = 0;
objectSelf = oidSelf;
ScriptContexts.Push(oidSelf);
try
{
- if (ScriptDispatchService != null)
- {
- retVal = (int)ScriptDispatchService.TryExecuteScript(script, oidSelf);
- }
+ retVal = (int)(ScriptDispatchService?.TryExecuteScript(script, oidSelf) ?? ScriptHandleResult.Handled);
}
catch (Exception e)
{
+ retVal = 0;
Log.Error(e, "An exception occured while executing script {Script}", script);
}