Change head_visualeffects to accessory_visualeffects

This commit is contained in:
2026-05-31 15:24:50 +02:00
parent 3e169276f7
commit 39f329343b
8 changed files with 72 additions and 72 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ repository-specific YAML:
- Canonical GFF JSON shape.
- ERF/MOD/HAK binary serialization.
- Supported autogen algorithms: `parts_rows`, `head_visualeffects`,
- Supported autogen algorithms: `parts_rows`, `accessory_visualeffects`,
`trailing_numeric_suffix`, `model_stem`, and `first_path_segment`.
- Native topdata dataset internals and generated JSON dataset formats.
- NWN validator resource-reference checks. These are candidates for future
+1 -1
View File
@@ -391,7 +391,7 @@ Hardening direction:
- Released autogen manifest discovery derives a Shadows Over Westgate assets repo spec from git remote and environment overrides.
- Supported autogen modes are hardcoded:
- `parts_rows`
- `head_visualeffects`
- `accessory_visualeffects`
- Supported derive kinds are hardcoded:
- `trailing_numeric_suffix`
- `model_stem`
+3 -3
View File
@@ -410,9 +410,9 @@ discovered model stems from the configured include globs to the selected
`cachedmodels` dataset without `.mdl` extensions and skips models already
present in authored rows.
For `head_visualeffects` autogen, producers can publish the group-to-row policy
in `autogen.producers[].head_visualeffects`, and consumers can override or
extend it in `autogen.consumers[].head_visualeffects`. The toolkit uses
For `accessory_visualeffects` autogen, producers can publish the group-to-row policy
in `autogen.producers[].accessory_visualeffects`, and consumers can override or
extend it in `autogen.consumers[].accessory_visualeffects`. The toolkit uses
compatibility defaults for older configs and manifests, but YAML can own the
group token source, category source, delimiter, case policy, legacy group
mapping, model stem prefixes to strip, key/label formats, model column, and
+6 -6
View File
@@ -2198,7 +2198,7 @@ func TestBuildHAKsWritesConfiguredHeadVisualeffectsAutogenManifest(t *testing.T)
"autogen": {
"producers": [
{
"id": "head_visualeffects",
"id": "accessory_visualeffects",
"root": "vfxs",
"include": ["chest_accessories/**/*.mdl", "head_accessories/**/*.mdl", "head_decorations/**/*.mdl", "head_features/**/*.mdl"],
"derive": {
@@ -2210,7 +2210,7 @@ func TestBuildHAKsWritesConfiguredHeadVisualeffectsAutogenManifest(t *testing.T)
"asset_name": "sow-head-vfx-manifest.json",
"cache_name": "sow-head-vfx-manifest.json"
},
"head_visualeffects": {
"accessory_visualeffects": {
"groups": {
"head_accessories": {
"prefix": "head_accessories",
@@ -2266,12 +2266,12 @@ func TestBuildHAKsWritesConfiguredHeadVisualeffectsAutogenManifest(t *testing.T)
}
text := string(headRaw)
for _, want := range []string{
`"id": "head_visualeffects"`,
`"id": "accessory_visualeffects"`,
`"group": "chest_accessories"`,
`"model_stem": "tfx_sash"`,
`"group": "head_accessories"`,
`"model_stem": "hfx_bandana"`,
`"head_visualeffects": {`,
`"accessory_visualeffects": {`,
`"model_columns": [`,
`"Imp_Root_H_Node"`,
`"group": "head_decorations"`,
@@ -2305,7 +2305,7 @@ func TestBuildHAKsWritesFolderCategoryInHeadVisualeffectsAutogenManifest(t *test
"autogen": {
"producers": [
{
"id": "head_visualeffects",
"id": "accessory_visualeffects",
"root": "vfxs",
"include": ["head_features/**/*.mdl"],
"derive": {
@@ -2317,7 +2317,7 @@ func TestBuildHAKsWritesFolderCategoryInHeadVisualeffectsAutogenManifest(t *test
"asset_name": "sow-head-vfx-manifest.json",
"cache_name": "sow-head-vfx-manifest.json"
},
"head_visualeffects": {
"accessory_visualeffects": {
"groups": {
"head_features": {
"model_columns": ["Imp_HeadCon_Node", "Imp_Root_H_Node"]
+6 -6
View File
@@ -368,7 +368,7 @@ type AutogenProducerConfig struct {
Include []string `json:"include" yaml:"include"`
Derive AutogenDeriveConfig `json:"derive" yaml:"derive"`
Manifest AutogenManifestConfig `json:"manifest" yaml:"manifest"`
HeadVisualeffects HeadVisualeffectsConfig `json:"head_visualeffects" yaml:"head_visualeffects"`
HeadVisualeffects HeadVisualeffectsConfig `json:"accessory_visualeffects" yaml:"accessory_visualeffects"`
}
type AutogenConsumerConfig struct {
@@ -381,7 +381,7 @@ type AutogenConsumerConfig struct {
Include []string `json:"include" yaml:"include"`
Derive AutogenDeriveConfig `json:"derive" yaml:"derive"`
PartsRows PartsRowsConfig `json:"parts_rows" yaml:"parts_rows"`
HeadVisualeffects HeadVisualeffectsConfig `json:"head_visualeffects" yaml:"head_visualeffects"`
HeadVisualeffects HeadVisualeffectsConfig `json:"accessory_visualeffects" yaml:"accessory_visualeffects"`
Manifest AutogenManifestConfig `json:"manifest" yaml:"manifest"`
LocalOverrideRoot string `json:"local_override_root,omitempty" yaml:"local_override_root,omitempty"`
}
@@ -1699,7 +1699,7 @@ func validateAutogenConfig(cfg AutogenConfig) []error {
failures = append(failures, validateAutogenDeriveConfig(fieldPrefix+".derive", producer.Derive)...)
failures = append(failures, validateAutogenManifestConfig(fieldPrefix+".manifest", producer.Manifest)...)
if headVisualeffectsConfigConfigured(producer.HeadVisualeffects) {
failures = append(failures, validateHeadVisualeffectsConfig(fieldPrefix+".head_visualeffects", producer.HeadVisualeffects)...)
failures = append(failures, validateHeadVisualeffectsConfig(fieldPrefix+".accessory_visualeffects", producer.HeadVisualeffects)...)
}
}
@@ -1732,7 +1732,7 @@ func validateAutogenConfig(cfg AutogenConfig) []error {
}
}
switch strings.TrimSpace(consumer.Mode) {
case "parts_rows", "head_visualeffects":
case "parts_rows", "accessory_visualeffects":
case "":
failures = append(failures, fmt.Errorf("%s.mode is required", fieldPrefix))
default:
@@ -1746,8 +1746,8 @@ func validateAutogenConfig(cfg AutogenConfig) []error {
}
failures = append(failures, validateGlobList(fieldPrefix+".include", consumer.Include)...)
failures = append(failures, validateAutogenDeriveConfig(fieldPrefix+".derive", consumer.Derive)...)
if strings.TrimSpace(consumer.Mode) == "head_visualeffects" && headVisualeffectsConfigConfigured(consumer.HeadVisualeffects) {
failures = append(failures, validateHeadVisualeffectsConfig(fieldPrefix+".head_visualeffects", consumer.HeadVisualeffects)...)
if strings.TrimSpace(consumer.Mode) == "accessory_visualeffects" && headVisualeffectsConfigConfigured(consumer.HeadVisualeffects) {
failures = append(failures, validateHeadVisualeffectsConfig(fieldPrefix+".accessory_visualeffects", consumer.HeadVisualeffects)...)
}
failures = append(failures, validateAutogenManifestConfig(fieldPrefix+".manifest", consumer.Manifest)...)
}
+20 -20
View File
@@ -1327,8 +1327,8 @@ func TestValidateLayoutRejectsInvalidAutogenConsumerConfig(t *testing.T) {
Autogen: AutogenConfig{
Consumers: []AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "unsupported",
Root: "vfxs",
@@ -1373,10 +1373,10 @@ func TestValidateLayoutRejectsInvalidHeadVisualeffectsConfig(t *testing.T) {
Autogen: AutogenConfig{
Consumers: []AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_jewels/**/*.mdl"},
Derive: AutogenDeriveConfig{Kind: "model_stem", GroupFrom: "first_path_segment"},
@@ -1405,10 +1405,10 @@ func TestValidateLayoutRejectsInvalidHeadVisualeffectsConfig(t *testing.T) {
t.Fatal("expected head visualeffects validation error")
}
for _, needle := range []string{
"autogen.consumers[0].head_visualeffects.groups[head_jewels].prefix",
"autogen.consumers[0].head_visualeffects.groups[head_jewels].model_columns[0]",
"autogen.consumers[0].head_visualeffects.strip_model_prefixes[0]",
"autogen.consumers[0].head_visualeffects.model_column",
"autogen.consumers[0].accessory_visualeffects.groups[head_jewels].prefix",
"autogen.consumers[0].accessory_visualeffects.groups[head_jewels].model_columns[0]",
"autogen.consumers[0].accessory_visualeffects.strip_model_prefixes[0]",
"autogen.consumers[0].accessory_visualeffects.model_column",
} {
if !strings.Contains(err.Error(), needle) {
t.Fatalf("expected validation error to mention %s, got %v", needle, err)
@@ -1429,10 +1429,10 @@ func TestValidateLayoutRejectsInvalidHeadVisualeffectsNamingConfig(t *testing.T)
Autogen: AutogenConfig{
Consumers: []AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_features/**/*.mdl"},
Derive: AutogenDeriveConfig{Kind: "model_stem", GroupFrom: "first_path_segment"},
@@ -1461,10 +1461,10 @@ func TestValidateLayoutRejectsInvalidHeadVisualeffectsNamingConfig(t *testing.T)
t.Fatal("expected head visualeffects naming validation error")
}
for _, needle := range []string{
"autogen.consumers[0].head_visualeffects.group_token_source",
"autogen.consumers[0].head_visualeffects.category_from",
"autogen.consumers[0].head_visualeffects.delimiter",
"autogen.consumers[0].head_visualeffects.case",
"autogen.consumers[0].accessory_visualeffects.group_token_source",
"autogen.consumers[0].accessory_visualeffects.category_from",
"autogen.consumers[0].accessory_visualeffects.delimiter",
"autogen.consumers[0].accessory_visualeffects.case",
} {
if !strings.Contains(err.Error(), needle) {
t.Fatalf("expected validation error to mention %s, got %v", needle, err)
@@ -1482,17 +1482,17 @@ paths:
source: src
autogen:
consumers:
- id: head_visualeffects
producer: head_visualeffects
- id: accessory_visualeffects
producer: accessory_visualeffects
dataset: visualeffects
mode: head_visualeffects
mode: accessory_visualeffects
root: vfxs
include:
- head_features/**/*.mdl
derive:
kind: model_stem
group_from: first_path_segment
head_visualeffects:
accessory_visualeffects:
groups:
head_features:
model_columns:
+3 -3
View File
@@ -21,7 +21,7 @@ type autogenManifest struct {
Repo string `json:"repo"`
Ref string `json:"ref"`
GeneratedAt string `json:"generated_at"`
HeadVisualeffects *project.HeadVisualeffectsConfig `json:"head_visualeffects,omitempty"`
HeadVisualeffects *project.HeadVisualeffectsConfig `json:"accessory_visualeffects,omitempty"`
Entries []autogenManifestEntry `json:"entries"`
}
@@ -76,7 +76,7 @@ func applyAutogenConsumers(p *project.Project, collected []nativeCollectedDatase
switch consumer.Mode {
case "parts_rows":
result = augmentWithAutogeneratedParts(result, autogenPartsInventory(entries))
case "head_visualeffects":
case "accessory_visualeffects":
result, err = augmentWithAutogeneratedHeadVisualeffects(result, entries, consumer, manifest.HeadVisualeffects)
if err != nil {
return nil, err
@@ -95,7 +95,7 @@ func autogenConsumerTargetsCollectedDataset(collected []nativeCollectedDataset,
if isAutogenEligiblePartsDataset(dataset) {
return true
}
case "head_visualeffects":
case "accessory_visualeffects":
if dataset.Dataset.Name == "visualeffects" {
return true
}
+32 -32
View File
@@ -7338,10 +7338,10 @@ func TestApplyAutogenConsumersAugmentsHeadVisualeffectsFromLocalOverride(t *test
p := testProject(root)
p.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_decorations/**/*.mdl", "head_features/**/*.mdl"},
Derive: project.AutogenDeriveConfig{Kind: "model_stem", GroupFrom: "first_path_segment"},
@@ -7418,10 +7418,10 @@ func TestApplyAutogenConsumersUsesFolderDrivenSlashHeadVisualeffectsNames(t *tes
p := testProject(root)
p.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_features/**/*.mdl"},
Derive: project.AutogenDeriveConfig{Kind: "model_stem", GroupFrom: "first_path_segment"},
@@ -7509,10 +7509,10 @@ topdata:
build: build/topdata
autogen:
consumers:
- id: head_visualeffects
producer: head_visualeffects
- id: accessory_visualeffects
producer: accessory_visualeffects
dataset: visualeffects
mode: head_visualeffects
mode: accessory_visualeffects
root: vfxs
include:
- chest_accessories/**/*.mdl
@@ -7525,7 +7525,7 @@ autogen:
asset_name: sow-head-vfx-manifest.json
cache_name: sow-head-vfx-manifest.json
local_override_root: autogen-assets
head_visualeffects:
accessory_visualeffects:
groups:
chest_accessories:
prefix: chest_accessories
@@ -12802,11 +12802,11 @@ func TestBuildNativeWithReleasedHeadVisualeffectsManifest(t *testing.T) {
writeFile(t, filepath.Join(projRoot, "reference", "build.py"), "print('ok')\n")
manifestJSON := `{
"id": "head_visualeffects",
"id": "accessory_visualeffects",
"repo": "ShadowsOverWestgate/sow-assets",
"ref": "test-manifest",
"generated_at": "2026-04-25T00:00:00Z",
"head_visualeffects": {
"accessory_visualeffects": {
"groups": {
"head_accessories": {
"model_columns": ["Imp_HeadCon_Node", "Imp_Root_H_Node"]
@@ -12872,10 +12872,10 @@ func TestBuildNativeWithReleasedHeadVisualeffectsManifest(t *testing.T) {
Autogen: project.AutogenConfig{
Consumers: []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},
Derive: project.AutogenDeriveConfig{
@@ -12939,7 +12939,7 @@ func TestBuildNativePrefersRemoteReleasedHeadVisualeffectsManifestOverFreshCache
cachePath := filepath.Join(projRoot, ".cache", "sow-head-vfx-manifest.json")
writeFile(t, cachePath, `{
"id": "head_visualeffects",
"id": "accessory_visualeffects",
"generated_at": "2026-04-25T00:00:00Z",
"entries": [
{
@@ -12953,7 +12953,7 @@ func TestBuildNativePrefersRemoteReleasedHeadVisualeffectsManifestOverFreshCache
setFileTime(t, cachePath, cacheTime)
manifestJSON := `{
"id": "head_visualeffects",
"id": "accessory_visualeffects",
"repo": "ShadowsOverWestgate/sow-assets",
"ref": "remote-manifest",
"generated_at": "2026-04-25T12:00:00Z",
@@ -12996,10 +12996,10 @@ func TestBuildNativePrefersRemoteReleasedHeadVisualeffectsManifestOverFreshCache
Autogen: project.AutogenConfig{
Consumers: []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},
Derive: project.AutogenDeriveConfig{
@@ -13052,7 +13052,7 @@ func TestBuildPackageInvalidatesFreshAutogenCacheWhenReleaseAssetIsNewer(t *test
setCompiledOutputTimes(t, result, outputTime)
cachePath := filepath.Join(root, ".cache", "sow-head-vfx-manifest.json")
writeFile(t, cachePath, `{"id":"head_visualeffects","generated_at":"2026-04-25T10:00:00Z","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`+"\n")
writeFile(t, cachePath, `{"id":"accessory_visualeffects","generated_at":"2026-04-25T10:00:00Z","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`+"\n")
setFileTime(t, cachePath, time.Now())
var server *httptest.Server
@@ -13063,7 +13063,7 @@ func TestBuildPackageInvalidatesFreshAutogenCacheWhenReleaseAssetIsNewer(t *test
_, _ = w.Write([]byte(`{"assets":[{"name":"sow-head-vfx-manifest.json","updated_at":"3026-04-25T12:00:00Z","browser_download_url":"` + server.URL + `/downloads/sow-head-vfx-manifest.json"}]}`))
case "/downloads/sow-head-vfx-manifest.json":
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"id":"head_visualeffects","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`))
_, _ = w.Write([]byte(`{"id":"accessory_visualeffects","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`))
default:
http.NotFound(w, r)
}
@@ -13075,10 +13075,10 @@ func TestBuildPackageInvalidatesFreshAutogenCacheWhenReleaseAssetIsNewer(t *test
proj.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Optional: true,
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},
@@ -13400,10 +13400,10 @@ func TestBuildPackageFailsWhenAutogenManifestCacheIsStale(t *testing.T) {
proj.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Optional: true,
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},
@@ -13419,7 +13419,7 @@ func TestBuildPackageFailsWhenAutogenManifestCacheIsStale(t *testing.T) {
},
}
cachePath := filepath.Join(root, ".cache", "sow-head-vfx-manifest.json")
writeFile(t, cachePath, `{"id":"head_visualeffects","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`+"\n")
writeFile(t, cachePath, `{"id":"accessory_visualeffects","entries":[{"group":"head_accessories","model_stem":"hfx_bandana","source":"head_accessories/hfx_bandana.mdl"}]}`+"\n")
setFileTime(t, cachePath, time.Now().Add(-2*autogenManifestCacheMaxAge))
if _, err := BuildPackage(proj, nil); err == nil || !strings.Contains(err.Error(), "older than source file") {
@@ -14348,10 +14348,10 @@ func testProject(root string) *project.Project {
},
},
{
ID: "head_visualeffects",
Producer: "head_visualeffects",
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "head_visualeffects",
Mode: "accessory_visualeffects",
Optional: true,
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},