Migrate parts data to assets repo

This commit is contained in:
2026-05-17 13:46:09 +02:00
parent faf1459dba
commit d7704c5f68
9 changed files with 652 additions and 48 deletions
+169 -28
View File
@@ -2120,10 +2120,9 @@ func TestPlanHAKsWritesManifestWithoutArchives(t *testing.T) {
}
}
func TestBuildHAKsWritesConfiguredAutogenManifests(t *testing.T) {
func TestBuildHAKsWritesConfiguredHeadVisualeffectsAutogenManifest(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src"))
mustMkdir(t, filepath.Join(root, "assets", "part", "belt"))
mustMkdir(t, filepath.Join(root, "assets", "vfxs", "head_accessories"))
mustMkdir(t, filepath.Join(root, "assets", "vfxs", "head_features", "hair"))
mustMkdir(t, filepath.Join(root, "build"))
@@ -2141,20 +2140,6 @@ func TestBuildHAKsWritesConfiguredAutogenManifests(t *testing.T) {
},
"autogen": {
"producers": [
{
"id": "parts",
"root": "part",
"include": ["**/*.mdl"],
"derive": {
"kind": "trailing_numeric_suffix",
"group_from": "first_path_segment"
},
"manifest": {
"release_tag": "parts-manifest-current",
"asset_name": "sow-parts-manifest.json",
"cache_name": "sow-parts-manifest.json"
}
},
{
"id": "head_visualeffects",
"root": "vfxs",
@@ -2177,12 +2162,12 @@ func TestBuildHAKsWritesConfiguredAutogenManifests(t *testing.T) {
"priority": 1,
"max_bytes": 0,
"split": false,
"include": ["part/**", "vfxs/**"]
"include": ["vfxs/**"]
}
]
}
`)
mustWriteFile(t, filepath.Join(root, "assets", "part", "belt", "pfa0_belt018.mdl"), "belt")
mustWriteFile(t, filepath.Join(root, "assets", "vfxs", "head_accessories", "hfx_bandana.mdl"), "bandana")
mustWriteFile(t, filepath.Join(root, "assets", "vfxs", "head_features", "hair", "hfx_hair_bangs.mdl"), "hair")
@@ -2201,16 +2186,11 @@ func TestBuildHAKsWritesConfiguredAutogenManifests(t *testing.T) {
if err != nil {
t.Fatalf("build haks: %v", err)
}
if len(result.AutogenManifestPaths) != 2 {
t.Fatalf("expected 2 autogen manifests, got %d", len(result.AutogenManifestPaths))
if len(result.AutogenManifestPaths) != 1 {
t.Fatalf("expected 1 autogen manifest, got %d", len(result.AutogenManifestPaths))
}
partsRaw, err := os.ReadFile(filepath.Join(root, "build", "sow-parts-manifest.json"))
if err != nil {
t.Fatalf("read parts manifest: %v", err)
}
if !strings.Contains(string(partsRaw), `"id": "parts"`) || !strings.Contains(string(partsRaw), `"row_id": 18`) {
t.Fatalf("unexpected parts manifest contents:\n%s", string(partsRaw))
if _, err := os.Stat(filepath.Join(root, "build", "sow-parts-manifest.json")); !os.IsNotExist(err) {
t.Fatalf("expected no parts manifest, got stat error %v", err)
}
headRaw, err := os.ReadFile(filepath.Join(root, "build", "sow-head-vfx-manifest.json"))
@@ -2231,6 +2211,167 @@ func TestBuildHAKsWritesConfiguredAutogenManifests(t *testing.T) {
}
}
func TestBuildHAKsGeneratesParts2DAAssetsFromLocalModels(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src"))
mustMkdir(t, filepath.Join(root, "assets", "part", "belt"))
mustMkdir(t, filepath.Join(root, "topdata", "data", "parts"))
mustMkdir(t, filepath.Join(root, "topdata", "data", "parts", "modules"))
mustMkdir(t, filepath.Join(root, "build"))
mustWriteFile(t, filepath.Join(root, "nwn-tool.json"), `{
"module": {
"name": "Test Module",
"resref": "testmod",
"hak_order": ["group:sow_part"]
},
"paths": {
"source": "src",
"assets": "assets",
"build": "build"
},
"generated_assets": {
"topdata_2da": [
{
"id": "parts",
"source": "topdata",
"output": "{paths.cache}/generated-assets/parts-2da",
"include_datasets": ["parts/**"],
"package_root": "part",
"autogen": {
"id": "parts",
"mode": "parts_rows",
"root": "part",
"include": ["**/*.mdl"],
"derive": {
"kind": "trailing_numeric_suffix",
"group_from": "first_path_segment"
}
}
}
]
},
"haks": [
{
"name": "sow_part",
"priority": 1,
"max_bytes": 0,
"split": false,
"include": ["part/**"]
}
]
}
`)
mustWriteFile(t, filepath.Join(root, "assets", "part", "belt", "pfa0_belt018.mdl"), "belt")
mustWriteFile(t, filepath.Join(root, "topdata", "data", "parts", "belt.json"), `{
"output": "parts_belt.2da",
"columns": ["COSTMODIFIER", "ACBONUS"],
"rows": [
{"id": 0, "COSTMODIFIER": 1, "ACBONUS": "0.25"}
]
}
`)
mustWriteFile(t, filepath.Join(root, "topdata", "data", "parts", "modules", "ovr_belt_acbonus_zero.json"), `{
"overrides": [
{"id": 18, "ACBONUS": "0.75"}
]
}
`)
p, err := project.Load(root)
if err != nil {
t.Fatalf("load project: %v", err)
}
if err := p.ValidateLayout(); err != nil {
t.Fatalf("validate layout: %v", err)
}
if err := p.Scan(); err != nil {
t.Fatalf("scan: %v", err)
}
result, err := BuildHAKs(p)
if err != nil {
t.Fatalf("build haks: %v", err)
}
if len(result.HAKPaths) != 1 {
t.Fatalf("expected one HAK, got %#v", result.HAKPaths)
}
raw, err := os.ReadFile(filepath.Join(root, "build", "haks.json"))
if err != nil {
t.Fatalf("read haks manifest: %v", err)
}
manifestText := string(raw)
if !strings.Contains(manifestText, `"part/parts_belt.2da"`) {
t.Fatalf("expected generated parts 2da in manifest, got:\n%s", manifestText)
}
partsRaw, err := os.ReadFile(filepath.Join(root, ".cache", "generated-assets", "parts-2da", "parts_belt.2da"))
if err != nil {
t.Fatalf("read generated parts 2da: %v", err)
}
partsText := string(partsRaw)
if !strings.Contains(partsText, "0\t1\t0.25") || !strings.Contains(partsText, "18\t0\t0.75") {
t.Fatalf("expected authored and generated rows in parts 2da, got:\n%s", partsText)
}
}
func TestBuildHAKsRejectsTLKBackedGeneratedParts2DAAssets(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src"))
mustMkdir(t, filepath.Join(root, "assets", "part", "belt"))
mustMkdir(t, filepath.Join(root, "topdata", "data", "parts"))
mustMkdir(t, filepath.Join(root, "build"))
mustWriteFile(t, filepath.Join(root, "nwn-tool.json"), `{
"module": {"name": "Test Module", "resref": "testmod"},
"paths": {"source": "src", "assets": "assets", "build": "build"},
"generated_assets": {
"topdata_2da": [
{
"id": "parts",
"source": "topdata",
"output": "{paths.cache}/generated-assets/parts-2da",
"include_datasets": ["parts/**"],
"package_root": "part",
"autogen": {
"id": "parts",
"mode": "parts_rows",
"root": "part",
"include": ["**/*.mdl"],
"derive": {"kind": "trailing_numeric_suffix", "group_from": "first_path_segment"}
}
}
]
},
"haks": [{"name": "sow_part", "priority": 1, "max_bytes": 0, "include": ["part/**"]}]
}
`)
mustWriteFile(t, filepath.Join(root, "assets", "part", "belt", "pfa0_belt018.mdl"), "belt")
mustWriteFile(t, filepath.Join(root, "topdata", "data", "parts", "belt.json"), `{
"output": "parts_belt.2da",
"columns": ["COSTMODIFIER", "ACBONUS", "NAME"],
"rows": [
{"id": 0, "COSTMODIFIER": 1, "ACBONUS": "0.25", "NAME": {"tlk": {"text": "Belt"}}}
]
}
`)
p, err := project.Load(root)
if err != nil {
t.Fatalf("load project: %v", err)
}
if err := p.ValidateLayout(); err != nil {
t.Fatalf("validate layout: %v", err)
}
if err := p.Scan(); err != nil {
t.Fatalf("scan: %v", err)
}
_, err = BuildHAKs(p)
if err == nil || !strings.Contains(err.Error(), "2DA-only generated asset") {
t.Fatalf("expected TLK-backed generated asset error, got %v", err)
}
}
func TestBuildSkipsEmptyHAKGroupsInModuleOrder(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src"))
@@ -2752,7 +2893,7 @@ func TestPlanHAKChunksPutsNewestAssetsInLastChunk(t *testing.T) {
t.Fatalf("scan: %v", err)
}
assets, err := collectAssetResources(p, false, nil, nil)
assets, err := collectAssetResources(p, false, nil, nil, nil)
if err != nil {
t.Fatalf("collect asset resources: %v", err)
}