autogen cached models

This commit is contained in:
2026-05-23 00:24:47 +02:00
parent a17477cff1
commit 82bd075ae4
6 changed files with 146 additions and 1 deletions
+57
View File
@@ -96,6 +96,10 @@ func autogenConsumerTargetsCollectedDataset(collected []nativeCollectedDataset,
if dataset.Dataset.Name == "visualeffects" {
return true
}
case "cachedmodels_rows":
if dataset.Dataset.Name == "cachedmodels" {
return true
}
}
}
return false
@@ -603,6 +607,59 @@ func autogenPartsInventory(entries []autogenManifestEntry) map[string]map[int]st
return result
}
func augmentWithAutogeneratedCachedModels(collected []nativeCollectedDataset, entries []autogenManifestEntry) ([]nativeCollectedDataset, error) {
if len(entries) == 0 {
return collected, nil
}
result := append([]nativeCollectedDataset(nil), collected...)
for i, dataset := range result {
if dataset.Dataset.Name != "cachedmodels" {
continue
}
if !slices.Contains(dataset.Columns, "Model") {
return nil, fmt.Errorf("cachedmodels dataset must include Model column for cachedmodels_rows autogen")
}
rows := make([]map[string]any, len(dataset.Rows), len(dataset.Rows)+len(entries))
seenModels := make(map[string]struct{}, len(dataset.Rows)+len(entries))
nextID := 0
for index, row := range dataset.Rows {
cloned := cloneRowMap(row)
rows[index] = cloned
if rowID, ok := cloned["id"].(int); ok && rowID >= nextID {
nextID = rowID + 1
}
if model, ok := cloned["Model"].(string); ok {
model = strings.TrimSpace(model)
if model != "" && model != nullValue {
seenModels[strings.ToLower(model)] = struct{}{}
}
}
}
for _, entry := range entries {
model := strings.TrimSpace(entry.ModelStem)
if model == "" {
continue
}
key := strings.ToLower(model)
if _, exists := seenModels[key]; exists {
continue
}
rows = append(rows, map[string]any{
"id": nextID,
"Model": model,
})
seenModels[key] = struct{}{}
nextID++
}
result[i].Rows = rows
}
return result, nil
}
func augmentWithAutogeneratedHeadVisualeffects(collected []nativeCollectedDataset, entries []autogenManifestEntry) ([]nativeCollectedDataset, error) {
if len(entries) == 0 {
return collected, nil
+2
View File
@@ -134,6 +134,8 @@ func applyAutogenConsumersForGeneratedAssets(collected []nativeCollectedDataset,
switch consumer.Mode {
case "parts_rows":
return augmentWithAutogeneratedPartsWithConfig(collected, autogenPartsInventory(entries), consumer.PartsRows), nil
case "cachedmodels_rows":
return augmentWithAutogeneratedCachedModels(collected, entries)
default:
return nil, fmt.Errorf("unsupported generated topdata 2DA autogen mode %q", consumer.Mode)
}
+68
View File
@@ -6294,6 +6294,74 @@ func TestApplyAutogenConsumersAugmentsHeadVisualeffectsFromLocalOverride(t *test
}
}
func TestBuildGenerated2DAAssetsAppendsCachedModelsFromHeadVisualeffects(t *testing.T) {
root := testProjectRoot(t)
mkdirAll(t, filepath.Join(root, "assets", "vfxs", "head_accessories"))
mkdirAll(t, filepath.Join(root, "assets", "vfxs", "head_features", "hair"))
mkdirAll(t, filepath.Join(root, "topdata", "data", "cachedmodels"))
writeFile(t, filepath.Join(root, "assets", "vfxs", "head_accessories", "hfx_bandana.mdl"), "mdl\n")
writeFile(t, filepath.Join(root, "assets", "vfxs", "head_accessories", "hfx_existing.mdl"), "mdl\n")
writeFile(t, filepath.Join(root, "assets", "vfxs", "head_features", "hair", "hfx_hair_bangs.mdl"), "mdl\n")
writeFile(t, filepath.Join(root, "topdata", "data", "cachedmodels", "base.json"), `{
"columns": ["Model"],
"rows": [
{"id": 0, "Model": "grn_m_bone"},
{"id": 1, "Model": "hfx_existing"}
]
}`+"\n")
p := testProject(root)
p.Config.Paths.Assets = "assets"
p.Config.Generated.TopData2DA = []project.GeneratedTopData2DAConfig{
{
ID: "cachedmodels",
Source: "topdata",
Output: ".cache/generated-assets/cachedmodels-2da",
IncludeDatasets: []string{"cachedmodels"},
PackageRoot: "vfxs",
Autogen: project.AutogenConsumerConfig{
ID: "cachedmodels",
Mode: "cachedmodels_rows",
Root: "vfxs",
Include: []string{"head_accessories/**/*.mdl", "head_features/**/*.mdl"},
Derive: project.AutogenDeriveConfig{Kind: "model_stem", GroupFrom: "first_path_segment"},
},
},
}
assets, err := BuildGenerated2DAAssets(p, nil)
if err != nil {
t.Fatalf("BuildGenerated2DAAssets failed: %v", err)
}
if len(assets) != 1 {
t.Fatalf("expected one generated asset, got %#v", assets)
}
if assets[0].Rel != "vfxs/cachedmodels.2da" {
t.Fatalf("expected vfxs/cachedmodels.2da rel, got %q", assets[0].Rel)
}
bytes, err := os.ReadFile(assets[0].SourcePath)
if err != nil {
t.Fatalf("read generated cachedmodels.2da: %v", err)
}
text := string(bytes)
for _, want := range []string{
"0\tgrn_m_bone",
"1\thfx_existing",
"2\thfx_bandana",
"3\thfx_hair_bangs",
} {
if !strings.Contains(text, want) {
t.Fatalf("expected generated cachedmodels output to contain %q, got:\n%s", want, text)
}
}
if strings.Contains(text, ".mdl") {
t.Fatalf("expected cached model rows without .mdl extension, got:\n%s", text)
}
if strings.Count(text, "hfx_existing") != 1 {
t.Fatalf("expected duplicate discovered model to be skipped, got:\n%s", text)
}
}
func TestNormalizeProjectImportsLegacyLoadscreens(t *testing.T) {
root := testProjectRoot(t)
mkdirAll(t, filepath.Join(root, "topdata", "data"))