using System.Collections.Generic;
using System.Threading.Tasks;
using ColdMint.scripts.debug;
using ColdMint.scripts.levelGraphEditor;
using ColdMint.scripts.map.dateBean;
using ColdMint.scripts.map.events;
using ColdMint.scripts.map.interfaces;
using ColdMint.scripts.map.LayoutParsingStrategy;
using ColdMint.scripts.map.layoutStrategy;
using ColdMint.scripts.map.room;
using ColdMint.scripts.serialization;
using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.map;
///
/// Map generator
/// 地图生成器
///
///
///Responsible for the overall map generation process control
///负责地图的整体生成流程控制
///
public static class MapGenerator
{
///
/// Layout map selection strategy
/// 布局图选择策略
///
private static ILayoutStrategy? _layoutStrategy;
private static bool _running;
///
/// Map root node
/// 地图根节点
///
private static Node? _mapRoot;
///
/// Room placement strategy
/// 房间的放置策略
///
private static IRoomPlacementStrategy? _roomPlacementStrategy;
private static ulong _seed;
private static Dictionary? _roomInjectionProcessorsDictionary;
///
/// Register the room injection processor
/// 注册房间注入处理器
///
///
///
public static bool RegisterRoomInjectionProcessor(IRoomInjectionProcessor roomInjectionProcessor)
{
var key = roomInjectionProcessor.GetId();
if (_roomInjectionProcessorsDictionary == null)
{
_roomInjectionProcessorsDictionary = new Dictionary
{ { key, roomInjectionProcessor } };
return true;
}
return _roomInjectionProcessorsDictionary.TryAdd(key, roomInjectionProcessor);
}
///
/// Log out of the room injection processor
/// 注销房间注入处理器
///
///
///
public static bool UnRegisterRoomInjectionProcessor(string id)
{
if (_roomInjectionProcessorsDictionary == null)
{
return false;
}
return _roomInjectionProcessorsDictionary.Remove(id);
}
///
/// Set seed
/// 设置种子
///
public static string Seed
{
get => _seed.ToString();
//If the player inputs integers, we seed them directly with the input values. If it is not an integer, the hash value is taken.
//如果玩家输入的是整数,那么我们直接用输入值作为种子。如果不是整数,则取哈希值。
set => _seed = ulong.TryParse(value, out var result) ? result : HashCodeUtils.GetFixedHashCode(value);
}
///
/// Layout diagram parsing policy
/// 布局图解析策略
///
private static ILayoutParsingStrategy? _layoutParsingStrategy;
public static Node? MapRoot
{
get => _mapRoot;
set => _mapRoot = value;
}
public static ILayoutParsingStrategy? LayoutParsingStrategy
{
get => _layoutParsingStrategy;
set => _layoutParsingStrategy = value;
}
public static IRoomPlacementStrategy? RoomPlacementStrategy
{
get => _roomPlacementStrategy;
set => _roomPlacementStrategy = value;
}
public static ILayoutStrategy? LayoutStrategy
{
get => _layoutStrategy;
set => _layoutStrategy = value;
}
///
/// Generating a map
/// 生成地图
///
public static async Task GenerateMap()
{
if (_running)
{
LogCat.LogWarning("map_generator_is_running");
return;
}
_running = true;
EventBus.MapGenerationStartEvent?.Invoke(new MapGenerationStartEvent());
if (_layoutStrategy == null || _roomPlacementStrategy == null || _layoutParsingStrategy == null ||
_mapRoot == null)
{
LogCat.LogError("map_generator_missing_parameters");
_running = false;
return;
}
if (GameSceneDepend.AiCharacterContainer != null)
{
NodeUtils.DeleteAllChild(GameSceneDepend.AiCharacterContainer);
}
NodeUtils.DeleteAllChild(_mapRoot);
if (!await _roomPlacementStrategy.StartGeneration(_mapRoot))
{
LogCat.LogError("room_placement_strategy_terminates_map_generation");
_running = false;
return;
}
//Get the layout data
//拿到布局图数据
var levelGraphEditorSaveData = await _layoutStrategy.GetLayout();
if (levelGraphEditorSaveData == null || levelGraphEditorSaveData.RoomNodeDataList == null ||
levelGraphEditorSaveData.RoomNodeDataList.Count == 0)
{
LogCat.LogError("map_generator_attempts_to_parse_empty_layout_diagrams");
_running = false;
return;
}
_layoutParsingStrategy.SetLevelGraph(levelGraphEditorSaveData);
//Save the dictionary, put the ID in the room data, corresponding to the successful placement of the room.
//保存字典,将房间数据内的ID,对应放置成功的房间。
var roomDictionary = new Dictionary();
var randomNumberGenerator = new RandomNumberGenerator();
randomNumberGenerator.Seed = _seed;
var startRoomNodeData = await _layoutParsingStrategy.GetStartRoomNodeData();
if (startRoomNodeData == null || string.IsNullOrEmpty(startRoomNodeData.Id))
{
LogCat.LogError("map_generator_has_no_starting_room_data");
_running = false;
return;
}
var startingRoomPlacementData =
await _roomPlacementStrategy.CalculatePlacementDataForStartingRoom(randomNumberGenerator,
startRoomNodeData);
if (startingRoomPlacementData == null)
{
LogCat.LogError("start_room_placement_information_returns_empty");
_running = false;
return;
}
var placeSuccess = await PlaceRoomAndAddRecord(startRoomNodeData.Id, startingRoomPlacementData, roomDictionary);
if (!placeSuccess)
{
LogCat.LogError("start_room_placement_failed");
_running = false;
return;
}
while (await _layoutParsingStrategy.HasNext())
{
//When a new room needs to be placed
//当有新的房间需要放置时
var roomNodeData = await _layoutParsingStrategy.Next();
if (roomNodeData == null || string.IsNullOrEmpty(roomNodeData.Id))
{
LogCat.LogWarning("room_data_missing");
continue;
}
var roomInjectionProcessorData = roomNodeData.RoomInjectionProcessorData;
//Whether room can be placed
//是否可放置房间
var canBePlaced = true;
if (_roomInjectionProcessorsDictionary != null && !string.IsNullOrEmpty(roomInjectionProcessorData))
{
var roomInjectionProcessorDataArray =
YamlSerialization.Deserialize(roomInjectionProcessorData);
if (roomInjectionProcessorDataArray is { Length: > 0 })
{
foreach (var injectionProcessorData in roomInjectionProcessorDataArray)
{
if (string.IsNullOrEmpty(injectionProcessorData.Id) ||
string.IsNullOrEmpty(injectionProcessorData.Config))
{
//The data is incomplete, and the injectionProcessorData is ignored.
//数据不全,忽略injectionProcessorData。
continue;
}
if (!_roomInjectionProcessorsDictionary.TryGetValue(injectionProcessorData.Id,
out var roomInjectionProcessor))
{
//If the room injection processor cannot be found, a print error occurs.
//如果找不到房间注入处理器,那么打印错误。
LogCat.LogErrorWithFormat("room_injection_processor_does_not_exist",
LogCat.LogLabel.Default, LogCat.UploadFormat, injectionProcessorData.Id);
continue;
}
if (await roomInjectionProcessor.CanBePlaced(randomNumberGenerator,
injectionProcessorData.Config)) continue;
//If the room cannot be placed, then out of the loop.
//如果此房间不能被放置,那么跳出循环。
canBePlaced = false;
break;
}
}
}
if (!canBePlaced)
{
continue;
}
var nextParentNodeId = await _layoutParsingStrategy.GetNextParentNodeId();
Room? parentRoomNode = null;
if (nextParentNodeId != null)
{
//If the new room has the parent's ID, then we pass the parent's room into the compute function.
//如果新房间有父节点的ID,那么我们将父节点的房间传入到计算函数内。
if (roomDictionary.TryGetValue(nextParentNodeId, out var value))
{
parentRoomNode = value;
}
}
var roomPlacementData =
await _roomPlacementStrategy.CalculateNewRoomPlacementData(randomNumberGenerator, parentRoomNode,
roomNodeData);
if (roomPlacementData == null)
{
LogCat.LogWithFormat("failed_to_calculate_the_room_location", LogCat.LogLabel.Default,
LogCat.UploadFormat, roomNodeData.Id);
continue;
}
if (await PlaceRoomAndAddRecord(roomNodeData.Id, roomPlacementData, roomDictionary))
{
MarkRoomSlot(roomPlacementData);
}
}
//Place barriers
//放置屏障
foreach (var roomDictionaryValue in roomDictionary.Values)
{
PlaceBarrier(roomDictionaryValue);
}
//All rooms have been placed.
//所有房间已放置完毕。
await _roomPlacementStrategy.GeneratedComplete(_mapRoot);
_running = false;
//Invoke the map generation completion event
//调用地图生成完成事件
var eventObj = new MapGenerationCompleteEvent
{
RandomNumberGenerator = randomNumberGenerator,
RoomDictionary = roomDictionary
};
EventBus.MapGenerationCompleteEvent?.Invoke(eventObj);
var aiCharacterGenerateEvent = new AiCharacterGenerateEvent
{
Tag = AiCharacterGenerateEvent.TagMapGenerationComplete
};
EventBus.AiCharacterGenerateEvent?.Invoke(aiCharacterGenerateEvent);
}
///
/// Place barriers
/// 放置屏障
///
///
///
private static void PlaceBarrier(Room? room)
{
if (room == null)
{
return;
}
var ground = room.GetTileMapLayer(Config.TileMapLayerName.Ground);
var barrier = room.GetTileMapLayer(Config.TileMapLayerName.Barrier);
if (ground == null || barrier == null)
{
return;
}
var roomSlots = room.RoomSlots;
if (roomSlots == null || roomSlots.Length == 0)
{
return;
}
foreach (var roomSlot in roomSlots)
{
if (roomSlot == null)
{
continue;
}
if (roomSlot.Matched)
{
continue;
}
//Place the corresponding coordinate tiles of the barrier layer on the ground level.
//将屏障层的对应坐标瓦片放到地面层。
CoordinateUtils.ForEachCell(roomSlot.StartPosition, roomSlot.EndPosition,
i =>
{
var cellSourceId = barrier.GetCellSourceId(i);
if (cellSourceId == -1)
{
return;
}
ground.SetCell(i, cellSourceId, barrier.GetCellAtlasCoords(i), barrier.GetCellAlternativeTile(i));
});
}
barrier.QueueFree();
}
///
/// Mark the room slot as matched
/// 将房间槽标记为已匹配
///
///
private static void MarkRoomSlot(RoomPlacementData roomPlacementData)
{
if (roomPlacementData.ParentRoomSlot != null)
{
roomPlacementData.ParentRoomSlot.Matched = true;
}
if (roomPlacementData.NewRoomSlot != null)
{
roomPlacementData.NewRoomSlot.Matched = true;
}
}
///
/// Place rooms and add mappings
/// 放置房间,并增加映射
///
///
///
///
///
private static async Task PlaceRoomAndAddRecord(string roomNodeDataId,
RoomPlacementData roomPlacementData, Dictionary dictionary)
{
//The input parameters are incomplete.
//输入参数不全。
if (_roomPlacementStrategy == null || _mapRoot == null || string.IsNullOrEmpty(roomNodeDataId) ||
roomPlacementData.NewRoom == null)
{
return false;
}
if (dictionary.ContainsKey(roomNodeDataId))
{
LogCat.LogWithFormat("place_existing_rooms", LogCat.LogLabel.Default, LogCat.UploadFormat, roomNodeDataId);
return false;
}
if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData))
{
LogCat.LogWarningWithFormat("room_placement_failed", LogCat.LogLabel.Default, LogCat.UploadFormat,
roomNodeDataId);
return false;
}
dictionary.Add(roomNodeDataId, roomPlacementData.NewRoom);
LogCat.LogWithFormat("room_placement_information", LogCat.LogLabel.Default, LogCat.UploadFormat, roomNodeDataId,
roomPlacementData.Position.ToString());
return true;
}
}