diff --git a/data/levelGraphs/test.json b/data/levelGraphs/test.json index e0cc39f..129664f 100644 --- a/data/levelGraphs/test.json +++ b/data/levelGraphs/test.json @@ -8,31 +8,7 @@ }, { "FromId": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03", - "ToId": "9d764cca-5057-470a-976d-ba472a21e2cc", - "FromPort": 0, - "ToPort": 0 - }, - { - "FromId": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03", - "ToId": "cf04b0af-5940-4d8d-b081-d0b597583771", - "FromPort": 0, - "ToPort": 0 - }, - { - "FromId": "9d764cca-5057-470a-976d-ba472a21e2cc", - "ToId": "96f264c0-7169-4916-904f-e0384564e491", - "FromPort": 0, - "ToPort": 0 - }, - { - "FromId": "96f264c0-7169-4916-904f-e0384564e491", - "ToId": "197d7935-be4f-4808-9264-0848c8069309", - "FromPort": 0, - "ToPort": 0 - }, - { - "FromId": "cf04b0af-5940-4d8d-b081-d0b597583771", - "ToId": "26822086-6b19-482f-92b9-71fa8eb3f20c", + "ToId": "ba32e05c-0c80-4a79-b5ce-5b8150400e05", "FromPort": 0, "ToPort": 0 } @@ -47,7 +23,9 @@ ], "Tags": [ "StartingRoom" - ] + ], + "RoomInjectionProcessorId": null, + "RoomInjectionProcessorConfig": null }, { "Id": "4ae948ea-82b7-4b2d-bec2-19ed8a9d4c03", @@ -56,52 +34,19 @@ "RoomTemplateSet": [ "res://prefab/roomTemplates/dungeon/utilityRoom.tscn" ], - "Tags": null + "Tags": null, + "RoomInjectionProcessorId": null, + "RoomInjectionProcessorConfig": null }, { - "Id": "9d764cca-5057-470a-976d-ba472a21e2cc", + "Id": "ba32e05c-0c80-4a79-b5ce-5b8150400e05", "Title": "房间3", "Description": "", - "RoomTemplateSet": [ - "res://prefab/roomTemplates/dungeon" - ], - "Tags": null - }, - { - "Id": "cf04b0af-5940-4d8d-b081-d0b597583771", - "Title": "房间8", - "Description": "", "RoomTemplateSet": [ "res://prefab/roomTemplates/dungeon/" ], - "Tags": null - }, - { - "Id": "96f264c0-7169-4916-904f-e0384564e491", - "Title": "房间5", - "Description": "", - "RoomTemplateSet": [ - "res://prefab/roomTemplates/dungeon" - ], - "Tags": null - }, - { - "Id": "197d7935-be4f-4808-9264-0848c8069309", - "Title": "房间6", - "Description": "", - "RoomTemplateSet": [ - "res://prefab/roomTemplates/dungeon" - ], - "Tags": null - }, - { - "Id": "26822086-6b19-482f-92b9-71fa8eb3f20c", - "Title": "房间7", - "Description": "", - "RoomTemplateSet": [ - "res://prefab/roomTemplates/dungeon" - ], - "Tags": null + "Tags": null, + "RoomInjectionProcessorData": "[\n {\n \"Id\": \"Chance\",\n \"Config\": \"{\\\"Chance\\\":35.5}\"\n }\n]" } ] } \ No newline at end of file diff --git a/locals/Log.csv b/locals/Log.csv index b50f575..2062ba1 100644 --- a/locals/Log.csv +++ b/locals/Log.csv @@ -16,4 +16,4 @@ failed_to_calculate_the_room_location,计算房间{0}位置时失败。,Failed t place_existing_rooms,放置已存在的房间{0}。,Place existing rooms {0}.,既存の部屋を置きます{0}。 room_placement_failed,房间{0}放置失败。,Room {0} placement failed.,部屋{0}の放置に失敗します。 room_placement_information,房间{0}已被成功放置在{1}。,Room {0} has been successfully placed in {1}.,部屋{0}を{1}に配置しました。 -slogan_not_exist,找不到位于{0}的标语文件。,The tagline file at {0} could not be found.,{0}にある標語ファイルが見つかりません。 \ No newline at end of file +room_injection_processor_does_not_exist,找不到房间注入处理器{0},请检测是否在MapGenerator内注册。,"Room injection processor {0} not found, check to see if it is registered in MapGenerator.",部屋注入プロセッサ{0}が見つかりません、MapGenerator内に登録されているかどうか検出してください。 \ No newline at end of file diff --git a/locals/Log.en.translation b/locals/Log.en.translation index 746750f..8a37c69 100644 Binary files a/locals/Log.en.translation and b/locals/Log.en.translation differ diff --git a/locals/Log.jp.translation b/locals/Log.jp.translation index c329b63..c79b462 100644 Binary files a/locals/Log.jp.translation and b/locals/Log.jp.translation differ diff --git a/locals/Log.zh.translation b/locals/Log.zh.translation index ef316a3..b125571 100644 Binary files a/locals/Log.zh.translation and b/locals/Log.zh.translation differ diff --git a/locals/UI.csv b/locals/UI.csv index 1152037..bc8f044 100644 --- a/locals/UI.csv +++ b/locals/UI.csv @@ -30,4 +30,5 @@ load,加载,Load,ろーど delete_selected_node,删除选中的节点,Delete selected node,選択されたノードを削除します re_create_map,重新创建地图,Re-create map,地図を再作成します seed_info,种子:{0},Seed: {0},シード:{0} -tags,标签,Tags,と呼ぶ \ No newline at end of file +tags,标签,Tags,と呼ぶ +room_injection_processor,房间注入处理器,Room injection processor,部屋注入処理器 \ No newline at end of file diff --git a/locals/UI.en.translation b/locals/UI.en.translation index 9da8a62..4ab0903 100644 Binary files a/locals/UI.en.translation and b/locals/UI.en.translation differ diff --git a/locals/UI.jp.translation b/locals/UI.jp.translation index d78dd25..0b8d92e 100644 Binary files a/locals/UI.jp.translation and b/locals/UI.jp.translation differ diff --git a/locals/UI.zh.translation b/locals/UI.zh.translation index 13e9ac6..2d9b91b 100644 Binary files a/locals/UI.zh.translation and b/locals/UI.zh.translation differ diff --git a/scenes/LevelGraphEditor.tscn b/scenes/LevelGraphEditor.tscn index b50e95a..2811dd6 100644 --- a/scenes/LevelGraphEditor.tscn +++ b/scenes/LevelGraphEditor.tscn @@ -73,10 +73,10 @@ text = "room_template_collection_prompt" [node name="RoomTemplateTipsLabel" type="Label" parent="CreateOrEditorPanel"] layout_mode = 1 -offset_left = 18.0 -offset_top = 319.0 -offset_right = 265.0 -offset_bottom = 344.0 +offset_left = 16.0 +offset_top = 259.0 +offset_right = 263.0 +offset_bottom = 284.0 text = "errorTip" [node name="RoomNameLineEdit" type="LineEdit" parent="CreateOrEditorPanel"] @@ -141,25 +141,43 @@ anchor_right = 1.0 offset_left = 9.0 offset_top = 184.0 offset_right = -11.0 -offset_bottom = 298.0 +offset_bottom = 245.0 grow_horizontal = 2 [node name="Label5" type="Label" parent="CreateOrEditorPanel"] layout_mode = 0 -offset_left = 21.0 -offset_top = 354.0 -offset_right = 61.0 -offset_bottom = 379.0 +offset_left = 16.0 +offset_top = 289.0 +offset_right = 56.0 +offset_bottom = 314.0 text = "tags" [node name="TagLineEdit" type="LineEdit" parent="CreateOrEditorPanel"] layout_mode = 1 anchors_preset = 10 anchor_right = 1.0 -offset_left = 16.0 -offset_top = 388.0 -offset_right = -15.0 -offset_bottom = 421.0 +offset_left = 11.0 +offset_top = 324.0 +offset_right = -20.0 +offset_bottom = 357.0 +grow_horizontal = 2 + +[node name="Label7" type="Label" parent="CreateOrEditorPanel"] +layout_mode = 1 +offset_left = 14.0 +offset_top = 368.0 +offset_right = 283.0 +offset_bottom = 393.0 +text = "room_injection_processor" + +[node name="RoomInjectionProcessorDataTextEdit" type="TextEdit" parent="CreateOrEditorPanel"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_left = 14.0 +offset_top = 404.0 +offset_right = -25.0 +offset_bottom = 493.0 grow_horizontal = 2 [node name="HBoxContainer" type="HBoxContainer" parent="."] diff --git a/scripts/Config.cs b/scripts/Config.cs index 663d5a4..4c991eb 100644 --- a/scripts/Config.cs +++ b/scripts/Config.cs @@ -149,6 +149,20 @@ public static class Config return OS.HasFeature("editor"); } + public class RoomInjectionProcessorId + { + /// + /// Chance + /// 概率的 + /// + public const string Chance = "Chance"; + /// + /// TimeInterval + /// 时间范围的 + /// + public const string TimeInterval = "TimeInterval"; + } + public enum OsEnum { //unknown diff --git a/scripts/levelGraphEditor/RoomInjectionProcessorData.cs b/scripts/levelGraphEditor/RoomInjectionProcessorData.cs new file mode 100644 index 0000000..b82c9cb --- /dev/null +++ b/scripts/levelGraphEditor/RoomInjectionProcessorData.cs @@ -0,0 +1,20 @@ +namespace ColdMint.scripts.levelGraphEditor; + +/// +/// Room injector data +/// 房间注入器数据 +/// +public class RoomInjectionProcessorData +{ + /// + /// Room injection processor ID + /// 房间注入处理器ID + /// + public string? Id { get; set; } + + /// + /// Room injection processor configuration information + /// 房间注入处理器的配置信息 + /// + public string? Config { get; set; } +} \ No newline at end of file diff --git a/scripts/levelGraphEditor/RoomNodeData.cs b/scripts/levelGraphEditor/RoomNodeData.cs index 4b5aa4d..3d62fa6 100644 --- a/scripts/levelGraphEditor/RoomNodeData.cs +++ b/scripts/levelGraphEditor/RoomNodeData.cs @@ -12,6 +12,11 @@ public class RoomNodeData public string[]? Tags { get; set; } + /// + /// Room injector data + /// 房间注入器数据 + /// + public string? RoomInjectionProcessorData { get; set; } /// /// Whether a tag is held diff --git a/scripts/loader/uiLoader/LevelGraphEditorLoader.cs b/scripts/loader/uiLoader/LevelGraphEditorLoader.cs index 92a61f4..284bce5 100644 --- a/scripts/loader/uiLoader/LevelGraphEditorLoader.cs +++ b/scripts/loader/uiLoader/LevelGraphEditorLoader.cs @@ -260,7 +260,6 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate roomNode.QueueFree(); _selectedNodes.Remove(node); } - }; } @@ -356,7 +355,8 @@ public partial class LevelGraphEditorLoader : UiLoaderTemplate Title = _nodeBinding.RoomNameLineEdit.Text, Description = _nodeBinding.RoomDescriptionLineEdit.Text, RoomTemplateSet = roomTemplateArray, - Tags = tagArray + Tags = tagArray, + RoomInjectionProcessorData = _nodeBinding.RoomInjectionProcessorDataTextEdit?.Text }; if (!_hasStartNode && roomNodeData.HasTag(Config.RoomDataTag.StartingRoom)) { diff --git a/scripts/loader/uiLoader/MainMenuLoader.cs b/scripts/loader/uiLoader/MainMenuLoader.cs index 6ecc1c8..d10a529 100644 --- a/scripts/loader/uiLoader/MainMenuLoader.cs +++ b/scripts/loader/uiLoader/MainMenuLoader.cs @@ -3,6 +3,8 @@ using System.IO; using System.Text; using ColdMint.scripts.camp; using ColdMint.scripts.debug; +using ColdMint.scripts.map; +using ColdMint.scripts.map.roomInjectionProcessor; using Godot; namespace ColdMint.scripts.loader.uiLoader; @@ -35,6 +37,9 @@ public partial class MainMenuLoader : UiLoaderTemplate //在发行版禁用所有日志。 LogCat.MinLogLevel = LogCat.DisableAllLogLevel; } + + MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor()); + MapGenerator.RegisterRoomInjectionProcessor(new TimeIntervalRoomInjectorProcessor()); //Register the corresponding encoding provider to solve the problem of garbled Chinese path of the compressed package //注册对应的编码提供程序,解决压缩包中文路径乱码问题 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); diff --git a/scripts/map/IRoomInjectionStrategy.cs b/scripts/map/IRoomInjectionStrategy.cs deleted file mode 100644 index 3f33fc8..0000000 --- a/scripts/map/IRoomInjectionStrategy.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ColdMint.scripts.map; - -/// -/// Room injection strategy -/// 房间注入策略 -/// -public interface IRoomInjectionStrategy -{ - -} \ No newline at end of file diff --git a/scripts/map/MapGenerator.cs b/scripts/map/MapGenerator.cs index 037f7c0..3034514 100644 --- a/scripts/map/MapGenerator.cs +++ b/scripts/map/MapGenerator.cs @@ -1,12 +1,14 @@ 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; @@ -64,7 +66,7 @@ public static class MapGenerator return _roomInjectionProcessorsDictionary.TryAdd(key, roomInjectionProcessor); } - + /// /// Log out of the room injection processor /// 注销房间注入处理器 @@ -77,7 +79,7 @@ public static class MapGenerator { return false; } - + return _roomInjectionProcessorsDictionary.Remove(id); } @@ -224,6 +226,46 @@ public static class MapGenerator continue; } + var roomInjectionProcessorData = roomNodeData.RoomInjectionProcessorData; + //Whether room can be placed + //是否可放置房间 + var canBePlaced = true; + if (_roomInjectionProcessorsDictionary != null && !string.IsNullOrEmpty(roomInjectionProcessorData)) + { + var roomInjectionProcessorDataArray = + JsonSerialization.Deserialize(roomInjectionProcessorData); + if (roomInjectionProcessorDataArray != null && roomInjectionProcessorDataArray.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", 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) diff --git a/scripts/map/interfaces/IRoomInjectionProcessor.cs b/scripts/map/interfaces/IRoomInjectionProcessor.cs index f7a03e5..08d7fcf 100644 --- a/scripts/map/interfaces/IRoomInjectionProcessor.cs +++ b/scripts/map/interfaces/IRoomInjectionProcessor.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using ColdMint.scripts.map.dateBean; +using Godot; namespace ColdMint.scripts.map.interfaces; @@ -15,11 +15,19 @@ public interface IRoomInjectionProcessor /// /// public string GetId(); - + /// - /// The processing method should return to the room to place the data - /// 处理方法,应当返回房间放置数据 + /// Whether it can be placed on the map + /// 是否能够被放置到地图内 /// + /// + ///Random probability generator based on world seed + ///根据世界种子确定的随机概率生成器 + /// + /// + ///Inject data into the processor + ///注入处理器的数据 + /// /// - public Task Processor(); + public Task CanBePlaced(RandomNumberGenerator randomNumberGenerator, string? jsonConfigData); } \ No newline at end of file diff --git a/scripts/map/roomInjectionProcessor/ChanceRoomInjectionProcessor.cs b/scripts/map/roomInjectionProcessor/ChanceRoomInjectionProcessor.cs new file mode 100644 index 0000000..2474bbe --- /dev/null +++ b/scripts/map/roomInjectionProcessor/ChanceRoomInjectionProcessor.cs @@ -0,0 +1,53 @@ +using System.Threading.Tasks; +using Godot; + +namespace ColdMint.scripts.map.roomInjectionProcessor; + +/// +/// Probabilistic room injection processor +/// 概率的房间注入处理器 +/// +/// +///This processor allows you to specify a probability and then decide whether to generate a room based on that probability. +///此处理器允许指定一个概率,然后根据概率来决定是否生成房间。 +/// +public class ChanceRoomInjectionProcessor : RoomInjectionProcessorTemplate +{ + public override string GetId() + { + return Config.RoomInjectionProcessorId.Chance; + } + + protected override Task OnCreateConfigData(RandomNumberGenerator randomNumberGenerator, ConfigData configData) + { + if (configData.Chance == null) + { + return Task.FromResult(false); + } + + //Generate a random number between 1 and 10000. + //生成1-10000的随机数。 + var round = randomNumberGenerator.Randi() % 10000 + 1; + //If the random number is less than or equal to the probability, the room is generated. + //如果随机数小于等于概率,则生成房间。 + return Task.FromResult(round <= configData.Chance * 100); + } + + + /// + /// Configuration Data + /// 配置数据 + /// + public class ConfigData + { + /// + /// The probability of generating this room + /// 生成此房间的概率 + /// + /// + ///The value ranges from 1 to 100. For example, if it is set to 1.5, it means that there is a 1.5% probability of generating this room. + ///支持小数,范围为1-100。例如,如果设置为1.5,则表示1.5%的概率生成此房间。 + /// + public float? Chance { get; set; } + } +} \ No newline at end of file diff --git a/scripts/map/roomInjectionProcessor/RoomInjectionProcessorTemplate.cs b/scripts/map/roomInjectionProcessor/RoomInjectionProcessorTemplate.cs new file mode 100644 index 0000000..c94ca30 --- /dev/null +++ b/scripts/map/roomInjectionProcessor/RoomInjectionProcessorTemplate.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using ColdMint.scripts.map.interfaces; +using ColdMint.scripts.serialization; +using Godot; + +namespace ColdMint.scripts.map.roomInjectionProcessor; + +/// +/// Room injection processor template +/// 房间注入处理器模板 +/// +/// +public abstract class RoomInjectionProcessorTemplate : IRoomInjectionProcessor +{ + public abstract string GetId(); + + public Task CanBePlaced(RandomNumberGenerator randomNumberGenerator, string? jsonConfigData) + { + if (jsonConfigData == null) + { + return Task.FromResult(false); + } + + var configData = JsonSerialization.Deserialize(jsonConfigData); + if (configData == null) + { + return Task.FromResult(false); + } + + return OnCreateConfigData(randomNumberGenerator, configData); + } + + /// + /// When creating a configuration class + /// 当创建配置类时 + /// + /// + /// + /// + protected abstract Task OnCreateConfigData(RandomNumberGenerator randomNumberGenerator, TConfig configData); +} \ No newline at end of file diff --git a/scripts/map/roomInjectionProcessor/TimeIntervalRoomInjectorProcessor.cs b/scripts/map/roomInjectionProcessor/TimeIntervalRoomInjectorProcessor.cs new file mode 100644 index 0000000..ee88205 --- /dev/null +++ b/scripts/map/roomInjectionProcessor/TimeIntervalRoomInjectorProcessor.cs @@ -0,0 +1,84 @@ +using System; +using System.Threading.Tasks; +using ColdMint.scripts.utils; +using Godot; + +namespace ColdMint.scripts.map.roomInjectionProcessor; + +/// +/// Time interval for room injection processor +/// 时间区间的房间注入处理器 +/// +/// +///This processor allows you to specify a time range and allows room generation within the specified time range. +///此处理器允许指定一个时间范围,并在指定的时间范围内允许生成房间。 +/// +public class + TimeIntervalRoomInjectorProcessor : RoomInjectionProcessorTemplate +{ + public override string GetId() + { + return Config.RoomInjectionProcessorId.TimeInterval; + } + + protected override Task OnCreateConfigData(RandomNumberGenerator randomNumberGenerator, ConfigData configData) + { + if (configData.StartTime == null) + { + return Task.FromResult(false); + } + + if (configData.EndTime == null) + { + //If no end time is specified, the default end time is the start time + //如果未指定结束时间,则默认结束时间为开始时间 + configData.EndTime = configData.StartTime; + } + + var now = DateTime.Now; + if (!configData.SpecifiedYear) + { + //If no year is specified, it is automatically added to the current year + //若未指定年份,则自动补充为当前年份 + var nowYear = now.Year; + configData.StartTime = $"{nowYear}-{configData.StartTime}"; + configData.EndTime = $"{nowYear}-{configData.EndTime}"; + } + + return Task.FromResult(TimeUtils.IsBetweenTimeSpan(now, configData.StartTime, configData.EndTime)); + } + + + public class ConfigData + { + /// + /// Whether to specify a year + /// 是否指定年份 + /// + /// + ///If true, then Year can be specified in StartTime and EndTime. The specified year is used to be executed only once in a given year, while configurations that do not specify a year are automatically replenished with the current year (performed annually). + ///如果为true,那么可以在StartTime和EndTime内指定Year。指定年份被用于在特定的年份仅执行一次,而未指定年份的配置会自动补充为当前年份(每年执行)。 + /// + public bool SpecifiedYear { get; set; } + + /// + /// Start time + /// 起始时间 + /// + /// + ///If the year is not specified, enter data in the format MM-DD hh:mm:ss. If the year is specified, enter data in the format yyyy-MM-dd hh:mm:ss. + ///若未指定年份,则可填入格式为MM-dd hh:mm:ss的数据,若指定了年份,那么请填入yyyy-MM-dd hh:mm:ss格式数据。 + /// + public string? StartTime { get; set; } + + /// + /// End time + /// 结束时间 + /// + /// + ///See StartTime + ///同StartTime + /// + public string? EndTime { get; set; } + } +} \ No newline at end of file diff --git a/scripts/nodeBinding/LevelGraphEditorBinding.cs b/scripts/nodeBinding/LevelGraphEditorBinding.cs index a481728..9919b37 100644 --- a/scripts/nodeBinding/LevelGraphEditorBinding.cs +++ b/scripts/nodeBinding/LevelGraphEditorBinding.cs @@ -31,6 +31,7 @@ public class LevelGraphEditorBinding : INodeBinding public Button? ShowLoadPanelButton; public Button? DeleteSelectedNodeButton; public LineEdit? TagLineEdit; + public TextEdit? RoomInjectionProcessorDataTextEdit; public void Binding(Node root) { RoomTemplateTipsLabel = root.GetNode