diff --git a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs index 89805c561..f9cfd9f44 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs @@ -3096,6 +3096,22 @@ namespace Barotrauma NewMessage("Level seed: " + Level.Loaded.Seed); } }); + + commands.Add(new Command("lua_cl", "lua_cl: runs a string on the client", (string[] args) => + { + if (GameMain.Client != null) + GameMain.Lua.DoString(string.Join(" ", args)); + else + ThrowError("Client not connected to any server."); + })); + + commands.Add(new Command("reloadlua_cl", "reloads lua on the client", (string[] args) => + { + if (GameMain.Client != null) + GameMain.Lua.Initialize(); + else + ThrowError("Client not connected to any server."); + })); } private static void ReloadWearables(Character character, int variant = 0) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs index 0dbbe81f8..114c52e72 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameMain.cs @@ -23,6 +23,8 @@ namespace Barotrauma { class GameMain : Game { + public static LuaSetup Lua; + public static bool ShowFPS = false; public static bool ShowPerf = false; public static bool DebugDraw; @@ -210,6 +212,8 @@ namespace Barotrauma Config = new GameSettings(); + Lua = new LuaSetup(); + Md5Hash.LoadCache(); ConsoleArguments = args; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index 363d909a3..f0db0650e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -393,6 +393,8 @@ namespace Barotrauma.Networking { GameMain.NetLobbyScreen.ChatInput.Enabled = true; } + + GameMain.Lua.Initialize(); }; clientPeer.OnRequestPassword = (int salt, int retries) => { @@ -2690,6 +2692,8 @@ namespace Barotrauma.Networking public override void Disconnect() { + GameMain.Lua.Stop(); + allowReconnect = false; if (clientPeer is SteamP2PClientPeer || clientPeer is SteamP2POwnerPeer) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaBarotraumaAdditions.cs b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaBarotraumaAdditions.cs index f8daf14cb..cfdba2fb6 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaBarotraumaAdditions.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaBarotraumaAdditions.cs @@ -1,21 +1,11 @@ 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 ClientList - { - get - { - return GameMain.Server.ConnectedClients; - } - } - public void SetClientCharacter(Character character) { GameMain.Server.SetClientCharacter(this, character); @@ -48,88 +38,30 @@ namespace Barotrauma.Networking return this.Permissions.HasFlag(permissions); } } - } -namespace Barotrauma +namespace Barotrauma { - using Barotrauma.Networking; - using System.Linq; - using System.Reflection; - - - - partial class Character - { - - } - - partial class AfflictionPrefab - { - public static AfflictionPrefab[] ListArray - { - get - { - return List.ToArray(); - } - } - } - - partial class CharacterInfo - { - public static CharacterInfo Create(string speciesName, string name = "", JobPrefab jobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced, string npcIdentifier = "") - { - return new CharacterInfo(speciesName, name, name, jobPrefab, ragdollFileName, variant, randSync, npcIdentifier); - } - } - - partial class Item - { - public static void AddToRemoveQueue(Item item) - { - EntitySpawner.Spawner.AddToRemoveQueue(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); - } - - } + using Microsoft.Xna.Framework; partial class ItemPrefab { public static void AddToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, object spawned = null) { - EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, position, onSpawned: (Item item) => { + EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, position, onSpawned: (Item item) => + { GameMain.Lua.CallFunction(spawned, new object[] { item }); }); } public static void AddToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, object spawned = null) { - EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, inventory, onSpawned: (Item item) => { + EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, inventory, onSpawned: (Item item) => + { GameMain.Lua.CallFunction(spawned, new object[] { item }); }); } - - 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; - } } - } namespace Barotrauma.Items.Components @@ -159,4 +91,6 @@ namespace Barotrauma.Items.Components return new Signal(value, stepsTaken, sender, source, power, strength); } } + + } \ No newline at end of file diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs index d0cbb9c0e..31368f1cb 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs @@ -11,27 +11,71 @@ using System.Net; using System.Linq; using System.Xml.Linq; + namespace Barotrauma { - partial class LuaSetup { - private static Vector2 CreateVector2(float x, float y) + partial class LuaGame { - return new Vector2(x, y); + public bool IsDedicated + { + get + { + return GameMain.Server.ServerPeer is LidgrenServerPeer; + } + } + + public ServerSettings ServerSettings => GameMain.Server.ServerSettings; + + + 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, string 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(); + } } - private static Vector3 CreateVector3(float x, float y, float z) - { - return new Vector3(x, y, z); - } - - private static Vector4 CreateVector4(float x, float y, float z, float w) - { - return new Vector4(x, y, z, w); - } - - private class LuaPlayer + partial class LuaPlayer { public static List GetAllCharacters() @@ -89,22 +133,22 @@ namespace Barotrauma public static void SetSpectatorPos(Client client, Vector2 pos) { - + } public static void SetRadioRange(Character character, float range) { - if(character.Inventory == null) { return; } + if (character.Inventory == null) { return; } - foreach(Item item in character.Inventory.AllItems) + foreach (Item item in character.Inventory.AllItems) { - if(item == null) { continue; } + if (item == null) { continue; } - if(item.Name == "Headset") + if (item.Name == "Headset") { item.GetComponent().Range = range; } - } + } } public static bool CheckPermission(Client client, ClientPermissions permissions) @@ -112,521 +156,5 @@ namespace Barotrauma return client.Permissions.HasFlag(permissions); } } - - public class LuaGame - { - LuaSetup env; - - public LuaGame(LuaSetup e) - { - env = e; - } - - public bool allowWifiChat = false; - public bool overrideTraitors = false; - public bool overrideRespawnSub = false; - public bool overrideSignalRadio = false; - public bool disableSpamFilter = false; - - public bool RoundStarted - { - get - { - return GameMain.Server.GameStarted; - } - } - - - public bool IsDedicated - { - get - { - return GameMain.Server.ServerPeer is LidgrenServerPeer; - } - } - - public ServerSettings Settings => GameMain.Server.ServerSettings; - - 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, string 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 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 static void Log(string message, ServerLog.MessageType type) - { - GameServer.Log(message, type); - } - - 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 Character Spawn(string name, Vector2 worldPos) - { - Character spawnedCharacter = null; - Vector2 spawnPosition = worldPos; - - string characterLowerCase = name.ToLowerInvariant(); - JobPrefab job = null; - if (!JobPrefab.Prefabs.ContainsKey(characterLowerCase)) - { - job = JobPrefab.Prefabs.Find(jp => jp.Name != null && jp.Name.Equals(characterLowerCase, StringComparison.OrdinalIgnoreCase)); - } - else - { - job = JobPrefab.Prefabs[characterLowerCase]; - } - bool human = job != null || characterLowerCase == CharacterPrefab.HumanSpeciesName; - - - if (string.IsNullOrWhiteSpace(name)) { return null; } - - if (human) - { - var variant = job != null ? Rand.Range(0, job.Variants, Rand.RandSync.Server) : 0; - CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, variant: variant); - spawnedCharacter = Character.Create(characterInfo, spawnPosition, ToolBox.RandomSeed(8)); - if (GameMain.GameSession != null) - { - //TODO: a way to select which team to spawn to? - spawnedCharacter.TeamID = Character.Controlled != null ? Character.Controlled.TeamID : CharacterTeamType.Team1; -#if CLIENT - GameMain.GameSession.CrewManager.AddCharacter(spawnedCharacter); -#endif - } - spawnedCharacter.GiveJobItems(null); - spawnedCharacter.Info.StartItemsGiven = true; - } - else - { - if (CharacterPrefab.FindBySpeciesName(name) != null) - { - spawnedCharacter = Character.Create(name, spawnPosition, ToolBox.RandomSeed(8)); - } - } - - return spawnedCharacter; - } - - 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 void RemoveItem(Item item) - { - EntitySpawner.Spawner.AddToRemoveQueue(item); - } - - 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 void AddItemPrefabToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, DynValue spawned = null) - { - EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, position, onSpawned: (Item item) => { - if (spawned?.Type == DataType.Function) env.lua.Call(spawned, UserData.Create(item)); - }); - } - - public void AddItemPrefabToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, DynValue spawned = null) - { - EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, inventory, onSpawned: (Item item) => { - if (spawned?.Type == DataType.Function) env.lua.Call(spawned, UserData.Create(item)); - }); - } - - public static Submarine GetRespawnSub() - { - if (GameMain.Server.RespawnManager == null) - return null; - return GameMain.Server.RespawnManager.RespawnShuttle; - } - - public static Items.Components.Steering GetSubmarineSteering(Submarine sub) - { - foreach (Item item in Item.ItemList) - { - if (item.Submarine != sub) continue; - - var steering = item.GetComponent(); - if (steering != null) - { - return steering; - } - } - - return null; - } - - public static WifiComponent GetWifiComponent(Item item) - { - if (item == null) return null; - return item.GetComponent(); - } - - public static LightComponent GetLightComponent(Item item) - { - if (item == null) return null; - return item.GetComponent(); - } - - public static CustomInterface GetCustomInterface(Item item) - { - if (item == null) return null; - return item.GetComponent(); - } - - public static Fabricator GetFabricatorComponent(Item item) - { - if (item == null) return null; - return item.GetComponent(); - } - - public static Holdable GetHoldableComponent(Item item) - { - if (item == null) return null; - return item.GetComponent(); - } - - public static void DispatchRespawnSub() - { - GameMain.Server.RespawnManager.DispatchShuttle(); - } - - public static void SetRespawnSubTeam(int team) - { - GameMain.Server.RespawnManager.RespawnShuttle.TeamID = (CharacterTeamType)team; - } - - public static void ExecuteCommand(string command) - { - DebugConsole.ExecuteCommand(command); - } - - - public static void StartGame() - { - GameMain.Server.StartGame(); - } - - 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); - } - - public static ContentPackage[] GetEnabledContentPackages() - { - return GameMain.Config.AllEnabledPackages.ToArray(); - } - - public static List GetEnabledPackagesDirectlyFromFile() - { - List enabledPackages = new List(); - - XDocument doc = XMLExtensions.LoadXml("config_player.xml"); - var contentPackagesElement = doc.Root.Element("contentpackages"); - - string coreName = contentPackagesElement.Element("core")?.GetAttributeString("name", ""); - enabledPackages.Add(coreName); - - XElement regularElement = contentPackagesElement.Element("regular"); - List subElements = regularElement?.Elements()?.ToList(); - - foreach (var subElement in subElements) - { - if (!bool.TryParse(subElement.GetAttributeString("enabled", "false"), out bool enabled) || !enabled) { continue; } - - string name = subElement.GetAttributeString("name", null); - enabledPackages.Add(name); - } - return enabledPackages; - } - } - - - private class LuaTimer - { - public LuaSetup env; - - public LuaTimer(LuaSetup e) - { - env = e; - } - - public static double GetTime() - { - return Timing.TotalTime; - } - - - } - - private class LuaRandom - { - Random random; - - public LuaRandom() - { - random = new Random(); - } - - public int Range(int min, int max) - { - return random.Next(min, max); - } - - public float RangeFloat(float min, float max) - { - double range = (double)max - (double)min; - double sample = random.NextDouble(); - double scaled = (sample * range) + min; - float f = (float)scaled; - - return f; - } - - } - - private class LuaFile - { - // TODO: SANDBOXING - - public static string Read(string path) - { - return File.ReadAllText(path); - } - - public static void Write(string path, string text) - { - File.WriteAllText(path, text); - } - - public static bool Exists(string path) - { - return File.Exists(path); - } - - public static bool DirectoryExists(string path) - { - return Directory.Exists(path); - } - - public static string[] GetFiles(string path) - { - return Directory.GetFiles(path); - } - - public static string[] GetDirectories(string path) - { - return Directory.GetDirectories(path); - } - - public static string[] DirSearch(string sDir) - { - List files = new List(); - - try - { - foreach (string f in Directory.GetFiles(sDir)) - { - files.Add(f); - } - - foreach (string d in Directory.GetDirectories(sDir)) - { - foreach (string f in Directory.GetFiles(d)) - { - files.Add(f); - } - DirSearch(d); - } - } - catch (System.Exception excpt) - { - Console.WriteLine(excpt.Message); - } - - return files.ToArray(); - } - } - - private class LuaNetworking - { - public LuaSetup env; - - public LuaNetworking(LuaSetup e) - { - env = e; - } - - public string RequestPostHTTP(string url, string data, string contentType = "application/json") - { - try - { - var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); - httpWebRequest.ContentType = contentType; - httpWebRequest.Method = "POST"; - - using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) - streamWriter.Write(data); - - var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - return streamReader.ReadToEnd(); - }catch(Exception e) - { - return e.ToString(); - } - } - - public string RequestGetHTTP(string url) - { - try - { - var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); - - var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - return streamReader.ReadToEnd(); - }catch(Exception e) - { - return e.ToString(); - } - } - } - - public class LuaHook - { - public LuaSetup env; - - public LuaHook(LuaSetup e) - { - env = e; - } - - public class HookFunction - { - public string name; - public string hookName; - public object function; - - public HookFunction(string n, string hn, object func) - { - name = n; - hookName = hn; - function = func; - } - } - - public Dictionary> hookFunctions = new Dictionary>(); - - public void Add(string name, string hookName, object function) - { - if (name == null && hookName == null && function == null) return; - - if (!hookFunctions.ContainsKey(name)) - hookFunctions.Add(name, new Dictionary()); - - - hookFunctions[name][hookName] = new HookFunction(name, hookName, function); - } - - public void Remove(string name, string hookName) - { - if (name == null && hookName == null) return; - - if (!hookFunctions.ContainsKey(name)) - return; - - if(hookFunctions[name].ContainsKey(hookName)) - hookFunctions[name].Remove(hookName); - } - - public object Call(string name, object[] args) - { - if (name == null) return null; - - if (!hookFunctions.ContainsKey(name)) - return null; - - object lastResult = null; - - foreach (HookFunction hf in hookFunctions[name].Values) - { - try - { - if (hf.function is Closure) - lastResult = env.lua.Call(hf.function, args); - // else if (hf.function is NLua.LuaFunction luaFunction) - // lastResult = luaFunction.Call(args); - } - catch (Exception e) - { - env.HandleLuaException(e); - } - } - - return lastResult; - } - } } -} \ No newline at end of file +} diff --git a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaBarotraumaAdditions.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaBarotraumaAdditions.cs new file mode 100644 index 000000000..9beec97ae --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaBarotraumaAdditions.cs @@ -0,0 +1,106 @@ +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 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 AfflictionPrefab + { + public static AfflictionPrefab[] ListArray + { + get + { + return List.ToArray(); + } + } + } + + partial class CharacterInfo + { + public static CharacterInfo Create(string speciesName, string name = "", JobPrefab jobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced, string npcIdentifier = "") + { + return new CharacterInfo(speciesName, name, name, jobPrefab, ragdollFileName, variant, randSync, npcIdentifier); + } + } + + partial class Item + { + public static void AddToRemoveQueue(Item item) + { + EntitySpawner.Spawner.AddToRemoveQueue(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; + } + } + +} + +namespace Barotrauma.Items.Components +{ + using Barotrauma.Networking; + + partial class CustomInterface + { + } + + partial struct Signal + { + } +} \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs new file mode 100644 index 000000000..3c9d4326f --- /dev/null +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs @@ -0,0 +1,507 @@ +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; + +namespace Barotrauma +{ + + partial class LuaSetup + { + private static Vector2 CreateVector2(float x, float y) + { + return new Vector2(x, y); + } + + private static Vector3 CreateVector3(float x, float y, float z) + { + return new Vector3(x, y, z); + } + + private static Vector4 CreateVector4(float x, float y, float z, float w) + { + return new Vector4(x, y, z, w); + } + + private partial class LuaPlayer + { + + } + + public partial class LuaGame + { + LuaSetup env; + + public LuaGame(LuaSetup e) + { + env = e; + } + + public bool allowWifiChat = false; + public bool overrideTraitors = false; + public bool overrideRespawnSub = false; + public bool overrideSignalRadio = false; + public bool disableSpamFilter = false; + + public bool RoundStarted + { + + get + { +#if SERVER + return GameMain.Server.GameStarted; +#else + return GameMain.Client.GameStarted; +#endif + } + } + + + + 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 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 Character Spawn(string name, Vector2 worldPos) + { + Character spawnedCharacter = null; + Vector2 spawnPosition = worldPos; + + string characterLowerCase = name.ToLowerInvariant(); + JobPrefab job = null; + if (!JobPrefab.Prefabs.ContainsKey(characterLowerCase)) + { + job = JobPrefab.Prefabs.Find(jp => jp.Name != null && jp.Name.Equals(characterLowerCase, StringComparison.OrdinalIgnoreCase)); + } + else + { + job = JobPrefab.Prefabs[characterLowerCase]; + } + bool human = job != null || characterLowerCase == CharacterPrefab.HumanSpeciesName; + + + if (string.IsNullOrWhiteSpace(name)) { return null; } + + if (human) + { + var variant = job != null ? Rand.Range(0, job.Variants, Rand.RandSync.Server) : 0; + CharacterInfo characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, variant: variant); + spawnedCharacter = Character.Create(characterInfo, spawnPosition, ToolBox.RandomSeed(8)); + if (GameMain.GameSession != null) + { + //TODO: a way to select which team to spawn to? + spawnedCharacter.TeamID = Character.Controlled != null ? Character.Controlled.TeamID : CharacterTeamType.Team1; +#if CLIENT + GameMain.GameSession.CrewManager.AddCharacter(spawnedCharacter); +#endif + } + spawnedCharacter.GiveJobItems(null); + spawnedCharacter.Info.StartItemsGiven = true; + } + else + { + if (CharacterPrefab.FindBySpeciesName(name) != null) + { + spawnedCharacter = Character.Create(name, spawnPosition, ToolBox.RandomSeed(8)); + } + } + + return spawnedCharacter; + } + + 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 void RemoveItem(Item item) + { + EntitySpawner.Spawner.AddToRemoveQueue(item); + } + + 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 void AddItemPrefabToSpawnQueue(ItemPrefab itemPrefab, Vector2 position, DynValue spawned = null) + { + EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, position, onSpawned: (Item item) => { + if (spawned?.Type == DataType.Function) env.lua.Call(spawned, UserData.Create(item)); + }); + } + + public void AddItemPrefabToSpawnQueue(ItemPrefab itemPrefab, Inventory inventory, DynValue spawned = null) + { + EntitySpawner.Spawner.AddToSpawnQueue(itemPrefab, inventory, onSpawned: (Item item) => { + if (spawned?.Type == DataType.Function) env.lua.Call(spawned, UserData.Create(item)); + }); + } + + 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(); + if (steering != null) + { + return steering; + } + } + + return null; + } + + public static WifiComponent GetWifiComponent(Item item) + { + if (item == null) return null; + return item.GetComponent(); + } + + public static LightComponent GetLightComponent(Item item) + { + if (item == null) return null; + return item.GetComponent(); + } + + public static CustomInterface GetCustomInterface(Item item) + { + if (item == null) return null; + return item.GetComponent(); + } + + public static Fabricator GetFabricatorComponent(Item item) + { + if (item == null) return null; + return item.GetComponent(); + } + + public static Holdable GetHoldableComponent(Item item) + { + if (item == null) return null; + return item.GetComponent(); + } + + 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); + } + + public static ContentPackage[] GetEnabledContentPackages() + { + return GameMain.Config.AllEnabledPackages.ToArray(); + } + + public static List GetEnabledPackagesDirectlyFromFile() + { + List enabledPackages = new List(); + + XDocument doc = XMLExtensions.LoadXml("config_player.xml"); + var contentPackagesElement = doc.Root.Element("contentpackages"); + + string coreName = contentPackagesElement.Element("core")?.GetAttributeString("name", ""); + enabledPackages.Add(coreName); + + XElement regularElement = contentPackagesElement.Element("regular"); + List subElements = regularElement?.Elements()?.ToList(); + + foreach (var subElement in subElements) + { + if (!bool.TryParse(subElement.GetAttributeString("enabled", "false"), out bool enabled) || !enabled) { continue; } + + string name = subElement.GetAttributeString("name", null); + enabledPackages.Add(name); + } + return enabledPackages; + } + } + + + private partial class LuaTimer + { + public LuaSetup env; + + public LuaTimer(LuaSetup e) + { + env = e; + } + + public static double GetTime() + { + return Timing.TotalTime; + } + + + } + + private partial class LuaRandom + { + Random random; + + public LuaRandom() + { + random = new Random(); + } + + public int Range(int min, int max) + { + return random.Next(min, max); + } + + public float RangeFloat(float min, float max) + { + double range = (double)max - (double)min; + double sample = random.NextDouble(); + double scaled = (sample * range) + min; + float f = (float)scaled; + + return f; + } + + } + + private partial class LuaFile + { + // TODO: SANDBOXING + + public static string Read(string path) + { + return File.ReadAllText(path); + } + + public static void Write(string path, string text) + { + File.WriteAllText(path, text); + } + + public static bool Exists(string path) + { + return File.Exists(path); + } + + public static bool DirectoryExists(string path) + { + return Directory.Exists(path); + } + + public static string[] GetFiles(string path) + { + return Directory.GetFiles(path); + } + + public static string[] GetDirectories(string path) + { + return Directory.GetDirectories(path); + } + + public static string[] DirSearch(string sDir) + { + List files = new List(); + + try + { + foreach (string f in Directory.GetFiles(sDir)) + { + files.Add(f); + } + + foreach (string d in Directory.GetDirectories(sDir)) + { + foreach (string f in Directory.GetFiles(d)) + { + files.Add(f); + } + DirSearch(d); + } + } + catch (System.Exception excpt) + { + Console.WriteLine(excpt.Message); + } + + return files.ToArray(); + } + } + + private partial class LuaNetworking + { + public LuaSetup env; + + public LuaNetworking(LuaSetup e) + { + env = e; + } + + public string RequestPostHTTP(string url, string data, string contentType = "application/json") + { + try + { + var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); + httpWebRequest.ContentType = contentType; + httpWebRequest.Method = "POST"; + + using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) + streamWriter.Write(data); + + var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + return streamReader.ReadToEnd(); + }catch(Exception e) + { + return e.ToString(); + } + } + + public string RequestGetHTTP(string url) + { + try + { + var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); + + var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + return streamReader.ReadToEnd(); + }catch(Exception e) + { + return e.ToString(); + } + } + } + + public partial class LuaHook + { + public LuaSetup env; + + public LuaHook(LuaSetup e) + { + env = e; + } + + public class HookFunction + { + public string name; + public string hookName; + public object function; + + public HookFunction(string n, string hn, object func) + { + name = n; + hookName = hn; + function = func; + } + } + + public Dictionary> hookFunctions = new Dictionary>(); + + public void Add(string name, string hookName, object function) + { + if (name == null && hookName == null && function == null) return; + + if (!hookFunctions.ContainsKey(name)) + hookFunctions.Add(name, new Dictionary()); + + + hookFunctions[name][hookName] = new HookFunction(name, hookName, function); + } + + public void Remove(string name, string hookName) + { + if (name == null && hookName == null) return; + + if (!hookFunctions.ContainsKey(name)) + return; + + if(hookFunctions[name].ContainsKey(hookName)) + hookFunctions[name].Remove(hookName); + } + + public object Call(string name, object[] args) + { + if (name == null) return null; + if(args == null) { args = new object[] { }; } + + if (!hookFunctions.ContainsKey(name)) + return null; + + object lastResult = null; + + foreach (HookFunction hf in hookFunctions[name].Values) + { + try + { + if (hf.function is Closure) + lastResult = env.lua.Call(hf.function, args); + // else if (hf.function is NLua.LuaFunction luaFunction) + // lastResult = luaFunction.Call(args); + } + catch (Exception e) + { + env.HandleLuaException(e); + } + } + + return lastResult; + } + } + } +} \ No newline at end of file diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaCustomConverters.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaCustomConverters.cs similarity index 100% rename from Barotrauma/BarotraumaServer/ServerSource/Lua/LuaCustomConverters.cs rename to Barotrauma/BarotraumaShared/SharedSource/Lua/LuaCustomConverters.cs diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaScriptLoader.cs similarity index 100% rename from Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs rename to Barotrauma/BarotraumaShared/SharedSource/Lua/LuaScriptLoader.cs diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs similarity index 95% rename from Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs rename to Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs index 3b3dee67d..91a169d83 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs @@ -41,6 +41,8 @@ namespace Barotrauma { if (message == null) { message = "nil"; } Console.WriteLine(message.ToString()); + +#if SERVER if (GameMain.Server != null) { foreach (var c in GameMain.Server.ConnectedClients) @@ -50,6 +52,10 @@ namespace Barotrauma GameServer.Log("[LUA] " + message.ToString(), ServerLog.MessageType.ServerMessage); } +#else + DebugConsole.NewMessage("[LUA] " + message.ToString()); +#endif + } public void PrintMessageNoLog(object message) @@ -158,6 +164,17 @@ namespace Barotrauma return value * 2; } + public void Stop() + { + + lua = null; + hook = null; + game = null; + luaScriptLoader = null; + + luaSetup = null; + } + public void Initialize() { luaSetup = this; @@ -246,6 +263,8 @@ namespace Barotrauma UserData.RegisterType(); UserData.RegisterType(); UserData.RegisterType(); + UserData.RegisterType>(); + UserData.RegisterType>(); lua = new Script(CoreModules.Preset_SoftSandbox); @@ -307,6 +326,21 @@ namespace Barotrauma lua.Globals["ClientPermissions"] = UserData.CreateStatic(); lua.Globals["Signal"] = UserData.CreateStatic(); + bool isServer = true; + +#if SERVER + isServer = true; +#else + isServer = false; +#endif + + lua.Globals["SERVER"] = isServer; + lua.Globals["CLIENT"] = !isServer; + +#if CLIENT + return; +#endif + if (File.Exists("Lua/MoonsharpSetup.lua")) // try the default loader DoFile("Lua/MoonsharpSetup.lua"); else if (File.Exists("Mods/LuaForBarotrauma/Lua/MoonsharpSetup.lua")) // in case its the workshop version diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/NLuaSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/NLuaSetup.cs similarity index 100% rename from Barotrauma/BarotraumaServer/ServerSource/Lua/NLuaSetup.cs rename to Barotrauma/BarotraumaShared/SharedSource/Lua/NLuaSetup.cs diff --git a/docs/lua/Client.lua b/docs/lua/Client.lua index 4ed8249f3..117924e54 100644 --- a/docs/lua/Client.lua +++ b/docs/lua/Client.lua @@ -34,4 +34,9 @@ function Client.Unban(player, endpoint) end --- List of all connected clients. -- @treturn table -- @realm shared -Client.ClientList = {} \ No newline at end of file +Client.ClientList = {} + +--- The Character that the client is currently controlling. +-- @treturn Character +-- @realm shared +Character = {} \ No newline at end of file