Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / generator / DungeonRoomGenerator.cs
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text.Json;
  7. using Godot;
  8.  
  9. namespace Generator;
  10.  
  11. /// <summary>
  12. /// 地牢房间数据生成器
  13. /// </summary>
  14. public static class DungeonRoomGenerator
  15. {
  16. /// <summary>
  17. /// 根据名称在编辑器中创建地牢的预制房间, open 表示创建完成后是否在编辑器中打开这个房间
  18. /// </summary>
  19. public static bool CreateDungeonRoom(string roomName, bool open = false)
  20. {
  21. try
  22. {
  23. //创建场景资源
  24. var prefabFile = GameConfig.RoomTileDir + roomName + ".tscn";
  25. var prefabResPath = "res://" + prefabFile;
  26. if (!Directory.Exists(GameConfig.RoomTileDir))
  27. {
  28. Directory.CreateDirectory(GameConfig.RoomTileDir);
  29. }
  30. //加载脚本资源
  31. // 这段代码在 Godot4.0.1rc1中会报错, 应该是个bug
  32. // var scriptRes = GD.Load<CSharpScript>("res://src/framework/map/DungeonRoomTemplate.cs");
  33. // var tileMap = new TileMap();
  34. // tileMap.Name = roomName;
  35. // tileMap.SetScript(scriptRes);
  36. // var scene = new PackedScene();
  37. // scene.Pack(tileMap); //报错在这一行, 报的是访问了被销毁的资源 scriptRes
  38. // ResourceSaver.Save(scene, prefabResPath);
  39. //临时处理
  40. {
  41. var tscnCode = $"[gd_scene load_steps=2 format=3]\n" +
  42. $"\n" +
  43. $"[ext_resource type=\"Script\" path=\"res://src/framework/map/DungeonRoomTemplate.cs\" id=\"dungeonRoomTemplate\"]\n" +
  44. $"\n" +
  45. $"[node name=\"{roomName}\" type=\"TileMap\"]\n" +
  46. $"format = 2\n" +
  47. $"script = ExtResource(\"dungeonRoomTemplate\")\n";
  48. File.WriteAllText(prefabFile, tscnCode);
  49. //重新保存一遍, 以让编辑器生成资源Id
  50. var scene = GD.Load<PackedScene>(prefabResPath);
  51. ResourceSaver.Save(scene, prefabResPath);
  52. }
  53.  
  54. //打包房间配置
  55. GenerateRoomConfig();
  56. //生成 UiManager_Methods.cs 代码
  57. UiManagerMethodsGenerator.Generate();
  58. #if TOOLS
  59. //打开房间
  60. if (open)
  61. {
  62. Plugin.Plugin.Instance.GetEditorInterface().OpenSceneFromPath(prefabResPath);
  63. }
  64. #endif
  65. }
  66. catch (Exception e)
  67. {
  68. GD.PrintErr(e.ToString());
  69. return false;
  70. }
  71. return true;
  72. }
  73. /// <summary>
  74. /// 执行生成 RoomConfig.json 操作, 返回是否执行成功
  75. /// </summary>
  76. public static bool GenerateRoomConfig()
  77. {
  78. try
  79. {
  80. //地图路径
  81. var tileDir = GameConfig.RoomTileDir;
  82. //地图描述数据路径
  83. var tileDataDir = GameConfig.RoomTileDataDir;
  84. var tileDirInfo = new DirectoryInfo(tileDir);
  85. var tileDataDirInfo = new DirectoryInfo(tileDataDir);
  86.  
  87. //所有地图列表
  88. var mapList = new HashSet<string>();
  89. //收集所有名称
  90. var fileDataInfos = tileDataDirInfo.GetFiles();
  91. foreach (var fileInfo in fileDataInfos)
  92. {
  93. mapList.Add(RemoveExtension(fileInfo.Name));
  94. }
  95. //收集所有名称
  96. var fileInfos = tileDirInfo.GetFiles();
  97. foreach (var fileInfo in fileInfos)
  98. {
  99. if (fileInfo.Extension == ".tscn")
  100. {
  101. mapList.Add(RemoveExtension(fileInfo.Name));
  102. }
  103. }
  104. //剔除多余的 tile.json
  105. var arrays = mapList.ToArray();
  106. foreach (var item in arrays)
  107. {
  108. if (!File.Exists(tileDir + item + ".tscn"))
  109. {
  110. mapList.Remove(item);
  111. var filePath = tileDataDir + item + ".json";
  112. if (File.Exists(filePath))
  113. {
  114. GD.Print($"未找到'{tileDir + item}.tscn', 删除配置文件: {filePath}");
  115. File.Delete(filePath);
  116. }
  117. }
  118. }
  119.  
  120. //手动生成缺失的 tile.json
  121. foreach (var item in mapList)
  122. {
  123. if (!File.Exists(tileDataDir + item + ".json"))
  124. {
  125. var tscnName = tileDir + item + ".tscn";
  126. var packedScene = ResourceManager.Load<PackedScene>(tscnName, false);
  127. if (packedScene != null)
  128. {
  129. var dungeonRoomTemplate = packedScene.Instantiate<DungeonRoomTemplate>();
  130. var usedRect = dungeonRoomTemplate.GetUsedRect();
  131. var dungeonTile = new DungeonTile(dungeonRoomTemplate);
  132. dungeonTile.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) });
  133. //计算导航网格
  134. dungeonTile.GenerateNavigationPolygon(0);
  135. var polygonData = dungeonTile.GetPolygonData();
  136. DungeonRoomTemplate.SaveConfig(new List<DoorAreaInfo>(), usedRect.Position, usedRect.Size, polygonData.ToList(), item);
  137. dungeonRoomTemplate.QueueFree();
  138. }
  139. }
  140. }
  141.  
  142. var list = new List<DungeonRoomSplit>();
  143. //整合操作
  144. foreach (var item in mapList)
  145. {
  146. var configPath = tileDataDir + item + ".json";
  147. var split = new DungeonRoomSplit();
  148. split.ScenePath = ToResPath(tileDir + item + ".tscn");
  149. split.ConfigPath = ToResPath(configPath);
  150. list.Add(split);
  151. }
  152.  
  153. //写出配置
  154. var config = new JsonSerializerOptions();
  155. config.WriteIndented = true;
  156. var text = JsonSerializer.Serialize(list, config);
  157. File.WriteAllText(GameConfig.RoomTileConfigFile, text);
  158.  
  159. GD.Print("地牢房间配置, 重新打包完成!");
  160. }
  161. catch (Exception e)
  162. {
  163. GD.PrintErr(e.ToString());
  164. return false;
  165. }
  166.  
  167. return true;
  168. }
  169. private static string ToResPath(string path)
  170. {
  171. var field = path.Replace("\\", "/");
  172. return "res://" + field;
  173. }
  174.  
  175. private static string RemoveExtension(string name)
  176. {
  177. var index = name.LastIndexOf(".", StringComparison.Ordinal);
  178. if (index >= 0)
  179. {
  180. return name.Substring(0, index);
  181. }
  182.  
  183. return name;
  184. }
  185. }