using System;
using System.IO;
using Barotrauma.Networking;
using MoonSharp.Interpreter;
using Microsoft.Xna.Framework;
using MoonSharp.Interpreter.Interop;
using System.Runtime.CompilerServices;
using System.Linq;
using System.Threading;
using LuaCsCompatPatchFunc = Barotrauma.LuaCsPatch;
using System.Diagnostics;
[assembly: InternalsVisibleTo(Barotrauma.CsScriptBase.CsScriptAssembly, AllInternalsVisible = true)]
[assembly: InternalsVisibleTo(Barotrauma.CsScriptBase.CsOneTimeScriptAssembly, AllInternalsVisible = true)]
namespace Barotrauma
{
class LuaCsSetupConfig
{
public bool FirstTimeCsWarning = true;
public LuaCsSetupConfig() { }
}
partial class LuaCsSetup
{
public const string LuaSetupFile = "Lua/LuaSetup.lua";
public const string VersionFile = "luacsversion.txt";
public static ContentPackageId LuaForBarotraumaId = new SteamWorkshopId(2559634234);
public static ContentPackageId CsForBarotraumaId = new SteamWorkshopId(2795927223);
private const string configFileName = "LuaCsSetupConfig.xml";
#if SERVER
public const bool IsServer = true;
public const bool IsClient = false;
#else
public const bool IsServer = false;
public const bool IsClient = true;
#endif
private static int executionNumber = 0;
public Script Lua { get; private set; }
public CsScriptRunner CsScript { get; private set; }
public LuaScriptLoader LuaScriptLoader { get; private set; }
public LuaGame Game { get; private set; }
public LuaCsHook Hook { get; private set; }
public LuaCsTimer Timer { get; private set; }
public LuaCsNetworking Networking { get; private set; }
public LuaCsSteam Steam { get; private set; }
public LuaCsPerformanceCounter PerformanceCounter { get; private set; }
public LuaCsModStore ModStore { get; private set; }
private LuaRequire require { get; set; }
public CsScriptLoader CsScriptLoader { get; private set; }
public LuaCsSetupConfig Config { get; private set; }
internal LuaCsExceptionHandler ExceptionHandler { get; set; }
internal LuaCsMessageLogger MessageLogger { get; set; }
public LuaCsSetup()
{
MessageLogger = DefaultMessageLogger;
ExceptionHandler = DefaultExceptionHandler;
Hook = new LuaCsHook(this);
ModStore = new LuaCsModStore();
Game = new LuaGame();
Networking = new LuaCsNetworking();
}
public void UpdateConfig()
{
FileStream file;
if (!File.Exists(configFileName)) file = File.Create(configFileName);
else file = File.Open(configFileName, FileMode.Truncate, FileAccess.Write);
LuaCsConfig.Save(file, Config);
file.Close();
}
///
/// due to there's a race on the process and the unloaded AssemblyLoadContexts,
/// should recreate runner after the script runs
///
public void RecreateCsScript()
{
CsScript = new CsScriptRunner(CsScript.setup);
Lua.Globals["CsScript"] = CsScript;
}
public static ContentPackage GetPackage(ContentPackageId id, bool fallbackToAll = true, bool useBackup = false)
{
foreach (ContentPackage package in ContentPackageManager.EnabledPackages.All)
{
if (package.UgcId.ValueEquals(id))
{
return package;
}
}
if (fallbackToAll)
{
foreach (ContentPackage package in ContentPackageManager.LocalPackages)
{
if (package.UgcId.ValueEquals(id))
{
return package;
}
}
foreach (ContentPackage package in ContentPackageManager.AllPackages)
{
if (package.UgcId.ValueEquals(id))
{
return package;
}
}
}
if (useBackup && ContentPackageManager.EnabledPackages.BackupPackages.Regular != null)
{
foreach (ContentPackage package in ContentPackageManager.EnabledPackages.BackupPackages.Regular.Value)
{
if (package.UgcId.ValueEquals(id))
{
return package;
}
}
}
return null;
}
internal void HandleException(Exception ex, LuaCsMessageOrigin origin)
{
this.ExceptionHandler?.Invoke(ex, origin);
}
private DynValue DoFile(string file, Table globalContext = null, string codeStringFriendly = null)
{
if (!LuaCsFile.CanReadFromPath(file))
{
throw new ScriptRuntimeException($"dofile: File access to {file} not allowed.");
}
if (!LuaCsFile.Exists(file))
{
throw new ScriptRuntimeException($"dofile: File {file} not found.");
}
return Lua.DoFile(file, globalContext, codeStringFriendly);
}
private DynValue LoadFile(string file, Table globalContext = null, string codeStringFriendly = null)
{
if (!LuaCsFile.CanReadFromPath(file))
{
throw new ScriptRuntimeException($"loadfile: File access to {file} not allowed.");
}
if (!LuaCsFile.Exists(file))
{
throw new ScriptRuntimeException($"loadfile: File {file} not found.");
}
return Lua.LoadFile(file, globalContext, codeStringFriendly);
}
public DynValue CallLuaFunction(object function, params object[] args)
{
// XXX: `lua` might be null if `LuaCsSetup.Stop()` is called while
// a patched function is still running.
if (Lua == null) return null;
lock (Lua)
{
try
{
return Lua.Call(function, args);
}
catch (Exception e)
{
HandleException(e, LuaCsMessageOrigin.LuaMod);
}
return null;
}
}
private void SetModulePaths(string[] str)
{
LuaScriptLoader.ModulePaths = str;
}
public void Update()
{
Hook?.Update();
Timer?.Update();
Steam?.Update();
}
public void Stop()
{
foreach (var type in AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name == CsScriptBase.CsScriptAssembly).SelectMany(assembly => assembly.GetTypes()))
{
UserData.UnregisterType(type, true);
}
foreach (var mod in ACsMod.LoadedMods.ToArray())
{
mod.Dispose();
}
ACsMod.LoadedMods.Clear();
if (Thread.CurrentThread == GameMain.MainThread)
{
Hook?.Call("stop");
}
Game?.Stop();
Hook.Clear();
ModStore.Clear();
Game = new LuaGame();
Networking = new LuaCsNetworking();
Timer = new LuaCsTimer();
Steam = new LuaCsSteam();
PerformanceCounter = new LuaCsPerformanceCounter();
LuaScriptLoader = null;
Lua = null;
CsScript = null;
Config = null;
if (CsScriptLoader != null)
{
CsScriptLoader.Clear();
CsScriptLoader.Unload();
CsScriptLoader = null;
}
}
public void Initialize()
{
Stop();
PrintMessage("Lua! Version " + AssemblyInfo.GitRevision);
if (File.Exists(configFileName))
{
using (var file = File.Open(configFileName, FileMode.Open, FileAccess.Read))
Config = LuaCsConfig.Load(file);
}
else
{
Config = new LuaCsSetupConfig();
}
bool csActive = GetPackage(CsForBarotraumaId, false, true) != null;
LuaScriptLoader = new LuaScriptLoader();
LuaScriptLoader.ModulePaths = new string[] { };
RegisterLuaConverters();
Lua = new Script(CoreModules.Preset_SoftSandbox | CoreModules.Debug);
Lua.Options.DebugPrint = PrintMessage;
Lua.Options.ScriptLoader = LuaScriptLoader;
Lua.Options.CheckThreadAccess = false;
Script.GlobalOptions.ShouldPCallCatchException = (Exception ex) => { return true; };
CsScript = new CsScriptRunner(this);
require = new LuaRequire(Lua);
Game = new LuaGame();
Networking = new LuaCsNetworking();
Timer = new LuaCsTimer();
Steam = new LuaCsSteam();
PerformanceCounter = new LuaCsPerformanceCounter();
Hook.Initialize();
ModStore.Initialize();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
UserData.RegisterType();
Lua.Globals["printerror"] = (Action