Praying for deliberately deleted entries to STOP BEING PARSED AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
This commit is contained in:
@@ -971,6 +971,7 @@ func collectBaseDataset(dataset nativeDataset) (nativeCollectedDataset, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if overrideRequestsNullRow(override) {
|
if overrideRequestsNullRow(override) {
|
||||||
|
retireRowIdentity(row, lockData, retiredKeys)
|
||||||
nullifyOverrideRow(row, columns, rowByKey)
|
nullifyOverrideRow(row, columns, rowByKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1051,6 +1052,9 @@ func collectBaseDataset(dataset nativeDataset) (nativeCollectedDataset, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, module := range generatedModules {
|
for _, module := range generatedModules {
|
||||||
|
if module.ApplyAfterModules {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err := applyModuleData(module.Name, module.Data); err != nil {
|
if err := applyModuleData(module.Name, module.Data); err != nil {
|
||||||
return nativeCollectedDataset{}, err
|
return nativeCollectedDataset{}, err
|
||||||
}
|
}
|
||||||
@@ -4284,6 +4288,20 @@ func nullifyOverrideRow(row map[string]any, columns []string, rowByKey map[strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func retireRowIdentity(row map[string]any, lockData map[string]int, retiredKeys map[string]struct{}) {
|
||||||
|
if row == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldKey, ok := row["key"].(string)
|
||||||
|
if !ok || oldKey == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(lockData, oldKey)
|
||||||
|
if retiredKeys != nil {
|
||||||
|
retiredKeys[oldKey] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateOverrideRowKey(datasetName string, row map[string]any, expanded map[string]any, rowByKey map[string]map[string]any, lockData map[string]int) (bool, string, error) {
|
func updateOverrideRowKey(datasetName string, row map[string]any, expanded map[string]any, rowByKey map[string]map[string]any, lockData map[string]int) (bool, string, error) {
|
||||||
oldKey, _ := row["key"].(string)
|
oldKey, _ := row["key"].(string)
|
||||||
newKeyValue, hasKey := expanded["key"]
|
newKeyValue, hasKey := expanded["key"]
|
||||||
|
|||||||
@@ -6409,6 +6409,48 @@ func TestBuildOverridePrecedenceSuppressesBaseAndEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildNullRowRetiresLockIdentityGlobally(t *testing.T) {
|
||||||
|
root := testProjectRoot(t)
|
||||||
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "dense", "modules"))
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "dense", "base.json"), `{
|
||||||
|
"output": "dense.2da",
|
||||||
|
"columns": ["Label", "Value"],
|
||||||
|
"rows": [
|
||||||
|
{"id": 0, "key": "dense:one", "Label": "One", "Value": "one"}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "dense", "lock.json"), `{
|
||||||
|
"dense:one": 0
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "dense", "modules", "rmv_one.json"), `{
|
||||||
|
"overrides": [
|
||||||
|
{"id": 0, "key": null, "null": true}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
mkdirAll(t, filepath.Join(root, "reference"))
|
||||||
|
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||||
|
|
||||||
|
result, err := BuildNative(testProject(root), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
lockRaw, err := os.ReadFile(filepath.Join(root, "topdata", "data", "dense", "lock.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read dense lock: %v", err)
|
||||||
|
}
|
||||||
|
if strings.Contains(string(lockRaw), `"dense:one"`) {
|
||||||
|
t.Fatalf("expected nulled row to retire lock identity, got:\n%s", string(lockRaw))
|
||||||
|
}
|
||||||
|
got, err := os.ReadFile(filepath.Join(result.Output2DADir, "dense.2da"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read dense.2da: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(got), "0\t****\t****\n") {
|
||||||
|
t.Fatalf("expected nulled dense row in output, got:\n%s", string(got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResolveOverrideTargetPrefersIDOverKey(t *testing.T) {
|
func TestResolveOverrideTargetPrefersIDOverKey(t *testing.T) {
|
||||||
keyRow := map[string]any{"id": 192, "key": "feat:skillfocus_intimidate"}
|
keyRow := map[string]any{"id": 192, "key": "feat:skillfocus_intimidate"}
|
||||||
idRow := map[string]any{"id": 916, "key": "feat:taunt"}
|
idRow := map[string]any{"id": 916, "key": "feat:taunt"}
|
||||||
@@ -8427,6 +8469,94 @@ func TestFeatGeneratedContextIgnoresExplicitlyRetiredFeatKeys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildGeneratedSkillFocusDoesNotReuseNulledFeatRow(t *testing.T) {
|
||||||
|
root := testProjectRoot(t)
|
||||||
|
writeFeatGeneratedHarness(t, root, map[string]string{
|
||||||
|
"skill_focus.json": `{
|
||||||
|
"family": "skill_focus",
|
||||||
|
"family_key": "skill_focus",
|
||||||
|
"template": "masterfeats:skillfocus",
|
||||||
|
"name_prefix": "Skill Focus",
|
||||||
|
"label_prefix": "FEAT_SKILL_FOCUS",
|
||||||
|
"constant_prefix": "FEAT_SKILL_FOCUS",
|
||||||
|
"default_fields": {
|
||||||
|
"CRValue": "0.5",
|
||||||
|
"ReqSkillMinRanks": "1",
|
||||||
|
"ALLCLASSESCANUSE": "1",
|
||||||
|
"TOOLSCATEGORIES": "6",
|
||||||
|
"PreReqEpic": "0",
|
||||||
|
"ReqAction": "1"
|
||||||
|
},
|
||||||
|
"apply_after_modules": true,
|
||||||
|
"child_ref_field": "REQSKILL",
|
||||||
|
"child_source": {
|
||||||
|
"dataset": "skills",
|
||||||
|
"predicate": "accessible"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"skills:intimidate": {
|
||||||
|
"ICON": "ife_X2SkFInti"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}` + "\n",
|
||||||
|
}, map[string]int{
|
||||||
|
"feat:skill_focus_intimidate": 916,
|
||||||
|
})
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "base.json"), `{
|
||||||
|
"output": "skills.2da",
|
||||||
|
"columns": ["Label", "Name", "Description", "Icon", "Untrained", "KeyAbility", "ArmorCheckPenalty", "AllClassesCanUse", "Category", "MaxCR", "Constant", "HostileSkill", "HideFromLevelUp"],
|
||||||
|
"rows": [
|
||||||
|
{"id": 18, "key": "skills:intimidate", "Label": "Intimidate", "Name": "8756", "Description": "8786", "Icon": "isk_x2inti", "Untrained": "1", "KeyAbility": "CHA", "ArmorCheckPenalty": "0", "AllClassesCanUse": "1", "Category": "****", "MaxCR": "****", "Constant": "SKILL_INTIMIDATE", "HostileSkill": "1", "HideFromLevelUp": "0"}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:intimidate":18}`+"\n")
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "feat", "base.json"), `{
|
||||||
|
"output": "feat.2da",
|
||||||
|
"compare_reference": false,
|
||||||
|
"columns": [
|
||||||
|
"LABEL","FEAT","DESCRIPTION","ICON","MINATTACKBONUS","MINSTR","MINDEX","MININT","MINWIS","MINCON","MINCHA",
|
||||||
|
"MINSPELLLVL","PREREQFEAT1","PREREQFEAT2","GAINMULTIPLE","EFFECTSSTACK","ALLCLASSESCANUSE","CATEGORY","MAXCR",
|
||||||
|
"SPELLID","SUCCESSOR","CRValue","USESPERDAY","MASTERFEAT","TARGETSELF","OrReqFeat0","OrReqFeat1","OrReqFeat2",
|
||||||
|
"OrReqFeat3","OrReqFeat4","REQSKILL","ReqSkillMinRanks","REQSKILL2","ReqSkillMinRanks2","Constant","TOOLSCATEGORIES",
|
||||||
|
"HostileFeat","MinLevel","MinLevelClass","MaxLevel","MinFortSave","PreReqEpic","ReqAction"
|
||||||
|
],
|
||||||
|
"rows": [
|
||||||
|
{"id": 192, "key": "feat:skill_focus_taunt", "LABEL": "FEAT_SKILL_FOCUS_TAUNT", "REQSKILL": 18, "MASTERFEAT": 4, "Constant": "FEAT_SKILL_FOCUS_TAUNT"},
|
||||||
|
{"id": 916, "key": "feat:skill_focus_intimidate", "LABEL": "FEAT_SKILL_FOCUS_INTIMIDATE", "REQSKILL": 24, "MASTERFEAT": 4, "Constant": "FEAT_SKILL_FOCUS_INTIMIDATE"}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
mkdirAll(t, filepath.Join(root, "topdata", "data", "feat", "modules", "removedandhidden"))
|
||||||
|
writeFile(t, filepath.Join(root, "topdata", "data", "feat", "modules", "removedandhidden", "rmv_feat_intimidate.json"), `{
|
||||||
|
"overrides": [
|
||||||
|
{"id": 916, "null": true, "key": null}
|
||||||
|
]
|
||||||
|
}`+"\n")
|
||||||
|
|
||||||
|
result, err := BuildNative(testProject(root), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildNative failed: %v", err)
|
||||||
|
}
|
||||||
|
lockRaw, err := os.ReadFile(filepath.Join(root, "topdata", "data", "feat", "lock.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read feat lock: %v", err)
|
||||||
|
}
|
||||||
|
lockText := string(lockRaw)
|
||||||
|
if strings.Contains(lockText, `"feat:skill_focus_intimidate": 916`) {
|
||||||
|
t.Fatalf("expected generated skill focus intimidate to avoid nulled row 916, got:\n%s", lockText)
|
||||||
|
}
|
||||||
|
got, err := os.ReadFile(filepath.Join(result.Output2DADir, "feat.2da"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read feat.2da: %v", err)
|
||||||
|
}
|
||||||
|
text := string(got)
|
||||||
|
if strings.Contains(text, "916\tFEAT_SKILL_FOCUS_INTIMIDATE\t") {
|
||||||
|
t.Fatalf("expected generated skill focus intimidate to avoid row 916, got:\n%s", text)
|
||||||
|
}
|
||||||
|
if !strings.Contains(text, "FEAT_SKILL_FOCUS_INTIMIDATE") {
|
||||||
|
t.Fatalf("expected generated skill focus intimidate row, got:\n%s", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestOverrideRequestsNullRowUsesExplicitNullFlag(t *testing.T) {
|
func TestOverrideRequestsNullRowUsesExplicitNullFlag(t *testing.T) {
|
||||||
if overrideRequestsNullRow(map[string]any{"key": nil}) {
|
if overrideRequestsNullRow(map[string]any{"key": nil}) {
|
||||||
t.Fatal("key: null should not blank a row")
|
t.Fatal("key: null should not blank a row")
|
||||||
|
|||||||
Reference in New Issue
Block a user