Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / generator / DungeonRoomGenerator.cs
@小李xl 小李xl on 7 Apr 2023 8 KB 房间添加权重功能
  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 groupName, string roomType, string roomName, bool open = false)
  20. {
  21. try
  22. {
  23. var path = GameConfig.RoomTileDir + groupName + "/" + roomType;
  24. if (!Directory.Exists(path))
  25. {
  26. Directory.CreateDirectory(path);
  27. }
  28. //创建场景资源
  29. var prefabFile = path + "/" + roomName + ".tscn";
  30. var prefabResPath = "res://" + prefabFile;
  31. if (!Directory.Exists(GameConfig.RoomTileDir))
  32. {
  33. Directory.CreateDirectory(GameConfig.RoomTileDir);
  34. }
  35. //加载脚本资源
  36. // 这段代码在 Godot4.0.1rc1中会报错, 应该是个bug
  37. // var scriptRes = GD.Load<CSharpScript>("res://src/framework/map/DungeonRoomTemplate.cs");
  38. // var tileMap = new TileMap();
  39. // tileMap.Name = roomName;
  40. // tileMap.SetScript(scriptRes);
  41. // var scene = new PackedScene();
  42. // scene.Pack(tileMap); //报错在这一行, 报的是访问了被销毁的资源 scriptRes
  43. // ResourceSaver.Save(scene, prefabResPath);
  44. //临时处理
  45. {
  46. var tscnCode = $"[gd_scene load_steps=2 format=3]\n" +
  47. $"\n" +
  48. $"[ext_resource type=\"Script\" path=\"res://src/framework/map/DungeonRoomTemplate.cs\" id=\"dungeonRoomTemplate\"]\n" +
  49. $"\n" +
  50. $"[node name=\"{roomName}\" type=\"TileMap\"]\n" +
  51. $"format = 2\n" +
  52. $"script = ExtResource(\"dungeonRoomTemplate\")\n";
  53. File.WriteAllText(prefabFile, tscnCode);
  54. //重新保存一遍, 以让编辑器生成资源Id
  55. var scene = GD.Load<PackedScene>(prefabResPath);
  56. ResourceSaver.Save(scene, prefabResPath);
  57. }
  58.  
  59. //打包房间配置
  60. GenerateRoomConfig();
  61. //生成 UiManager_Methods.cs 代码
  62. UiManagerMethodsGenerator.Generate();
  63. #if TOOLS
  64. //打开房间
  65. if (open)
  66. {
  67. Plugin.Plugin.Instance.GetEditorInterface().OpenSceneFromPath(prefabResPath);
  68. }
  69. #endif
  70. }
  71. catch (Exception e)
  72. {
  73. GD.PrintErr(e.ToString());
  74. return false;
  75. }
  76. return true;
  77. }
  78. /// <summary>
  79. /// 执行生成 RoomConfig.json 操作, 返回是否执行成功
  80. /// </summary>
  81. public static bool GenerateRoomConfig()
  82. {
  83. try
  84. {
  85. //地图路径
  86. var tileDir = GameConfig.RoomTileDir;
  87. //地图描述数据路径
  88. var tileDataDir = GameConfig.RoomTileDataDir;
  89. var tileGroup = new DirectoryInfo(tileDir).GetDirectories();
  90. var tileDataGroup = new DirectoryInfo(tileDataDir).GetDirectories();
  91.  
  92. //所有地图列表
  93. var map = new Dictionary<string, FileInfo>();
  94. //地图场景
  95. foreach (var groupDir in tileGroup)
  96. {
  97. var groupName = groupDir.Name;
  98. var typeDirArray = groupDir.GetDirectories();
  99. //遍历枚举, 获取指定路径文件
  100. foreach (DungeonRoomType roomType in Enum.GetValues(typeof(DungeonRoomType)))
  101. {
  102. var typeName = DungeonRoomTemplate.DungeonRoomTypeToString(roomType);
  103.  
  104. //收集所有文件名称
  105. var tempFileDataInfos = typeDirArray.FirstOrDefault(dirInfo => dirInfo.Name == typeName);
  106. if (tempFileDataInfos != null)
  107. {
  108. foreach (var fileInfo in tempFileDataInfos.GetFiles())
  109. {
  110. if (fileInfo.Extension == ".tscn")
  111. {
  112. var pathInfo = new FileInfo(groupName, roomType, typeName, RemoveExtension(fileInfo.Name));
  113. map.TryAdd(pathInfo.GetPath(), pathInfo);
  114. }
  115. }
  116. }
  117. }
  118. }
  119.  
  120. //地图配置数据
  121. foreach (var groupDir in tileDataGroup)
  122. {
  123. var groupName = groupDir.Name;
  124. var typeDirArray = groupDir.GetDirectories();
  125. //遍历枚举, 获取指定路径文件
  126. foreach (DungeonRoomType roomType in Enum.GetValues(typeof(DungeonRoomType)))
  127. {
  128. var typeName = DungeonRoomTemplate.DungeonRoomTypeToString(roomType);
  129.  
  130. //收集所有文件名称
  131. var tempFileDataInfos = typeDirArray.FirstOrDefault(dirInfo => dirInfo.Name == typeName);
  132. if (tempFileDataInfos != null)
  133. {
  134. foreach (var fileInfo in tempFileDataInfos.GetFiles())
  135. {
  136. if (fileInfo.Extension == ".json")
  137. {
  138. var pathInfo = new FileInfo(groupName, roomType, typeName, RemoveExtension(fileInfo.Name));
  139. map.TryAdd(pathInfo.GetPath(), pathInfo);
  140. }
  141. }
  142. }
  143. }
  144. }
  145.  
  146. //剔除多余的 tile.json
  147. foreach (var item in map)
  148. {
  149. var path = item.Key;
  150. if (!File.Exists(tileDir + path + ".tscn"))
  151. {
  152. map.Remove(path);
  153. var filePath = tileDataDir + path + ".json";
  154. if (File.Exists(filePath))
  155. {
  156. GD.Print($"未找到'{tileDir + path}.tscn', 删除配置文件: {filePath}");
  157. File.Delete(filePath);
  158. }
  159. }
  160. }
  161.  
  162. //手动生成缺失的 tile.json
  163. foreach (var item in map)
  164. {
  165. if (!File.Exists(tileDataDir + item.Key + ".json"))
  166. {
  167. var tscnName = tileDir + item.Key + ".tscn";
  168. var packedScene = ResourceManager.Load<PackedScene>(tscnName, false);
  169. if (packedScene != null)
  170. {
  171. var dungeonRoomTemplate = packedScene.Instantiate<DungeonRoomTemplate>();
  172. var usedRect = dungeonRoomTemplate.GetUsedRect();
  173. var dungeonTile = new DungeonTile(dungeonRoomTemplate);
  174. dungeonTile.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) });
  175. //计算导航网格
  176. dungeonTile.GenerateNavigationPolygon(0);
  177. var polygonData = dungeonTile.GetPolygonData();
  178. DungeonRoomTemplate.SaveConfig(new List<DoorAreaInfo>(), usedRect.Position, usedRect.Size, polygonData.ToList(),
  179. item.Value.GroupName, item.Value.RoomType, item.Value.FileName, dungeonRoomTemplate.Weight);
  180. dungeonRoomTemplate.QueueFree();
  181. }
  182. }
  183. }
  184.  
  185. var roomGroupMap = new Dictionary<string, DungeonRoomGroup>();
  186. //var list = new List<DungeonRoomSplit>();
  187. //整合操作
  188. foreach (var item in map)
  189. {
  190. var path = item.Key;
  191. var configPath = tileDataDir + path + ".json";
  192. var split = new DungeonRoomSplit();
  193. split.ScenePath = ToResPath(tileDir + path + ".tscn");
  194. split.ConfigPath = ToResPath(configPath);
  195.  
  196. if (!roomGroupMap.TryGetValue(item.Value.GroupName, out var group))
  197. {
  198. group = new DungeonRoomGroup();
  199. group.GroupName = item.Value.GroupName;
  200. roomGroupMap.Add(group.GroupName, group);
  201. }
  202. group.GetRoomList(item.Value.RoomType).Add(split);
  203. }
  204.  
  205. //写出配置
  206. var config = new JsonSerializerOptions();
  207. config.WriteIndented = true;
  208. var text = JsonSerializer.Serialize(roomGroupMap, config);
  209. File.WriteAllText(GameConfig.RoomTileConfigFile, text);
  210.  
  211. GD.Print("地牢房间配置, 重新打包完成!");
  212. }
  213. catch (Exception e)
  214. {
  215. GD.PrintErr(e.ToString());
  216. return false;
  217. }
  218.  
  219. return true;
  220. }
  221.  
  222. private class FileInfo
  223. {
  224. public FileInfo(string groupName, DungeonRoomType roomType, string typeName, string fileName)
  225. {
  226. GroupName = groupName;
  227. RoomType = roomType;
  228. TypeName = typeName;
  229. FileName = fileName;
  230. }
  231.  
  232. public string GroupName;
  233. public DungeonRoomType RoomType;
  234. public string TypeName;
  235. public string FileName;
  236.  
  237. public string GetPath()
  238. {
  239. return GroupName + "/" + TypeName + "/" + FileName;
  240. }
  241. }
  242. private static string ToResPath(string path)
  243. {
  244. var field = path.Replace("\\", "/");
  245. return "res://" + field;
  246. }
  247.  
  248. private static string RemoveExtension(string name)
  249. {
  250. var index = name.LastIndexOf(".", StringComparison.Ordinal);
  251. if (index >= 0)
  252. {
  253. return name.Substring(0, index);
  254. }
  255.  
  256. return name;
  257. }
  258. }