Fix mixed spaces and tabs

This commit is contained in:
EvilFactory
2022-10-28 12:29:35 -03:00
parent 43810a3509
commit 5e29d1d8ba
11 changed files with 1864 additions and 1864 deletions
@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting;
@@ -14,40 +14,40 @@ using System.Runtime.CompilerServices;
namespace Barotrauma namespace Barotrauma
{ {
class CsScriptBase : AssemblyLoadContext class CsScriptBase : AssemblyLoadContext
{ {
public const string CsOneTimeScriptAssembly = "NetOneTimeScriptAssembly"; public const string CsOneTimeScriptAssembly = "NetOneTimeScriptAssembly";
public const string CsScriptAssembly = "NetScriptAssembly"; public const string CsScriptAssembly = "NetScriptAssembly";
public static readonly string[] LoadedAssemblyName = { public static readonly string[] LoadedAssemblyName = {
CsScriptBase.CsScriptAssembly, CsScriptBase.CsScriptAssembly,
CsScriptBase.CsOneTimeScriptAssembly CsScriptBase.CsOneTimeScriptAssembly
};
public static Dictionary<string, object> Revision = new Dictionary<string, object>()
{
{ CsScriptAssembly, 0},
{ CsOneTimeScriptAssembly, 0}
}; };
public CSharpParseOptions ParseOptions { get; protected set; } public static Dictionary<string, object> Revision = new Dictionary<string, object>()
public CsScriptBase() : base(isCollectible: true) {
ParseOptions = CSharpParseOptions.Default
.WithPreprocessorSymbols(new[] { LuaCsSetup.IsServer ? "SERVER" : (LuaCsSetup.IsClient ? "CLIENT" : "UNDEFINED") });
}
public static SyntaxTree AssemblyInfoSyntaxTree(string asmName = null)
{ {
Revision[asmName] = (int)Revision[asmName] + 1; { CsScriptAssembly, 0},
var asmInfo = new StringBuilder(); { CsOneTimeScriptAssembly, 0}
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() { } public CSharpParseOptions ParseOptions { get; protected set; }
}
public CsScriptBase() : base(isCollectible: true) {
ParseOptions = CSharpParseOptions.Default
.WithPreprocessorSymbols(new[] { LuaCsSetup.IsServer ? "SERVER" : (LuaCsSetup.IsClient ? "CLIENT" : "UNDEFINED") });
}
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() { }
}
} }
@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting;
@@ -14,208 +14,208 @@ using System.Xml.Linq;
namespace Barotrauma namespace Barotrauma
{ {
class CsScriptLoader : CsScriptBase class CsScriptLoader : CsScriptBase
{ {
private List<MetadataReference> defaultReferences; private List<MetadataReference> defaultReferences;
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() public CsScriptLoader()
{
defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit")))
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
.ToList();
sources = new Dictionary<string, List<string>>();
Assembly = null;
}
private enum RunType { Standard, Forced, None };
private bool ShouldRun(ContentPackage cp, string path)
{
if (!Directory.Exists(path + "CSharp"))
{
return false;
}
var isEnabled = ContentPackageManager.EnabledPackages.All.Contains(cp);
if (File.Exists(path + "CSharp/RunConfig.xml"))
{
Stream stream = File.Open(path + "CSharp/RunConfig.xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var doc = XDocument.Load(stream);
var elems = doc.Root.Elements().ToArray();
var elem = elems.FirstOrDefault(e => e.Name.LocalName.Equals(LuaCsSetup.IsServer ? "Server" : (LuaCsSetup.IsClient ? "Client" : "None"), StringComparison.OrdinalIgnoreCase));
if (elem != null && Enum.TryParse(elem.Value, true, out RunType rtValue))
{
if (rtValue == RunType.Standard && isEnabled)
{
LuaCsSetup.PrintCsMessage($"Standard run C# of {cp.Name}");
return true;
}
else if (rtValue == RunType.Forced)
{
LuaCsSetup.PrintCsMessage($"Forced run C# of {cp.Name}");
return true;
}
else if (rtValue == RunType.None)
{
return false;
}
}
stream.Close();
}
if (isEnabled)
{
LuaCsSetup.PrintCsMessage($"Assumed run C# of {cp.Name}");
return true;
}
else
{
return false;
}
}
public void SearchFolders()
{
var paths = new Dictionary<string, string>();
foreach (var cp in ContentPackageManager.AllPackages.Concat(ContentPackageManager.EnabledPackages.All))
{
var path = $"{Path.GetFullPath(Path.GetDirectoryName(cp.Path)).Replace('\\', '/')}/";
if (ShouldRun(cp, path))
{
if (paths.ContainsKey(cp.Name))
{
if (ContentPackageManager.EnabledPackages.All.Contains(cp))
{
paths[cp.Name] = path;
}
}
else
{
paths.Add(cp.Name, path);
}
}
}
foreach ((var _, var path) in paths)
{
RunFolder(path);
}
}
public bool HasSources { get => sources.Count > 0; }
private void AddSources(string folder)
{ {
foreach (var str in DirSearch(folder)) defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
{ .Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit")))
string s = str.Replace("\\", "/"); .Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
.ToList();
if (sources.ContainsKey(folder)) sources = new Dictionary<string, List<string>>();
{ Assembly = null;
sources[folder].Add(s); }
}
else
{
sources.Add(folder, new List<string> { s });
}
}
}
private void RunFolder(string folder) private enum RunType { Standard, Forced, None };
{ private bool ShouldRun(ContentPackage cp, string path)
{
AddSources(folder + "/CSharp/Shared"); if (!Directory.Exists(path + "CSharp"))
#if SERVER
AddSources(folder + "/CSharp/Server");
#else
AddSources(folder + "/CSharp/Client");
#endif
}
private IEnumerable<SyntaxTree> ParseSources() {
var syntaxTrees = new List<SyntaxTree>();
if (sources.Count <= 0) throw new Exception("No Cs sources detected");
syntaxTrees.Add(AssemblyInfoSyntaxTree(CsScriptAssembly));
foreach ((var folder, var src) in sources)
{ {
try return false;
{
foreach (var file in src)
{
var tree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(file), ParseOptions, file);
syntaxTrees.Add(tree);
}
}
catch (Exception ex)
{
LuaCsSetup.PrintCsError("Error loading '" + folder + "':\n" + ex.Message + "\n" + ex.StackTrace);
}
}
return syntaxTrees;
}
public List<Type> Compile()
{
IEnumerable<SyntaxTree> syntaxTrees = ParseSources();
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithAllowUnsafe(false);
var compilation = CSharpCompilation.Create(CsScriptAssembly, syntaxTrees, defaultReferences, options);
using (var mem = new MemoryStream())
{
var result = compilation.Emit(mem);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error);
string errStr = "CS MODS NOT LOADED | Compilation errors:";
foreach (Diagnostic diagnostic in failures)
errStr += $"\n{diagnostic}";
LuaCsSetup.PrintCsError(errStr);
}
else
{
mem.Seek(0, SeekOrigin.Begin);
Assembly = LoadFromStream(mem);
}
}
if (Assembly != null)
{
return Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ACsMod))).ToList();
}
else
{
throw new Exception("Unable to create cs mods assembly.");
}
}
private static string[] DirSearch(string sDir)
{
if (!Directory.Exists(sDir))
{
return new string[] {};
} }
return Directory.GetFiles(sDir, "*.cs", SearchOption.AllDirectories); var isEnabled = ContentPackageManager.EnabledPackages.All.Contains(cp);
} if (File.Exists(path + "CSharp/RunConfig.xml"))
{
Stream stream = File.Open(path + "CSharp/RunConfig.xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var doc = XDocument.Load(stream);
var elems = doc.Root.Elements().ToArray();
var elem = elems.FirstOrDefault(e => e.Name.LocalName.Equals(LuaCsSetup.IsServer ? "Server" : (LuaCsSetup.IsClient ? "Client" : "None"), StringComparison.OrdinalIgnoreCase));
public void Clear() if (elem != null && Enum.TryParse(elem.Value, true, out RunType rtValue))
{ {
Assembly = null; if (rtValue == RunType.Standard && isEnabled)
{
LuaCsSetup.PrintCsMessage($"Standard run C# of {cp.Name}");
return true;
}
else if (rtValue == RunType.Forced)
{
LuaCsSetup.PrintCsMessage($"Forced run C# of {cp.Name}");
return true;
}
else if (rtValue == RunType.None)
{
return false;
}
}
stream.Close();
}
if (isEnabled)
{
LuaCsSetup.PrintCsMessage($"Assumed run C# of {cp.Name}");
return true;
}
else
{
return false;
}
} }
}
public void SearchFolders()
{
var paths = new Dictionary<string, string>();
foreach (var cp in ContentPackageManager.AllPackages.Concat(ContentPackageManager.EnabledPackages.All))
{
var path = $"{Path.GetFullPath(Path.GetDirectoryName(cp.Path)).Replace('\\', '/')}/";
if (ShouldRun(cp, path))
{
if (paths.ContainsKey(cp.Name))
{
if (ContentPackageManager.EnabledPackages.All.Contains(cp))
{
paths[cp.Name] = path;
}
}
else
{
paths.Add(cp.Name, path);
}
}
}
foreach ((var _, var path) in paths)
{
RunFolder(path);
}
}
public bool HasSources { get => sources.Count > 0; }
private void AddSources(string folder)
{
foreach (var str in DirSearch(folder))
{
string s = str.Replace("\\", "/");
if (sources.ContainsKey(folder))
{
sources[folder].Add(s);
}
else
{
sources.Add(folder, new List<string> { s });
}
}
}
private void RunFolder(string folder)
{
AddSources(folder + "/CSharp/Shared");
#if SERVER
AddSources(folder + "/CSharp/Server");
#else
AddSources(folder + "/CSharp/Client");
#endif
}
private IEnumerable<SyntaxTree> ParseSources() {
var syntaxTrees = new List<SyntaxTree>();
if (sources.Count <= 0) throw new Exception("No Cs sources detected");
syntaxTrees.Add(AssemblyInfoSyntaxTree(CsScriptAssembly));
foreach ((var folder, var src) in sources)
{
try
{
foreach (var file in src)
{
var tree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(file), ParseOptions, file);
syntaxTrees.Add(tree);
}
}
catch (Exception ex)
{
LuaCsSetup.PrintCsError("Error loading '" + folder + "':\n" + ex.Message + "\n" + ex.StackTrace);
}
}
return syntaxTrees;
}
public List<Type> Compile()
{
IEnumerable<SyntaxTree> syntaxTrees = ParseSources();
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithAllowUnsafe(false);
var compilation = CSharpCompilation.Create(CsScriptAssembly, syntaxTrees, defaultReferences, options);
using (var mem = new MemoryStream())
{
var result = compilation.Emit(mem);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error);
string errStr = "CS MODS NOT LOADED | Compilation errors:";
foreach (Diagnostic diagnostic in failures)
errStr += $"\n{diagnostic}";
LuaCsSetup.PrintCsError(errStr);
}
else
{
mem.Seek(0, SeekOrigin.Begin);
Assembly = LoadFromStream(mem);
}
}
if (Assembly != null)
{
return Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ACsMod))).ToList();
}
else
{
throw new Exception("Unable to create cs mods assembly.");
}
}
private static string[] DirSearch(string sDir)
{
if (!Directory.Exists(sDir))
{
return new string[] {};
}
return Directory.GetFiles(sDir, "*.cs", SearchOption.AllDirectories);
}
public void Clear()
{
Assembly = null;
}
}
} }
@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting;
@@ -13,109 +13,109 @@ using MoonSharp.Interpreter;
namespace Barotrauma namespace Barotrauma
{ {
class CsScriptRunner : CsScriptBase class CsScriptRunner : CsScriptBase
{ {
public LuaCsSetup setup; public LuaCsSetup setup;
private List<MetadataReference> defaultReferences; private List<MetadataReference> defaultReferences;
private CSharpCompilationOptions compileOptions; private CSharpCompilationOptions compileOptions;
private static readonly string[] usings = { private static readonly string[] usings = {
"System", "System",
"Barotrauma", "Barotrauma",
"System.Collections.Generic", "System.Collections.Generic",
"System.Linq" "System.Linq"
}; };
public CsScriptRunner(LuaCsSetup setup) public CsScriptRunner(LuaCsSetup setup)
{
this.setup = setup;
defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit")))
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
.ToList();
compileOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithAllowUnsafe(false);
}
private static string ToOneTimeScript(string code)
{ {
var prefix = ""; this.setup = setup;
foreach (var u in usings) prefix += $"using {u}; ";
prefix += "namespace NetOneTimeScript { public class NetOneTimeScriptRunner { public NetOneTimeScriptRunner() { } public object Run() {\n";
var postfix = "\nreturn null; } } }";
return prefix + code + postfix;
}
public object Run(string code) defaultReferences = AppDomain.CurrentDomain.GetAssemblies()
{ .Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit")))
object scriptResilt = null; .Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
.ToList();
compileOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithAllowUnsafe(false);
}
try private static string ToOneTimeScript(string code)
{ {
code = ToOneTimeScript(code); var prefix = "";
var syntaxTree = SyntaxFactory.ParseSyntaxTree(code, ParseOptions); foreach (var u in usings) prefix += $"using {u}; ";
var compilation = CSharpCompilation.Create(CsOneTimeScriptAssembly, new[] { AssemblyInfoSyntaxTree(CsOneTimeScriptAssembly), syntaxTree }, defaultReferences, compileOptions); prefix += "namespace NetOneTimeScript { public class NetOneTimeScriptRunner { public NetOneTimeScriptRunner() { } public object Run() {\n";
var postfix = "\nreturn null; } } }";
return prefix + code + postfix;
}
Assembly assembly = null; public object Run(string code)
using (var mem = new MemoryStream()) {
{ object scriptResilt = null;
var result = compilation.Emit(mem);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error);
string errStr = "Script compilation errors:"; try
var lineErr = new SortedDictionary<int, (string, string)>(); {
foreach (Diagnostic diagnostic in failures) code = ToOneTimeScript(code);
var syntaxTree = SyntaxFactory.ParseSyntaxTree(code, ParseOptions);
var compilation = CSharpCompilation.Create(CsOneTimeScriptAssembly, new[] { AssemblyInfoSyntaxTree(CsOneTimeScriptAssembly), syntaxTree }, defaultReferences, compileOptions);
Assembly assembly = null;
using (var mem = new MemoryStream())
{
var result = compilation.Emit(mem);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error);
string errStr = "Script compilation errors:";
var lineErr = new SortedDictionary<int, (string, string)>();
foreach (Diagnostic diagnostic in failures)
{ {
var line = syntaxTree.GetLineSpan(diagnostic.Location.SourceSpan).StartLinePosition.Line; var line = syntaxTree.GetLineSpan(diagnostic.Location.SourceSpan).StartLinePosition.Line;
lineErr[line] = (diagnostic.Id, diagnostic.ToString()); lineErr[line] = (diagnostic.Id, diagnostic.ToString());
} }
var lines = code.Split('\n'); var lines = code.Split('\n');
for (var i = 1; i < lines.Length - 1; i++) for (var i = 1; i < lines.Length - 1; i++)
{ {
errStr += $"\n{i} >> {lines[i]}"; errStr += $"\n{i} >> {lines[i]}";
if (lineErr.ContainsKey(i)) errStr += $" <=== {lineErr[i].Item1}"; if (lineErr.ContainsKey(i)) errStr += $" <=== {lineErr[i].Item1}";
} }
errStr += "\n"; errStr += "\n";
foreach ((var idx, (var id, var err)) in lineErr) foreach ((var idx, (var id, var err)) in lineErr)
{ {
errStr += $"\n{idx}: {err}"; errStr += $"\n{idx}: {err}";
} }
LuaCsSetup.PrintCsError(errStr); LuaCsSetup.PrintCsError(errStr);
} }
else else
{ {
mem.Seek(0, SeekOrigin.Begin); mem.Seek(0, SeekOrigin.Begin);
assembly = LoadFromStream(mem); assembly = LoadFromStream(mem);
var runner = assembly.CreateInstance("NetOneTimeScript.NetOneTimeScriptRunner"); var runner = assembly.CreateInstance("NetOneTimeScript.NetOneTimeScriptRunner");
if (runner != null) if (runner != null)
{ {
var method = runner.GetType().GetMethod("Run", BindingFlags.Public | BindingFlags.Instance); var method = runner.GetType().GetMethod("Run", BindingFlags.Public | BindingFlags.Instance);
if (method != null) if (method != null)
{ {
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);
} }
} }
else { LuaCsSetup.PrintCsError("Script Error - no run method detected"); } else { LuaCsSetup.PrintCsError("Script Error - no run method detected"); }
} }
else { LuaCsSetup.PrintCsError("Script Error - no runner class detected"); } else { LuaCsSetup.PrintCsError("Script Error - no runner class detected"); }
} }
} }
Unload(); Unload();
} }
catch (Exception ex) catch (Exception ex)
{ {
LuaCsSetup.PrintCsError("Error running script:\n" + ex.Message + "\n" + ex.StackTrace); LuaCsSetup.PrintCsError("Error running script:\n" + ex.Message + "\n" + ex.StackTrace);
} }
return scriptResilt; return scriptResilt;
} }
} }
} }
@@ -7,19 +7,19 @@ using Barotrauma.Networking;
namespace Barotrauma.Networking namespace Barotrauma.Networking
{ {
partial class Client partial class Client
{ {
public static IReadOnlyList<Client> ClientList public static IReadOnlyList<Client> ClientList
{ {
get get
{ {
#if SERVER #if SERVER
return GameMain.Server.ConnectedClients; return GameMain.Server.ConnectedClients;
#else #else
return GameMain.Client.ConnectedClients; return GameMain.Client.ConnectedClients;
#endif #endif
} }
} }
public ulong SteamID public ulong SteamID
{ {
@@ -36,71 +36,71 @@ namespace Barotrauma.Networking
} }
} }
} }
} }
namespace Barotrauma namespace Barotrauma
{ {
using Barotrauma.Networking; using Barotrauma.Networking;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
partial class Character partial class Character
{ {
} }
partial class Item partial class Item
{ {
public object GetComponentString(string component) public object GetComponentString(string component)
{ {
Type type = Type.GetType("Barotrauma.Items.Components." + component); Type type = Type.GetType("Barotrauma.Items.Components." + component);
if (type == null) if (type == null)
return null; return null;
MethodInfo method = typeof(Item).GetMethod(nameof(Item.GetComponent)); MethodInfo method = typeof(Item).GetMethod(nameof(Item.GetComponent));
MethodInfo generic = method.MakeGenericMethod(type); MethodInfo generic = method.MakeGenericMethod(type);
return generic.Invoke(this, null); return generic.Invoke(this, null);
} }
} }
partial class ItemPrefab partial class ItemPrefab
{ {
public static ItemPrefab GetItemPrefab(string itemNameOrId) public static ItemPrefab GetItemPrefab(string itemNameOrId)
{ {
ItemPrefab itemPrefab = ItemPrefab itemPrefab =
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ?? (MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab; MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
return itemPrefab; return itemPrefab;
} }
} }
abstract partial class MapEntity abstract partial class MapEntity
{ {
public void AddLinked(MapEntity entity) public void AddLinked(MapEntity entity)
{ {
linkedTo.Add(entity); linkedTo.Add(entity);
} }
} }
} }
namespace Barotrauma.Items.Components namespace Barotrauma.Items.Components
{ {
using Barotrauma.Networking; using Barotrauma.Networking;
partial class CustomInterface partial class CustomInterface
{ {
} }
partial struct Signal partial struct Signal
{ {
} }
} }
@@ -10,86 +10,86 @@ using MoonSharp.Interpreter;
namespace Barotrauma namespace Barotrauma
{ {
partial class LuaGame partial class LuaGame
{ {
public bool IsSingleplayer => GameMain.IsSingleplayer; public bool IsSingleplayer => GameMain.IsSingleplayer;
public bool IsMultiplayer => GameMain.IsMultiplayer; public bool IsMultiplayer => GameMain.IsMultiplayer;
public string SaveFolder => SaveUtil.SaveFolder; public string SaveFolder => SaveUtil.SaveFolder;
#if CLIENT #if CLIENT
public GameClient Client public GameClient Client
{
get
{
return GameMain.Client;
}
}
public bool Paused => GameMain.Instance?.Paused == true;
public byte SessionId => GameMain.Client.SessionId;
public byte MyID => SessionId; // compatibility
public ChatMode ActiveChatMode => GameMain.ActiveChatMode;
public ChatBox ChatBox
{
get
{
if (GameMain.IsSingleplayer)
return GameMain.GameSession.CrewManager.ChatBox;
else
return GameMain.Client.ChatBox;
}
}
public Sounds.SoundManager SoundManager
{ {
get get
{ {
return GameMain.SoundManager; return GameMain.Client;
} }
} }
public Lights.LightManager LightManager public bool Paused => GameMain.Instance?.Paused == true;
{ public byte SessionId => GameMain.Client.SessionId;
get public byte MyID => SessionId; // compatibility
{
return GameMain.LightManager;
}
}
public SubEditorScreen SubEditorScreen public ChatMode ActiveChatMode => GameMain.ActiveChatMode;
{
get
{
return GameMain.SubEditorScreen;
}
}
public bool IsSubEditor public ChatBox ChatBox
{ {
get get
{ {
return Screen.Selected is SubEditorScreen; if (GameMain.IsSingleplayer)
return GameMain.GameSession.CrewManager.ChatBox;
else
return GameMain.Client.ChatBox;
}
}
public Sounds.SoundManager SoundManager
{
get
{
return GameMain.SoundManager;
}
}
public Lights.LightManager LightManager
{
get
{
return GameMain.LightManager;
}
}
public SubEditorScreen SubEditorScreen
{
get
{
return GameMain.SubEditorScreen;
}
}
public bool IsSubEditor
{
get
{
return Screen.Selected is SubEditorScreen;
} }
} }
#else #else
public GameServer Server public GameServer Server
{ {
get get
{ {
return GameMain.Server; return GameMain.Server;
} }
} }
public bool IsDedicated public bool IsDedicated
{ {
get get
{ {
return GameMain.Server.ServerPeer is LidgrenServerPeer; return GameMain.Server.ServerPeer is LidgrenServerPeer;
} }
} }
#endif #endif
public ServerSettings ServerSettings public ServerSettings ServerSettings
@@ -121,296 +121,296 @@ namespace Barotrauma
public DynValue Settings; public DynValue Settings;
public bool allowWifiChat = false; public bool allowWifiChat = false;
public bool overrideTraitors = false; public bool overrideTraitors = false;
public bool overrideRespawnSub = false; public bool overrideRespawnSub = false;
public bool overrideSignalRadio = false; public bool overrideSignalRadio = false;
public bool disableSpamFilter = false; public bool disableSpamFilter = false;
public bool disableDisconnectCharacter = false; public bool disableDisconnectCharacter = false;
public bool enableControlHusk = false; public bool enableControlHusk = false;
public int mapEntityUpdateInterval public int mapEntityUpdateInterval
{
get { return MapEntity.MapEntityUpdateInterval; }
set { MapEntity.MapEntityUpdateInterval = value; }
}
public int gapUpdateInterval
{
get { return MapEntity.GapUpdateInterval; }
set { MapEntity.GapUpdateInterval = value; }
}
public int poweredUpdateInterval
{
get { return MapEntity.PoweredUpdateInterval; }
set { MapEntity.PoweredUpdateInterval = value; }
}
public int characterUpdateInterval
{
get { return Character.CharacterUpdateInterval; }
set { Character.CharacterUpdateInterval = value; }
}
public HashSet<Item> updatePriorityItems = new HashSet<Item>();
public HashSet<Character> updatePriorityCharacters = new HashSet<Character>();
public void AddPriorityItem(Item item)
{
updatePriorityItems.Add(item);
}
public void RemovePriorityItem(Item item)
{
updatePriorityItems.Remove(item);
}
public void ClearPriorityItem()
{
updatePriorityItems.Clear();
}
public void AddPriorityCharacter(Character character)
{
updatePriorityCharacters.Add(character);
}
public void RemovePriorityCharacter(Character character)
{
updatePriorityCharacters.Remove(character);
}
public void ClearPriorityCharacter()
{
updatePriorityCharacters.Clear();
}
public bool RoundStarted
{
get
{
#if SERVER
return GameMain.Server?.GameStarted == true;
#else
return GameMain.Client?.GameStarted == true;
#endif
}
}
public GameSession GameSession
{
get
{
return GameMain.GameSession;
}
}
public NetLobbyScreen NetLobbyScreen
{
get
{
return GameMain.NetLobbyScreen;
}
}
public GameScreen GameScreen
{
get
{
return GameMain.GameScreen;
}
}
public World World
{
get
{
return GameMain.World;
}
}
#if SERVER
public ServerPeer Peer
{
get
{
return GameMain.Server.ServerPeer;
}
}
#else
public ClientPeer Peer
{
get
{
return GameMain.Client.ClientPeer;
}
}
#endif
public LuaGame()
{ {
LuaUserData.MakeFieldAccessible(UserData.RegisterType(typeof(GameSettings)), "currentConfig"); get { return MapEntity.MapEntityUpdateInterval; }
Settings = UserData.CreateStatic(typeof(GameSettings)); set { MapEntity.MapEntityUpdateInterval = value; }
} }
public void OverrideTraitors(bool o) public int gapUpdateInterval
{
overrideTraitors = o;
}
public void OverrideRespawnSub(bool o)
{
overrideRespawnSub = o;
}
public void AllowWifiChat(bool o)
{
allowWifiChat = o;
}
public void OverrideSignalRadio(bool o)
{
overrideSignalRadio = o;
}
public void DisableSpamFilter(bool o)
{
disableSpamFilter = o;
}
public void DisableDisconnectCharacter(bool o)
{
disableDisconnectCharacter = o;
}
public void EnableControlHusk(bool o)
{
enableControlHusk = o;
}
public static void Explode(Vector2 pos, float range = 100, float force = 30, float damage = 30, float structureDamage = 30, float itemDamage = 30, float empStrength = 0, float ballastFloraStrength = 0)
{
new Explosion(range, force, damage, structureDamage, itemDamage, empStrength, ballastFloraStrength).Explode(pos, null);
}
public static string SpawnItem(string name, Vector2 pos, bool inventory = false, Character character = null)
{
string error;
DebugConsole.SpawnItem(new string[] { name, inventory ? "inventory" : "cursor" }, pos, character, out error);
return error;
}
public static ContentPackage[] GetEnabledContentPackages()
{ {
return ContentPackageManager.EnabledPackages.All.ToArray(); get { return MapEntity.GapUpdateInterval; }
set { MapEntity.GapUpdateInterval = value; }
} }
public static ItemPrefab GetItemPrefab(string itemNameOrId) public int poweredUpdateInterval
{ {
ItemPrefab itemPrefab = get { return MapEntity.PoweredUpdateInterval; }
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ?? set { MapEntity.PoweredUpdateInterval = value; }
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab; }
return itemPrefab; public int characterUpdateInterval
} {
get { return Character.CharacterUpdateInterval; }
set { Character.CharacterUpdateInterval = value; }
}
public static Submarine GetRespawnSub()
{ public HashSet<Item> updatePriorityItems = new HashSet<Item>();
public HashSet<Character> updatePriorityCharacters = new HashSet<Character>();
public void AddPriorityItem(Item item)
{
updatePriorityItems.Add(item);
}
public void RemovePriorityItem(Item item)
{
updatePriorityItems.Remove(item);
}
public void ClearPriorityItem()
{
updatePriorityItems.Clear();
}
public void AddPriorityCharacter(Character character)
{
updatePriorityCharacters.Add(character);
}
public void RemovePriorityCharacter(Character character)
{
updatePriorityCharacters.Remove(character);
}
public void ClearPriorityCharacter()
{
updatePriorityCharacters.Clear();
}
public bool RoundStarted
{
get
{
#if SERVER #if SERVER
if (GameMain.Server.RespawnManager == null) return GameMain.Server?.GameStarted == true;
return null;
return GameMain.Server.RespawnManager.RespawnShuttle;
#else #else
if (GameMain.Client.RespawnManager == null) return GameMain.Client?.GameStarted == true;
return null;
return GameMain.Client.RespawnManager.RespawnShuttle;
#endif #endif
} }
}
public static Items.Components.Steering GetSubmarineSteering(Submarine sub) public GameSession GameSession
{ {
foreach (Item item in Item.ItemList) get
{ {
if (item.Submarine != sub) continue; return GameMain.GameSession;
}
}
var steering = item.GetComponent<Items.Components.Steering>(); public NetLobbyScreen NetLobbyScreen
if (steering != null) {
{ get
return steering; {
} return GameMain.NetLobbyScreen;
} }
}
return null; public GameScreen GameScreen
} {
get
{
return GameMain.GameScreen;
}
}
public static WifiComponent GetWifiComponent(Item item) public World World
{ {
if (item == null) return null; get
return item.GetComponent<WifiComponent>(); {
} return GameMain.World;
}
}
public static LightComponent GetLightComponent(Item item) #if SERVER
{ public ServerPeer Peer
if (item == null) return null; {
return item.GetComponent<LightComponent>(); get
} {
return GameMain.Server.ServerPeer;
}
}
#else
public ClientPeer Peer
{
get
{
return GameMain.Client.ClientPeer;
}
}
#endif
public static CustomInterface GetCustomInterface(Item item) public LuaGame()
{ {
if (item == null) return null; LuaUserData.MakeFieldAccessible(UserData.RegisterType(typeof(GameSettings)), "currentConfig");
return item.GetComponent<CustomInterface>(); Settings = UserData.CreateStatic(typeof(GameSettings));
} }
public static Fabricator GetFabricatorComponent(Item item) public void OverrideTraitors(bool o)
{ {
if (item == null) return null; overrideTraitors = o;
return item.GetComponent<Fabricator>(); }
}
public static Holdable GetHoldableComponent(Item item) public void OverrideRespawnSub(bool o)
{ {
if (item == null) return null; overrideRespawnSub = o;
return item.GetComponent<Holdable>(); }
}
public static void ExecuteCommand(string command) public void AllowWifiChat(bool o)
{ {
DebugConsole.ExecuteCommand(command); allowWifiChat = o;
} }
public static Signal CreateSignal(string value, int stepsTaken = 1, Character sender = null, Item source = null, float power = 0, float strength = 1) public void OverrideSignalRadio(bool o)
{ {
return new Signal(value, stepsTaken, sender, source, power, strength); overrideSignalRadio = o;
} }
private List<DebugConsole.Command> luaAddedCommand = new List<DebugConsole.Command>(); public void DisableSpamFilter(bool o)
{
disableSpamFilter = o;
}
public void RemoveCommand(string name) public void DisableDisconnectCharacter(bool o)
{ {
for (var i = 0; i < DebugConsole.Commands.Count; i++) disableDisconnectCharacter = o;
{ }
foreach (var cmdname in DebugConsole.Commands[i].names)
{
if (cmdname == name)
{
luaAddedCommand.Remove(DebugConsole.Commands[i]);
DebugConsole.Commands.RemoveAt(i);
continue;
}
}
}
}
public void AddCommand(string name, string help, LuaCsAction onExecute, LuaCsFunc getValidArgs = null, bool isCheat = false)
{ public void EnableControlHusk(bool o)
var cmd = new DebugConsole.Command(name, help, (string[] arg1) => onExecute(new object[] { arg1 }), {
() => enableControlHusk = o;
{ }
if (getValidArgs == null) return null;
public static void Explode(Vector2 pos, float range = 100, float force = 30, float damage = 30, float structureDamage = 30, float itemDamage = 30, float empStrength = 0, float ballastFloraStrength = 0)
{
new Explosion(range, force, damage, structureDamage, itemDamage, empStrength, ballastFloraStrength).Explode(pos, null);
}
public static string SpawnItem(string name, Vector2 pos, bool inventory = false, Character character = null)
{
string error;
DebugConsole.SpawnItem(new string[] { name, inventory ? "inventory" : "cursor" }, pos, character, out error);
return error;
}
public static ContentPackage[] GetEnabledContentPackages()
{
return ContentPackageManager.EnabledPackages.All.ToArray();
}
public static ItemPrefab GetItemPrefab(string itemNameOrId)
{
ItemPrefab itemPrefab =
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
return itemPrefab;
}
public static Submarine GetRespawnSub()
{
#if SERVER
if (GameMain.Server.RespawnManager == null)
return null;
return GameMain.Server.RespawnManager.RespawnShuttle;
#else
if (GameMain.Client.RespawnManager == null)
return null;
return GameMain.Client.RespawnManager.RespawnShuttle;
#endif
}
public static Items.Components.Steering GetSubmarineSteering(Submarine sub)
{
foreach (Item item in Item.ItemList)
{
if (item.Submarine != sub) continue;
var steering = item.GetComponent<Items.Components.Steering>();
if (steering != null)
{
return steering;
}
}
return null;
}
public static WifiComponent GetWifiComponent(Item item)
{
if (item == null) return null;
return item.GetComponent<WifiComponent>();
}
public static LightComponent GetLightComponent(Item item)
{
if (item == null) return null;
return item.GetComponent<LightComponent>();
}
public static CustomInterface GetCustomInterface(Item item)
{
if (item == null) return null;
return item.GetComponent<CustomInterface>();
}
public static Fabricator GetFabricatorComponent(Item item)
{
if (item == null) return null;
return item.GetComponent<Fabricator>();
}
public static Holdable GetHoldableComponent(Item item)
{
if (item == null) return null;
return item.GetComponent<Holdable>();
}
public static void ExecuteCommand(string command)
{
DebugConsole.ExecuteCommand(command);
}
public static Signal CreateSignal(string value, int stepsTaken = 1, Character sender = null, Item source = null, float power = 0, float strength = 1)
{
return new Signal(value, stepsTaken, sender, source, power, strength);
}
private List<DebugConsole.Command> luaAddedCommand = new List<DebugConsole.Command>();
public void RemoveCommand(string name)
{
for (var i = 0; i < DebugConsole.Commands.Count; i++)
{
foreach (var cmdname in DebugConsole.Commands[i].names)
{
if (cmdname == name)
{
luaAddedCommand.Remove(DebugConsole.Commands[i]);
DebugConsole.Commands.RemoveAt(i);
continue;
}
}
}
}
public void AddCommand(string name, string help, LuaCsAction onExecute, LuaCsFunc getValidArgs = null, bool isCheat = false)
{
var cmd = new DebugConsole.Command(name, help, (string[] arg1) => onExecute(new object[] { arg1 }),
() =>
{
if (getValidArgs == null) return null;
var validArgs = getValidArgs(); var validArgs = getValidArgs();
if (validArgs is DynValue luaValue) if (validArgs is DynValue luaValue)
{ {
@@ -419,96 +419,96 @@ namespace Barotrauma
return (string[][])validArgs; return (string[][])validArgs;
}, isCheat); }, isCheat);
luaAddedCommand.Add(cmd); luaAddedCommand.Add(cmd);
DebugConsole.Commands.Add(cmd); DebugConsole.Commands.Add(cmd);
}
public List<DebugConsole.Command> Commands => DebugConsole.Commands;
public void AssignOnExecute(string names, object onExecute) => DebugConsole.AssignOnExecute(names, (string[] a) => { GameMain.LuaCs.CallLuaFunction(onExecute, new object[] { a }); });
public void SaveGame(string path)
{
if (!LuaCsFile.CanWriteToPath(path)) { throw new ScriptRuntimeException($"Saving files to {path} is disallowed."); }
SaveUtil.SaveGame(path);
} }
public void LoadGame(string path) public List<DebugConsole.Command> Commands => DebugConsole.Commands;
{
SaveUtil.LoadGame(path); public void AssignOnExecute(string names, object onExecute) => DebugConsole.AssignOnExecute(names, (string[] a) => { GameMain.LuaCs.CallLuaFunction(onExecute, new object[] { a }); });
}
public void SaveGame(string path)
{
if (!LuaCsFile.CanWriteToPath(path)) { throw new ScriptRuntimeException($"Saving files to {path} is disallowed."); }
SaveUtil.SaveGame(path);
}
public void LoadGame(string path)
{
SaveUtil.LoadGame(path);
}
#if SERVER #if SERVER
public void LoadCampaign(string path) public void LoadCampaign(string path)
{ {
MultiPlayerCampaign.LoadCampaign(path); MultiPlayerCampaign.LoadCampaign(path);
} }
public static void SendMessage(string msg, ChatMessageType? messageType = null, Client sender = null, Character character = null) public static void SendMessage(string msg, ChatMessageType? messageType = null, Client sender = null, Character character = null)
{ {
GameMain.Server.SendChatMessage(msg, messageType, sender, character); GameMain.Server.SendChatMessage(msg, messageType, sender, character);
} }
public static void SendMessage(string msg, int messageType, Client sender = null, Character character = null) public static void SendMessage(string msg, int messageType, Client sender = null, Character character = null)
{ {
GameMain.Server.SendChatMessage(msg, (ChatMessageType)messageType, sender, character); GameMain.Server.SendChatMessage(msg, (ChatMessageType)messageType, sender, character);
} }
public static void SendTraitorMessage(Client client, string msg, Identifier missionid, TraitorMessageType type) public static void SendTraitorMessage(Client client, string msg, Identifier missionid, TraitorMessageType type)
{ {
GameMain.Server.SendTraitorMessage(client, msg, missionid, type); GameMain.Server.SendTraitorMessage(client, msg, missionid, type);
} }
public static void SendDirectChatMessage(string sendername, string text, Character sender, ChatMessageType messageType = ChatMessageType.Private, Client client = null, string iconStyle = "") public static void SendDirectChatMessage(string sendername, string text, Character sender, ChatMessageType messageType = ChatMessageType.Private, Client client = null, string iconStyle = "")
{ {
ChatMessage cm = ChatMessage.Create(sendername, text, messageType, sender, client); ChatMessage cm = ChatMessage.Create(sendername, text, messageType, sender, client);
cm.IconStyle = iconStyle; cm.IconStyle = iconStyle;
GameMain.Server.SendDirectChatMessage(cm, client); GameMain.Server.SendDirectChatMessage(cm, client);
} }
public static void SendDirectChatMessage(ChatMessage chatMessage, Client client) public static void SendDirectChatMessage(ChatMessage chatMessage, Client client)
{ {
GameMain.Server.SendDirectChatMessage(chatMessage, client); GameMain.Server.SendDirectChatMessage(chatMessage, client);
} }
public static void Log(string message, ServerLog.MessageType type) public static void Log(string message, ServerLog.MessageType type)
{ {
GameServer.Log(message, type); GameServer.Log(message, type);
} }
public static void DispatchRespawnSub() public static void DispatchRespawnSub()
{ {
GameMain.Server.RespawnManager.DispatchShuttle(); GameMain.Server.RespawnManager.DispatchShuttle();
} }
public static void StartGame() public static void StartGame()
{ {
GameMain.Server.StartGame(); GameMain.Server.StartGame();
} }
public static void EndGame() public static void EndGame()
{ {
GameMain.Server.EndGame(); GameMain.Server.EndGame();
} }
public void AssignOnClientRequestExecute(string names, object onExecute) => DebugConsole.AssignOnClientRequestExecute(names, (Client a, Vector2 b, string[] c) => { GameMain.LuaCs.CallLuaFunction(onExecute, new object[] { a, b, c }); }); public void AssignOnClientRequestExecute(string names, object onExecute) => DebugConsole.AssignOnClientRequestExecute(names, (Client a, Vector2 b, string[] c) => { GameMain.LuaCs.CallLuaFunction(onExecute, new object[] { a, b, c }); });
#endif #endif
public void Stop() public void Stop()
{ {
mapEntityUpdateInterval = 1; mapEntityUpdateInterval = 1;
gapUpdateInterval = 4; gapUpdateInterval = 4;
characterUpdateInterval = 1; characterUpdateInterval = 1;
foreach (var cmd in luaAddedCommand) foreach (var cmd in luaAddedCommand)
{ {
DebugConsole.Commands.Remove(cmd); DebugConsole.Commands.Remove(cmd);
} }
} }
} }
} }
@@ -7,265 +7,265 @@ using MoonSharp.Interpreter.Interop;
namespace Barotrauma namespace Barotrauma
{ {
partial class LuaUserData partial class LuaUserData
{ {
public static Type GetType(string typeName) public static Type GetType(string typeName)
{ {
if (typeName == null || typeName.Length == 0) return null; if (typeName == null || typeName.Length == 0) return null;
var byRef = false; var byRef = false;
if (typeName.StartsWith("out ") || typeName.StartsWith("ref ")) if (typeName.StartsWith("out ") || typeName.StartsWith("ref "))
{ {
typeName = typeName.Remove(0, 4); typeName = typeName.Remove(0, 4);
byRef = true; byRef = true;
} }
var type = Type.GetType(typeName); var type = Type.GetType(typeName);
if (type != null) return byRef ? type.MakeByRefType() : type; if (type != null) return byRef ? type.MakeByRefType() : type;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{ {
if (CsScriptBase.LoadedAssemblyName.Contains(a.GetName().Name)) if (CsScriptBase.LoadedAssemblyName.Contains(a.GetName().Name))
{ {
var attrs = a.GetCustomAttributes<AssemblyMetadataAttribute>(); var attrs = a.GetCustomAttributes<AssemblyMetadataAttribute>();
var revision = attrs.FirstOrDefault(attr => attr.Key == "Revision")?.Value; var revision = attrs.FirstOrDefault(attr => attr.Key == "Revision")?.Value;
if (revision != null && int.Parse(revision) != (int)CsScriptBase.Revision[a.GetName().Name]) { continue; } 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 byRef ? type.MakeByRefType() : type; return byRef ? type.MakeByRefType() : type;
} }
} }
return null; return null;
} }
public static IUserDataDescriptor RegisterType(string typeName) public static IUserDataDescriptor RegisterType(string typeName)
{
Type type = GetType(typeName);
if (type == null)
{
throw new ScriptRuntimeException($"Tried to register a type that doesn't exist: {typeName}.");
}
return UserData.RegisterType(type);
}
public static void UnregisterType(string typeName, bool deleteHistory = false)
{
Type type = GetType(typeName);
if (type == null)
{
throw new ScriptRuntimeException($"Tried to unregister a type that doesn't exist: {typeName}.");
}
UserData.UnregisterType(type, deleteHistory);
}
public static IUserDataDescriptor RegisterGenericType(string typeName, params string[] typeNameArguements)
{
Type type = GetType(typeName);
Type[] typeArguements = typeNameArguements.Select(x => GetType(x)).ToArray();
Type genericType = type.MakeGenericType(typeArguements);
return UserData.RegisterType(genericType);
}
public static void UnregisterGenericType(string typeName, params string[] typeNameArguements)
{
Type type = GetType(typeName);
Type[] typeArguements = typeNameArguements.Select(x => GetType(x)).ToArray();
Type genericType = type.MakeGenericType(typeArguements);
UserData.UnregisterType(genericType);
}
private static bool IsType<T>(object obj) { return obj is T; }
public static bool IsTargetType(object obj, string typeName)
{
var type = GetType(typeName);
MethodInfo method = typeof(LuaUserData).GetMethod(nameof(IsType), BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo generic = method.MakeGenericMethod(type);
return (bool)generic.Invoke(null, new object[] { obj });
}
public static object CreateStatic(string typeName)
{
Type type = GetType(typeName);
if (type == null)
{
throw new ScriptRuntimeException($"Tried to create a static userdata of a type that doesn't exist: {typeName}.");
}
MethodInfo method = typeof(UserData).GetMethod(nameof(UserData.CreateStatic), 1, new Type[0]);
MethodInfo generic = method.MakeGenericMethod(type);
return generic.Invoke(null, null);
}
public static object CreateEnumTable(string typeName)
{ {
Type type = GetType(typeName); Type type = GetType(typeName);
if (type == null) if (type == null)
{
throw new ScriptRuntimeException($"Tried to create an enum table with a type that doesn't exist:: {typeName}.");
}
Dictionary<string, object> result = new Dictionary<string, object>();
foreach (var value in Enum.GetValues(type))
{ {
string name = Enum.GetName(type, value); throw new ScriptRuntimeException($"Tried to register a type that doesn't exist: {typeName}.");
result[name] = value;
} }
return result; return UserData.RegisterType(type);
} }
private static FieldInfo FindFieldRecursively(Type type, string fieldName) public static void UnregisterType(string typeName, bool deleteHistory = false)
{ {
var field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); Type type = GetType(typeName);
if (field == null && type.BaseType != null) if (type == null)
{ {
return FindFieldRecursively(type.BaseType, fieldName); throw new ScriptRuntimeException($"Tried to unregister a type that doesn't exist: {typeName}.");
} }
return field; UserData.UnregisterType(type, deleteHistory);
} }
public static IUserDataDescriptor RegisterGenericType(string typeName, params string[] typeNameArguements)
{
Type type = GetType(typeName);
Type[] typeArguements = typeNameArguements.Select(x => GetType(x)).ToArray();
Type genericType = type.MakeGenericType(typeArguements);
return UserData.RegisterType(genericType);
}
public static void MakeFieldAccessible(IUserDataDescriptor IUUD, string fieldName) public static void UnregisterGenericType(string typeName, params string[] typeNameArguements)
{ {
if (IUUD == null) Type type = GetType(typeName);
{ Type[] typeArguements = typeNameArguements.Select(x => GetType(x)).ToArray();
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to make {fieldName} accessible."); Type genericType = type.MakeGenericType(typeArguements);
} UserData.UnregisterType(genericType);
}
var descriptor = (StandardUserDataDescriptor)IUUD; private static bool IsType<T>(object obj) { return obj is T; }
var field = IUUD.Type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (field == null) public static bool IsTargetType(object obj, string typeName)
{
var type = GetType(typeName);
MethodInfo method = typeof(LuaUserData).GetMethod(nameof(IsType), BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo generic = method.MakeGenericMethod(type);
return (bool)generic.Invoke(null, new object[] { obj });
}
public static object CreateStatic(string typeName)
{
Type type = GetType(typeName);
if (type == null)
{ {
field = FindFieldRecursively(IUUD.Type, fieldName); throw new ScriptRuntimeException($"Tried to create a static userdata of a type that doesn't exist: {typeName}.");
} }
if (field == null) MethodInfo method = typeof(UserData).GetMethod(nameof(UserData.CreateStatic), 1, new Type[0]);
{ MethodInfo generic = method.MakeGenericMethod(type);
throw new ScriptRuntimeException($"Tried to make field '{fieldName}' accessible, but the field doesn't exist."); return generic.Invoke(null, null);
} }
descriptor.RemoveMember(fieldName); public static object CreateEnumTable(string typeName)
descriptor.AddMember(fieldName, new FieldMemberDescriptor(field, InteropAccessMode.Default)); {
} Type type = GetType(typeName);
private static MethodInfo FindMethodRecursively(Type type, string methodName) if (type == null)
{ {
var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); throw new ScriptRuntimeException($"Tried to create an enum table with a type that doesn't exist:: {typeName}.");
}
if (method == null && type.BaseType != null) Dictionary<string, object> result = new Dictionary<string, object>();
{
return FindMethodRecursively(type.BaseType, methodName);
}
return method; foreach (var value in Enum.GetValues(type))
} {
string name = Enum.GetName(type, value);
public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName) result[name] = value;
{ }
if (IUUD == null)
{
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to make {methodName} accessible.");
}
var descriptor = (StandardUserDataDescriptor)IUUD; return result;
var method = IUUD.Type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); }
if (method == null) private static FieldInfo FindFieldRecursively(Type type, string fieldName)
{ {
method = FindMethodRecursively(IUUD.Type, methodName); var field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
}
if (method == null) if (field == null && type.BaseType != null)
{ {
throw new ScriptRuntimeException($"Tried to make method '{methodName}' accessible, but the method doesn't exist."); return FindFieldRecursively(type.BaseType, fieldName);
} }
descriptor.RemoveMember(methodName); return field;
descriptor.AddMember(methodName, new MethodMemberDescriptor(method, InteropAccessMode.Default)); }
}
public static void AddMethod(IUserDataDescriptor IUUD, string methodName, object function) public static void MakeFieldAccessible(IUserDataDescriptor IUUD, string fieldName)
{ {
if (IUUD == null) if (IUUD == null)
{ {
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to add method {methodName}."); throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to make {fieldName} accessible.");
} }
var descriptor = (StandardUserDataDescriptor)IUUD; var descriptor = (StandardUserDataDescriptor)IUUD;
var field = IUUD.Type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
descriptor.RemoveMember(methodName); if (field == null)
descriptor.AddMember(methodName, new ObjectCallbackMemberDescriptor(methodName, (object arg1, ScriptExecutionContext arg2, CallbackArguments arg3) => {
{ field = FindFieldRecursively(IUUD.Type, fieldName);
if (GameMain.LuaCs != null) }
return GameMain.LuaCs.CallLuaFunction(function, arg3.GetArray());
return null;
}));
}
public static void AddField(IUserDataDescriptor IUUD, string fieldName, DynValue value) if (field == null)
{ {
if (IUUD == null) throw new ScriptRuntimeException($"Tried to make field '{fieldName}' accessible, but the field doesn't exist.");
{ }
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to add field {fieldName}.");
}
var descriptor = (StandardUserDataDescriptor)IUUD; descriptor.RemoveMember(fieldName);
descriptor.RemoveMember(fieldName); descriptor.AddMember(fieldName, new FieldMemberDescriptor(field, InteropAccessMode.Default));
descriptor.AddMember(fieldName, new DynValueMemberDescriptor(fieldName, value)); }
}
public static void RemoveMember(IUserDataDescriptor IUUD, string memberName) private static MethodInfo FindMethodRecursively(Type type, string methodName)
{ {
if (IUUD == null) var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
{
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to remove the member {memberName}.");
}
var descriptor = (StandardUserDataDescriptor)IUUD; if (method == null && type.BaseType != null)
descriptor.RemoveMember(memberName); {
} return FindMethodRecursively(type.BaseType, methodName);
}
/// <summary> return method;
/// See <see cref="CreateUserDataFromType"/>. }
/// </summary>
/// <param name="scriptObject">Lua value to convert and wrap in a userdata.</param>
/// <param name="desiredTypeDescriptor">Descriptor of the type of the object to convert the Lua value to. Uses MoonSharp ScriptToClr converters.</param>
/// <returns>A userdata that wraps the Lua value converted to an object of the desired type as described by <paramref name="desiredTypeDescriptor"/>.</returns>
public static DynValue CreateUserDataFromDescriptor(DynValue scriptObject, IUserDataDescriptor desiredTypeDescriptor)
{
return UserData.Create(scriptObject.ToObject(desiredTypeDescriptor.Type), desiredTypeDescriptor);
}
/// <summary> public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName)
/// Converts a Lua value to a CLR object of a desired type and wraps it in a userdata. {
/// If the type is not registered, then a new <see cref="MoonSharp.Interpreter.Interop.StandardUserDataDescriptor"/> will be created and used. if (IUUD == null)
/// The goal of this method is to allow Lua scripts to create userdata to wrap certain data without having to register types. {
/// <remarks>Wrapping the value in a userdata preserves the original type during script-to-CLR conversions.</remarks> throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to make {methodName} accessible.");
/// <example>A Lua script needs to pass a List`1 to a CLR method expecting System.Object, MoonSharp gets }
/// in the way by converting the List`1 to a MoonSharp.Interpreter.Table and breaking everything.
/// Registering the List`1 type can break other scripts relying on default converters, so instead var descriptor = (StandardUserDataDescriptor)IUUD;
/// it is better to manually wrap the List`1 object into a userdata. var method = IUUD.Type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
/// </example>
/// </summary> if (method == null)
/// <param name="scriptObject">Lua value to convert and wrap in a userdata.</param> {
/// <param name="desiredType">Type describing the CLR type of the object to convert the Lua value to.</param> method = FindMethodRecursively(IUUD.Type, methodName);
/// <returns>A userdata that wraps the Lua value converted to an object of the desired type.</returns> }
public static DynValue CreateUserDataFromType(DynValue scriptObject, Type desiredType)
{ if (method == null)
IUserDataDescriptor descriptor = UserData.GetDescriptorForType(desiredType, true); {
descriptor ??= new StandardUserDataDescriptor(desiredType, InteropAccessMode.Default); throw new ScriptRuntimeException($"Tried to make method '{methodName}' accessible, but the method doesn't exist.");
return CreateUserDataFromDescriptor(scriptObject, descriptor); }
}
} descriptor.RemoveMember(methodName);
descriptor.AddMember(methodName, new MethodMemberDescriptor(method, InteropAccessMode.Default));
}
public static void AddMethod(IUserDataDescriptor IUUD, string methodName, object function)
{
if (IUUD == null)
{
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to add method {methodName}.");
}
var descriptor = (StandardUserDataDescriptor)IUUD;
descriptor.RemoveMember(methodName);
descriptor.AddMember(methodName, new ObjectCallbackMemberDescriptor(methodName, (object arg1, ScriptExecutionContext arg2, CallbackArguments arg3) =>
{
if (GameMain.LuaCs != null)
return GameMain.LuaCs.CallLuaFunction(function, arg3.GetArray());
return null;
}));
}
public static void AddField(IUserDataDescriptor IUUD, string fieldName, DynValue value)
{
if (IUUD == null)
{
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to add field {fieldName}.");
}
var descriptor = (StandardUserDataDescriptor)IUUD;
descriptor.RemoveMember(fieldName);
descriptor.AddMember(fieldName, new DynValueMemberDescriptor(fieldName, value));
}
public static void RemoveMember(IUserDataDescriptor IUUD, string memberName)
{
if (IUUD == null)
{
throw new ScriptRuntimeException($"Tried to use a UserDataDescriptor that is null to remove the member {memberName}.");
}
var descriptor = (StandardUserDataDescriptor)IUUD;
descriptor.RemoveMember(memberName);
}
/// <summary>
/// See <see cref="CreateUserDataFromType"/>.
/// </summary>
/// <param name="scriptObject">Lua value to convert and wrap in a userdata.</param>
/// <param name="desiredTypeDescriptor">Descriptor of the type of the object to convert the Lua value to. Uses MoonSharp ScriptToClr converters.</param>
/// <returns>A userdata that wraps the Lua value converted to an object of the desired type as described by <paramref name="desiredTypeDescriptor"/>.</returns>
public static DynValue CreateUserDataFromDescriptor(DynValue scriptObject, IUserDataDescriptor desiredTypeDescriptor)
{
return UserData.Create(scriptObject.ToObject(desiredTypeDescriptor.Type), desiredTypeDescriptor);
}
/// <summary>
/// Converts a Lua value to a CLR object of a desired type and wraps it in a userdata.
/// If the type is not registered, then a new <see cref="MoonSharp.Interpreter.Interop.StandardUserDataDescriptor"/> will be created and used.
/// The goal of this method is to allow Lua scripts to create userdata to wrap certain data without having to register types.
/// <remarks>Wrapping the value in a userdata preserves the original type during script-to-CLR conversions.</remarks>
/// <example>A Lua script needs to pass a List`1 to a CLR method expecting System.Object, MoonSharp gets
/// in the way by converting the List`1 to a MoonSharp.Interpreter.Table and breaking everything.
/// Registering the List`1 type can break other scripts relying on default converters, so instead
/// it is better to manually wrap the List`1 object into a userdata.
/// </example>
/// </summary>
/// <param name="scriptObject">Lua value to convert and wrap in a userdata.</param>
/// <param name="desiredType">Type describing the CLR type of the object to convert the Lua value to.</param>
/// <returns>A userdata that wraps the Lua value converted to an object of the desired type.</returns>
public static DynValue CreateUserDataFromType(DynValue scriptObject, Type desiredType)
{
IUserDataDescriptor descriptor = UserData.GetDescriptorForType(desiredType, true);
descriptor ??= new StandardUserDataDescriptor(desiredType, InteropAccessMode.Default);
return CreateUserDataFromDescriptor(scriptObject, descriptor);
}
}
} }
@@ -8,21 +8,21 @@ using System.Linq;
namespace Barotrauma namespace Barotrauma
{ {
class LuaScriptLoader : ScriptLoaderBase class LuaScriptLoader : ScriptLoaderBase
{ {
public override object LoadFile(string file, Table globalContext) public override object LoadFile(string file, Table globalContext)
{ {
if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return null; if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return null;
return File.ReadAllText(file); return File.ReadAllText(file);
} }
public override bool ScriptFileExists(string file) public override bool ScriptFileExists(string file)
{ {
if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return false; if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return false;
return File.Exists(file); return File.Exists(file);
} }
} }
} }
@@ -8,229 +8,229 @@ using LuaCsCompatPatchFunc = Barotrauma.LuaCsPatch;
namespace Barotrauma namespace Barotrauma
{ {
// XXX: this can't be renamed because of backward compatibility with C# mods // XXX: this can't be renamed because of backward compatibility with C# mods
public delegate object LuaCsPatch(object self, Dictionary<string, object> args); public delegate object LuaCsPatch(object self, Dictionary<string, object> args);
partial class LuaCsHook partial class LuaCsHook
{ {
private Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> compatHookPrefixMethods = new Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>>(); private Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> compatHookPrefixMethods = new Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>>();
private Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> compatHookPostfixMethods = new Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>>(); private Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> compatHookPostfixMethods = new Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>>();
private static void _hookLuaCsPatch(MethodBase __originalMethod, object[] __args, object __instance, out object result, HookMethodType hookType) private static void _hookLuaCsPatch(MethodBase __originalMethod, object[] __args, object __instance, out object result, HookMethodType hookType)
{ {
result = null; result = null;
try try
{ {
var funcAddr = ((long)__originalMethod.MethodHandle.GetFunctionPointer()); var funcAddr = ((long)__originalMethod.MethodHandle.GetFunctionPointer());
HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet = null; HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet = null;
switch (hookType) switch (hookType)
{ {
case HookMethodType.Before: case HookMethodType.Before:
instance.compatHookPrefixMethods.TryGetValue(funcAddr, out methodSet); instance.compatHookPrefixMethods.TryGetValue(funcAddr, out methodSet);
break; break;
case HookMethodType.After: case HookMethodType.After:
instance.compatHookPostfixMethods.TryGetValue(funcAddr, out methodSet); instance.compatHookPostfixMethods.TryGetValue(funcAddr, out methodSet);
break; break;
default: default:
throw new ArgumentException($"Invalid {nameof(HookMethodType)} enum value.", nameof(hookType)); throw new ArgumentException($"Invalid {nameof(HookMethodType)} enum value.", nameof(hookType));
} }
if (methodSet != null) if (methodSet != null)
{ {
var @params = __originalMethod.GetParameters(); var @params = __originalMethod.GetParameters();
var args = new Dictionary<string, object>(); var args = new Dictionary<string, object>();
for (int i = 0; i < @params.Length; i++) for (int i = 0; i < @params.Length; i++)
{ {
args.Add(@params[i].Name, __args[i]); args.Add(@params[i].Name, __args[i]);
} }
var outOfSocpe = new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>(); var outOfSocpe = new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>();
foreach (var tuple in methodSet) foreach (var tuple in methodSet)
{ {
if (tuple.Item3 != null && tuple.Item3.IsDisposed) if (tuple.Item3 != null && tuple.Item3.IsDisposed)
{ {
outOfSocpe.Add(tuple); outOfSocpe.Add(tuple);
} }
else else
{ {
var _result = tuple.Item2(__instance, args); var _result = tuple.Item2(__instance, args);
if (_result != null) if (_result != null)
{ {
if (_result is DynValue res) if (_result is DynValue res)
{ {
if (!res.IsNil()) if (!res.IsNil())
{ {
if (__originalMethod is MethodInfo mi && mi.ReturnType != typeof(void)) if (__originalMethod is MethodInfo mi && mi.ReturnType != typeof(void))
{ {
result = res.ToObject(mi.ReturnType); result = res.ToObject(mi.ReturnType);
} }
else else
{ {
result = res.ToObject(); result = res.ToObject();
} }
} }
} }
else else
{ {
result = _result; result = _result;
} }
} }
} }
} }
foreach (var tuple in outOfSocpe) { methodSet.Remove(tuple); } foreach (var tuple in outOfSocpe) { methodSet.Remove(tuple); }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
GameMain.LuaCs.PrintError($"Error in {__originalMethod.Name}:", LuaCsMessageOrigin.Unknown); GameMain.LuaCs.PrintError($"Error in {__originalMethod.Name}:", LuaCsMessageOrigin.Unknown);
GameMain.LuaCs.HandleException(ex, LuaCsMessageOrigin.Unknown); GameMain.LuaCs.HandleException(ex, LuaCsMessageOrigin.Unknown);
} }
} }
private static bool HookLuaCsPatchPrefix(MethodBase __originalMethod, object[] __args, object __instance) private static bool HookLuaCsPatchPrefix(MethodBase __originalMethod, object[] __args, object __instance)
{ {
_hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.Before); _hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.Before);
return result == null; return result == null;
} }
private static void HookLuaCsPatchPostfix(MethodBase __originalMethod, object[] __args, object __instance) => private static void HookLuaCsPatchPostfix(MethodBase __originalMethod, object[] __args, object __instance) =>
_hookLuaCsPatch(__originalMethod, __args, __instance, out object _, HookMethodType.After); _hookLuaCsPatch(__originalMethod, __args, __instance, out object _, HookMethodType.After);
private static bool HookLuaCsPatchRetPrefix(MethodBase __originalMethod, object[] __args, ref object __result, object __instance) private static bool HookLuaCsPatchRetPrefix(MethodBase __originalMethod, object[] __args, ref object __result, object __instance)
{ {
_hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.Before); _hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.Before);
if (result != null) if (result != null)
{ {
__result = result; __result = result;
return false; return false;
} }
else return true; else return true;
} }
private static void HookLuaCsPatchRetPostfix(MethodBase __originalMethod, object[] __args, ref object __result, object __instance) private static void HookLuaCsPatchRetPostfix(MethodBase __originalMethod, object[] __args, ref object __result, object __instance)
{ {
_hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.After); _hookLuaCsPatch(__originalMethod, __args, __instance, out object result, HookMethodType.After);
if (result != null) __result = result; if (result != null) __result = result;
} }
private static MethodInfo _miHookLuaCsPatchPrefix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchPrefix", BindingFlags.NonPublic | BindingFlags.Static); private static MethodInfo _miHookLuaCsPatchPrefix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchPrefix", BindingFlags.NonPublic | BindingFlags.Static);
private static MethodInfo _miHookLuaCsPatchPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchPostfix", BindingFlags.NonPublic | BindingFlags.Static); private static MethodInfo _miHookLuaCsPatchPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchPostfix", BindingFlags.NonPublic | BindingFlags.Static);
private static MethodInfo _miHookLuaCsPatchRetPrefix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static); private static MethodInfo _miHookLuaCsPatchRetPrefix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static);
private static MethodInfo _miHookLuaCsPatchRetPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static); private static MethodInfo _miHookLuaCsPatchRetPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static);
// TODO: deprecate this // TODO: deprecate this
public void HookMethod(string identifier, MethodBase method, LuaCsCompatPatchFunc patch, HookMethodType hookType = HookMethodType.Before, ACsMod owner = null) public void HookMethod(string identifier, MethodBase method, LuaCsCompatPatchFunc patch, HookMethodType hookType = HookMethodType.Before, ACsMod owner = null)
{ {
if (identifier == null || method == null || patch == null) if (identifier == null || method == null || patch == null)
{
luaCs.HandleException(new ArgumentNullException("Identifier, Method and Patch arguments must not be null."), LuaCsMessageOrigin.Unknown);
return;
}
ValidatePatchTarget(method);
var funcAddr = ((long)method.MethodHandle.GetFunctionPointer());
var patches = Harmony.GetPatchInfo(method);
if (hookType == HookMethodType.Before)
{
if (method is MethodInfo mi && mi.ReturnType != typeof(void))
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPrefix) == null)
{
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchRetPrefix));
}
}
else
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPrefix) == null)
{
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchPrefix));
}
}
if (compatHookPrefixMethods.TryGetValue(funcAddr, out HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet))
{
if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
methodSet.Add((identifier, patch, owner));
}
else if (patch != null)
{
compatHookPrefixMethods.Add(funcAddr, new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>() { (identifier, patch, owner) });
}
}
else if (hookType == HookMethodType.After)
{
if (method is MethodInfo mi && mi.ReturnType != typeof(void))
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPostfix) == null)
{
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchRetPostfix));
}
}
else
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPostfix) == null)
{
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchPostfix));
}
}
if (compatHookPostfixMethods.TryGetValue(funcAddr, out HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet))
{
if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
methodSet.Add((identifier, patch, owner));
}
else if (patch != null)
{
compatHookPostfixMethods.Add(funcAddr, new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>() { (identifier, patch, owner) });
}
}
}
protected void HookMethod(string identifier, string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before)
{
var method = ResolveMethod(className, methodName, parameterNames);
if (method == null) return;
if (method.GetParameters().Any(x => x.ParameterType.IsByRef))
{ {
throw new InvalidOperationException($"{nameof(HookMethod)} doesn't support ByRef parameters; use {nameof(Patch)} instead."); luaCs.HandleException(new ArgumentNullException("Identifier, Method and Patch arguments must not be null."), LuaCsMessageOrigin.Unknown);
return;
} }
HookMethod(identifier, method, patch, hookMethodType); ValidatePatchTarget(method);
}
protected void HookMethod(string identifier, string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) => var funcAddr = ((long)method.MethodHandle.GetFunctionPointer());
HookMethod(identifier, className, methodName, null, patch, hookMethodType); var patches = Harmony.GetPatchInfo(method);
protected void HookMethod(string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
HookMethod("", className, methodName, null, patch, hookMethodType); if (hookType == HookMethodType.Before)
protected void HookMethod(string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) => {
HookMethod("", className, methodName, parameterNames, patch, hookMethodType); if (method is MethodInfo mi && mi.ReturnType != typeof(void))
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPrefix) == null)
{
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchRetPrefix));
}
}
else
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPrefix) == null)
{
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchPrefix));
}
}
if (compatHookPrefixMethods.TryGetValue(funcAddr, out HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet))
{
if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
methodSet.Add((identifier, patch, owner));
}
else if (patch != null)
{
compatHookPrefixMethods.Add(funcAddr, new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>() { (identifier, patch, owner) });
}
}
else if (hookType == HookMethodType.After)
{
if (method is MethodInfo mi && mi.ReturnType != typeof(void))
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPostfix) == null)
{
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchRetPostfix));
}
}
else
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPostfix) == null)
{
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchPostfix));
}
}
if (compatHookPostfixMethods.TryGetValue(funcAddr, out HashSet<(string, LuaCsCompatPatchFunc, ACsMod)> methodSet))
{
if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
methodSet.Add((identifier, patch, owner));
}
else if (patch != null)
{
compatHookPostfixMethods.Add(funcAddr, new HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>() { (identifier, patch, owner) });
}
}
}
protected void HookMethod(string identifier, string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before)
{
var method = ResolveMethod(className, methodName, parameterNames);
if (method == null) return;
if (method.GetParameters().Any(x => x.ParameterType.IsByRef))
{
throw new InvalidOperationException($"{nameof(HookMethod)} doesn't support ByRef parameters; use {nameof(Patch)} instead.");
}
HookMethod(identifier, method, patch, hookMethodType);
}
protected void HookMethod(string identifier, string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
HookMethod(identifier, className, methodName, null, patch, hookMethodType);
protected void HookMethod(string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
HookMethod("", className, methodName, null, patch, hookMethodType);
protected void HookMethod(string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
HookMethod("", className, methodName, parameterNames, patch, hookMethodType);
public void UnhookMethod(string identifier, MethodBase method, HookMethodType hookType = HookMethodType.Before) public void UnhookMethod(string identifier, MethodBase method, HookMethodType hookType = HookMethodType.Before)
{ {
var funcAddr = (long)method.MethodHandle.GetFunctionPointer(); var funcAddr = (long)method.MethodHandle.GetFunctionPointer();
Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> methods; Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> methods;
if (hookType == HookMethodType.Before) methods = compatHookPrefixMethods; if (hookType == HookMethodType.Before) methods = compatHookPrefixMethods;
else if (hookType == HookMethodType.After) methods = compatHookPostfixMethods; else if (hookType == HookMethodType.After) methods = compatHookPostfixMethods;
else throw null; else throw null;
if (methods.ContainsKey(funcAddr)) methods[funcAddr]?.RemoveWhere(t => t.Item1 == identifier); if (methods.ContainsKey(funcAddr)) methods[funcAddr]?.RemoveWhere(t => t.Item1 == identifier);
} }
protected void UnhookMethod(string identifier, string className, string methodName, string[] parameterNames, HookMethodType hookType = HookMethodType.Before) protected void UnhookMethod(string identifier, string className, string methodName, string[] parameterNames, HookMethodType hookType = HookMethodType.Before)
{ {
var method = ResolveMethod(className, methodName, parameterNames); var method = ResolveMethod(className, methodName, parameterNames);
if (method == null) return; if (method == null) return;
UnhookMethod(identifier, method, hookType); UnhookMethod(identifier, method, hookType);
} }
} }
} }
@@ -11,286 +11,286 @@ using MoonSharp.Interpreter;
namespace Barotrauma namespace Barotrauma
{ {
partial class LuaCsNetworking partial class LuaCsNetworking
{ {
public class HttpListener public class HttpListener
{ {
private System.Net.HttpListener listener; private System.Net.HttpListener listener;
public HttpListener(System.Net.HttpListener list) public HttpListener(System.Net.HttpListener list)
{
listener = list;
}
public void Close()
{
listener.Close();
}
}
public class IncomingHttpRequest
{
private HttpListenerRequest request;
public IncomingHttpRequest(HttpListenerRequest req)
{ {
request = req; listener = list;
} }
public string ContentType => request.ContentType; public void Close()
public string LocalEndPoint => request.LocalEndPoint.ToString(); {
public string RemoteEndPoint => request.RemoteEndPoint.ToString(); listener.Close();
public string RawUrl => request.RawUrl; }
public Uri Url => request.Url; }
public string UserAgent => request.UserAgent;
public string UserHostName => request.UserHostName;
public string UserHostAddress => request.UserHostAddress;
public NameValueCollection Headers => request.Headers;
public string HttpMethod => request.HttpMethod;
}
public class IncomingHttpResponse public class IncomingHttpRequest
{ {
private HttpListenerResponse response; private HttpListenerRequest request;
public IncomingHttpResponse(HttpListenerResponse resp) public IncomingHttpRequest(HttpListenerRequest req)
{ {
response = resp; request = req;
}
response.ContentType = "text/html"; public string ContentType => request.ContentType;
} public string LocalEndPoint => request.LocalEndPoint.ToString();
public string RemoteEndPoint => request.RemoteEndPoint.ToString();
public string RawUrl => request.RawUrl;
public Uri Url => request.Url;
public string UserAgent => request.UserAgent;
public string UserHostName => request.UserHostName;
public string UserHostAddress => request.UserHostAddress;
public NameValueCollection Headers => request.Headers;
public string HttpMethod => request.HttpMethod;
}
public string ContentType public class IncomingHttpResponse
{
private HttpListenerResponse response;
public IncomingHttpResponse(HttpListenerResponse resp)
{
response = resp;
response.ContentType = "text/html";
}
public string ContentType
{ {
get { return response.ContentType; } get { return response.ContentType; }
set { response.ContentType = value; } set { response.ContentType = value; }
} }
public void Write(string text) public void Write(string text)
{ {
byte[] data = Encoding.UTF8.GetBytes(text); byte[] data = Encoding.UTF8.GetBytes(text);
response.ContentEncoding = Encoding.UTF8; response.ContentEncoding = Encoding.UTF8;
response.ContentLength64 = data.LongLength; response.ContentLength64 = data.LongLength;
response.OutputStream.Write(data, 0, data.Length); response.OutputStream.Write(data, 0, data.Length);
} }
} }
public bool RestrictMessageSize = true; public bool RestrictMessageSize = true;
public Dictionary<string, LuaCsAction> LuaCsNetReceives = new Dictionary<string, LuaCsAction>(); public Dictionary<string, LuaCsAction> LuaCsNetReceives = new Dictionary<string, LuaCsAction>();
#if SERVER #if SERVER
[MoonSharpHidden] [MoonSharpHidden]
public void NetMessageReceived(IReadMessage netMessage, ClientPacketHeader header, Client client = null) public void NetMessageReceived(IReadMessage netMessage, ClientPacketHeader header, Client client = null)
{
if (header == ClientPacketHeader.LUA_NET_MESSAGE)
{
string netMessageName = netMessage.ReadString();
if (LuaCsNetReceives.ContainsKey(netMessageName))
{
try
{
LuaCsNetReceives[netMessageName](netMessage, client);
}
catch (Exception e)
{
// TODO: make LuaCsNetworking hold a reference to LuaCsSetup instead of using this global
GameMain.LuaCs.PrintError($"Exception thrown inside NetMessageReceive({netMessageName})", LuaCsMessageOrigin.Unknown);
GameMain.LuaCs.HandleException(e, LuaCsMessageOrigin.Unknown);
}
}
}
else
{
GameMain.LuaCs.Hook.Call("netMessageReceived", netMessage, header, client);
}
}
#else
[MoonSharpHidden]
public void NetMessageReceived(IReadMessage netMessage, ServerPacketHeader header, Client client = null)
{
if (header == ServerPacketHeader.LUA_NET_MESSAGE)
{
string netMessageName = netMessage.ReadString();
if (LuaCsNetReceives.ContainsKey(netMessageName))
{
try
{
LuaCsNetReceives[netMessageName](netMessage, client);
}
catch (Exception e)
{
GameMain.LuaCs.PrintError($"Exception thrown inside NetMessageReceive({netMessageName})", LuaCsMessageOrigin.Unknown);
GameMain.LuaCs.HandleException(e, LuaCsMessageOrigin.Unknown);
}
}
}
else
{
GameMain.LuaCs.Hook.Call("netMessageReceived", netMessage, header, client);
}
}
#endif
public void Receive(string netMessageName, LuaCsAction callback)
{
LuaCsNetReceives[netMessageName] = callback;
}
public IWriteMessage Start(string netMessageName)
{
var message = new WriteOnlyMessage();
#if SERVER
message.WriteByte((byte)ServerPacketHeader.LUA_NET_MESSAGE);
#else
message.WriteByte((byte)ClientPacketHeader.LUA_NET_MESSAGE);
#endif
message.WriteString(netMessageName);
return message;
}
public IWriteMessage Start()
{
return new WriteOnlyMessage();
}
#if SERVER
public void ClientWriteLobby(Client client) => GameMain.Server.ClientWriteLobby(client);
public void Send(IWriteMessage netMessage, NetworkConnection connection = null, DeliveryMethod deliveryMethod = DeliveryMethod.Reliable)
{
if (connection == null)
{
foreach (NetworkConnection conn in Client.ClientList.Select(c => c.Connection))
{
GameMain.Server.ServerPeer.Send(netMessage, conn, deliveryMethod);
}
}
else
{
GameMain.Server.ServerPeer.Send(netMessage, connection, deliveryMethod);
}
}
#else
public void Send(IWriteMessage netMessage, DeliveryMethod deliveryMethod = DeliveryMethod.Reliable)
{
GameMain.Client.ClientPeer.Send(netMessage, deliveryMethod);
}
#endif
public void HttpRequest(string url, LuaCsAction callback, string data = null, string method = "POST", string contentType = "application/json")
{
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = contentType;
httpWebRequest.Method = method;
if (data != null)
{
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
streamWriter.Write(data);
}
httpWebRequest.BeginGetResponse(new AsyncCallback((IAsyncResult result) =>
{
try
{
var httpResponse = httpWebRequest.EndGetResponse(result);
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
string responseResult = streamReader.ReadToEnd();
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(responseResult); }, 0);
}
}
catch (Exception e)
{
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(e.Message); }, 0);
}
}), null);
}
catch (Exception e)
{
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(e.Message); }, 0);
}
}
public void HttpPost(string url, LuaCsAction callback, string data, string contentType = "application/json")
{ {
HttpRequest(url, callback, data, "POST", contentType); if (header == ClientPacketHeader.LUA_NET_MESSAGE)
} {
string netMessageName = netMessage.ReadString();
if (LuaCsNetReceives.ContainsKey(netMessageName))
{
try
{
LuaCsNetReceives[netMessageName](netMessage, client);
}
catch (Exception e)
{
// TODO: make LuaCsNetworking hold a reference to LuaCsSetup instead of using this global
GameMain.LuaCs.PrintError($"Exception thrown inside NetMessageReceive({netMessageName})", LuaCsMessageOrigin.Unknown);
GameMain.LuaCs.HandleException(e, LuaCsMessageOrigin.Unknown);
}
}
}
else
{
GameMain.LuaCs.Hook.Call("netMessageReceived", netMessage, header, client);
}
}
#else
[MoonSharpHidden]
public void NetMessageReceived(IReadMessage netMessage, ServerPacketHeader header, Client client = null)
{
if (header == ServerPacketHeader.LUA_NET_MESSAGE)
{
string netMessageName = netMessage.ReadString();
if (LuaCsNetReceives.ContainsKey(netMessageName))
{
try
{
LuaCsNetReceives[netMessageName](netMessage, client);
}
catch (Exception e)
{
GameMain.LuaCs.PrintError($"Exception thrown inside NetMessageReceive({netMessageName})", LuaCsMessageOrigin.Unknown);
GameMain.LuaCs.HandleException(e, LuaCsMessageOrigin.Unknown);
}
}
}
else
{
GameMain.LuaCs.Hook.Call("netMessageReceived", netMessage, header, client);
}
}
#endif
public void Receive(string netMessageName, LuaCsAction callback)
{
LuaCsNetReceives[netMessageName] = callback;
}
public IWriteMessage Start(string netMessageName)
{
var message = new WriteOnlyMessage();
#if SERVER
message.WriteByte((byte)ServerPacketHeader.LUA_NET_MESSAGE);
#else
message.WriteByte((byte)ClientPacketHeader.LUA_NET_MESSAGE);
#endif
message.WriteString(netMessageName);
return message;
}
public IWriteMessage Start()
{
return new WriteOnlyMessage();
}
#if SERVER
public void ClientWriteLobby(Client client) => GameMain.Server.ClientWriteLobby(client);
public void Send(IWriteMessage netMessage, NetworkConnection connection = null, DeliveryMethod deliveryMethod = DeliveryMethod.Reliable)
{
if (connection == null)
{
foreach (NetworkConnection conn in Client.ClientList.Select(c => c.Connection))
{
GameMain.Server.ServerPeer.Send(netMessage, conn, deliveryMethod);
}
}
else
{
GameMain.Server.ServerPeer.Send(netMessage, connection, deliveryMethod);
}
}
#else
public void Send(IWriteMessage netMessage, DeliveryMethod deliveryMethod = DeliveryMethod.Reliable)
{
GameMain.Client.ClientPeer.Send(netMessage, deliveryMethod);
}
#endif
public void HttpRequest(string url, LuaCsAction callback, string data = null, string method = "POST", string contentType = "application/json")
{
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = contentType;
httpWebRequest.Method = method;
if (data != null)
{
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
streamWriter.Write(data);
}
httpWebRequest.BeginGetResponse(new AsyncCallback((IAsyncResult result) =>
{
try
{
var httpResponse = httpWebRequest.EndGetResponse(result);
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
string responseResult = streamReader.ReadToEnd();
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(responseResult); }, 0);
}
}
catch (Exception e)
{
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(e.Message); }, 0);
}
}), null);
}
catch (Exception e)
{
GameMain.LuaCs.Timer.Wait((object[] par) => { callback(e.Message); }, 0);
}
}
public void HttpPost(string url, LuaCsAction callback, string data, string contentType = "application/json")
{
HttpRequest(url, callback, data, "POST", contentType);
}
public void HttpGet(string url, LuaCsAction callback) public void HttpGet(string url, LuaCsAction callback)
{ {
HttpRequest(url, callback, null, "GET"); HttpRequest(url, callback, null, "GET");
} }
public static async void HandleIncomingConnections(System.Net.HttpListener listener, LuaCsAction onRequestReceived) public static async void HandleIncomingConnections(System.Net.HttpListener listener, LuaCsAction onRequestReceived)
{ {
try try
{ {
while (listener.IsListening) while (listener.IsListening)
{ {
HttpListenerContext ctx = await listener.GetContextAsync(); HttpListenerContext ctx = await listener.GetContextAsync();
IncomingHttpRequest req = new IncomingHttpRequest(ctx.Request); IncomingHttpRequest req = new IncomingHttpRequest(ctx.Request);
IncomingHttpResponse resp = new IncomingHttpResponse(ctx.Response); IncomingHttpResponse resp = new IncomingHttpResponse(ctx.Response);
onRequestReceived(req, resp); onRequestReceived(req, resp);
ctx.Response.Close(); ctx.Response.Close();
} }
} }
catch (Exception) catch (Exception)
{ {
} }
} }
public LuaCsNetworking.HttpListener StartHttpServer(string address, LuaCsAction onRequestReceived) public LuaCsNetworking.HttpListener StartHttpServer(string address, LuaCsAction onRequestReceived)
{ {
var listener = new System.Net.HttpListener(); var listener = new System.Net.HttpListener();
listener.Prefixes.Add(address); listener.Prefixes.Add(address);
listener.Start(); listener.Start();
HandleIncomingConnections(listener, onRequestReceived); HandleIncomingConnections(listener, onRequestReceived);
return new LuaCsNetworking.HttpListener(listener); return new LuaCsNetworking.HttpListener(listener);
} }
public void CreateEntityEvent(INetSerializable entity, NetEntityEvent.IData extraData) public void CreateEntityEvent(INetSerializable entity, NetEntityEvent.IData extraData)
{ {
GameMain.NetworkMember.CreateEntityEvent(entity, extraData); GameMain.NetworkMember.CreateEntityEvent(entity, extraData);
} }
#if SERVER #if SERVER
public void UpdateClientPermissions(Client client) public void UpdateClientPermissions(Client client)
{ {
GameMain.Server.UpdateClientPermissions(client); GameMain.Server.UpdateClientPermissions(client);
} }
public void RemovePendingClient(ServerPeer.PendingClient pendingClient, PeerDisconnectPacket peerDisconnectPacket) public void RemovePendingClient(ServerPeer.PendingClient pendingClient, PeerDisconnectPacket peerDisconnectPacket)
{ {
GameMain.Server.ServerPeer.RemovePendingClient(pendingClient, peerDisconnectPacket); GameMain.Server.ServerPeer.RemovePendingClient(pendingClient, peerDisconnectPacket);
} }
public int FileSenderMaxPacketsPerUpdate public int FileSenderMaxPacketsPerUpdate
{ {
get { return FileSender.FileTransferOut.MaxPacketsPerUpdate; } get { return FileSender.FileTransferOut.MaxPacketsPerUpdate; }
set { FileSender.FileTransferOut.MaxPacketsPerUpdate = value; } set { FileSender.FileTransferOut.MaxPacketsPerUpdate = value; }
} }
#endif #endif
public ushort LastClientListUpdateID public ushort LastClientListUpdateID
{ {
get { return GameMain.NetworkMember.LastClientListUpdateID; } get { return GameMain.NetworkMember.LastClientListUpdateID; }
set { GameMain.NetworkMember.LastClientListUpdateID = value; } set { GameMain.NetworkMember.LastClientListUpdateID = value; }
} }
} }
} }
@@ -1,4 +1,4 @@
using Steamworks; using Steamworks;
using Steamworks.Data; using Steamworks.Data;
using Barotrauma.Steam; using Barotrauma.Steam;
using System.Threading; using System.Threading;
@@ -10,8 +10,8 @@ using System;
namespace Barotrauma namespace Barotrauma
{ {
partial class LuaCsSteam partial class LuaCsSteam
{ {
private struct WorkshopItemDownload private struct WorkshopItemDownload
{ {
public ulong ID; public ulong ID;
@@ -54,7 +54,7 @@ namespace Barotrauma
{ {
itemsBeingDownloaded.Add(download); itemsBeingDownloaded.Add(download);
} }
} }
public void DownloadWorkshopItem(ulong id, string destination, LuaCsAction callback) public void DownloadWorkshopItem(ulong id, string destination, LuaCsAction callback)
@@ -13,47 +13,47 @@ using System.Xml.Linq;
namespace Barotrauma namespace Barotrauma
{ {
partial class LuaCsFile partial class LuaCsFile
{ {
public static bool CanReadFromPath(string path) public static bool CanReadFromPath(string path)
{ {
string getFullPath(string p) => System.IO.Path.GetFullPath(p).CleanUpPath(); string getFullPath(string p) => System.IO.Path.GetFullPath(p).CleanUpPath();
path = getFullPath(path); path = getFullPath(path);
bool pathStartsWith(string prefix) => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); bool pathStartsWith(string prefix) => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
string localModsDir = getFullPath(ContentPackage.LocalModsDir); string localModsDir = getFullPath(ContentPackage.LocalModsDir);
string workshopModsDir = getFullPath(ContentPackage.WorkshopModsDir); string workshopModsDir = getFullPath(ContentPackage.WorkshopModsDir);
#if CLIENT #if CLIENT
string tempDownloadDir = getFullPath(ModReceiver.DownloadFolder); string tempDownloadDir = getFullPath(ModReceiver.DownloadFolder);
#endif #endif
if (pathStartsWith(localModsDir)) if (pathStartsWith(localModsDir))
return true; return true;
if (pathStartsWith(workshopModsDir)) if (pathStartsWith(workshopModsDir))
return true; return true;
#if CLIENT #if CLIENT
if (pathStartsWith(tempDownloadDir)) if (pathStartsWith(tempDownloadDir))
return true; return true;
#endif #endif
if (pathStartsWith(getFullPath("."))) if (pathStartsWith(getFullPath(".")))
return true; return true;
return false; return false;
} }
public static bool CanWriteToPath(string path) public static bool CanWriteToPath(string path)
{ {
string getFullPath(string p) => System.IO.Path.GetFullPath(p).CleanUpPath(); string getFullPath(string p) => System.IO.Path.GetFullPath(p).CleanUpPath();
path = getFullPath(path); path = getFullPath(path);
bool pathStartsWith(string prefix) => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); bool pathStartsWith(string prefix) => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
foreach (var package in ContentPackageManager.AllPackages) foreach (var package in ContentPackageManager.AllPackages)
{ {
@@ -67,451 +67,451 @@ namespace Barotrauma
return true; return true;
if (pathStartsWith(getFullPath(ContentPackage.LocalModsDir))) if (pathStartsWith(getFullPath(ContentPackage.LocalModsDir)))
return true; return true;
if (pathStartsWith(getFullPath(ContentPackage.WorkshopModsDir))) if (pathStartsWith(getFullPath(ContentPackage.WorkshopModsDir)))
return true; return true;
#if CLIENT #if CLIENT
if (pathStartsWith(getFullPath(ModReceiver.DownloadFolder))) if (pathStartsWith(getFullPath(ModReceiver.DownloadFolder)))
return true; return true;
#endif #endif
return false; return false;
} }
public static bool IsPathAllowedException(string path, bool write = true, LuaCsMessageOrigin origin = LuaCsMessageOrigin.Unknown) public static bool IsPathAllowedException(string path, bool write = true, LuaCsMessageOrigin origin = LuaCsMessageOrigin.Unknown)
{ {
if (write) if (write)
{ {
if (CanWriteToPath(path)) if (CanWriteToPath(path))
{ {
return true; return true;
} }
else else
{ {
throw new Exception("File access to \"" + path + "\" not allowed."); throw new Exception("File access to \"" + path + "\" not allowed.");
} }
} }
else else
{ {
if (CanReadFromPath(path)) if (CanReadFromPath(path))
{ {
return true; return true;
} }
else else
{ {
throw new Exception("File access to \"" + path + "\" not allowed."); throw new Exception("File access to \"" + path + "\" not allowed.");
} }
} }
} }
public static bool IsPathAllowedLuaException(string path, bool write = true) => public static bool IsPathAllowedLuaException(string path, bool write = true) =>
IsPathAllowedException(path, write, LuaCsMessageOrigin.LuaMod); IsPathAllowedException(path, write, LuaCsMessageOrigin.LuaMod);
public static bool IsPathAllowedCsException(string path, bool write = true) => public static bool IsPathAllowedCsException(string path, bool write = true) =>
IsPathAllowedException(path, write, LuaCsMessageOrigin.CSharpMod); IsPathAllowedException(path, write, LuaCsMessageOrigin.CSharpMod);
public static string Read(string path) public static string Read(string path)
{ {
if (!IsPathAllowedException(path, false)) if (!IsPathAllowedException(path, false))
return ""; return "";
return File.ReadAllText(path); return File.ReadAllText(path);
} }
public static void Write(string path, string text) public static void Write(string path, string text)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return; return;
File.WriteAllText(path, text); File.WriteAllText(path, text);
} }
public static void Delete(string path) public static void Delete(string path)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return; return;
File.Delete(path); File.Delete(path);
} }
public static void DeleteDirectory(string path) public static void DeleteDirectory(string path)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return; return;
Directory.Delete(path, true); Directory.Delete(path, true);
} }
public static FileStream OpenRead(string path) public static FileStream OpenRead(string path)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return null; return null;
return File.Open(path, FileMode.Open, FileAccess.Read); return File.Open(path, FileMode.Open, FileAccess.Read);
} }
public static FileStream OpenWrite(string path) public static FileStream OpenWrite(string path)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return null; return null;
if (File.Exists(path)) return File.Open(path, FileMode.Truncate, FileAccess.Write); if (File.Exists(path)) return File.Open(path, FileMode.Truncate, FileAccess.Write);
else return File.Open(path, FileMode.Create, FileAccess.Write); else return File.Open(path, FileMode.Create, FileAccess.Write);
} }
public static bool Exists(string path) public static bool Exists(string path)
{ {
if (!IsPathAllowedException(path, false)) if (!IsPathAllowedException(path, false))
return false; return false;
return File.Exists(path); return File.Exists(path);
} }
public static bool CreateDirectory(string path) public static bool CreateDirectory(string path)
{ {
if (!IsPathAllowedException(path)) if (!IsPathAllowedException(path))
return false; return false;
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
return true; return true;
} }
public static bool DirectoryExists(string path) public static bool DirectoryExists(string path)
{ {
if (!IsPathAllowedException(path, false)) if (!IsPathAllowedException(path, false))
return false; return false;
return Directory.Exists(path); return Directory.Exists(path);
} }
public static string[] GetFiles(string path) public static string[] GetFiles(string path)
{ {
if (!IsPathAllowedException(path, false)) if (!IsPathAllowedException(path, false))
return null; return null;
return Directory.GetFiles(path); return Directory.GetFiles(path);
} }
public static string[] GetDirectories(string path) public static string[] GetDirectories(string path)
{ {
if (!IsPathAllowedException(path, false)) if (!IsPathAllowedException(path, false))
return new string[] { }; return new string[] { };
return Directory.GetDirectories(path); return Directory.GetDirectories(path);
} }
public static string[] DirSearch(string sDir) public static string[] DirSearch(string sDir)
{ {
if (!IsPathAllowedException(sDir, false)) if (!IsPathAllowedException(sDir, false))
return new string[] { }; return new string[] { };
List<string> files = new List<string>(); List<string> files = new List<string>();
try try
{ {
foreach (string f in Directory.GetFiles(sDir)) foreach (string f in Directory.GetFiles(sDir))
{ {
files.Add(f); files.Add(f);
} }
foreach (string d in Directory.GetDirectories(sDir)) foreach (string d in Directory.GetDirectories(sDir))
{ {
foreach (string f in Directory.GetFiles(d)) foreach (string f in Directory.GetFiles(d))
{ {
files.Add(f); files.Add(f);
} }
DirSearch(d); DirSearch(d);
} }
} }
catch (System.Exception excpt) catch (System.Exception excpt)
{ {
Console.WriteLine(excpt.Message); Console.WriteLine(excpt.Message);
} }
return files.ToArray(); return files.ToArray();
} }
} }
class LuaCsConfig class LuaCsConfig
{ {
private enum ValueType private enum ValueType
{ {
None, None,
Text, Text,
Integer, Integer,
Decimal, Decimal,
Boolean, Boolean,
Collection, Collection,
Object, Object,
Enum Enum
} }
private static Type[] LoadDocTypes(XElement typesElem) private static Type[] LoadDocTypes(XElement typesElem)
{ {
var result = new List<Type>(); var result = new List<Type>();
foreach (var elem in typesElem.Elements()) foreach (var elem in typesElem.Elements())
{ {
var type = Type.GetType(elem.Value); var type = Type.GetType(elem.Value);
if (type == null && GameMain.LuaCs?.CsScriptLoader?.Assembly != null) type = GameMain.LuaCs.CsScriptLoader.Assembly.GetType(elem.Value); if (type == null && GameMain.LuaCs?.CsScriptLoader?.Assembly != null) type = GameMain.LuaCs.CsScriptLoader.Assembly.GetType(elem.Value);
if (type == null) throw new Exception($"Type {elem.Value} not found."); if (type == null) throw new Exception($"Type {elem.Value} not found.");
result.Add(type); result.Add(type);
} }
return result.ToArray(); return result.ToArray();
} }
private static IEnumerable<XElement> SaveDocTypes(IEnumerable<Type> types) private static IEnumerable<XElement> SaveDocTypes(IEnumerable<Type> types)
{
return types.Select(t => new XElement("Type", t.ToString()));
}
private static Type GetTypeAttr(Type[] types, XElement elem)
{ {
var idx = elem.GetAttributeInt("Type", -1); return types.Select(t => new XElement("Type", t.ToString()));
if (idx < 0 || idx >= types.Length) throw new Exception($"Type index '{idx}' is outside of saved types bounds"); }
return types[idx];
} private static Type GetTypeAttr(Type[] types, XElement elem)
private static ValueType GetValueType(XElement elem)
{ {
Enum.TryParse(typeof(ValueType), elem.Attribute("Value")?.Value, out object result); var idx = elem.GetAttributeInt("Type", -1);
if (result != null) return (ValueType)result; if (idx < 0 || idx >= types.Length) throw new Exception($"Type index '{idx}' is outside of saved types bounds");
else return ValueType.None; return types[idx];
} }
private static object ParseValue(Type[] types, XElement elem) private static ValueType GetValueType(XElement elem)
{ {
var type = GetValueType(elem); Enum.TryParse(typeof(ValueType), elem.Attribute("Value")?.Value, out object result);
if (result != null) return (ValueType)result;
else return ValueType.None;
}
private static object ParseValue(Type[] types, XElement elem)
{
var type = GetValueType(elem);
if (elem.IsEmpty) return null; if (elem.IsEmpty) return null;
if (type == ValueType.Enum) if (type == ValueType.Enum)
{ {
var tType = GetTypeAttr(types, elem); var tType = GetTypeAttr(types, elem);
if (tType == null || !tType.IsSubclassOf(typeof(Enum))) return null; if (tType == null || !tType.IsSubclassOf(typeof(Enum))) return null;
if (Enum.TryParse(tType, elem.Value, out object result)) return result; if (Enum.TryParse(tType, elem.Value, out object result)) return result;
else return null; else return null;
} }
if (type == ValueType.Collection) if (type == ValueType.Collection)
{
var tType = GetTypeAttr(types, elem);
var tInt = tType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
var gArg = tInt.GetGenericArguments()[0];
if (tType == null || !tType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))) return null;
object result = null;
if (result == null) {
var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c =>
{
var param = c.GetParameters();
return param.Count() == 1 && param.Any(p => p.ParameterType.IsGenericType && p.ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
});
if (ctor != null)
{
var elements = elem.Elements().Select(x => ParseValue(types, x));
var castElems = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(gArg).Invoke(elements, new object[] { elements });
result = ctor.Invoke(new object[] { castElems });
}
}
if (result == null)
{
var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Count() == 0);
var addMethod = tType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(m =>
{
if (m.Name != "Add") return false;
var param = m.GetParameters();
return param.Count() == 1 && param[0].ParameterType == gArg;
});
if (ctor != null && addMethod != null)
{
var elements = elem.Elements().Select(x => ParseValue(types, x));
result = ctor.Invoke(null);
foreach (var el in elements) addMethod.Invoke(result, new object[] { el });
}
}
if (result == null)
{
var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault();
var setMethod = tType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(m =>
{
if (m.Name != "Set") return false;
var param = m.GetParameters();
return param.Count() == 2 && param[0].ParameterType == typeof(int) && param[1].ParameterType == gArg;
});
if (ctor != null || setMethod != null)
{
var elements = elem.Elements().Select(x => ParseValue(types, x));
result = ctor.Invoke(new object[] { elements.Count() });
int i = 0;
foreach (var el in elements)
{
setMethod.Invoke(result, new object[] { i, el });
i++;
}
}
}
return result;
}
else if (type == ValueType.Text) return elem.Value;
else if (type == ValueType.Integer)
{
int.TryParse(elem.Value, out var num);
return num;
}
else if (type == ValueType.Decimal)
{ {
float.TryParse(elem.Value, out var num); var tType = GetTypeAttr(types, elem);
return num; var tInt = tType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
} var gArg = tInt.GetGenericArguments()[0];
else if (type == ValueType.Boolean) if (tType == null || !tType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))) return null;
{
bool.TryParse(elem.Value, out var boolean);
return boolean;
}
else if (type == ValueType.Object)
{
var tType = GetTypeAttr(types, elem);
if (tType == null) return null;
IEnumerable<FieldInfo> fields = tType.GetFields(BindingFlags.Instance | BindingFlags.Public) object result = null;
.Concat(tType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic));
IEnumerable<PropertyInfo> properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetSetMethod() != null)
.Concat(tType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Where(p => p.GetSetMethod() != null));
object result = null; if (result == null) {
var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Count() == 0); var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c =>
if (ctor == null) {
{ var param = c.GetParameters();
if (!tType.IsValueType) return null; return param.Count() == 1 && param.Any(p => p.ParameterType.IsGenericType && p.ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
result = Activator.CreateInstance(tType); });
} if (ctor != null)
else result = ctor.Invoke(null); {
var elements = elem.Elements().Select(x => ParseValue(types, x));
foreach(var el in elem.Elements()) var castElems = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(gArg).Invoke(elements, new object[] { elements });
{ result = ctor.Invoke(new object[] { castElems });
var value = ParseValue(types, el); }
var field = fields.FirstOrDefault(f => f.Name == el.Name.LocalName);
if (field != null) field.SetValue(result, value);
var property = properties.FirstOrDefault(p => p.Name == el.Name.LocalName);
if (property != null) property.SetValue(result, value);
} }
return result;
}
else return elem.Value;
} if (result == null)
private static void AddTypeAttr(List<Type> types, Type type, XElement elem)
{
if (!types.Contains(type)) types.Add(type);
elem.SetAttributeValue("Type", types.IndexOf(type));
}
private static XElement ParseObject(List<Type> types, string name, object value)
{
XElement result = new XElement(name);
if (value != null)
{
var tType = value.GetType();
if (tType.IsEnum)
{ {
result.SetAttributeValue("Value", ValueType.Enum); var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Count() == 0);
AddTypeAttr(types, tType, result); var addMethod = tType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(m =>
{
result.Value = Enum.GetName(tType, value) ?? ""; if (m.Name != "Add") return false;
var param = m.GetParameters();
return param.Count() == 1 && param[0].ParameterType == gArg;
});
if (ctor != null && addMethod != null)
{
var elements = elem.Elements().Select(x => ParseValue(types, x));
result = ctor.Invoke(null);
foreach (var el in elements) addMethod.Invoke(result, new object[] { el });
}
} }
else if (value is string str)
{
result.SetAttributeValue("Value", ValueType.Text);
result.Value = str;
}
else if (value is int integer)
{
result.SetAttributeValue("Value", ValueType.Integer);
result.Value = integer.ToString();
}
else if (value is float || value is double)
{
result.SetAttributeValue("Value", ValueType.Decimal);
result.Value = value.ToString();
}
else if (value is bool boolean)
{
result.SetAttributeValue("Value", ValueType.Boolean);
result.Value = boolean.ToString();
}
else if (tType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
result.SetAttributeValue("Value", ValueType.Collection);
AddTypeAttr(types, tType, result);
var enumerator = (IEnumerator)tType.GetMethod("GetEnumerator").Invoke(value, null); if (result == null)
while (enumerator.MoveNext())
{
var elVal = ParseObject(types, "Item", enumerator.Current);
result.Add(elVal);
}
}
else if (tType.IsClass || tType.IsValueType)
{ {
result.SetAttributeValue("Value", ValueType.Object); var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault();
AddTypeAttr(types, tType, result); var setMethod = tType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(m =>
{
if (m.Name != "Set") return false;
var param = m.GetParameters();
return param.Count() == 2 && param[0].ParameterType == typeof(int) && param[1].ParameterType == gArg;
});
if (ctor != null || setMethod != null)
{
var elements = elem.Elements().Select(x => ParseValue(types, x));
result = ctor.Invoke(new object[] { elements.Count() });
int i = 0;
foreach (var el in elements)
{
setMethod.Invoke(result, new object[] { i, el });
i++;
}
}
}
IEnumerable<FieldInfo> fields = tType.GetFields(BindingFlags.Instance | BindingFlags.Public) return result;
.Concat(tType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)); }
IEnumerable<PropertyInfo> properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetSetMethod() != null) else if (type == ValueType.Text) return elem.Value;
.Concat(tType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Where(p => p.GetSetMethod() != null)); else if (type == ValueType.Integer)
{
int.TryParse(elem.Value, out var num);
return num;
}
else if (type == ValueType.Decimal)
{
float.TryParse(elem.Value, out var num);
return num;
}
else if (type == ValueType.Boolean)
{
bool.TryParse(elem.Value, out var boolean);
return boolean;
}
else if (type == ValueType.Object)
{
var tType = GetTypeAttr(types, elem);
if (tType == null) return null;
foreach(var field in fields) result.Add(ParseObject(types, field.Name, field.GetValue(value))); IEnumerable<FieldInfo> fields = tType.GetFields(BindingFlags.Instance | BindingFlags.Public)
foreach (var property in properties) result.Add(ParseObject(types, property.Name, property.GetValue(value))); .Concat(tType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic));
} IEnumerable<PropertyInfo> properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetSetMethod() != null)
else .Concat(tType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Where(p => p.GetSetMethod() != null));
{
result.SetAttributeValue("Value", ValueType.None);
result.Value = value.ToString();
}
}
return result; object result = null;
var ctor = tType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Count() == 0);
if (ctor == null)
{
if (!tType.IsValueType) return null;
result = Activator.CreateInstance(tType);
}
else result = ctor.Invoke(null);
foreach(var el in elem.Elements())
{
var value = ParseValue(types, el);
var field = fields.FirstOrDefault(f => f.Name == el.Name.LocalName);
if (field != null) field.SetValue(result, value);
var property = properties.FirstOrDefault(p => p.Name == el.Name.LocalName);
if (property != null) property.SetValue(result, value);
}
return result;
}
else return elem.Value;
}
private static void AddTypeAttr(List<Type> types, Type type, XElement elem)
{
if (!types.Contains(type)) types.Add(type);
elem.SetAttributeValue("Type", types.IndexOf(type));
}
private static XElement ParseObject(List<Type> types, string name, object value)
{
XElement result = new XElement(name);
if (value != null)
{
var tType = value.GetType();
if (tType.IsEnum)
{
result.SetAttributeValue("Value", ValueType.Enum);
AddTypeAttr(types, tType, result);
result.Value = Enum.GetName(tType, value) ?? "";
}
else if (value is string str)
{
result.SetAttributeValue("Value", ValueType.Text);
result.Value = str;
}
else if (value is int integer)
{
result.SetAttributeValue("Value", ValueType.Integer);
result.Value = integer.ToString();
}
else if (value is float || value is double)
{
result.SetAttributeValue("Value", ValueType.Decimal);
result.Value = value.ToString();
}
else if (value is bool boolean)
{
result.SetAttributeValue("Value", ValueType.Boolean);
result.Value = boolean.ToString();
}
else if (tType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
{
result.SetAttributeValue("Value", ValueType.Collection);
AddTypeAttr(types, tType, result);
var enumerator = (IEnumerator)tType.GetMethod("GetEnumerator").Invoke(value, null);
while (enumerator.MoveNext())
{
var elVal = ParseObject(types, "Item", enumerator.Current);
result.Add(elVal);
}
}
else if (tType.IsClass || tType.IsValueType)
{
result.SetAttributeValue("Value", ValueType.Object);
AddTypeAttr(types, tType, result);
IEnumerable<FieldInfo> fields = tType.GetFields(BindingFlags.Instance | BindingFlags.Public)
.Concat(tType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic));
IEnumerable<PropertyInfo> properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.GetSetMethod() != null)
.Concat(tType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Where(p => p.GetSetMethod() != null));
foreach(var field in fields) result.Add(ParseObject(types, field.Name, field.GetValue(value)));
foreach (var property in properties) result.Add(ParseObject(types, property.Name, property.GetValue(value)));
}
else
{
result.SetAttributeValue("Value", ValueType.None);
result.Value = value.ToString();
}
}
return result;
} }
public static T Load<T>(FileStream file) public static T Load<T>(FileStream file)
{
var doc = XDocument.Load(file);
var rootElems = doc.Root.Elements().ToArray();
var types = rootElems[0];
var elem = rootElems[1];
var dict = ParseValue(LoadDocTypes(types), elem);
if (dict.GetType() == typeof(T)) return (T)dict;
else throw new Exception($"Loaded configuration is not of the type '{typeof(T).Name}'");
}
public static void Save(FileStream file, object obj)
{
var types = new List<Type>();
var elem = ParseObject(types, "Root", obj);
var root = new XElement("Configuration", new XElement("Types", SaveDocTypes(types)), elem);
var doc = new XDocument(root);
doc.Save(file);
}
public static T Load<T>(string path)
{
using (var file = LuaCsFile.OpenRead(path)) return Load<T>(file);
}
public static void Save(string path, object obj)
{ {
using (var file = LuaCsFile.OpenWrite(path)) Save(file, obj); var doc = XDocument.Load(file);
}
var rootElems = doc.Root.Elements().ToArray();
var types = rootElems[0];
var elem = rootElems[1];
var dict = ParseValue(LoadDocTypes(types), elem);
if (dict.GetType() == typeof(T)) return (T)dict;
else throw new Exception($"Loaded configuration is not of the type '{typeof(T).Name}'");
}
public static void Save(FileStream file, object obj)
{
var types = new List<Type>();
var elem = ParseObject(types, "Root", obj);
var root = new XElement("Configuration", new XElement("Types", SaveDocTypes(types)), elem);
var doc = new XDocument(root);
doc.Save(file);
}
public static T Load<T>(string path)
{
using (var file = LuaCsFile.OpenRead(path)) return Load<T>(file);
}
public static void Save(string path, object obj)
{
using (var file = LuaCsFile.OpenWrite(path)) Save(file, obj);
}
} }
} }