HotfixCodeGenHandler.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. ---@class HotfixCodeGenHandler 热更层代码生成器
  2. local HotfixCodeGenHandler = {}
  3. --- 执行生成热更层代码
  4. ---@param handler CS.FairyEditor.PublishHandler
  5. ---@param codeGenConfig CodeGenConfig
  6. function HotfixCodeGenHandler.Do(handler, codeGenConfig)
  7. local codePkgName = handler:ToFilename(handler.pkg.name); --convert chinese to pinyin, remove special chars etc.
  8. --- 从自定义配置中读取路径和命名空间
  9. local exportCodePath = codeGenConfig.HotfixCodeOutPutPath .. '/' .. codePkgName
  10. local namespaceName = codeGenConfig.HotfixNameSpace
  11. --- 初始化自定义组件名前缀
  12. local classNamePrefix = codeGenConfig.ClassNamePrefix
  13. --- 初始化自定义成员变量名前缀
  14. local memberVarNamePrefix = codeGenConfig.MemerVarNamePrefix
  15. --- 从FGUI编辑器中读取配置
  16. ---@type CS.FairyEditor.GlobalPublishSettings.CodeGenerationConfig
  17. local settings = handler.project:GetSettings("Publish").codeGeneration
  18. local getMemberByName = settings.getMemberByName
  19. --- 所有将要导出的类(当前包的所有设置为导出的组件,以及当前包所有被引用的组件)
  20. ---@type CS.FairyEditor.PublishHandler.ClassInfo[]
  21. local classes = handler:CollectClasses(codeGenConfig.CodeStrip, codeGenConfig.CodeStrip, nil)
  22. handler:SetupCodeFolder(exportCodePath, "cs") --check if target folder exists, and delete old files
  23. local classCnt = classes.Count
  24. local writer = CodeWriter.new()
  25. for i = 0, classCnt - 1 do
  26. local classInfo = classes[i]
  27. local members = classInfo.members
  28. writer:reset()
  29. writer:writeln('using FairyGUI;')
  30. writer:writeln('using Cysharp.Threading.Tasks;')
  31. writer:writeln()
  32. writer:writeln('namespace %s', namespaceName)
  33. writer:startBlock()
  34. --- 组装自定义组件前缀
  35. local className = classNamePrefix .. classInfo.className
  36. -- 1
  37. writer:writeln([[public class %sAwakeSystem : AwakeSystem<%s, GObject>
  38. {
  39. public override void Awake(%s self, GObject go)
  40. {
  41. self.Awake(go);
  42. }
  43. }
  44. ]], className, className, className)
  45. writer:writeln([[public class %sDestroySystem : DestroySystem<%s>
  46. {
  47. public override void Destroy(%s self)
  48. {
  49. self.Destroy();
  50. }
  51. }
  52. ]], className, className, className)
  53. writer:writeln([[public sealed class %s : FUI
  54. {
  55. public const string UIPackageName = "%s";
  56. public const string UIResName = "%s";
  57. /// <summary>
  58. /// {uiResName}的组件类型(GComponent、GButton、GProcessBar等),它们都是GObject的子类。
  59. /// </summary>
  60. public %s self;
  61. ]], className, codePkgName, classInfo.resName, classInfo.superClassName)
  62. local memberCnt = members.Count
  63. -- 是否为自定义类型组件标记数组
  64. local customComponentFlagsArray = {}
  65. -- 是否为跨包组件标记数组
  66. local crossPackageFlagsArray = {}
  67. for j = 0, memberCnt - 1
  68. do
  69. local memberInfo = members[j]
  70. customComponentFlagsArray[j] = false
  71. crossPackageFlagsArray[j] = false
  72. -- 判断是不是我们自定义类型组件
  73. local typeName = memberInfo.type
  74. for k = 0, classCnt - 1
  75. do
  76. if typeName == classes[k].className
  77. then
  78. typeName = classNamePrefix .. classes[k].className
  79. customComponentFlagsArray[j] = true
  80. break
  81. end
  82. end
  83. -- 判断是不是跨包类型组件
  84. if memberInfo.res ~= nil then
  85. --- 组装自定义组件前缀
  86. typeName = classNamePrefix .. memberInfo.res.name
  87. crossPackageFlagsArray[j] = true
  88. end
  89. --- 组装自定义成员前缀
  90. writer:writeln('\tpublic %s %s;', typeName, memberVarNamePrefix .. memberInfo.varName)
  91. end
  92. writer:writeln('\tpublic const string URL = "ui://%s%s";', handler.pkg.id, classInfo.resId)
  93. writer:writeln()
  94. writer:writeln([[
  95. private static GObject CreateGObject()
  96. {
  97. return UIPackage.CreateObject(UIPackageName, UIResName);
  98. }
  99. private static void CreateGObjectAsync(UIPackage.CreateObjectCallback result)
  100. {
  101. UIPackage.CreateObjectAsync(UIPackageName, UIResName, result);
  102. }
  103. ]])
  104. writer:writeln([[
  105. public static %s CreateInstance(Entity parent)
  106. {
  107. return parent.AddChild<%s, GObject>(CreateGObject());
  108. }
  109. ]], className, className)
  110. writer:writeln([[
  111. public static UniTask<%s> CreateInstanceAsync(Entity parent)
  112. {
  113. UniTaskCompletionSource<%s> tcs = new UniTaskCompletionSource<%s>();
  114. CreateGObjectAsync((go) =>
  115. {
  116. tcs.TrySetResult(parent.AddChild<%s, GObject>(go));
  117. });
  118. return tcs.Task;
  119. }
  120. ]], className, className, className, className)
  121. writer:writeln([[
  122. /// <summary>
  123. /// 仅用于go已经实例化情况下的创建(例如另一个组件引用了此组件)
  124. /// </summary>
  125. /// <param name="domain"></param>
  126. /// <param name="go"></param>
  127. /// <returns></returns>
  128. public static %s Create(Entity parent, GObject go)
  129. {
  130. return parent.AddChild<%s, GObject>(go);
  131. }
  132. ]], className, className)
  133. writer:writeln([[
  134. /// <summary>
  135. /// 通过此方法获取的FUI,在Dispose时不会释放GObject,需要自行管理(一般在配合FGUI的Pool机制时使用)。
  136. /// </summary>
  137. public static %s GetFormPool(Entity domain, GObject go)
  138. {
  139. var fui = go.Get<%s>();
  140. if(fui == null)
  141. {
  142. fui = Create(domain, go);
  143. }
  144. fui.isFromFGUIPool = true;
  145. return fui;
  146. }
  147. ]], className, className)
  148. writer:writeln([[
  149. public void Awake(GObject go)
  150. {
  151. if(go == null)
  152. {
  153. return;
  154. }
  155. GObject = go;
  156. if (string.IsNullOrWhiteSpace(Name))
  157. {
  158. Name = Id.ToString();
  159. }
  160. self = (%s)go;
  161. self.Add(this);
  162. var com = go.asCom;
  163. if(com != null)
  164. {
  165. ]], classInfo.superClassName)
  166. for j = 0, memberCnt - 1
  167. do
  168. local memberInfo = members[j]
  169. --- 组装自定义成员前缀
  170. local memberVarName = memberVarNamePrefix .. memberInfo.varName
  171. if memberInfo.group == 0
  172. then
  173. if getMemberByName
  174. then
  175. if customComponentFlagsArray[j]
  176. then
  177. --- 组装自定义组件前缀
  178. writer:writeln('\t\t\t%s = %s.Create(this, com.GetChild("%s"));', memberVarName, classNamePrefix .. memberInfo.type, memberInfo.name)
  179. elseif crossPackageFlagsArray[j]
  180. then
  181. --- 组装自定义组件前缀
  182. writer:writeln('\t\t\t%s = %s.Create(this, com.GetChild("%s"));', memberVarName, classNamePrefix .. memberInfo.res.name, memberInfo.name)
  183. else
  184. writer:writeln('\t\t\t%s = (%s)com.GetChild("%s");', memberVarName, memberInfo.type, memberInfo.name)
  185. end
  186. else
  187. if customComponentFlagsArray[j]
  188. then
  189. --- 组装自定义组件前缀
  190. writer:writeln('\t\t\t%s = %s.Create(this, com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.type, memberInfo.index)
  191. elseif crossPackageFlagsArray[j]
  192. then
  193. --- 组装自定义组件前缀
  194. writer:writeln('\t\t\t%s = %s.Create(this, com.GetChildAt(%s));', memberVarName, classNamePrefix .. memberInfo.res.name, memberInfo.index)
  195. else
  196. writer:writeln('\t\t\t%s = (%s)com.GetChildAt(%s);', memberVarName, memberInfo.type, memberInfo.index)
  197. end
  198. end
  199. elseif memberInfo.group == 1
  200. then
  201. if getMemberByName
  202. then
  203. writer:writeln('\t\t\t%s = com.GetController("%s");', memberVarName, memberInfo.name)
  204. else
  205. writer:writeln('\t\t\t%s = com.GetControllerAt(%s);', memberVarName, memberInfo.index)
  206. end
  207. else
  208. if getMemberByName
  209. then
  210. writer:writeln('\t\t\t%s = com.GetTransition("%s");', memberVarName, memberInfo.name)
  211. else
  212. writer:writeln('\t\t\t%s = com.GetTransitionAt(%s);', memberVarName, memberInfo.index)
  213. end
  214. end
  215. end
  216. writer:writeln('\t\t}')
  217. writer:writeln('\t}')
  218. writer:writeln([[
  219. public override void Destroy()
  220. {
  221. base.Destroy();
  222. self.Remove();
  223. self = null;
  224. ]])
  225. for j = 0, memberCnt - 1 do
  226. local memberInfo = members[j]
  227. --- 组装自定义成员前缀
  228. local memberVarName = memberVarNamePrefix .. memberInfo.varName
  229. if memberInfo.group == 0 then
  230. if customComponentFlagsArray[j] or crossPackageFlagsArray[j] then
  231. writer:writeln('\t\t%s.Dispose();', memberVarName)
  232. end
  233. writer:writeln('\t\t%s = null;', memberVarName)
  234. elseif memberInfo.group == 1 then
  235. writer:writeln('\t\t%s = null;', memberVarName)
  236. else
  237. writer:writeln('\t\t%s = null;', memberVarName)
  238. end
  239. end
  240. writer:writeln('\t}')
  241. writer:writeln('}')
  242. writer:endBlock()
  243. writer:save(exportCodePath .. '/' .. className .. '.cs')
  244. end
  245. -- 写入fuipackage
  246. writer:reset()
  247. writer:writeln('namespace %s', namespaceName)
  248. writer:startBlock()
  249. writer:writeln('public static partial class FUIPackage')
  250. writer:startBlock()
  251. writer:writeln('public const string %s = "%s";', codePkgName, codePkgName)
  252. for i = 0, classCnt - 1 do
  253. local classInfo = classes[i]
  254. writer:writeln('public const string %s_%s = "ui://%s/%s";', codePkgName, classInfo.resName, codePkgName, classInfo.resName)
  255. end
  256. writer:endBlock() --class
  257. writer:endBlock() --namespace
  258. local binderPackageName = 'Package' .. codePkgName
  259. writer:save(exportCodePath .. '/' .. binderPackageName .. '.cs')
  260. end
  261. return HotfixCodeGenHandler