UnityAssetsScriptLoader.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. namespace MoonSharp.Interpreter.Loaders
  6. {
  7. /// <summary>
  8. /// A script loader which can load scripts from assets in Unity3D.
  9. /// Scripts should be saved as .txt files in a subdirectory of Assets/Resources.
  10. ///
  11. /// When MoonSharp is activated on Unity3D and the default script loader is used,
  12. /// scripts should be saved as .txt files in Assets/Resources/MoonSharp/Scripts.
  13. /// </summary>
  14. public class UnityAssetsScriptLoader : ScriptLoaderBase
  15. {
  16. Dictionary<string, string> m_Resources = new Dictionary<string, string>();
  17. /// <summary>
  18. /// The default path where scripts are meant to be stored (if not changed)
  19. /// </summary>
  20. public const string DEFAULT_PATH = "MoonSharp/Scripts";
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="UnityAssetsScriptLoader"/> class.
  23. /// </summary>
  24. /// <param name="assetsPath">The path, relative to Assets/Resources. For example
  25. /// if your scripts are stored under Assets/Resources/Scripts, you should
  26. /// pass the value "Scripts". If null, "MoonSharp/Scripts" is used. </param>
  27. public UnityAssetsScriptLoader(string assetsPath = null)
  28. {
  29. assetsPath = assetsPath ?? DEFAULT_PATH;
  30. #if UNITY_5
  31. LoadResourcesUnityNative(assetsPath);
  32. #else
  33. LoadResourcesWithReflection(assetsPath);
  34. #endif
  35. }
  36. /// <summary>
  37. /// Initializes a new instance of the <see cref="UnityAssetsScriptLoader"/> class.
  38. /// </summary>
  39. /// <param name="scriptToCodeMap">A dictionary mapping filenames to the proper Lua script code.</param>
  40. public UnityAssetsScriptLoader(Dictionary<string, string> scriptToCodeMap)
  41. {
  42. m_Resources = scriptToCodeMap;
  43. }
  44. #if UNITY_5
  45. void LoadResourcesUnityNative(string assetsPath)
  46. {
  47. try
  48. {
  49. UnityEngine.Object[] array = UnityEngine.Resources.LoadAll(assetsPath, typeof(UnityEngine.TextAsset));
  50. for (int i = 0; i < array.Length; i++)
  51. {
  52. UnityEngine.TextAsset o = (UnityEngine.TextAsset)array[i];
  53. string name = o.name;
  54. string text = o.text;
  55. m_Resources.Add(name, text);
  56. }
  57. }
  58. catch (Exception ex)
  59. {
  60. UnityEngine.Debug.LogErrorFormat("Error initializing UnityScriptLoader : {0}", ex);
  61. }
  62. }
  63. #endif
  64. void LoadResourcesWithReflection(string assetsPath)
  65. {
  66. try
  67. {
  68. Type resourcesType = Type.GetType("UnityEngine.Resources, UnityEngine");
  69. Type textAssetType = Type.GetType("UnityEngine.TextAsset, UnityEngine");
  70. MethodInfo textAssetNameGet = textAssetType.GetProperty("name").GetGetMethod();
  71. MethodInfo textAssetTextGet = textAssetType.GetProperty("text").GetGetMethod();
  72. MethodInfo loadAll = resourcesType.GetMethod("LoadAll",
  73. new Type[] { typeof(string), typeof(Type) });
  74. Array array = (Array)loadAll.Invoke(null, new object[] { assetsPath, textAssetType });
  75. for (int i = 0; i < array.Length; i++)
  76. {
  77. object o = array.GetValue(i);
  78. string name = textAssetNameGet.Invoke(o, null) as string;
  79. string text = textAssetTextGet.Invoke(o, null) as string;
  80. m_Resources.Add(name, text);
  81. }
  82. }
  83. catch (Exception ex)
  84. {
  85. #if !(PCL || ENABLE_DOTNET)
  86. Console.WriteLine("Error initializing UnityScriptLoader : {0}", ex);
  87. #endif
  88. }
  89. }
  90. private string GetFileName(string filename)
  91. {
  92. int b = Math.Max(filename.LastIndexOf('\\'), filename.LastIndexOf('/'));
  93. if (b > 0)
  94. filename = filename.Substring(b + 1);
  95. return filename;
  96. }
  97. /// <summary>
  98. /// Opens a file for reading the script code.
  99. /// It can return either a string, a byte[] or a Stream.
  100. /// If a byte[] is returned, the content is assumed to be a serialized (dumped) bytecode. If it's a string, it's
  101. /// assumed to be either a script or the output of a string.dump call. If a Stream, autodetection takes place.
  102. /// </summary>
  103. /// <param name="file">The file.</param>
  104. /// <param name="globalContext">The global context.</param>
  105. /// <returns>
  106. /// A string, a byte[] or a Stream.
  107. /// </returns>
  108. /// <exception cref="System.Exception">UnityAssetsScriptLoader.LoadFile : Cannot load + file</exception>
  109. public override object LoadFile(string file, Table globalContext)
  110. {
  111. file = GetFileName(file);
  112. if (m_Resources.ContainsKey(file))
  113. return m_Resources[file];
  114. else
  115. {
  116. var error = string.Format(
  117. @"Cannot load script '{0}'. By default, scripts should be .txt files placed under a Assets/Resources/{1} directory.
  118. If you want scripts to be put in another directory or another way, use a custom instance of UnityAssetsScriptLoader or implement
  119. your own IScriptLoader (possibly extending ScriptLoaderBase).", file, DEFAULT_PATH);
  120. throw new Exception(error);
  121. }
  122. }
  123. /// <summary>
  124. /// Checks if a given file exists
  125. /// </summary>
  126. /// <param name="file">The file.</param>
  127. /// <returns></returns>
  128. public override bool ScriptFileExists(string file)
  129. {
  130. file = GetFileName(file);
  131. return m_Resources.ContainsKey(file);
  132. }
  133. /// <summary>
  134. /// Gets the list of loaded scripts filenames (useful for debugging purposes).
  135. /// </summary>
  136. /// <returns></returns>
  137. public string[] GetLoadedScripts()
  138. {
  139. return m_Resources.Keys.ToArray();
  140. }
  141. }
  142. }