Files
Workspace/Assets/Demos/Demo2/Domain/Demo2Content.cs
T
2026-08-18 02:03:34 +08:00

151 lines
12 KiB
C#

#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<string, Demo2RuleDefinition> _rules = new(StringComparer.Ordinal);
private readonly Dictionary<int, Demo2RecipeDefinition> _recipes = new();
private readonly Dictionary<Demo2MachineKind, Demo2MachineDefinition> _machines = new();
private readonly List<Demo2WaveDefinition> _waves = new();
public IReadOnlyDictionary<string, Demo2RuleDefinition> Rules => _rules;
public IReadOnlyDictionary<int, Demo2RecipeDefinition> Recipes => _recipes;
public IReadOnlyDictionary<Demo2MachineKind, Demo2MachineDefinition> Machines => _machines;
public IReadOnlyList<Demo2WaveDefinition> 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<Demo2RuleDefinition> 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<Demo2RuleInstructionData> 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 };
}
}