diff --git a/internal/topdata/convert.go b/internal/topdata/convert.go index ef47bad..d2ce37a 100644 --- a/internal/topdata/convert.go +++ b/internal/topdata/convert.go @@ -876,7 +876,7 @@ func write2DAFile(data parsed2DA, path string) error { if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil && filepath.Dir(path) != "." { return err } - return write2DA(table, path, false) + return write2DA(table, path, false, -1) } func cloneStringMap(in map[string]string) map[string]string { diff --git a/internal/topdata/generated_assets.go b/internal/topdata/generated_assets.go index a8ad32c..e0591ab 100644 --- a/internal/topdata/generated_assets.go +++ b/internal/topdata/generated_assets.go @@ -106,7 +106,7 @@ func buildGenerated2DAAssetGroup(p *project.Project, cfg project.GeneratedTopDat outputPath := filepath.Join(outputDir, dataset.Dataset.OutputName) denseRows := dataset.Dataset.Kind == nativeDatasetBase || (consumer.Mode == "parts_rows" && isPartsDataset(dataset.Dataset.Name)) - if err := write2DA(compiled, outputPath, denseRows); err != nil { + if err := write2DA(compiled, outputPath, denseRows, -1); err != nil { return nil, err } results = append(results, Generated2DAAsset{ diff --git a/internal/topdata/native.go b/internal/topdata/native.go index 2dbe1e8..054bd75 100644 --- a/internal/topdata/native.go +++ b/internal/topdata/native.go @@ -48,6 +48,7 @@ type nativeCollectedDataset struct { LockData map[string]int RetiredKeys map[string]struct{} TableKey string + DenseRowMax int LockAdded int LockPruned int LockModified bool @@ -370,7 +371,7 @@ func buildNativeUnchecked(p *project.Project, opts NativeBuildOptions, progress if err != nil { return BuildResult{}, err } - if err := write2DA(compiled, filepath.Join(output2DA, dataset.Dataset.OutputName), dataset.Dataset.Kind == nativeDatasetBase); err != nil { + if err := write2DA(compiled, filepath.Join(output2DA, dataset.Dataset.OutputName), dataset.Dataset.Kind == nativeDatasetBase, dataset.DenseRowMax); err != nil { return BuildResult{}, err } } @@ -1228,6 +1229,7 @@ func collectBaseDataset(dataset nativeDataset) (nativeCollectedDataset, error) { Rows: rows, LockData: lockData, RetiredKeys: retiredKeys, + DenseRowMax: baseBoundaryID, LockAdded: lockAdded, LockPruned: lockPruned, LockModified: lockModified, @@ -5181,7 +5183,7 @@ func normalizeCollectedSpellImpactScripts(rows []map[string]any, baseRowKeys map } } -func write2DA(data map[string]any, path string, denseRows bool) error { +func write2DA(data map[string]any, path string, denseRows bool, denseRowMax int) error { columns, ok := data["columns"].([]string) if !ok { return fmt.Errorf("2da columns must be []string") @@ -5223,6 +5225,17 @@ func write2DA(data map[string]any, path string, denseRows bool) error { nextID = rowID + 1 } } + if denseRows { + for nextID <= denseRowMax { + builder.WriteString(strconv.Itoa(nextID)) + for range columns { + builder.WriteByte('\t') + builder.WriteString(nullValue) + } + builder.WriteByte('\n') + nextID++ + } + } return os.WriteFile(path, []byte(builder.String()), 0o644) } diff --git a/internal/topdata/topdata_test.go b/internal/topdata/topdata_test.go index 2245141..d26329f 100644 --- a/internal/topdata/topdata_test.go +++ b/internal/topdata/topdata_test.go @@ -657,14 +657,16 @@ func TestBuildNativeAllocatesConfiguredDatasetsIntoFirstNullBaseRows(t *testing. {"id": 0, "key": "portraits:none", "BaseResRef": "****", "Sex": 4}, {"id": 1, "BaseResRef": "****", "Sex": "****"}, {"id": 2, "BaseResRef": null, "Sex": null}, - {"id": 3, "key": "portraits:existing", "BaseResRef": "existing_", "Sex": 1} + {"id": 3, "key": "portraits:existing", "BaseResRef": "existing_", "Sex": 1}, + {"id": 4, "BaseResRef": "****", "Sex": "****"}, + {"id": 5, "BaseResRef": "****", "Sex": "****"} ] }`+"\n") writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), `{ "portraits:none": 0, "portraits:existing": 3, - "portraits:first": 4, - "portraits:second": 5 + "portraits:first": 6, + "portraits:second": 7 }`+"\n") writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "modules", "custom.json"), `{ "entries": { @@ -698,6 +700,8 @@ func TestBuildNativeAllocatesConfiguredDatasetsIntoFirstNullBaseRows(t *testing. for _, want := range []string{ "1\tfirst_\t4", "2\tsecond_\t4", + "4\t****\t****", + "5\t****\t****", } { if !strings.Contains(output, want) { t.Fatalf("expected generated portraits row %q, got:\n%s", want, output)