forked from nwn-dotnet/Anvil
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnvilCore.cs
More file actions
165 lines (144 loc) · 5.09 KB
/
AnvilCore.cs
File metadata and controls
165 lines (144 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Anvil.API;
using Anvil.Internal;
using Anvil.Services;
using LightInject;
using NLog;
using NWN.Core;
using NWN.Native.API;
using NWNX.NET;
namespace Anvil
{
/// <summary>
/// Handles bootstrap and interop between %NWN, %NWN.Core and the %Anvil %API. The entry point of the implementing module should point to this class.<br/>
/// Until <see cref="Bootstrap"/> is called, all APIs are unavailable for usage.
/// </summary>
public sealed partial class AnvilCore
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static AnvilCore instance = null!;
private readonly IServiceManager serviceManager;
private AnvilCore(IServiceManager serviceManager)
{
Log.Info("Using {ServiceManager} to manage Anvil services", serviceManager.GetType().FullName);
this.serviceManager = serviceManager;
this.serviceManager.CoreServiceContainer.InjectProperties(this);
}
/// <summary>
/// Gets the specified anvil service instance.
/// </summary>
/// <typeparam name="T">The service type to get.</typeparam>
/// <returns>The associated anvil service instance.</returns>
public static T? GetService<T>()
{
return instance.serviceManager.AnvilServiceContainer.GetInstance<T>();
}
/// <summary>
/// Entrypoint to start Anvil. This should be specified in the "NWNX_DOTNET_METHOD" environment variable to be triggered by NWNX.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void Bootstrap()
{
AnvilServiceManager serviceManager = new AnvilServiceManager();
instance = new AnvilCore(serviceManager);
NWNCore.Init(instance);
NWNXAPI.RegisterSignalHandler(&OnNWNXSignal);
NWNXAPI.RegisterRunScriptHandler(&OnRunScript);
NWNXAPI.RegisterClosureHandler(&OnClosure);
NWNXAPI.RegisterMainLoopHandler(&OnLoop);
NWNXAPI.RegisterAssertHandler(&OnAssertFail);
}
/// <summary>
/// Initiates a complete reload of plugins and Anvil services.<br/>
/// This will reload all plugins.
/// </summary>
public static void Reload()
{
if (!EnvironmentConfig.ReloadEnabled)
{
Log.Error("Hot Reload of plugins is not enabled (ANVIL_RELOAD_ENABLED=true)");
}
GetService<SchedulerService>()?.Schedule(() =>
{
Log.Info("Reloading Anvil");
instance.Unload();
instance.LoadAndStart();
}, TimeSpan.Zero);
}
private void CheckServerVersion()
{
AssemblyName assemblyName = Assemblies.Anvil.GetName();
Version serverVersion = NwServer.Instance.ServerVersion;
if (assemblyName.Version?.Major != serverVersion.Major || assemblyName.Version.Minor != serverVersion.Minor)
{
Log.Warn("The current version of {Name} targets version {TargetVersion}, but the server is running {ServerVersion}! You may encounter compatibility issues",
assemblyName.Name,
assemblyName.Version,
serverVersion);
}
}
private void Init()
{
runtimeInfo = new RuntimeInfo
{
AssemblyName = Assemblies.Anvil.GetName().Name,
AssemblyVersion = AssemblyInfo.VersionInfo.InformationalVersion,
CoreVersion = Assemblies.Core.GetName().Version?.ToString(),
NativeVersion = Assemblies.Native.GetName().Version?.ToString(),
NWNXDotNetVersion = Assemblies.NWNXDotNet.GetName().Version?.ToString(),
};
serviceManager.Init();
try
{
PrelinkNative();
}
catch (Exception e)
{
Log.Fatal(e, $"Failed to load {runtimeInfo.AssemblyName} {runtimeInfo.AssemblyVersion} (NWN.Core: {runtimeInfo.CoreVersion}, NWN.Native: {runtimeInfo.NativeVersion}, NWNX.NET: {runtimeInfo.NWNXDotNetVersion})");
throw;
}
Log.Info($"Loading {runtimeInfo.AssemblyName} {runtimeInfo.AssemblyVersion} (NWN.Core: {runtimeInfo.CoreVersion}, NWN.Native: {runtimeInfo.NativeVersion}, NWNX.NET: {runtimeInfo.NWNXDotNetVersion})");
CheckServerVersion();
}
private void LoadAndStart()
{
serviceManager.Load();
serviceManager.Start();
}
private void PrelinkNative()
{
if (!EnvironmentConfig.NativePrelinkEnabled)
{
Log.Warn("Marshaller prelinking is disabled (ANVIL_PRELINK_ENABLED=false). You may encounter random crashes or issues");
return;
}
Log.Info("Prelinking native methods");
try
{
Marshal.PrelinkAll(typeof(NWNXLibPINVOKE));
Log.Info("Prelinking complete");
}
catch (TypeInitializationException)
{
Log.Fatal("The NWNX_SWIG_DotNET plugin could not be found. Has it been enabled? (NWNX_SWIG_DOTNET_SKIP=n)");
throw;
}
catch (Exception)
{
Log.Fatal("The NWNX_SWIG_DotNET plugin could not be loaded");
throw;
}
}
private void Shutdown()
{
serviceManager.Shutdown();
}
private void Unload()
{
serviceManager.Unload();
}
}
}