In-line Portrait Generation
This commit is contained in:
+124
-315
@@ -6147,157 +6147,49 @@ func TestBuildBaseDatasetAllowsModuleDeclaredColumns(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeProjectImportsLegacyAppearanceAndPortraits(t *testing.T) {
|
||||
func TestBuildInjectsExpansionDataIntoTargetDataset(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data"))
|
||||
mkdirAll(t, filepath.Join(root, "reference", "data", "appearance", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "reference", "data", "portraits", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "base.json"), `{
|
||||
"columns": ["LABEL", "PORTRAIT"],
|
||||
"rows": [
|
||||
{"key": "appearance:dwarf", "id": 0, "LABEL": "Dwarf", "PORTRAIT": "****"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "lock.json"), `{
|
||||
"appearance:blacklagoonreaver": 15105,
|
||||
"appearance:crawlingclaw": 15107,
|
||||
"appearance:halfogre": 15108,
|
||||
"appearance:zombieknight3": 15109,
|
||||
"appearance:zombieknight4": 15110,
|
||||
"appearance:blacklagoonreaverswimming": 15111
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "modules", "cotblreaver.json"), `{"entries":{"appearance:blacklagoonreaver":{"LABEL":"Black Lagoon Reaver","PORTRAIT":"po_cotbl"},"appearance:blacklagoonreaverswimming":{"LABEL":"Black Lagoon Reaver, Swimming","PORTRAIT":"po_cotbl"}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "modules", "crawlingclaw.json"), `{"entries":{"appearance:crawlingclaw":{"LABEL":"Crawling Claw","PORTRAIT":"po_cclaw"}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "modules", "halfogre.json"), `{"entries":{"appearance:halfogre":{"LABEL":"Half-Ogre","PORTRAIT":"****"}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "appearance", "modules", "zombieknight.json"), `{"entries":{"appearance:zombieknight3":{"LABEL":"Zombie_Knight3","PORTRAIT":"po_zk"},"appearance:zombieknight4":{"LABEL":"Zombie_Knight4","PORTRAIT":"po_zk"}}}`+"\n")
|
||||
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "base.json"), `{
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": [
|
||||
{"id": 0, "BaseResRef": "****", "Sex": 4, "Race": "****", "InanimateType": "****", "Plot": "****", "LowGore": "****"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "lock.json"), `{
|
||||
"zarathustra:id_572": 16001,
|
||||
"tiberiusmorguhn:zknight": 16002,
|
||||
"shemsuheru:id_1513": 16003,
|
||||
"cepnwn2lib:id_10041": 16004,
|
||||
"ceporiental:id_3854": 16020
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "modules", "add_cclaw.json"), `{"entries":{"zarathustra:id_572":{"BaseResRef":"cclaw_","Sex":4,"Race":10,"Plot":0}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "modules", "add_cotblreaver.json"), `{"entries":{"shemsuheru:id_1513":{"BaseResRef":"cotbl_","Sex":4,"Race":15,"Plot":0}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "modules", "add_nwn2lib.json"), `{"entries":{"cepnwn2lib:id_10041":{"BaseResRef":"nw2book1_","Sex":4,"InanimateType":4}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "modules", "add_orientalplcs.json"), `{"entries":{"ceporiental:id_3854":{"BaseResRef":"ccc_adori01","Sex":4,"InanimateType":1}}}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "reference", "data", "portraits", "modules", "add_zknight.json"), `{"entries":{"tiberiusmorguhn:zknight":{"BaseResRef":"po_zk_","Sex":4,"Race":10,"Plot":0}}}`+"\n")
|
||||
|
||||
result, err := NormalizeProject(testProject(root))
|
||||
if err != nil {
|
||||
t.Fatalf("NormalizeProject failed: %v", err)
|
||||
}
|
||||
if result.UpdatedFiles < 13 {
|
||||
t.Fatalf("expected appearance and portraits files to be imported, got %#v", result)
|
||||
}
|
||||
for _, path := range []string{
|
||||
filepath.Join(root, "topdata", "data", "appearance", "base.json"),
|
||||
filepath.Join(root, "topdata", "data", "appearance", "lock.json"),
|
||||
filepath.Join(root, "topdata", "data", "appearance", "modules", "cotblreaver.json"),
|
||||
filepath.Join(root, "topdata", "data", "appearance", "modules", "crawlingclaw.json"),
|
||||
filepath.Join(root, "topdata", "data", "appearance", "modules", "halfogre.json"),
|
||||
filepath.Join(root, "topdata", "data", "appearance", "modules", "zombieknight.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "base.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "lock.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "modules", "add_cclaw.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "modules", "add_cotblreaver.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "modules", "add_nwn2lib.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "modules", "add_orientalplcs.json"),
|
||||
filepath.Join(root, "topdata", "data", "portraits", "modules", "add_zknight.json"),
|
||||
} {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("expected imported path %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
appearanceBase, err := os.ReadFile(filepath.Join(root, "topdata", "data", "appearance", "base.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read appearance base: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(appearanceBase), `"output": "appearance.2da"`) {
|
||||
t.Fatalf("expected imported appearance output name, got:\n%s", string(appearanceBase))
|
||||
}
|
||||
portraitsBase, err := os.ReadFile(filepath.Join(root, "topdata", "data", "portraits", "base.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits base: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(portraitsBase), `"output": "portraits.2da"`) {
|
||||
t.Fatalf("expected imported portraits output name, got:\n%s", string(portraitsBase))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDenseGenerationDefaultsMissingColumnsAndPortraitFields(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "dense", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "plain"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "appearance"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "appearance", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits", "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": ["A", "B"],
|
||||
"rows": [
|
||||
{"id": 0, "A": "base"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "dense", "lock.json"), `{"dense:add":1}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "dense", "modules", "add.json"), `{
|
||||
"entries": {
|
||||
"dense:add": {
|
||||
"A": "entry"
|
||||
}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "plain", "table.json"), `{
|
||||
"output": "table.2da",
|
||||
"columns": ["A", "B"],
|
||||
"rows": [
|
||||
{"id": 0, "A": "plain"}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "base.json"), `{
|
||||
"output": "portraits.2da",
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "base.json"), `{
|
||||
"output": "placeables.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{
|
||||
"key": "placeables:bookshelf_special",
|
||||
"id": 10,
|
||||
"Label": "BookshelfSpecial"
|
||||
}
|
||||
{"id": 0, "BaseResRef": "****", "Sex": 4}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "lock.json"), `{"placeables:bookshelf_special":10}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "modules", "add_bookshelf_special.json"), `{
|
||||
"overrides": [
|
||||
{
|
||||
"key": "placeables:bookshelf_special",
|
||||
"meta": {
|
||||
"portrait": {
|
||||
"resref": "nw2book1_",
|
||||
"sex": 4,
|
||||
"inanimate_type": 4
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), "{}")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "base.json"), `{
|
||||
"output": "appearance.2da",
|
||||
"columns": ["LABEL", "PORTRAIT"],
|
||||
"rows": [
|
||||
{"key": "appearance:crawlingclaw", "id": 0, "LABEL": "Crawling Claw", "PORTRAIT": "****"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "lock.json"), `{"appearance:crawlingclaw":0}`)
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "modules", "add_crawlingclaw.json"), `{
|
||||
"entries": {
|
||||
"appearance:crawlingclaw": {
|
||||
"LABEL": "Crawling Claw",
|
||||
"PORTRAIT": {
|
||||
"value": "po_cclaw_",
|
||||
"data": {
|
||||
"portraits": {
|
||||
"BaseResRef": "cclaw_",
|
||||
"Sex": 4,
|
||||
"Race": 10,
|
||||
"Plot": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`+"\n")
|
||||
|
||||
mkdirAll(t, filepath.Join(root, "reference"))
|
||||
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
@@ -6306,40 +6198,112 @@ func TestBuildDenseGenerationDefaultsMissingColumnsAndPortraitFields(t *testing.
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
|
||||
denseBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "dense.2da"))
|
||||
appearanceBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "appearance.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read dense.2da: %v", err)
|
||||
t.Fatalf("read appearance.2da: %v", err)
|
||||
}
|
||||
if string(denseBytes) != "2DA V2.0\n\nA\tB\n0\tbase\t****\n1\tentry\t****\n" {
|
||||
t.Fatalf("unexpected dense.2da output:\n%s", string(denseBytes))
|
||||
}
|
||||
|
||||
plainBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "table.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read table.2da: %v", err)
|
||||
}
|
||||
if string(plainBytes) != "2DA V2.0\n\nA\tB\n0\tplain\t****\n" {
|
||||
t.Fatalf("unexpected table.2da output:\n%s", string(plainBytes))
|
||||
if !strings.Contains(string(appearanceBytes), "po_cclaw_") {
|
||||
t.Fatalf("expected PORTRAIT value in appearance.2da, got:\n%s", string(appearanceBytes))
|
||||
}
|
||||
|
||||
portraitsBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "portraits.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits.2da: %v", err)
|
||||
}
|
||||
wantPortraits := "2DA V2.0\n\nBaseResRef\tSex\tRace\tInanimateType\tPlot\tLowGore\n0\tnw2book1_\t4\t****\t4\t****\t****\n"
|
||||
if string(portraitsBytes) != wantPortraits {
|
||||
t.Fatalf("unexpected portraits.2da output:\n%s", string(portraitsBytes))
|
||||
text := string(portraitsBytes)
|
||||
if !strings.Contains(text, "cclaw_") || !strings.Contains(text, "Sex\t") || !strings.Contains(text, "Race\t") {
|
||||
t.Fatalf("expected injected portrait data in portraits.2da, got:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "4\t10\t") {
|
||||
t.Fatalf("expected Sex=4 Race=10 in portraits.2da, got:\n%s", text)
|
||||
}
|
||||
|
||||
placeablesBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "placeables.2da"))
|
||||
lockBytes, err := os.ReadFile(filepath.Join(root, "topdata", "data", "portraits", "lock.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read placeables.2da: %v", err)
|
||||
t.Fatalf("read portraits lock.json: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(placeablesBytes), "Label\n") || !strings.Contains(string(placeablesBytes), "10\tBookshelfSpecial\n") {
|
||||
t.Fatalf("unexpected placeables.2da output:\n%s", string(placeablesBytes))
|
||||
lockText := string(lockBytes)
|
||||
if !strings.Contains(lockText, "portraits:cclaw_") {
|
||||
t.Fatalf("expected lockfile entry for portraits:cclaw_, got:\n%s", lockText)
|
||||
}
|
||||
if strings.Contains(string(placeablesBytes), "portrait") || strings.Contains(string(placeablesBytes), "meta") {
|
||||
t.Fatalf("expected metadata to stay out of placeables.2da, got:\n%s", string(placeablesBytes))
|
||||
}
|
||||
|
||||
func TestBuildExpansionDataDoesNotDuplicatePortraitRows(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "appearance"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "appearance", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "base.json"), `{
|
||||
"output": "portraits.2da",
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": [
|
||||
{"id": 0, "BaseResRef": "****", "Sex": 4}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), "{}")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "base.json"), `{
|
||||
"output": "appearance.2da",
|
||||
"columns": ["LABEL", "PORTRAIT"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "lock.json"), "{}")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "appearance", "modules", "add_zombieknight.json"), `{
|
||||
"entries": {
|
||||
"appearance:zombieknight3": {
|
||||
"LABEL": "Zombie Knight 3",
|
||||
"PORTRAIT": {
|
||||
"value": "po_zk_",
|
||||
"data": {
|
||||
"portraits": {
|
||||
"BaseResRef": "zk_",
|
||||
"Sex": 4,
|
||||
"Race": 23,
|
||||
"Plot": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"appearance:zombieknight4": {
|
||||
"LABEL": "Zombie Knight 4",
|
||||
"PORTRAIT": {
|
||||
"value": "po_zk_",
|
||||
"data": {
|
||||
"portraits": {
|
||||
"BaseResRef": "zk_",
|
||||
"Sex": 4,
|
||||
"Race": 23,
|
||||
"Plot": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`+"\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)
|
||||
}
|
||||
|
||||
portraitsBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "portraits.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits.2da: %v", err)
|
||||
}
|
||||
text := string(portraitsBytes)
|
||||
lines := strings.Split(text, "\n")
|
||||
zkCount := 0
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "zk_") {
|
||||
zkCount++
|
||||
}
|
||||
}
|
||||
if zkCount != 1 {
|
||||
t.Fatalf("expected exactly 1 portrait row with zk_, got %d:\n%s", zkCount, text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6350,8 +6314,7 @@ func TestValidateProjectRejectsUnknownMetadataKey(t *testing.T) {
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "base.json"), `{
|
||||
"output": "placeables.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{"id": 0, "Label": "Shelf", "meta": {"unknown": {}}}
|
||||
"rows": [{"id": 0, "Label": "Shelf", "meta": {"unknown": {}}}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
@@ -6424,58 +6387,6 @@ func TestBuildNativeTreatsMetaCaseInsensitive(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRejectsConflictingPortraitMetadata(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "genericdoors"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "genericdoors", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "base.json"), `{
|
||||
"output": "portraits.2da",
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "base.json"), `{
|
||||
"output": "placeables.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{"key": "placeables:shelf", "id": 1, "Label": "Shelf"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "lock.json"), `{"placeables:shelf":1}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "genericdoors", "base.json"), `{
|
||||
"output": "genericdoors.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{"key": "genericdoors:door", "id": 2, "Label": "Door"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "genericdoors", "lock.json"), `{"genericdoors:door":2}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "modules", "ovr_shelf.json"), `{
|
||||
"overrides": [
|
||||
{"key": "placeables:shelf", "meta": {"portrait": {"resref": "nw2book1_", "sex": 4}}}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "genericdoors", "modules", "ovr_door.json"), `{
|
||||
"overrides": [
|
||||
{"key": "genericdoors:door", "meta": {"portrait": {"resref": "nw2book1_", "sex": 1}}}
|
||||
]
|
||||
}`+"\n")
|
||||
mkdirAll(t, filepath.Join(root, "reference"))
|
||||
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
_, err := BuildNative(testProject(root), nil)
|
||||
if err == nil {
|
||||
t.Fatalf("expected BuildNative to fail on conflicting portrait metadata")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "conflicts for column Sex") {
|
||||
t.Fatalf("expected portrait conflict error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCanonicalAppearanceMatchesReference(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data"))
|
||||
@@ -7828,108 +7739,6 @@ with open(os.path.join(tlk, "sow_tlk.tlk"), "wb") as f:
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSupportsCanonicalPortraitsFromDatasetAndMetadata(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits", "modules"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "base.json"), `{
|
||||
"output": "portraits.2da",
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": [
|
||||
{"id": 0, "BaseResRef": "****", "Sex": 4}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), `{"portraits:auto:nw2book1_":16004,"shemsuheru:id_1513":16003}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "modules", "add_cotblreaver.json"), `{
|
||||
"entries": {
|
||||
"shemsuheru:id_1513": {
|
||||
"BaseResRef": "cotbl_",
|
||||
"Sex": 4,
|
||||
"Race": 15,
|
||||
"Plot": 0
|
||||
}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "base.json"), `{
|
||||
"output": "placeables.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{"key": "placeables:bookshelf", "id": 1, "Label": "Bookshelf"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "lock.json"), `{"placeables:bookshelf":1}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "modules", "ovr_bookshelf.json"), `{
|
||||
"overrides": [
|
||||
{"key": "placeables:bookshelf", "meta": {"portrait": {"resref": "nw2book1_", "sex": 4, "inanimate_type": 4}}}
|
||||
]
|
||||
}`+"\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)
|
||||
}
|
||||
got, err := os.ReadFile(filepath.Join(result.Output2DADir, "portraits.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits.2da: %v", err)
|
||||
}
|
||||
text := string(got)
|
||||
if !strings.Contains(text, "BaseResRef\tSex\tRace\tInanimateType\tPlot\tLowGore\n") ||
|
||||
!strings.Contains(text, "0\t****\t4\t****\t****\t****\t****\n") ||
|
||||
!strings.Contains(text, "16003\tcotbl_\t4\t15\t****\t0\t****\n") ||
|
||||
!strings.Contains(text, "16004\tnw2book1_\t4\t****\t4\t****\t****\n") {
|
||||
t.Fatalf("unexpected portraits.2da output:\n%s", string(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildIgnoresBasePortraitMetadataWithoutModuleOptInAndPrunesAutoLocks(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "portraits"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "placeables"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "base.json"), `{
|
||||
"output": "portraits.2da",
|
||||
"columns": ["BaseResRef", "Sex", "Race", "InanimateType", "Plot", "LowGore"],
|
||||
"rows": [
|
||||
{"id": 0, "BaseResRef": "****", "Sex": 4}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "portraits", "lock.json"), `{"portraits:auto:nw2book1_":16004}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "base.json"), `{
|
||||
"output": "placeables.2da",
|
||||
"columns": ["Label"],
|
||||
"rows": [
|
||||
{"key": "placeables:bookshelf", "id": 1, "Label": "Bookshelf", "meta": {"portrait": {"resref": "nw2book1_", "sex": 4, "inanimate_type": 4}}}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "placeables", "lock.json"), `{"placeables:bookshelf":1}`+"\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)
|
||||
}
|
||||
got, err := os.ReadFile(filepath.Join(result.Output2DADir, "portraits.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits.2da: %v", err)
|
||||
}
|
||||
want := "2DA V2.0\n\nBaseResRef\tSex\tRace\tInanimateType\tPlot\tLowGore\n0\t****\t4\t****\t****\t****\t****\n"
|
||||
if string(got) != want {
|
||||
t.Fatalf("unexpected portraits.2da output:\n%s", string(got))
|
||||
}
|
||||
lockBytes, err := os.ReadFile(filepath.Join(root, "topdata", "data", "portraits", "lock.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read portraits lock: %v", err)
|
||||
}
|
||||
if strings.TrimSpace(string(lockBytes)) != "{}" {
|
||||
t.Fatalf("expected stale auto portrait lock to be pruned, got:\n%s", string(lockBytes))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeProjectImportsRacialtypesRegistry(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data"))
|
||||
|
||||
Reference in New Issue
Block a user