#nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; namespace Demo2.Domain { public interface IDemo2Mod { string Id { get; } string Version { get; } void Register(Demo2ContentRegistry registry); } public sealed class Demo2ModManifest { public string Id = string.Empty; public string Version = string.Empty; public string ContentSha256 = string.Empty; } public sealed class Demo2ContentRegistry { private readonly Dictionary _rules = new(StringComparer.Ordinal); private readonly Dictionary _recipes = new(); private readonly Dictionary _machines = new(); private readonly List _waves = new(); public IReadOnlyDictionary Rules => _rules; public IReadOnlyDictionary Recipes => _recipes; public IReadOnlyDictionary Machines => _machines; public IReadOnlyList Waves => _waves; public void AddRule(Demo2RuleDefinition definition) => _rules.Add(definition.Id, definition); public void AddRecipe(Demo2RecipeDefinition definition) => _recipes.Add(definition.Id, definition); public void AddMachine(Demo2MachineDefinition definition) => _machines.Add(definition.Kind, definition); public void AddWave(Demo2WaveDefinition definition) => _waves.Add(definition); public string ComputeContentHash() { var text = new StringBuilder(); foreach (var rule in _rules.Values.OrderBy(value => value.Id, StringComparer.Ordinal)) { text.Append(rule.Id).Append('|').Append(rule.Name).Append('|').Append((int)rule.Category); foreach (var instruction in rule.Instructions) text.Append(':').Append((int)instruction.Opcode).Append(',').Append((int)instruction.Condition).Append(',').Append(instruction.Operand); text.AppendLine(); } foreach (var recipe in _recipes.Values.OrderBy(value => value.Id)) text.Append(recipe.Id).Append('|').Append(recipe.Name).Append('|') .Append((int)recipe.InputA).Append(',').Append(recipe.InputCountA).Append('|') .Append((int)recipe.InputB).Append(',').Append(recipe.InputCountB).Append('|') .Append((int)recipe.Output).Append(',').Append(recipe.OutputCount).Append('|').Append(recipe.ProcessTicks).AppendLine(); foreach (var machine in _machines.Values.OrderBy(value => (int)value.Kind)) text.Append("machine|").Append((int)machine.Kind).Append('|').Append(machine.Name).Append('|') .Append(machine.Cost).Append('|').Append(machine.RecipeId).Append('|').Append(machine.Capacity).AppendLine(); foreach (var wave in _waves.OrderBy(value => value.Cycle)) text.Append("wave|").Append(wave.Cycle).Append('|').Append(wave.TotalHealth).Append('|').Append(wave.Trait).AppendLine(); using var sha = SHA256.Create(); var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text.ToString())); var hex = new StringBuilder(bytes.Length * 2); for (var i = 0; i < bytes.Length; i++) hex.Append(bytes[i].ToString("x2")); return hex.ToString(); } } public static class Demo2BuiltInContent { public static Demo2ContentRegistry Create() { var registry = new Demo2ContentRegistry(); AddMachinesAndRecipes(registry); AddWaves(registry); foreach (var rule in BuildRules()) registry.AddRule(rule); return registry; } public static IReadOnlyList BuildRules() => new[] { Rule("production.triple-echo", "三连复写", "连续完成三次相同配方后复制下一件产物。", Demo2RuleCategory.Production, Demo2RuleOpcode.DuplicateNextOutput, 1, Demo2RuleCondition.ThreeSameRecipes), Rule("production.hot-ingot", "灼热锭", "无故障时,每周期增加 120 载荷。", Demo2RuleCategory.Production, Demo2RuleOpcode.AddPayload, 120, Demo2RuleCondition.NoFaults), Rule("production.precision-gears", "精密齿轮", "首批齿轮使载荷提高 25%。", Demo2RuleCategory.Production, Demo2RuleOpcode.MultiplyPayload, 1250, Demo2RuleCondition.FirstBatch), Rule("production.dense-ammo", "高密弹药", "结算载荷固定增加 180。", Demo2RuleCategory.Production, Demo2RuleOpcode.AddPayload, 180), Rule("logistics.twin-stream", "双流共振", "铁矿与燃料相邻流动时,倍率增加 0.35。", Demo2RuleCategory.Logistics, Demo2RuleOpcode.AddMultiplier, 350, Demo2RuleCondition.IronFuelAdjacent), Rule("logistics.clear-belt", "净空运输", "传送带占用低于 80% 时,倍率提高 20%。", Demo2RuleCategory.Logistics, Demo2RuleOpcode.MultiplyMultiplier, 1200, Demo2RuleCondition.BeltBelowEightyPercent), Rule("logistics.split-balance", "均衡分流", "稳定分流为载荷增加 90。", Demo2RuleCategory.Logistics, Demo2RuleOpcode.AddPayload, 90), Rule("logistics.long-haul", "长距惯性", "低占用且无故障时,倍率增加 0.2。", Demo2RuleCategory.Logistics, Demo2RuleOpcode.AddMultiplier, 200, Demo2RuleCondition.BeltBelowEightyPercent | Demo2RuleCondition.NoFaults), Rule("machine.overclock", "红区超频", "载荷提高 50%,并增加 1 次故障。", Demo2RuleCategory.MachineState, new[] { Instruction(Demo2RuleOpcode.MultiplyPayload, 1500), Instruction(Demo2RuleOpcode.AddFaults, 1) }), Rule("machine.preventive-maintenance", "预防维护", "存在故障时修复 1 次并增加 60 载荷。", Demo2RuleCategory.MachineState, new[] { Instruction(Demo2RuleOpcode.RepairFaults, 1, Demo2RuleCondition.HasFaults), Instruction(Demo2RuleOpcode.AddPayload, 60, Demo2RuleCondition.HasFaults) }), Rule("machine.night-shift", "夜班协议", "无故障时倍率增加 0.25。", Demo2RuleCategory.MachineState, Demo2RuleOpcode.AddMultiplier, 250, Demo2RuleCondition.NoFaults), Rule("machine.thermal-bank", "余热银行", "剩余能量每点转化 3 载荷。", Demo2RuleCategory.MachineState, Demo2RuleOpcode.ConvertEnergyToPayload, 3, Demo2RuleCondition.HasExcessEnergy), Rule("cycle.energy-settlement", "能量清算", "结算时剩余能量每点转化 5 载荷。", Demo2RuleCategory.CycleSettlement, Demo2RuleOpcode.ConvertEnergyToPayload, 5, Demo2RuleCondition.HasExcessEnergy), Rule("cycle.excess-credit", "过量授信", "每 20 点超额火力兑换 1 资金。", Demo2RuleCategory.CycleSettlement, Demo2RuleOpcode.AddMoneyFromExcess, 20), Rule("cycle.first-batch", "首批红利", "首批完成时倍率增加 0.3。", Demo2RuleCategory.CycleSettlement, Demo2RuleOpcode.AddMultiplier, 300, Demo2RuleCondition.FirstBatch), Rule("cycle.reserve-capacitor", "储备电容", "剩余能量使倍率提高 15%。", Demo2RuleCategory.CycleSettlement, Demo2RuleOpcode.MultiplyMultiplier, 1150, Demo2RuleCondition.HasExcessEnergy), Rule("risk.glass-core", "玻璃核心", "核心仅剩 1 点耐久时,倍率提高 65%。", Demo2RuleCategory.RiskExchange, Demo2RuleOpcode.AddMultiplier, 650, Demo2RuleCondition.CoreAtRisk), Rule("risk.debt-leverage", "负债杠杆", "立即增加 260 载荷,但故障计数增加 2。", Demo2RuleCategory.RiskExchange, new[] { Instruction(Demo2RuleOpcode.AddPayload, 260), Instruction(Demo2RuleOpcode.AddFaults, 2) }) }; private static void AddMachinesAndRecipes(Demo2ContentRegistry registry) { registry.AddRecipe(new Demo2RecipeDefinition { Id = 1, Name = "采集铁矿", Output = Demo2MaterialKind.IronOre, OutputCount = 1, ProcessTicks = 20 }); registry.AddRecipe(new Demo2RecipeDefinition { Id = 2, Name = "燃料电解", Output = Demo2MaterialKind.Fuel, OutputCount = 1, ProcessTicks = 30 }); registry.AddRecipe(new Demo2RecipeDefinition { Id = 3, Name = "铁锭熔炼", InputA = Demo2MaterialKind.IronOre, InputB = Demo2MaterialKind.Fuel, Output = Demo2MaterialKind.Ingot, InputCountA = 2, InputCountB = 1, OutputCount = 1, ProcessTicks = 40 }); registry.AddRecipe(new Demo2RecipeDefinition { Id = 4, Name = "齿轮装配", InputA = Demo2MaterialKind.Ingot, Output = Demo2MaterialKind.Gear, InputCountA = 2, OutputCount = 1, ProcessTicks = 50 }); registry.AddRecipe(new Demo2RecipeDefinition { Id = 5, Name = "弹药压制", InputA = Demo2MaterialKind.Gear, InputB = Demo2MaterialKind.Energy, Output = Demo2MaterialKind.Ammo, InputCountA = 1, InputCountB = 1, OutputCount = 4, ProcessTicks = 35 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Miner, Name = "采集器", Cost = 40, RecipeId = 1, Capacity = 8 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Conveyor, Name = "传送带", Cost = 5, Capacity = 4 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Splitter, Name = "分流器", Cost = 15, Capacity = 8 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Smelter, Name = "熔炼机", Cost = 80, RecipeId = 3, Capacity = 12 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Assembler, Name = "组装机", Cost = 110, RecipeId = 4, Capacity = 12 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Loader, Name = "弹药装填器", Cost = 70, RecipeId = 5, Capacity = 24 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Turret, Name = "自动炮塔", Cost = 150, Capacity = 200 }); registry.AddMachine(new Demo2MachineDefinition { Kind = Demo2MachineKind.Generator, Name = "能量站", Cost = 60, RecipeId = 2, Capacity = 16 }); } private static void AddWaves(Demo2ContentRegistry registry) { var health = 500L; var traits = new[] { "标准装甲", "分散队列", "电磁护盾", "高速突击", "核心压制" }; for (var cycle = 1; cycle <= Demo2Protocol.CycleCount; cycle++) { registry.AddWave(new Demo2WaveDefinition { Cycle = cycle, TotalHealth = health, Trait = traits[cycle - 1] }); health = SaturatingMath.MultiplyScaled(health, 1800); } } private static Demo2RuleDefinition Rule(string id, string name, string description, Demo2RuleCategory category, Demo2RuleOpcode opcode, long operand, Demo2RuleCondition condition = Demo2RuleCondition.None) => Rule(id, name, description, category, new[] { Instruction(opcode, operand, condition) }); private static Demo2RuleDefinition Rule(string id, string name, string description, Demo2RuleCategory category, IEnumerable instructions) => new() { Id = id, Name = name, Description = description, Category = category, Instructions = instructions.ToList() }; private static Demo2RuleInstructionData Instruction(Demo2RuleOpcode opcode, long operand, Demo2RuleCondition condition = Demo2RuleCondition.None) => new() { Opcode = opcode, Operand = operand, Condition = condition }; } }