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();
}
}
}