some improves and fixes:
1. should get the last loadded aseembly by checking its version instead of reversing. 2. fixed throw an exception when CsScriptRunner run the second time. 3. an argument carried by an UnregisterType called somewhere have had been accidentally removed.
This commit is contained in:
@@ -3234,6 +3234,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameMain.LuaCs.CsScript.Run(string.Join(" ", args));
|
GameMain.LuaCs.CsScript.Run(string.Join(" ", args));
|
||||||
|
GameMain.LuaCs.RecreateCsScript();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("cl_reloadlua", "reloads lua on the client", (string[] args) =>
|
commands.Add(new Command("cl_reloadlua", "reloads lua on the client", (string[] args) =>
|
||||||
|
|||||||
@@ -1248,6 +1248,7 @@ namespace Barotrauma
|
|||||||
commands.Add(new Command("cs", "cs: runs a string", (string[] args) =>
|
commands.Add(new Command("cs", "cs: runs a string", (string[] args) =>
|
||||||
{
|
{
|
||||||
GameMain.LuaCs.CsScript.Run(string.Join(" ", args));
|
GameMain.LuaCs.CsScript.Run(string.Join(" ", args));
|
||||||
|
GameMain.LuaCs.RecreateCsScript();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("reloadlua", "reloads lua", (string[] args) =>
|
commands.Add(new Command("reloadlua", "reloads lua", (string[] args) =>
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Text;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class CsScriptBase : AssemblyLoadContext
|
||||||
|
{
|
||||||
|
public const string NET_ONE_TIME_SCRIPT_ASSEMBLY = "NetOneTimeScriptAssembly";
|
||||||
|
public const string NET_SCRIPT_ASSEMBLY = "NetScriptAssembly";
|
||||||
|
|
||||||
|
public static Dictionary<string, object> Revision = new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
{ NET_SCRIPT_ASSEMBLY, 0},
|
||||||
|
{ NET_ONE_TIME_SCRIPT_ASSEMBLY, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
public CsScriptBase() : base(isCollectible: true) { }
|
||||||
|
|
||||||
|
public static SyntaxTree AssemblyInfoSyntaxTree(string asmName = null)
|
||||||
|
{
|
||||||
|
Revision[asmName] = (int)Revision[asmName] + 1;
|
||||||
|
var asmInfo = new StringBuilder();
|
||||||
|
asmInfo.AppendLine("using System.Reflection;");
|
||||||
|
asmInfo.AppendLine($"[assembly: AssemblyMetadata(\"Revision\", \"{Revision[asmName]}\")]");
|
||||||
|
asmInfo.AppendLine($"[assembly: AssemblyVersion(\"0.0.0.{Revision[asmName]}\")]");
|
||||||
|
return CSharpSyntaxTree.ParseText(asmInfo.ToString(), CSharpParseOptions.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
~CsScriptBase() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,11 @@ using System.Reflection.Metadata;
|
|||||||
namespace Barotrauma {
|
namespace Barotrauma {
|
||||||
class CsScriptFilter
|
class CsScriptFilter
|
||||||
{
|
{
|
||||||
|
public static readonly string[] LoadedAssemblyName = {
|
||||||
|
CsScriptBase.NET_SCRIPT_ASSEMBLY,
|
||||||
|
CsScriptBase.NET_ONE_TIME_SCRIPT_ASSEMBLY
|
||||||
|
};
|
||||||
|
|
||||||
private static readonly string[] typesPermitted = {
|
private static readonly string[] typesPermitted = {
|
||||||
// Basics
|
// Basics
|
||||||
"System",
|
"System",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using System.Reflection.Metadata;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class CsScriptLoader : AssemblyLoadContext
|
class CsScriptLoader : CsScriptBase
|
||||||
{
|
{
|
||||||
public LuaCsSetup setup;
|
public LuaCsSetup setup;
|
||||||
private List<MetadataReference> defaultReferences;
|
private List<MetadataReference> defaultReferences;
|
||||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
|||||||
private Dictionary<string, List<string>> sources;
|
private Dictionary<string, List<string>> sources;
|
||||||
public Assembly Assembly { get; private set; }
|
public Assembly Assembly { get; private set; }
|
||||||
|
|
||||||
public CsScriptLoader(LuaCsSetup setup) : base(isCollectible: true)
|
public CsScriptLoader(LuaCsSetup setup)
|
||||||
{
|
{
|
||||||
this.setup = setup;
|
this.setup = setup;
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ namespace Barotrauma
|
|||||||
var syntaxTrees = new List<SyntaxTree>();
|
var syntaxTrees = new List<SyntaxTree>();
|
||||||
|
|
||||||
if (sources.Count <= 0) throw new Exception("No Cs sources detected");
|
if (sources.Count <= 0) throw new Exception("No Cs sources detected");
|
||||||
|
syntaxTrees.Add(AssemblyInfoSyntaxTree(NET_SCRIPT_ASSEMBLY));
|
||||||
foreach ((var folder, var src) in sources)
|
foreach ((var folder, var src) in sources)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -92,7 +93,7 @@ namespace Barotrauma
|
|||||||
.WithMetadataImportOptions(MetadataImportOptions.All)
|
.WithMetadataImportOptions(MetadataImportOptions.All)
|
||||||
.WithOptimizationLevel(OptimizationLevel.Release)
|
.WithOptimizationLevel(OptimizationLevel.Release)
|
||||||
.WithAllowUnsafe(false);
|
.WithAllowUnsafe(false);
|
||||||
var compilation = CSharpCompilation.Create("NetScriptAssembly",syntaxTrees, defaultReferences, options);
|
var compilation = CSharpCompilation.Create(NET_SCRIPT_ASSEMBLY,syntaxTrees, defaultReferences, options);
|
||||||
|
|
||||||
using (var mem = new MemoryStream())
|
using (var mem = new MemoryStream())
|
||||||
{
|
{
|
||||||
@@ -153,10 +154,5 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Assembly = null;
|
Assembly = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
~CsScriptLoader()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ using MoonSharp.Interpreter;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class CsScriptRunner : AssemblyLoadContext
|
class CsScriptRunner : CsScriptBase
|
||||||
{
|
{
|
||||||
public LuaCsSetup setup;
|
public LuaCsSetup setup;
|
||||||
private List<MetadataReference> defaultReferences;
|
private List<MetadataReference> defaultReferences;
|
||||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
|||||||
"System.Linq"
|
"System.Linq"
|
||||||
};
|
};
|
||||||
|
|
||||||
public CsScriptRunner(LuaCsSetup setup) : base(isCollectible: true)
|
public CsScriptRunner(LuaCsSetup setup)
|
||||||
{
|
{
|
||||||
this.setup = setup;
|
this.setup = setup;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
code = ToOneTimeScript(code);
|
code = ToOneTimeScript(code);
|
||||||
var syntaxTree = SyntaxFactory.ParseSyntaxTree(code, CSharpParseOptions.Default);
|
var syntaxTree = SyntaxFactory.ParseSyntaxTree(code, CSharpParseOptions.Default);
|
||||||
var compilation = CSharpCompilation.Create("NetOneTimeScriptAssembly", new[] { syntaxTree }, defaultReferences, compileOptions);
|
var compilation = CSharpCompilation.Create(NET_ONE_TIME_SCRIPT_ASSEMBLY, new[] { AssemblyInfoSyntaxTree(NET_ONE_TIME_SCRIPT_ASSEMBLY), syntaxTree }, defaultReferences, compileOptions);
|
||||||
|
|
||||||
Assembly assembly = null;
|
Assembly assembly = null;
|
||||||
using (var mem = new MemoryStream())
|
using (var mem = new MemoryStream())
|
||||||
@@ -103,8 +103,7 @@ namespace Barotrauma
|
|||||||
scriptResilt = method.Invoke(runner, null);
|
scriptResilt = method.Invoke(runner, null);
|
||||||
foreach (var type in assembly.GetTypes())
|
foreach (var type in assembly.GetTypes())
|
||||||
{
|
{
|
||||||
//UserData.UnregisterType(type, true);
|
UserData.UnregisterType(type, true);
|
||||||
UserData.UnregisterType(type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else LuaCsSetup.PrintCsError("Script Error - no run method detected");
|
else LuaCsSetup.PrintCsError("Script Error - no run method detected");
|
||||||
@@ -115,6 +114,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unload();
|
Unload();
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,8 +13,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
var type = Type.GetType(typeName);
|
var type = Type.GetType(typeName);
|
||||||
if (type != null) return type;
|
if (type != null) return type;
|
||||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies().Reverse())
|
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
{
|
{
|
||||||
|
if (CsScriptFilter.LoadedAssemblyName.Contains(a.GetName().Name))
|
||||||
|
{
|
||||||
|
var attrs = a.GetCustomAttributes<AssemblyMetadataAttribute>();
|
||||||
|
var revision = attrs.FirstOrDefault(attr => attr.Key == "Revision")?.Value;
|
||||||
|
if (revision != null && int.Parse(revision) != (int)CsScriptBase.Revision[a.GetName().Name]) { continue; }
|
||||||
|
}
|
||||||
type = a.GetType(typeName);
|
type = a.GetType(typeName);
|
||||||
if (type != null)
|
if (type != null)
|
||||||
return type;
|
return type;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("NetScriptAssembly", AllInternalsVisible = true)]
|
[assembly: InternalsVisibleTo(Barotrauma.CsScriptBase.NET_SCRIPT_ASSEMBLY, AllInternalsVisible = true)]
|
||||||
[assembly: InternalsVisibleTo("NetOneTimeScriptAssembly", AllInternalsVisible = true)]
|
[assembly: InternalsVisibleTo(Barotrauma.CsScriptBase.NET_ONE_TIME_SCRIPT_ASSEMBLY, AllInternalsVisible = true)]
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class LuaCsSetupConfig
|
class LuaCsSetupConfig
|
||||||
@@ -40,6 +40,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Script lua;
|
private Script lua;
|
||||||
public CsScriptRunner CsScript { get; private set; }
|
public CsScriptRunner CsScript { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// due to there's a race on the process and the unloaded AssemblyLoadContexts,
|
||||||
|
/// should recreate runner after the script runs
|
||||||
|
/// </summary>
|
||||||
|
public void RecreateCsScript()
|
||||||
|
{
|
||||||
|
GameMain.LuaCs.CsScript = new CsScriptRunner(GameMain.LuaCs.CsScript.setup);
|
||||||
|
lua.Globals["CsScript"] = CsScript;
|
||||||
|
}
|
||||||
|
|
||||||
public LuaGame Game { get; private set; }
|
public LuaGame Game { get; private set; }
|
||||||
public LuaScriptLoader LuaScriptLoader { get; private set; }
|
public LuaScriptLoader LuaScriptLoader { get; private set; }
|
||||||
|
|
||||||
@@ -314,9 +325,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
foreach (var type in AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name == "NetScriptAssembly").SelectMany(assembly => assembly.GetTypes()))
|
foreach (var type in AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name == CsScriptBase.NET_SCRIPT_ASSEMBLY).SelectMany(assembly => assembly.GetTypes()))
|
||||||
{
|
{
|
||||||
UserData.UnregisterType(type);
|
UserData.UnregisterType(type, true);
|
||||||
}
|
}
|
||||||
foreach (var mod in ACsMod.LoadedMods.ToArray()) mod.Dispose();
|
foreach (var mod in ACsMod.LoadedMods.ToArray()) mod.Dispose();
|
||||||
ACsMod.LoadedMods.Clear();
|
ACsMod.LoadedMods.Clear();
|
||||||
@@ -450,7 +461,8 @@ modding needs.
|
|||||||
var modTypes = CsScriptLoader.Compile();
|
var modTypes = CsScriptLoader.Compile();
|
||||||
modTypes.ForEach(t =>
|
modTypes.ForEach(t =>
|
||||||
{
|
{
|
||||||
UserData.RegisterType(t);
|
//Please register `t` in lua-side
|
||||||
|
//UserData.RegisterType(t);
|
||||||
t.GetConstructor(new Type[] { })?.Invoke(null);
|
t.GetConstructor(new Type[] { })?.Invoke(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user