G5: bump engine (regex tooling), showcase grouping/patch/validators
Engine pointer -> d044caf (formula gene grouping, content patches, def
field validation). Game-side demonstration of all three:
- genes.json: GeneHardiness whose effect is gsum('Gene.*Tolerance') — a
derived trait summing all tolerance genes via regex grouping.
- patches.json: a content patch giving every Bush* plant a wood harvest
product, applied to Core's own defs at load.
- GameContent registers load-time validators: Gene/Product defNames must
carry their type prefix.
- Program: a --check-content headless mode that loads all mod defs (running
patches + validators) and computes a sample genome's traits (compiling
every gene formula, grouping included) — a CI-friendly content lint.
Verified: --check-content reports 6 def types, 18 genes, 8 plants, 18
traits with hardiness computed from the gene group. Full suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7fc4bcd301
commit
37d8c976a3
@@ -59,6 +59,12 @@
|
|||||||
"default": 0.33, "min": 0, "max": 1, "spread": 0.04, "tags": ["morphology", "color"],
|
"default": 0.33, "min": 0, "max": 1, "spread": 0.04, "tags": ["morphology", "color"],
|
||||||
"effects": { "leafHue": "value" } },
|
"effects": { "leafHue": "value" } },
|
||||||
|
|
||||||
|
// Производный ген: признак собирается группировкой по регэкспу — сумма всех генов-толерантностей
|
||||||
|
// (демонстрация gsom-функций фазы G5). Собственное значение гена не используется.
|
||||||
|
{ "defName": "GeneHardiness", "parent": "BaseNumericGene", "label": "gene.hardiness",
|
||||||
|
"default": 0, "min": 0, "max": 1, "spread": 0, "mutationChance": 0, "tags": ["derived"],
|
||||||
|
"effects": { "hardiness": "gsum('Gene.*Tolerance')" } },
|
||||||
|
|
||||||
// Дискретный ген морфы: вариант 0 доминирует, 1 (рецессивный) виден только в гомозиготе.
|
// Дискретный ген морфы: вариант 0 доминирует, 1 (рецессивный) виден только в гомозиготе.
|
||||||
{ "defName": "GeneMorph", "kind": "Discrete", "label": "gene.morph",
|
{ "defName": "GeneMorph", "kind": "Discrete", "label": "gene.morph",
|
||||||
"variants": 2, "variantWeights": [0.82, 0.18], "mutationChance": 0.05, "tags": ["morphology"],
|
"variants": 2, "variantWeights": [0.82, 0.18], "mutationChance": 0.05, "tags": ["morphology"],
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"type": "Patch",
|
||||||
|
// Контент-патчи (фаза G5): применяются ко всем дефам типа defType, чьё имя подходит под regex match,
|
||||||
|
// проставляя поля set. Демонстрация: даём кустам древесину при сборе (веточки).
|
||||||
|
"patches": [
|
||||||
|
{ "defType": "Plant", "match": "Bush.*", "set": { "harvestProduct": "ProductWood" } }
|
||||||
|
]
|
||||||
|
}
|
||||||
+1
-1
Submodule engine updated: ead22517ee...d044cafad9
@@ -62,6 +62,14 @@ public sealed class GameContent
|
|||||||
defs.RegisterType<PlantDef>("Plant");
|
defs.RegisterType<PlantDef>("Plant");
|
||||||
defs.RegisterType<PawnDef>("Pawn");
|
defs.RegisterType<PawnDef>("Pawn");
|
||||||
defs.RegisterType<WorldPresetDef>("WorldPreset");
|
defs.RegisterType<WorldPresetDef>("WorldPreset");
|
||||||
|
// Валидация имён при загрузке (фаза G5): гены и продукты обязаны иметь префикс типа.
|
||||||
|
defs.RegisterValidator("Gene", "defName", "^Gene", "gene defName must start with 'Gene'");
|
||||||
|
defs.RegisterValidator(
|
||||||
|
"Product",
|
||||||
|
"defName",
|
||||||
|
"^Product",
|
||||||
|
"product defName must start with 'Product'"
|
||||||
|
);
|
||||||
defs.Load(mods);
|
defs.Load(mods);
|
||||||
|
|
||||||
var languages = new LanguageManager(defaultLanguage: "ru");
|
var languages = new LanguageManager(defaultLanguage: "ru");
|
||||||
|
|||||||
@@ -1,8 +1,35 @@
|
|||||||
|
using LittleSim.Content;
|
||||||
using LittleSim.Scenes;
|
using LittleSim.Scenes;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MrGameEng.Core;
|
using MrGameEng.Core;
|
||||||
|
using MrGameEng.Genetics;
|
||||||
using MrGameEng.Host;
|
using MrGameEng.Host;
|
||||||
|
|
||||||
|
// Контент-линт без окна/GPU: грузит моды/дефы (патчи и валидаторы тоже), компилирует формулы генов
|
||||||
|
// (включая группировку gsum) и выходит. Удобно для CI.
|
||||||
|
if (args.Contains("--check-content"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = GameContent.Load();
|
||||||
|
var genes = content.Defs.All<GeneDef>();
|
||||||
|
var registry = genes.ToDictionary(g => g.DefName, g => g, StringComparer.Ordinal);
|
||||||
|
var traits = Phenotype.Compute(Genome.Generate(genes, new Random(1)), registry);
|
||||||
|
Console.WriteLine(
|
||||||
|
$"content ok: {content.Defs.TypeKeys.Count} def types, {genes.Count} genes, "
|
||||||
|
+ $"{content.Defs.NamesOf("Plant").Count} plants, {traits.Count} traits "
|
||||||
|
+ $"(hardiness={traits.GetValueOrDefault("hardiness"):0.##})"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"content FAILED: {error.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Контент Core-мода грузится уже в окне — на загрузочном экране (BootScene), в фоне.
|
// Контент Core-мода грузится уже в окне — на загрузочном экране (BootScene), в фоне.
|
||||||
using var host = new GameHost(
|
using var host = new GameHost(
|
||||||
new GameHostOptions
|
new GameHostOptions
|
||||||
|
|||||||
Reference in New Issue
Block a user