Refactor and fix #56

This commit is contained in:
Evil Factory
2022-04-15 19:05:24 -03:00
parent 6eb575ea81
commit 42df433d3e
35 changed files with 144 additions and 97 deletions
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Barotrauma
{
public abstract class ACsMod : IDisposable
{
private static List<ACsMod> mods = new List<ACsMod>();
public static List<ACsMod> LoadedMods { get => mods; }
public bool IsDisposed { get; private set; }
public ACsMod()
{
IsDisposed = false;
LoadedMods.Add(this);
Start();
}
public void Dispose() {
Stop();
LoadedMods.Remove(this);
IsDisposed = true;
}
// TODO: some hooks
/// Mod initialization
public abstract void Start();
/// Error or client exit
public abstract void Stop();
}
}
@@ -0,0 +1,79 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
namespace Barotrauma {
class CsScriptFilter
{
private const bool useWhitelist = false;
private static string[] typesPermited = new string[] {
// Basics
"System.Runtime.CompilerServices.CompilationRelaxationsAttribute",
"System.Runtime.CompilerServices.RuntimeCompatibilityAttribute",
"System.Diagnostics.DebuggableAttribute",
"System.Object",
"System.String",
"System.Collections",
// Some roslyn magic
".DebuggingModes",
// Barotrauma
"Barotrauma",
};
private static string[] typessProhibited = new string[] {
//"System.Reflection",
"System.IO",
};
public static bool IsTypeAllowed(string usingName)
{
if (useWhitelist && !typesPermited.Any(u => u.StartsWith(usingName))) return false;
if (typessProhibited.Any(u => u.StartsWith(usingName))) return false;
return true;
}
public static string FilterSyntaxTree(CSharpSyntaxTree tree)
{
if (tree == null) throw new ArgumentNullException("Syntax tree must not be null.");
{ // Disallow top-level statements
var nodeCheck = tree.GetRoot().DescendantNodes();
var tlStatements = nodeCheck.Where(n => n is GlobalStatementSyntax).ToList();
if (tlStatements.Count > 0)
{
string errStr = "Cmopilation Error:";
foreach (var tls in tlStatements) tls.GetDiagnostics().ToList().ForEach(d => errStr += $"\n {d.ToString()}");
return errStr;
}
}
return null;
}
public static string FilterMetadata(MetadataReader reader)
{
if (reader == null) throw new ArgumentNullException("Metadata Reader must not be null.");
var conflictingTypes = new List<string>();
reader.TypeReferences.ToList().ForEach(t =>
{
var tRef = reader.GetTypeReference(t);
var typeName = $"{reader.GetString(tRef.Namespace)}.{reader.GetString(tRef.Name)}";
if (!IsTypeAllowed(typeName)) conflictingTypes.Add(typeName);
});
if (conflictingTypes.Count > 0)
{
string errStr = "Metadata Error:";
conflictingTypes.ForEach(t => errStr += $"\n Usage of type '{t}' in mods is prohibited.");
return errStr;
}
return null;
}
}
}
@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis.Scripting;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp;
using System.Linq;
using Microsoft.CodeAnalysis;
using System.Runtime.Loader;
using System.Reflection.PortableExecutable;
using System.Reflection.Metadata;
namespace Barotrauma
{
class CsScriptLoader : AssemblyLoadContext
{
public LuaCsSetup setup;
private List<MetadataReference> defaultReferences;
private List<SyntaxTree> syntaxTrees;
public Assembly Assembly { get; private set; }
public CsScriptLoader(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();
syntaxTrees = new List<SyntaxTree>();
Assembly = null;
}
public void SearchFolders()
{
foreach(ContentPackage cp in ContentPackageManager.EnabledPackages.All)
{
var path = Path.GetDirectoryName(cp.Path);
RunFolder(path);
}
}
private void RunFolder(string folder)
{
var scriptFiles = new List<string>();
foreach (var str in DirSearch(folder))
{
var s = str.Replace("\\", "/");
if (s.EndsWith(".cs") && LuaCsFile.IsPathAllowedCsException(s)) scriptFiles.Add(s);
}
try
{
if (scriptFiles.Count <= 0) return;
// Check file content for prohibited stuff
foreach (var file in scriptFiles)
{
var tree = SyntaxFactory.ParseSyntaxTree(File.ReadAllText(file), CSharpParseOptions.Default, file);
var error = CsScriptFilter.FilterSyntaxTree(tree as CSharpSyntaxTree);
if (error != null) throw new Exception(error);
syntaxTrees.Add(tree);
}
}
catch (CompilationErrorException ex)
{
string errStr = "Cmopilation Error in '" + folder + "':";
foreach (var diag in ex.Diagnostics)
{
errStr += "\n" + diag.ToString();
}
LuaCsSetup.PrintCsMessage(errStr);
}
catch (Exception ex)
{
LuaCsSetup.PrintCsMessage("Error loading '" + folder + "':\n" + ex.Message + "\n" + ex.StackTrace);
}
}
public List<Type> Compile()
{
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithMetadataImportOptions(MetadataImportOptions.All)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithAllowUnsafe(false);
var compilation = CSharpCompilation.Create("NetScriptAssembly",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 = "NET MODS NOT LOADED | Mod cmopilation errors:";
foreach (Diagnostic diagnostic in failures)
errStr = $"\n{diagnostic}";
LuaCsSetup.PrintCsMessage(errStr);
}
else
{
mem.Seek(0, SeekOrigin.Begin);
var errStr = CsScriptFilter.FilterMetadata(new PEReader(mem).GetMetadataReader());
if (errStr == null)
{
mem.Seek(0, SeekOrigin.Begin);
Assembly = LoadFromStream(mem);
}
else LuaCsSetup.PrintCsMessage(errStr);
}
}
syntaxTrees.Clear();
if (Assembly != null)
return Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ACsMod))).ToList();
else
throw new Exception("Unable to create net mods assembly.");
}
private static string[] DirSearch(string sDir)
{
List<string> files = new List<string>();
try
{
foreach (string f in Directory.GetFiles(sDir))
{
files.Add(f);
}
foreach (string d in Directory.GetDirectories(sDir))
{
files.AddRange(DirSearch(d));
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
return files.ToArray();
}
}
}
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Text;
using MoonSharp.Interpreter;
using Microsoft.Xna.Framework;
namespace Barotrauma.Networking
{
partial class Client
{
public static List<Client> ClientList
{
get
{
#if SERVER
return GameMain.Server.ConnectedClients;
#else
return GameMain.Client.ConnectedClients;
#endif
}
}
}
}
namespace Barotrauma
{
using Barotrauma.Networking;
using System.Linq;
using System.Reflection;
partial class Character
{
}
partial class Item
{
public object GetComponentString(string component)
{
Type type = Type.GetType("Barotrauma.Items.Components." + component);
if (type == null)
return null;
MethodInfo method = typeof(Item).GetMethod(nameof(Item.GetComponent));
MethodInfo generic = method.MakeGenericMethod(type);
return generic.Invoke(this, null);
}
}
partial class ItemPrefab
{
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;
}
}
abstract partial class MapEntity
{
public void AddLinked(MapEntity entity)
{
linkedTo.Add(entity);
}
}
}
namespace Barotrauma.Items.Components
{
using Barotrauma.Networking;
partial class CustomInterface
{
}
partial struct Signal
{
}
}
@@ -0,0 +1,432 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using MoonSharp.Interpreter;
namespace Barotrauma
{
partial class LuaGame
{
public bool IsSingleplayer => GameMain.IsSingleplayer;
public bool IsMultiplayer => GameMain.IsMultiplayer;
#if CLIENT
public bool Paused => GameMain.Instance?.Paused == true;
public byte MyID => GameMain.Client.ID;
public ChatBox ChatBox
{
get
{
if (GameMain.IsSingleplayer)
return GameMain.GameSession.CrewManager.ChatBox;
else
return GameMain.Client.ChatBox;
}
}
#else
public bool IsDedicated
{
get
{
return GameMain.Server.ServerPeer is LidgrenServerPeer;
}
}
public ServerSettings ServerSettings => GameMain.Server.ServerSettings;
#endif
public DynValue Settings;
public bool allowWifiChat = false;
public bool overrideTraitors = false;
public bool overrideRespawnSub = false;
public bool overrideSignalRadio = false;
public bool disableSpamFilter = false;
public bool disableDisconnectCharacter = false;
public bool enableControlHusk = false;
public int mapEntityUpdateInterval
{
get { return MapEntity.MapEntityUpdateInterval; }
set { MapEntity.MapEntityUpdateInterval = value; }
}
public int gapUpdateInterval
{
get { return MapEntity.GapUpdateInterval; }
set { MapEntity.GapUpdateInterval = 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;
#else
return GameMain.Client.GameStarted;
#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");
Settings = UserData.CreateStatic(typeof(GameSettings));
}
public void OverrideTraitors(bool o)
{
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();
}
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, CsAction onExecute, CsFunc getValidArgs = null, bool isCheat = false)
{
var cmd = new DebugConsole.Command(name, help, (string[] arg1) => { onExecute(arg1); },
() =>
{
if (getValidArgs == null) return null;
var obj = getValidArgs();
if (obj is LuaResult res) obj = res.Object();
if (obj is string[][]) return (string[][])obj;
return null;
}, isCheat);
luaAddedCommand.Add(cmd);
DebugConsole.Commands.Add(cmd);
#if SERVER
foreach (var client in GameMain.Server.ConnectedClients) {
var index = client.PermittedConsoleCommands.FindIndex((pc) => pc.names[0] == cmd.names[0]);
if (index > -1) {
client.PermittedConsoleCommands[index] = cmd;
}
}
foreach (var permissions in GameMain.Server.ServerSettings.ClientPermissions) {
var index = permissions.PermittedCommands.FindIndex((pc) => pc.names[0] == cmd.names[0]);
if (index > -1) {
permissions.PermittedCommands[index] = cmd;
}
}
#endif
}
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 }); });
#if SERVER
public static void SendMessage(string msg, ChatMessageType? messageType = null, Client sender = null, Character character = null)
{
GameMain.Server.SendChatMessage(msg, messageType, sender, character);
}
public static void SendMessage(string msg, int messageType, Client sender = null, Character character = null)
{
GameMain.Server.SendChatMessage(msg, (ChatMessageType)messageType, sender, character);
}
public static void SendTraitorMessage(Client client, string msg, Identifier missionid, TraitorMessageType 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 = "")
{
ChatMessage cm = ChatMessage.Create(sendername, text, messageType, sender, client);
cm.IconStyle = iconStyle;
GameMain.Server.SendDirectChatMessage(cm, client);
}
public static void SendDirectChatMessage(ChatMessage chatMessage, Client client)
{
GameMain.Server.SendDirectChatMessage(chatMessage, client);
}
public static void Log(string message, ServerLog.MessageType type)
{
GameServer.Log(message, type);
}
public static void DispatchRespawnSub()
{
GameMain.Server.RespawnManager.DispatchShuttle();
}
public static void StartGame()
{
GameMain.Server.StartGame();
}
public static void 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 }); });
#endif
public void Stop()
{
mapEntityUpdateInterval = 1;
gapUpdateInterval = 4;
characterUpdateInterval = 1;
foreach (var cmd in luaAddedCommand)
{
DebugConsole.Commands.Remove(cmd);
}
}
}
}
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text;
using MoonSharp.Interpreter;
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using Barotrauma.Items.Components;
using System.IO;
using System.Net;
using System.Linq;
using System.Xml.Linq;
using FarseerPhysics.Dynamics;
using System.Reflection;
using HarmonyLib;
using MoonSharp.Interpreter.Interop;
using System.Diagnostics;
namespace Barotrauma
{
public class LuaResult
{
object result;
public LuaResult(object arg)
{
result = arg;
}
public bool IsNull()
{
if (result == null)
return true;
if (result is DynValue dynValue)
return dynValue.IsNil();
return false;
}
public bool Bool()
{
if (result is DynValue dynValue)
{
return dynValue.CastToBool();
}
return false;
}
public float Float()
{
if (result is DynValue dynValue)
{
var num = dynValue.CastToNumber();
if (num == null) { return 0f; }
return (float)num.Value;
}
return 0f;
}
public double Double()
{
if (result is DynValue dynValue)
{
var num = dynValue.CastToNumber();
if (num == null) { return 0f; }
return num.Value;
}
return 0f;
}
public string String()
{
if (result is DynValue dynValue)
{
var str = dynValue.CastToString();
if (str == null) { return ""; }
return str;
}
return "";
}
public object Object()
{
if (result is DynValue dynValue)
{
return dynValue.ToObject();
}
return null;
}
public DynValue DynValue()
{
if (result is DynValue dynValue)
{
return dynValue;
}
return null;
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.ComponentModel;
namespace Barotrauma
{
public class LuaByte
{
public byte Value;
public LuaByte(byte v)
{
Value = v;
}
public static implicit operator byte(LuaByte lb) => lb.Value;
}
public class LuaUShort
{
public ushort Value;
public LuaUShort(ushort v)
{
Value = v;
}
public static implicit operator ushort(LuaUShort lb) => lb.Value;
}
public class LuaFloat
{
public float Value;
public LuaFloat(float v)
{
Value = v;
}
public static implicit operator float(LuaFloat lb) => lb.Value;
}
}
@@ -0,0 +1,219 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using MoonSharp.Interpreter;
using MoonSharp.Interpreter.Interop;
namespace Barotrauma
{
partial class LuaUserData
{
public static Type GetType(string typeName)
{
var type = Type.GetType(typeName);
if (type != null) return type;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
type = a.GetType(typeName);
if (type != null)
return type;
}
return null;
}
public static IUserDataDescriptor RegisterType(string typeName)
{
Type type = GetType(typeName);
if (type == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to register a type that doesn't exist: {typeName}."));
return null;
}
return UserData.RegisterType(type);
}
public static void UnregisterType(string typeName)
{
Type type = GetType(typeName);
if (type == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to unregister a type that doesn't exist: {typeName}."));
return;
}
UserData.UnregisterType(type);
}
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)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to create a static userdata of a type that doesn't exist: {typeName}."));
return null;
}
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);
if (type == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to create an enum table with a type that doesn't exist:: {typeName}."));
return null;
}
Dictionary<string, object> result = new Dictionary<string, object>();
foreach (var value in Enum.GetValues(type))
{
string name = Enum.GetName(type, value);
result[name] = value;
}
return result;
}
private static FieldInfo FindFieldRecursively(Type type, string fieldName)
{
var field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (field == null && type.BaseType != null)
{
return FindFieldRecursively(type.BaseType, fieldName);
}
return field;
}
public static void MakeFieldAccessible(IUserDataDescriptor IUUD, string fieldName)
{
if (IUUD == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to use a UserDataDescriptor that is null to make {fieldName} accessible."));
return;
}
var descriptor = (StandardUserDataDescriptor)IUUD;
var field = IUUD.Type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (field == null)
{
field = FindFieldRecursively(IUUD.Type, fieldName);
}
if (field == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to make field '{fieldName}' accessible, but the field doesn't exist."));
return;
}
descriptor.RemoveMember(fieldName);
descriptor.AddMember(fieldName, new FieldMemberDescriptor(field, InteropAccessMode.Default));
}
private static MethodInfo FindMethodRecursively(Type type, string methodName)
{
var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (method == null && type.BaseType != null)
{
return FindMethodRecursively(type.BaseType, methodName);
}
return method;
}
public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName)
{
if (IUUD == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to use a UserDataDescriptor that is null to make {methodName} accessible."));
return;
}
var descriptor = (StandardUserDataDescriptor)IUUD;
var method = IUUD.Type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
if (method == null)
{
method = FindMethodRecursively(IUUD.Type, methodName);
}
if (method == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to make method '{methodName}' accessible, but the method doesn't exist."));
return;
}
descriptor.RemoveMember(methodName);
descriptor.AddMember(methodName, new MethodMemberDescriptor(method, InteropAccessMode.Default));
}
public static void AddMethod(IUserDataDescriptor IUUD, string methodName, object function)
{
if (IUUD == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to use a UserDataDescriptor that is null to add method {methodName}."));
return;
}
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 RemoveMember(IUserDataDescriptor IUUD, string memberName)
{
if (IUUD == null)
{
GameMain.LuaCs.HandleException(new Exception($"Tried to use a UserDataDescriptor that is null to remove the member {memberName}."));
return;
}
var descriptor = (StandardUserDataDescriptor)IUUD;
descriptor.RemoveMember(memberName);
}
}
}
@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Text;
using MoonSharp.Interpreter;
using Microsoft.Xna.Framework;
using FarseerPhysics.Dynamics;
namespace Barotrauma
{
public static class LuaCustomConverters
{
public static void RegisterAll()
{
RegisterAction<Item>();
RegisterAction<Character>();
RegisterAction<Entity>();
RegisterAction();
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(Func<Fixture, Vector2, Vector2, float, float>), v =>
{
var function = v.Function;
return (Func<Fixture, Vector2, Vector2, float, float>)((Fixture a, Vector2 b, Vector2 c, float d) => new LuaResult(function.Call(a, b, c, d)).Float());
});
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(CsAction), v => (CsAction)( args => GameMain.LuaCs.CallLuaFunction(v.Function, args) ));
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(CsFunc), v => (CsFunc)( args => new LuaResult(GameMain.LuaCs.CallLuaFunction(v.Function, args)) ));
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(CsPatch), v => (CsPatch)( (self, args) => new LuaResult(GameMain.LuaCs.CallLuaFunction(v.Function, self, args)) ));
#if CLIENT
RegisterAction<float>();
RegisterAction<Microsoft.Xna.Framework.Graphics.SpriteBatch, float>();
{
object Call(object function, params object[] arguments) => GameMain.LuaCs.CallLuaFunction(function, arguments);
void RegisterHandler<T>(Func<Closure, object> converter)
{
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(T), v => converter(v.Function));
}
RegisterHandler<GUIComponent.SecondaryButtonDownHandler>(f =>
(GUIComponent.SecondaryButtonDownHandler)((GUIComponent a1, object a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIButton.OnClickedHandler>(f =>
(GUIButton.OnClickedHandler)((GUIButton a1, object a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIButton.OnButtonDownHandler>(f =>
(GUIButton.OnButtonDownHandler)(() => new LuaResult(Call(f)).Bool()));
RegisterHandler<GUIButton.OnPressedHandler>(f =>
(GUIButton.OnPressedHandler)(() => new LuaResult(Call(f)).Bool()));
RegisterHandler<GUIColorPicker.OnColorSelectedHandler>(f =>
(GUIColorPicker.OnColorSelectedHandler)((GUIColorPicker a1, Color a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIDropDown.OnSelectedHandler>(f =>
(GUIDropDown.OnSelectedHandler)((GUIComponent a1, object a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIListBox.OnSelectedHandler>(f =>
(GUIListBox.OnSelectedHandler)((GUIComponent a1, object a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIListBox.OnRearrangedHandler>(f =>
(GUIListBox.OnRearrangedHandler)((GUIListBox a1, object a2) => Call(f, a1, a2)));
RegisterHandler<GUIListBox.CheckSelectedHandler>(f =>
(GUIListBox.CheckSelectedHandler)(() => new LuaResult(Call(f)).Object()));
RegisterHandler<GUINumberInput.OnValueChangedHandler>(f =>
(GUINumberInput.OnValueChangedHandler)((GUINumberInput a1) => Call(f, a1)));
RegisterHandler<GUIProgressBar.ProgressGetterHandler>(f =>
(GUIProgressBar.ProgressGetterHandler)(() => new LuaResult(Call(f)).Float()));
RegisterHandler<GUIRadioButtonGroup.RadioButtonGroupDelegate>(f =>
(GUIRadioButtonGroup.RadioButtonGroupDelegate)((GUIRadioButtonGroup a1, int? a2) => Call(f, a1, a2)));
RegisterHandler<GUIScrollBar.OnMovedHandler>(f =>
(GUIScrollBar.OnMovedHandler)((GUIScrollBar a1, float a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUIScrollBar.ScrollConversion>(f =>
(GUIScrollBar.ScrollConversion)((GUIScrollBar a1, float a2) => new LuaResult(Call(f, a1, a2)).Float()));
RegisterHandler<GUITextBlock.TextGetterHandler>(f =>
(GUITextBlock.TextGetterHandler)(() => new LuaResult(Call(f, new object[] { })).String()));
RegisterHandler<GUITextBox.OnEnterHandler>(f =>
(GUITextBox.OnEnterHandler)((GUITextBox a1, string a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<GUITextBox.OnTextChangedHandler>(f =>
(GUITextBox.OnTextChangedHandler)((GUITextBox a1, string a2) => new LuaResult(Call(f, a1, a2)).Bool()));
RegisterHandler<TextBoxEvent>(f =>
(TextBoxEvent)((GUITextBox a1, Microsoft.Xna.Framework.Input.Keys a2) => Call(f, a1, a2)));
RegisterHandler<GUITickBox.OnSelectedHandler>(f =>
(GUITickBox.OnSelectedHandler)((GUITickBox a1) => new LuaResult(Call(f, a1)).Bool()));
}
#endif
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Table, typeof(Pair<JobPrefab, int>), v =>
{
return new Pair<JobPrefab, int>((JobPrefab)v.Table.Get(1).ToObject(), (int)v.Table.Get(2).CastToNumber());
});
Script.GlobalOptions.CustomConverters.SetClrToScriptCustomConversion<UInt64>((Script script, UInt64 v) =>
{
return DynValue.NewString(v.ToString());
});
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.UserData, typeof(object), v =>
{
if (v.UserData.Object is LuaByte lbyte)
{
return lbyte.Value;
}
else if (v.UserData.Object is LuaUShort lushort)
{
return lushort.Value;
}
else if (v.UserData.Object is LuaFloat lfloat)
{
return lfloat.Value;
}
return v.UserData.Object;
});
}
public static void RegisterAction<T>()
{
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(Action<T>), v =>
{
var function = v.Function;
return (Action<T>)(p => GameMain.LuaCs.CallLuaFunction(function, p));
});
}
public static void RegisterAction<T1, T2>()
{
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(Action<T1, T2>), v =>
{
var function = v.Function;
return (Action<T1, T2>)((a1, a2) => GameMain.LuaCs.CallLuaFunction(function, a1, a2));
});
}
public static void RegisterAction()
{
Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Function, typeof(Action), v =>
{
var function = v.Function;
return (Action)(() => GameMain.LuaCs.CallLuaFunction(function));
});
}
}
}
@@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using System.Text;
using MoonSharp.Interpreter;
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using System.Threading.Tasks;
using Barotrauma.Items.Components;
using System.IO;
using System.Net;
using System.Linq;
using System.Xml.Linq;
using System.Reflection;
namespace Barotrauma
{
public static class LuaDocs
{
public static string ConvertTypeName(string type)
{
switch (type)
{
case "Boolean":
return "bool";
case "String":
return "string";
case "int":
return "number";
case "Single":
return "number";
case "Double":
return "number";
case "float":
return "number";
case "UInt16":
return "number";
case "UInt32":
return "number";
case "UInt64":
return "number";
case "Int32":
return "number";
case "List`1":
return "table";
case "Dictionary`2":
return "table";
}
if (type.StartsWith("Action"))
return "function";
if (type.StartsWith("Func"))
return "function";
if (type.StartsWith("IEnumerable"))
return "Enumerable";
return type;
}
public static string EscapeName(string n)
{
if (n == "end")
return "endparam";
return n;
}
public static void GenerateDocsAll()
{
GenerateDocs(typeof(Character), "Character.lua");
GenerateDocs(typeof(CharacterInfo), "CharacterInfo.lua");
GenerateDocs(typeof(CharacterHealth), "CharacterHealth.lua");
GenerateDocs(typeof(AnimController), "AnimController.lua");
GenerateDocs(typeof(Client), "Client.lua");
GenerateDocs(typeof(Entity), "Entity.lua");
GenerateDocs(typeof(EntitySpawner), "Entity.Spawner.lua", "Entity.Spawner");
GenerateDocs(typeof(Item), "Item.lua");
GenerateDocs(typeof(ItemPrefab), "ItemPrefab.lua");
GenerateDocs(typeof(Submarine), "Submarine.lua");
GenerateDocs(typeof(SubmarineInfo), "SubmarineInfo.lua");
GenerateDocs(typeof(Job), "Job.lua");
GenerateDocs(typeof(JobPrefab), "JobPrefab.lua");
GenerateDocs(typeof(GameSession), "GameSession.lua", "Game.GameSession");
GenerateDocs(typeof(NetLobbyScreen), "NetLobbyScreen.lua", "Game.NetLobbyScreen");
GenerateDocs(typeof(GameScreen), "GameScreen.lua", "Game.GameScreen");
GenerateDocs(typeof(FarseerPhysics.Dynamics.World), "World.lua", "Game.World");
GenerateDocs(typeof(Inventory), "Inventory.lua", "Inventory");
GenerateDocs(typeof(ItemInventory), "ItemInventory.lua", "ItemInventory");
GenerateDocs(typeof(CharacterInventory), "CharacterInventory.lua", "CharacterInventory");
GenerateDocs(typeof(Hull), "Hull.lua", "Hull");
GenerateDocs(typeof(Level), "Level.lua", "Level");
GenerateDocs(typeof(Affliction), "Affliction.lua", "Affliction");
GenerateDocs(typeof(AfflictionPrefab), "AfflictionPrefab.lua", "AfflictionPrefab");
GenerateDocs(typeof(WayPoint), "WayPoint.lua", "WayPoint");
}
public static void GenerateDocs(Type type, string name, string categoryName = null)
{
GenerateDocs(type, "../../../../docs/baseluadocs/" + name, "../../../../docs/lua/generated/" + name, categoryName);
}
public static void GenerateDocs(Type type, string baselua, string fileresult, string categoryName = null)
{
var sb = new StringBuilder();
if (categoryName == null)
categoryName = type.Name;
var baseluatext = "";
if (!File.Exists(baselua))
{
const string EMPTY_TABLE = "{}";
baseluatext = @$"-- luacheck: ignore 111
--[[--
{type.FullName}
]]
-- @code {categoryName}
-- @pragma nostrip
local {type.Name} = {EMPTY_TABLE}";
File.WriteAllText(baselua, baseluatext);
}
else
baseluatext = File.ReadAllText(baselua);
HashSet<string> removed = new HashSet<string>();
foreach(var line in baseluatext.Split('\n'))
{
if(line.Contains("-- @remove "))
{
var replaced = line.Replace("-- @remove ", "").Replace("\r", "");
removed.Add(replaced);
}
}
sb.Append(baseluatext + "\n\n");
var members = type.GetMembers();
foreach(var member in members)
{
Console.WriteLine("'{0}' is a {1}", member.Name, member.MemberType);
if (member.MemberType == MemberTypes.Method)
{
var method = (MethodInfo)member;
if (method.Name.StartsWith("get_") || method.Name.StartsWith("set_"))
continue;
var lsb = new StringBuilder();
lsb.Append($"--- {method.Name}\n");
lsb.Append($"-- @realm shared\n");
var paramNames = "";
var parameters = method.GetParameters();
for(var i=0; i < parameters.Length; i++)
{
var parameter = parameters[i];
if(i == parameters.Length - 1)
paramNames = paramNames + EscapeName(parameter.Name);
else
paramNames = paramNames + EscapeName(parameter.Name) + ", ";
lsb.Append($"-- @tparam {ConvertTypeName(parameter.ParameterType.Name)} {EscapeName(parameter.Name)}\n");
}
if (method.ReturnType != typeof(void))
{
lsb.Append($"-- @treturn {ConvertTypeName(method.ReturnType.Name)}\n");
}
string functionDecoration;
if (method.IsStatic)
functionDecoration = $"function {type.Name}.{method.Name}({paramNames}) end";
else
functionDecoration = $"function {method.Name}({paramNames}) end";
if (removed.Contains(functionDecoration))
{
continue;
}
lsb.Append(functionDecoration);
lsb.Append("\n\n");
sb.Append(lsb);
}
if (member.MemberType == MemberTypes.Field)
{
var lsb = new StringBuilder();
var field = (FieldInfo)member;
lsb.Append($"---\n");
lsb.Append($"-- ");
var name = EscapeName(field.Name);
var returnName = ConvertTypeName(field.FieldType.Name);
if (field.IsStatic)
name = type.Name + "." + field.Name;
if (removed.Contains(name))
continue;
lsb.Append(name);
lsb.Append($", Field of type {returnName}\n");
lsb.Append($"-- @realm shared\n");
lsb.Append($"-- @{returnName} {name}\n");
lsb.Append("\n");
sb.Append(lsb);
}
if (member.MemberType == MemberTypes.Property)
{
var lsb = new StringBuilder();
var property = (PropertyInfo)member;
lsb.Append($"---\n");
lsb.Append($"-- ");
var name = EscapeName(property.Name);
var returnName = ConvertTypeName(property.PropertyType.Name);
if (property.GetGetMethod().IsStatic)
name = type.Name + "." + property.Name;
if (removed.Contains(name))
continue;
lsb.Append(name);
lsb.Append($", Field of type {returnName}\n");
lsb.Append($"-- @realm shared\n");
lsb.Append($"-- @{returnName} {name}\n");
lsb.Append("\n");
sb.Append(lsb);
}
}
File.WriteAllText(fileresult, sb.ToString());
}
}
}
@@ -0,0 +1,8 @@
using System;
using MoonSharp.Interpreter;
using Barotrauma.Networking;
namespace Barotrauma
{
}
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using MoonSharp.Interpreter;
using MoonSharp.Interpreter.Loaders;
using System.Linq;
namespace Barotrauma
{
class LuaScriptLoader : ScriptLoaderBase
{
public override object LoadFile(string file, Table globalContext)
{
if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return null;
return File.ReadAllText(file);
}
public override bool ScriptFileExists(string file)
{
if (!LuaCsFile.IsPathAllowedLuaException(file, false)) return false;
return File.Exists(file);
}
}
}
@@ -47,6 +47,8 @@ namespace Barotrauma
}
}
private Harmony harmony;
private Dictionary<string, Dictionary<string, (LuaCsHookCallback, ACsMod)>> hookFunctions;
private Dictionary<long, HashSet<(string, CsPatch, ACsMod)>> hookPrefixMethods;
@@ -54,7 +56,11 @@ namespace Barotrauma
private Queue<(float, CsAction, object[])> queuedFunctionCalls;
private LuaCsHook() {
private static LuaCsHook instance;
public LuaCsHook() {
instance = this;
hookFunctions = new Dictionary<string, Dictionary<string, (LuaCsHookCallback, ACsMod)>>();
hookPrefixMethods = new Dictionary<long, HashSet<(string, CsPatch, ACsMod)>>();
@@ -63,10 +69,12 @@ namespace Barotrauma
queuedFunctionCalls = new Queue<(float, CsAction, object[])>();
}
private static LuaCsHook _inst;
static LuaCsHook() => _inst = new LuaCsHook();
public static LuaCsHook Instance { get => _inst; }
public void Initialize()
{
harmony = new Harmony("LuaCsForBarotrauma");
}
private static void _hookLuaCsPatch(MethodBase __originalMethod, object[] __args, object __instance, out object result, HookMethodType hookMethodType)
{
result = null;
@@ -81,10 +89,10 @@ namespace Barotrauma
switch (hookMethodType)
{
case HookMethodType.Before:
_inst.hookPrefixMethods.TryGetValue(funcAddr, out methodSet);
instance.hookPrefixMethods.TryGetValue(funcAddr, out methodSet);
break;
case HookMethodType.After:
_inst.hookPostfixMethods.TryGetValue(funcAddr, out methodSet);
instance.hookPostfixMethods.TryGetValue(funcAddr, out methodSet);
break;
default:
break;
@@ -196,7 +204,6 @@ namespace Barotrauma
public void HookMethod(string identifier, MethodInfo method, CsPatch patch, HookMethodType hookType = HookMethodType.Before, ACsMod owner = null)
{
Console.WriteLine($" --== '{identifier}' {method.ReflectedType.Name}.{method.Name} -> {method.ReturnType.Name} | {hookType.ToString("G")}");
if (identifier == null || method == null || patch == null) throw new ArgumentNullException("Identifier, Method and Patch arguments must not be null.");
var funcAddr = ((long)method.MethodHandle.GetFunctionPointer());
@@ -208,14 +215,14 @@ namespace Barotrauma
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPrefix) == null)
{
GameMain.LuaCs.harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchRetPrefix));
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchRetPrefix));
}
}
else
{
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPrefix) == null)
{
GameMain.LuaCs.harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchPrefix));
harmony.Patch(method, prefix: new HarmonyMethod(_miHookLuaCsPatchPrefix));
}
}
@@ -236,14 +243,14 @@ namespace Barotrauma
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPostfix) == null)
{
GameMain.LuaCs.harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchRetPostfix));
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchRetPostfix));
}
}
else
{
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchPostfix) == null)
{
GameMain.LuaCs.harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchPostfix));
harmony.Patch(method, postfix: new HarmonyMethod(_miHookLuaCsPatchPostfix));
}
}
@@ -312,7 +319,6 @@ namespace Barotrauma
{
name = name.ToLower();
LuaCsSetup.PrintLogMessage($"'{name}' | '{hookName}'");
if (name == null || hookName == null || hook == null) throw new ArgumentNullException("Names and Hook must not be null");
if (!hookFunctions.ContainsKey(name))
@@ -340,7 +346,7 @@ namespace Barotrauma
queuedFunctionCalls.Clear();
GameMain.LuaCs.harmony?.UnpatchAll();
harmony?.UnpatchAll();
}
@@ -24,19 +24,18 @@ namespace Barotrauma
internal LuaCsHook Hook { get; private set; }
public LuaGame game;
public LuaCsNetworking networking;
public Harmony harmony;
public LuaGame Game;
public LuaCsNetworking Networking;
public LuaScriptLoader luaScriptLoader;
public CsScriptLoader netScriptLoader;
public LuaScriptLoader LuaScriptLoader;
public CsScriptLoader NetScriptLoader;
public LuaCsSetup()
{
Hook = LuaCsHook.Instance;
Hook = new LuaCsHook();
game = new LuaGame();
networking = new LuaCsNetworking();
Game = new LuaGame();
Networking = new LuaCsNetworking();
}
@@ -265,7 +264,7 @@ namespace Barotrauma
public void SetModulePaths(string[] str)
{
luaScriptLoader.ModulePaths = str;
LuaScriptLoader.ModulePaths = str;
}
public void Update()
@@ -279,31 +278,12 @@ namespace Barotrauma
ACsMod.LoadedMods.Clear();
Hook?.Call("stop");
game?.Stop();
//harmony?.UnpatchAll();
Game?.Stop();
//Hook = new LuaCsHook();
Hook.Clear();
game = new LuaGame();
networking = new LuaCsNetworking();
luaScriptLoader = null;
}
private void InitCs()
{
netScriptLoader = new CsScriptLoader(this);
netScriptLoader.SearchFolders();
if (netScriptLoader == null) throw new Exception("LuaCsSetup was not properly initialized.");
try
{
var modTypes = netScriptLoader.Compile();
//modTypes.ForEach(t => ACsMod.CreateInstance(t));
modTypes.ForEach(t => t.GetConstructor(new Type[] { })?.Invoke(null));
}
catch (Exception ex)
{
PrintMessage(ex);
}
Game = new LuaGame();
Networking = new LuaCsNetworking();
LuaScriptLoader = null;
}
public void Initialize()
@@ -312,32 +292,27 @@ namespace Barotrauma
PrintMessage("LuaCs! Version " + AssemblyInfo.GitRevision);
luaScriptLoader = new LuaScriptLoader();
luaScriptLoader.ModulePaths = new string[] { };
InitCs();
LuaScriptLoader = new LuaScriptLoader();
LuaScriptLoader.ModulePaths = new string[] { };
NetScriptLoader = new CsScriptLoader(this);
LuaCustomConverters.RegisterAll();
lua = new Script(CoreModules.Preset_SoftSandbox | CoreModules.Debug);
lua.Options.DebugPrint = PrintMessage;
lua.Options.ScriptLoader = luaScriptLoader;
lua.Options.ScriptLoader = LuaScriptLoader;
harmony = new Harmony("com.LuaForBarotrauma");
harmony.UnpatchAll();
Hook.Initialize();
Game = new LuaGame();
Networking = new LuaCsNetworking();
//Hook = new LuaCsHook();
game = new LuaGame();
networking = new LuaCsNetworking();
//UserData.RegisterType<LuaCsHook>();
UserData.RegisterType<LuaGame>();
UserData.RegisterType<LuaCsTimer>();
UserData.RegisterType<LuaCsFile>();
UserData.RegisterType<LuaCsNetworking>();
UserData.RegisterType<LuaUserData>();
UserData.RegisterType<IUserDataDescriptor>();
lua.Globals["printerror"] = (Action<object>)PrintError;
var hookType = UserData.RegisterType<LuaCsHook>();
var hookDesc = (StandardUserDataDescriptor)hookType;
@@ -353,6 +328,8 @@ namespace Barotrauma
}
});
lua.Globals["printerror"] = (Action<object>)PrintError;
lua.Globals["setmodulepaths"] = (Action<string[]>)SetModulePaths;
lua.Globals["dofile"] = (Func<string, Table, string, DynValue>)DoFile;
@@ -363,11 +340,11 @@ namespace Barotrauma
lua.Globals["load"] = (Func<string, Table, string, DynValue>)LoadString;
lua.Globals["LuaUserData"] = UserData.CreateStatic<LuaUserData>();
lua.Globals["Game"] = game;
lua.Globals["Game"] = Game;
lua.Globals["Hook"] = Hook;
lua.Globals["Timer"] = new LuaCsTimer();
lua.Globals["File"] = UserData.CreateStatic<LuaCsFile>();
lua.Globals["Networking"] = networking;
lua.Globals["Networking"] = Networking;
bool isServer;
@@ -382,6 +359,20 @@ namespace Barotrauma
// LuaDocs.GenerateDocsAll();
NetScriptLoader.SearchFolders();
if (NetScriptLoader == null) throw new Exception("LuaCsSetup was not properly initialized.");
try
{
var modTypes = NetScriptLoader.Compile();
modTypes.ForEach(t => t.GetConstructor(new Type[] { })?.Invoke(null));
}
catch (Exception ex)
{
PrintMessage(ex);
}
ContentPackage luaPackage = GetPackage();
if (File.Exists(LUASETUP_FILE))
@@ -411,7 +402,7 @@ namespace Barotrauma
}
else
{
PrintError("LuaCs loader not found! Lua/LuaSetup.lua, no Lua scripts will be executed or work.");
PrintError("LuaSetup.lua not found! Lua/LuaSetup.lua, no Lua scripts will be executed or work.");
}
}