using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace MoonSharp.Interpreter.Loaders { /// /// A script loader which can load scripts from assets in Unity3D. /// Scripts should be saved as .txt files in a subdirectory of Assets/Resources. /// /// When MoonSharp is activated on Unity3D and the default script loader is used, /// scripts should be saved as .txt files in Assets/Resources/MoonSharp/Scripts. /// public class UnityAssetsScriptLoader : ScriptLoaderBase { Dictionary m_Resources = new Dictionary(); /// /// The default path where scripts are meant to be stored (if not changed) /// public const string DEFAULT_PATH = "MoonSharp/Scripts"; /// /// Initializes a new instance of the class. /// /// The path, relative to Assets/Resources. For example /// if your scripts are stored under Assets/Resources/Scripts, you should /// pass the value "Scripts". If null, "MoonSharp/Scripts" is used. public UnityAssetsScriptLoader(string assetsPath = null) { assetsPath = assetsPath ?? DEFAULT_PATH; #if UNITY_5 LoadResourcesUnityNative(assetsPath); #else LoadResourcesWithReflection(assetsPath); #endif } /// /// Initializes a new instance of the class. /// /// A dictionary mapping filenames to the proper Lua script code. public UnityAssetsScriptLoader(Dictionary scriptToCodeMap) { m_Resources = scriptToCodeMap; } #if UNITY_5 void LoadResourcesUnityNative(string assetsPath) { try { UnityEngine.Object[] array = UnityEngine.Resources.LoadAll(assetsPath, typeof(UnityEngine.TextAsset)); for (int i = 0; i < array.Length; i++) { UnityEngine.TextAsset o = (UnityEngine.TextAsset)array[i]; string name = o.name; string text = o.text; m_Resources.Add(name, text); } } catch (Exception ex) { UnityEngine.Debug.LogErrorFormat("Error initializing UnityScriptLoader : {0}", ex); } } #endif void LoadResourcesWithReflection(string assetsPath) { try { Type resourcesType = Type.GetType("UnityEngine.Resources, UnityEngine"); Type textAssetType = Type.GetType("UnityEngine.TextAsset, UnityEngine"); MethodInfo textAssetNameGet = textAssetType.GetProperty("name").GetGetMethod(); MethodInfo textAssetTextGet = textAssetType.GetProperty("text").GetGetMethod(); MethodInfo loadAll = resourcesType.GetMethod("LoadAll", new Type[] { typeof(string), typeof(Type) }); Array array = (Array)loadAll.Invoke(null, new object[] { assetsPath, textAssetType }); for (int i = 0; i < array.Length; i++) { object o = array.GetValue(i); string name = textAssetNameGet.Invoke(o, null) as string; string text = textAssetTextGet.Invoke(o, null) as string; m_Resources.Add(name, text); } } catch (Exception ex) { #if !(PCL || ENABLE_DOTNET) Console.WriteLine("Error initializing UnityScriptLoader : {0}", ex); #endif } } private string GetFileName(string filename) { int b = Math.Max(filename.LastIndexOf('\\'), filename.LastIndexOf('/')); if (b > 0) filename = filename.Substring(b + 1); return filename; } /// /// Opens a file for reading the script code. /// It can return either a string, a byte[] or a Stream. /// If a byte[] is returned, the content is assumed to be a serialized (dumped) bytecode. If it's a string, it's /// assumed to be either a script or the output of a string.dump call. If a Stream, autodetection takes place. /// /// The file. /// The global context. /// /// A string, a byte[] or a Stream. /// /// UnityAssetsScriptLoader.LoadFile : Cannot load + file public override object LoadFile(string file, Table globalContext) { file = GetFileName(file); if (m_Resources.ContainsKey(file)) return m_Resources[file]; else { var error = string.Format( @"Cannot load script '{0}'. By default, scripts should be .txt files placed under a Assets/Resources/{1} directory. If you want scripts to be put in another directory or another way, use a custom instance of UnityAssetsScriptLoader or implement your own IScriptLoader (possibly extending ScriptLoaderBase).", file, DEFAULT_PATH); throw new Exception(error); } } /// /// Checks if a given file exists /// /// The file. /// public override bool ScriptFileExists(string file) { file = GetFileName(file); return m_Resources.ContainsKey(file); } /// /// Gets the list of loaded scripts filenames (useful for debugging purposes). /// /// public string[] GetLoadedScripts() { return m_Resources.Keys.ToArray(); } } }