From d17900d7f37ec715c0dd81bda9cb6436d6463df1 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Wed, 13 Apr 2016 11:48:48 +0100 Subject: [PATCH 1/2] Pre compile Lua script on startup for fast execution --- .../FungusLua/Scripts/LuaEnvironment.cs | 56 ++++++++++++------- Assets/Fungus/FungusLua/Scripts/LuaScript.cs | 56 +++++++++++++------ 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/Assets/Fungus/FungusLua/Scripts/LuaEnvironment.cs b/Assets/Fungus/FungusLua/Scripts/LuaEnvironment.cs index 21c57073..783f56cb 100644 --- a/Assets/Fungus/FungusLua/Scripts/LuaEnvironment.cs +++ b/Assets/Fungus/FungusLua/Scripts/LuaEnvironment.cs @@ -202,22 +202,11 @@ namespace Fungus /// Run the Lua code as a coroutine to support asynchronous operations. /// Method to callback when the Lua code finishes exection. Supports return parameters. /// - public void DoLuaString(string luaString, string friendlyName, bool runAsCoroutine, Action onComplete = null) + public virtual void DoLuaString(string luaString, string friendlyName, bool runAsCoroutine, Action onComplete = null) { - InitEnvironment(); + Closure fn = LoadLuaString(luaString, friendlyName); - // Load the Lua script - DynValue res = null; - try - { - res = interpreter.LoadString(luaString, null, friendlyName); - } - catch (InterpreterException ex) - { - LogException(ex.DecoratedMessage, luaString); - } - - if (res == null) + if (fn == null) { if (onComplete != null) { @@ -230,14 +219,14 @@ namespace Fungus // Execute the Lua script if (runAsCoroutine) { - StartCoroutine(RunLuaCoroutineInternal(res.Function, luaString, onComplete)); + StartCoroutine(RunLuaCoroutineInternal(fn, luaString, onComplete)); } else { DynValue returnValue = null; try { - returnValue = res.Function.Call(); + returnValue = fn.Call(); } catch (InterpreterException ex) { @@ -251,13 +240,42 @@ namespace Fungus } } + /// + /// Loads and compiles a string containing Lua script, returning a closure (Lua function) which can be executed later. + /// The Lua code to be run. + /// A descriptive name to be used in error reports. + /// + public virtual Closure LoadLuaString(string luaString, string friendlyName) + { + InitEnvironment(); + + // Load the Lua script + DynValue res = null; + try + { + res = interpreter.LoadString(luaString, null, friendlyName); + } + catch (InterpreterException ex) + { + LogException(ex.DecoratedMessage, luaString); + } + + if (res.Type != DataType.Function) + { + UnityEngine.Debug.LogError("Failed to create Lua function from Lua string"); + return null; + } + + return res.Function; + } + /// /// Starts a Unity coroutine which updates a Lua coroutine each frame. /// A MoonSharp closure object representing a function. /// Debug text to display if an exception occurs (usually the Lua code that is being executed). /// A delegate method that is called when the coroutine completes. Includes return parameter. /// - public void RunLuaCoroutine(Closure closure, string debugInfo, Action onComplete = null) + public virtual void RunLuaCoroutine(Closure closure, string debugInfo, Action onComplete = null) { StartCoroutine(RunLuaCoroutineInternal(closure, debugInfo, onComplete)); } @@ -268,7 +286,7 @@ namespace Fungus /// Debug text to display if an exception occurs (usually the Lua code that is being executed). /// A delegate method that is called when the coroutine completes. Includes return parameter. /// - protected IEnumerator RunLuaCoroutineInternal(Closure closure, string debugInfo, Action onComplete = null) + protected virtual IEnumerator RunLuaCoroutineInternal(Closure closure, string debugInfo, Action onComplete = null) { DynValue co = interpreter.CreateCoroutine(closure); @@ -296,7 +314,7 @@ namespace Fungus /// /// Start a Unity coroutine from a Lua call. /// - public Task RunUnityCoroutine(IEnumerator coroutine) + public virtual Task RunUnityCoroutine(IEnumerator coroutine) { if (coroutine == null) { diff --git a/Assets/Fungus/FungusLua/Scripts/LuaScript.cs b/Assets/Fungus/FungusLua/Scripts/LuaScript.cs index f4666335..a9542bea 100644 --- a/Assets/Fungus/FungusLua/Scripts/LuaScript.cs +++ b/Assets/Fungus/FungusLua/Scripts/LuaScript.cs @@ -13,13 +13,13 @@ using Object = UnityEngine.Object; namespace Fungus { - + public class LuaScript : MonoBehaviour { /// /// The Lua Environment to use when executing Lua script. /// - [Tooltip("The Lua Environment to use when executing Lua script.")] + [Tooltip("The Lua Environment to use when executing Lua script.")] public LuaEnvironment luaEnvironment; /// @@ -45,6 +45,9 @@ namespace Fungus protected bool initialised; + // Stores the compiled Lua code for fast execution later. + protected Closure luaFunction; + // Recursively build the full hierarchy path to this game object private static string GetPath(Transform current) { @@ -60,6 +63,9 @@ namespace Fungus InitLuaScript(); } + /// + /// Initialises the Lua environment and compiles the Lua string for execution later on. + /// protected virtual void InitLuaScript() { if (initialised) @@ -85,7 +91,34 @@ namespace Fungus // Cache a descriptive name to use in Lua error messages friendlyName = GetPath(transform) + ".LuaScript"; - initialised = true; + string s = GetLuaString(); + luaFunction = luaEnvironment.LoadLuaString(s, friendlyName); + + // Always initialise when playing in the editor. + // Allows the user to edit the Lua script while the game is playing. + if ( !(Application.isPlaying && Application.isEditor) ) + { + initialised = true; + } + } + + /// + /// Returns the Lua string to be executed. + /// + /// The lua string. + protected virtual string GetLuaString() + { + string s = ""; + if (luaFile != null) + { + s = luaFile.text; + } + else if (luaScript.Length > 0) + { + s = luaScript; + } + + return s; } /// @@ -94,7 +127,7 @@ namespace Fungus /// public virtual void OnExecute() { - // Make sure the environment is initialised before executing + // Make sure the script and Lua environment are initialised before executing InitLuaScript(); if (luaEnvironment == null) @@ -103,20 +136,7 @@ namespace Fungus } else { - // Ensure the Lua Environment is initialised first. - luaEnvironment.InitEnvironment(); - - string s = ""; - if (luaFile != null) - { - s = luaFile.text; - } - else if (luaScript.Length > 0) - { - s = luaScript; - } - - luaEnvironment.DoLuaString(s, friendlyName, runAsCoroutine); + luaEnvironment.RunLuaCoroutine(luaFunction, friendlyName); } } } From fc0dde1d05afefb372e03e5706a06f8afbe1d87a Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Wed, 13 Apr 2016 12:05:58 +0100 Subject: [PATCH 2/2] Tidied up ExecuteLua initialisation --- .../Fungus/Lua/Scripts/Commands/ExecuteLua.cs | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/Assets/Fungus/Lua/Scripts/Commands/ExecuteLua.cs b/Assets/Fungus/Lua/Scripts/Commands/ExecuteLua.cs index 3e1c447c..ff8c2033 100644 --- a/Assets/Fungus/Lua/Scripts/Commands/ExecuteLua.cs +++ b/Assets/Fungus/Lua/Scripts/Commands/ExecuteLua.cs @@ -30,33 +30,41 @@ namespace Fungus protected string friendlyName = ""; + protected bool initialised ; + protected virtual void Start() { + InitExecuteLua(); + } + + /// + /// Initialises the Lua environment and compiles the Lua string for execution later on. + /// + protected virtual void InitExecuteLua() + { + if (initialised) + { + return; + } + // Cache a descriptive name to use in Lua error messages friendlyName = gameObject.name + "." + parentBlock.blockName + "." + "ExecuteLua #" + commandIndex.ToString(); - if (luaEnvironment == null) - { - luaEnvironment = LuaEnvironment.GetLua(); - } - } + if (luaEnvironment == null) + { + luaEnvironment = LuaEnvironment.GetLua(); + } + + initialised = true; + } public override void OnEnter() { - // This command could be executed from the Start of another component, so we - // need to check the Lua Environment here and in Start. - if (luaEnvironment == null) - { - luaEnvironment = LuaEnvironment.GetLua(); - } - - if (luaEnvironment == null) - { - Debug.LogError("No Lua Environment found"); - Continue(); - return; - } + InitExecuteLua(); + // Note: We can't pre compile the Lua script in this command because we want to + // support variable substitution in the Lua string. + // If this is too slow, consider using a LuaScript object and calling OnExecute() on it instead. string subbed = GetFlowchart().SubstituteVariables(luaScript); luaEnvironment.DoLuaString(subbed, friendlyName, runAsCoroutine, (returnValue) => {