Release Healer Man 0.1.8

This commit is contained in:
phenom
2026-08-27 13:29:58 -04:00
parent eca6b5db9b
commit c245a199b6
90 changed files with 8249 additions and 232 deletions
File diff suppressed because it is too large Load Diff
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/TempestKeepArcane", "mapDirectory": "World/Maps/TempestKeepArcane",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/AuchindounDraenei", "mapDirectory": "World/Maps/AuchindounDraenei",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "burning-crusade", "expansion": "burning-crusade",
"extraction": { "extraction": {
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Blackfathom", "mapDirectory": "World/Maps/Blackfathom",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [20, 30]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [20, 30]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/BlackrockDepths", "mapDirectory": "World/Maps/BlackrockDepths",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [50, 60]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [50, 60]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/BlackRockSpire", "mapDirectory": "World/Maps/BlackRockSpire",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/HellfireDemon", "mapDirectory": "World/Maps/HellfireDemon",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [58, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [58, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/TempestKeepAtrium", "mapDirectory": "World/Maps/TempestKeepAtrium",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+2
View File
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/DireMaul", "mapDirectory": "World/Maps/DireMaul",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [0, 0, 0], "yawDegrees": 180},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [50, 60]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [50, 60]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "burning-crusade", "expansion": "burning-crusade",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/GnomeragonInstance", "mapDirectory": "World/Maps/GnomeragonInstance",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [25, 40]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [25, 40]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/HellfireRampart", "mapDirectory": "World/Maps/HellfireRampart",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [1262.4427, -60.8902, 1622.5397], "yawDegrees": 262.143},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [58, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [58, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Sunwell5ManFix", "mapDirectory": "World/Maps/Sunwell5ManFix",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [70, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [70, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/AuchindounEthereal", "mapDirectory": "World/Maps/AuchindounEthereal",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Mauradon", "mapDirectory": "World/Maps/Mauradon",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [40, 55]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [40, 55]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/TempestKeepFactory", "mapDirectory": "World/Maps/TempestKeepFactory",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/OrgrimmarInstance", "mapDirectory": "World/Maps/OrgrimmarInstance",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"globalWmoAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [13, 25]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [13, 25]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/RazorfenDowns", "mapDirectory": "World/Maps/RazorfenDowns",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [-2402.2809, 62, 1208.3219], "yawDegrees": 0},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [35, 50]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [35, 50]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+2 -1
View File
@@ -8,7 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/RazorfenKraulInstance", "mapDirectory": "World/Maps/RazorfenKraulInstance",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"globalWmoSourceBasis": "flip-x", "coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [-1952.1803, 87.684, 1587.8923], "yawDegrees": -133},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [25, 40]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [25, 40]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a", "clientBuild": "3.3.5a",
"mapDirectory": "World/Maps/MonasteryInstances", "mapDirectory": "World/Maps/MonasteryInstances",
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"adtSourceBasis": "z-y-negative-x",
"difficultyVariants": [ "difficultyVariants": [
{ "id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [26, 45] } { "id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [26, 45] }
], ],
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/SchoolofNecromancy", "mapDirectory": "World/Maps/SchoolofNecromancy",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [-141.694, 148.0683, 105.6784], "yawDegrees": 1},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/AuchindounDemon", "mapDirectory": "World/Maps/AuchindounDemon",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/AuchindounShadow", "mapDirectory": "World/Maps/AuchindounShadow",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [65, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -7,12 +7,14 @@
"expansion": "classic", "expansion": "classic",
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Shadowfang", "mapDirectory": "World/Maps/Shadowfang",
"environmentMode": "global-wmo", "environmentMode": "detect",
"coordinateAlignment": "source",
"adtSourceBasis": "z-y-negative-x",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [18, 30]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [18, 30]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
"extraction": {"rootWmo": "World/wmo/Dungeon/LD_ShadowFang/LD_ShadowFang.wmo", "doodadSets": ["Set_$DefaultGlobal"]}, "extraction": {"adtTiles": "all-present"},
"navigation": {"cellSize": 0.2, "cellHeight": 0.1, "agentHeight": 1.8, "agentRadius": 0.36, "agentMaxClimb": 0.5, "agentMaxSlope": 50}, "navigation": {"cellSize": 0.2, "cellHeight": 0.1, "tileSize": 256, "retainTileIntermediates": false, "agentHeight": 1.8, "agentRadius": 0.36, "agentMaxClimb": 0.5, "agentMaxSlope": 50},
"review": {"entrance": "required", "bossOrder": "required", "optionalEncounters": "required", "presentation": "required", "offMeshLinks": "required"}, "review": {"entrance": "required", "bossOrder": "required", "optionalEncounters": "required", "presentation": "required", "offMeshLinks": "required"},
"exceptions": [] "exceptions": []
} }
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/HellfireMilitary", "mapDirectory": "World/Maps/HellfireMilitary",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/CoilfangDraenei", "mapDirectory": "World/Maps/CoilfangDraenei",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/CoilfangPumping", "mapDirectory": "World/Maps/CoilfangPumping",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+2
View File
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Stratholme", "mapDirectory": "World/Maps/Stratholme",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source-transform",
"coordinateTransform": {"origin": [-3449.6608, 144.3848, -3379.6966], "yawDegrees": 0},
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [55, 60]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/SunkenTemple", "mapDirectory": "World/Maps/SunkenTemple",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [45, 55]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [45, 55]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
+1
View File
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+1
View File
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/Uldaman", "mapDirectory": "World/Maps/Uldaman",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [ "difficultyVariants": [
{ {
"id": "normal", "id": "normal",
+1
View File
@@ -8,6 +8,7 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/CoilfangMarsh", "mapDirectory": "World/Maps/CoilfangMarsh",
"environmentMode": "global-wmo", "environmentMode": "global-wmo",
"coordinateAlignment": "source",
"difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}], "difficultyVariants": [{"id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [60, 70]}],
"clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"}, "clientSource": {"rootEnvironmentVariable": "WOW_CLIENT_ROOT", "relativeDefault": "../wow335a"},
"serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true}, "serverSource": {"rootEnvironmentVariable": "WOW_SERVER_DATA", "adapter": "normalized-json", "readOnly": true},
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
@@ -27,6 +27,7 @@
} }
], ],
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"exceptions": [], "exceptions": [],
"expansion": "wrath", "expansion": "wrath",
"extraction": { "extraction": {
+2
View File
@@ -8,6 +8,8 @@
"clientBuild": "3.3.5a-Ascension", "clientBuild": "3.3.5a-Ascension",
"mapDirectory": "World/Maps/TanarisInstance", "mapDirectory": "World/Maps/TanarisInstance",
"environmentMode": "detect", "environmentMode": "detect",
"coordinateAlignment": "source",
"adtSourceBasis": "z-y-negative-x",
"difficultyVariants": [ "difficultyVariants": [
{ "id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [40, 54] } { "id": "normal", "difficulty": "normal", "spawnMask": 1, "levelRange": [40, 54] }
], ],
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "healer-man", "name": "healer-man",
"version": "0.1.7", "version": "0.1.8",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "healer-man", "name": "healer-man",
"version": "0.1.7", "version": "0.1.8",
"dependencies": { "dependencies": {
"@capacitor/android": "8.4.1", "@capacitor/android": "8.4.1",
"@capacitor/core": "8.4.1", "@capacitor/core": "8.4.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "healer-man", "name": "healer-man",
"private": true, "private": true,
"version": "0.1.7", "version": "0.1.8",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,4 +1,4 @@
{ {
"versionName": "0.1.7", "versionName": "0.1.8",
"versionCode": 1007 "versionCode": 1008
} }
@@ -0,0 +1,122 @@
#!/usr/bin/env node
import path from "node:path";
import { fileURLToPath } from "node:url";
import { NodeIO } from "@gltf-transform/core";
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
import { BufferAttribute, BufferGeometry, Vector3 } from "three";
import { MeshBVH } from "three-mesh-bvh";
import { MeshoptDecoder } from "meshoptimizer";
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const campaign = await import("../../src/game/generated/dungeonCampaignCatalog.json", {
with: { type: "json" },
}).then((module) => module.default);
const useCollision = process.argv.includes("--collision");
const requestedSlugs = new Set(process.argv.slice(2).filter((argument) => argument !== "--collision"));
const definitions = campaign.definitions.filter((definition) => (
!requestedSlugs.size || requestedSlugs.has(definition.id)
));
if (!definitions.length) {
throw new Error("No matching dungeon definitions. Pass one or more dungeon slugs.");
}
await MeshoptDecoder.ready;
const io = new NodeIO()
.registerExtensions(ALL_EXTENSIONS)
.registerDependencies({ "meshopt.decoder": MeshoptDecoder });
const point = new Vector3();
function normalizerFor(accessor, array) {
if (!accessor.getNormalized()) return (value) => value;
if (array instanceof Int16Array) return (value) => Math.max(value / 32_767, -1);
if (array instanceof Uint16Array) return (value) => value / 65_535;
if (array instanceof Int8Array) return (value) => Math.max(value / 127, -1);
if (array instanceof Uint8Array) return (value) => value / 255;
return (value) => value;
}
async function geometryTrees(file) {
const document = await io.read(file);
const trees = [];
for (const node of document.getRoot().listNodes()) {
const mesh = node.getMesh();
if (!mesh) continue;
const matrix = node.getWorldMatrix();
for (const primitive of mesh.listPrimitives()) {
const accessor = primitive.getAttribute("POSITION");
const source = accessor?.getArray();
if (!accessor || !source) continue;
const normalize = normalizerFor(accessor, source);
const positions = new Float32Array(source.length);
for (let offset = 0; offset < source.length; offset += 3) {
const x = normalize(source[offset]);
const y = normalize(source[offset + 1]);
const z = normalize(source[offset + 2]);
positions[offset] = matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12];
positions[offset + 1] = matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13];
positions[offset + 2] = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14];
}
const geometry = new BufferGeometry();
geometry.setAttribute("position", new BufferAttribute(positions, 3));
const indices = primitive.getIndices()?.getArray();
if (indices) geometry.setIndex(new BufferAttribute(indices, 1));
trees.push(new MeshBVH(geometry));
}
}
return trees;
}
function nearestDistance(trees, position) {
point.fromArray(position);
let distance = Infinity;
for (const tree of trees) {
const result = tree.closestPointToPoint(point);
distance = Math.min(distance, result?.distance ?? Infinity);
}
return distance;
}
function percentile(sorted, proportion) {
return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * proportion))] ?? 0;
}
const results = [];
for (const definition of definitions) {
const geometryUrls = useCollision
? definition.assets.collision.map((chunk) => chunk.url)
: [definition.assets.navigation.url];
const trees = (await Promise.all(geometryUrls.map((url) => (
geometryTrees(path.join(projectRoot, "public", url.replace(/^\//, "")))
)))).flat();
const samples = [
{ id: "entrance", position: definition.entrance.footPosition },
...definition.staticSpawns.map((spawn) => ({ id: spawn.id, position: spawn.position })),
...definition.roamingPacks.flatMap((pack) => (
pack.waypoints.map((position, index) => ({ id: `${pack.id}:${index}`, position }))
)),
];
const distances = samples
.map((sample) => ({ ...sample, distance: nearestDistance(trees, sample.position) }))
.sort((left, right) => left.distance - right.distance);
const values = distances.map((sample) => sample.distance);
results.push({
dungeonId: definition.id,
geometry: useCollision ? "collision" : "navigation",
coordinateAlignment: definition.provenance.coordinateAlignment,
coordinateTransform: definition.provenance.coordinateTransform,
samples: values.length,
withinOneMeter: values.filter((distance) => distance <= 1).length,
medianDistance: percentile(values, 0.5),
p90Distance: percentile(values, 0.9),
maximumDistance: values.at(-1) ?? 0,
furthest: distances.slice(-5).reverse().map(({ id, position, distance }) => ({
id,
position,
distance,
})),
});
}
console.log(JSON.stringify(results, null, 2));
@@ -175,6 +175,10 @@ function interpolate(left, right, alpha) {
return left.map((value, axis) => rounded(value + (right[axis] - value) * alpha)); return left.map((value, axis) => rounded(value + (right[axis] - value) * alpha));
} }
function horizontalDistanceSquared(left, right) {
return (left[0] - right[0]) ** 2 + (left[2] - right[2]) ** 2;
}
function normalizedName(value) { function normalizedName(value) {
return String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, ""); return String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "");
} }
@@ -201,7 +205,7 @@ const ADT_SOURCE_BASES = new Set([
"z-y-negative-x", "z-y-negative-x",
]); ]);
const GLOBAL_WMO_SOURCE_BASES = new Set(["draft", "flip-x"]); const GLOBAL_WMO_SOURCE_BASES = new Set(["draft", "flip-x"]);
const GLOBAL_WMO_ALIGNMENTS = new Set(["player-anchor", "source"]); const COORDINATE_ALIGNMENTS = new Set(["player-anchor", "source", "source-transform"]);
function sourceBasisFor(recipe, environmentMode) { function sourceBasisFor(recipe, environmentMode) {
if (environmentMode !== "adt-hybrid") { if (environmentMode !== "adt-hybrid") {
@@ -222,14 +226,42 @@ function sourceBasisFor(recipe, environmentMode) {
} }
function coordinateAlignmentFor(recipe, environmentMode) { function coordinateAlignmentFor(recipe, environmentMode) {
if (environmentMode !== "global-wmo") return "player-anchor"; const legacyGlobalWmoAlignment = environmentMode === "global-wmo"
const alignment = recipe.globalWmoAlignment ?? "player-anchor"; ? recipe.globalWmoAlignment
if (!GLOBAL_WMO_ALIGNMENTS.has(alignment)) { : undefined;
throw new Error(`${recipe.slug}: unsupported global WMO alignment ${alignment}.`); if (
recipe.coordinateAlignment
&& legacyGlobalWmoAlignment
&& recipe.coordinateAlignment !== legacyGlobalWmoAlignment
) {
throw new Error(`${recipe.slug}: coordinate alignment overrides disagree.`);
}
const alignment = recipe.coordinateAlignment ?? legacyGlobalWmoAlignment ?? "player-anchor";
if (!COORDINATE_ALIGNMENTS.has(alignment)) {
throw new Error(`${recipe.slug}: unsupported coordinate alignment ${alignment}.`);
} }
return alignment; return alignment;
} }
function sourceTransformFor(recipe, alignment) {
const transform = recipe.coordinateTransform;
if (alignment !== "source-transform") {
if (transform) {
throw new Error(`${recipe.slug}: coordinateTransform requires source-transform alignment.`);
}
return undefined;
}
if (!transform || !Array.isArray(transform.origin) || transform.origin.length !== 3) {
throw new Error(`${recipe.slug}: source-transform alignment requires a three-value coordinateTransform.origin.`);
}
const origin = transform.origin.map(Number);
const yawDegrees = Number(transform.yawDegrees ?? 0);
if (!origin.every(Number.isFinite) || !Number.isFinite(yawDegrees)) {
throw new Error(`${recipe.slug}: coordinateTransform values must be finite numbers.`);
}
return { origin, yawDegrees };
}
/** /**
* Runtime drafts retain the original pipeline convention. wow.export ADT * Runtime drafts retain the original pipeline convention. wow.export ADT
* packages have an additional horizontal basis change baked into their GLBs. * packages have an additional horizontal basis change baked into their GLBs.
@@ -248,10 +280,39 @@ function sourceToPackageBasis(position, environmentMode, sourceBasis) {
: point; : point;
} }
function coordinateMapper(draft, environmentMode, playerAnchor, sourceBasis, alignment) { function rotateAroundY(position, yawDegrees) {
const radians = yawDegrees * Math.PI / 180;
const cosine = Math.cos(radians);
const sine = Math.sin(radians);
return vector([
position[0] * cosine - position[2] * sine,
position[1],
position[0] * sine + position[2] * cosine,
]);
}
function coordinateMapper(
draft,
environmentMode,
playerAnchor,
sourceBasis,
alignment,
sourceTransform,
) {
if (alignment === "source") { if (alignment === "source") {
return (position) => sourceToPackageBasis(position, environmentMode, sourceBasis); return (position) => sourceToPackageBasis(position, environmentMode, sourceBasis);
} }
if (alignment === "source-transform") {
const basisOrigin = sourceToPackageBasis(
sourceTransform.origin,
environmentMode,
sourceBasis,
);
return (position) => rotateAroundY(
subtract(sourceToPackageBasis(position, environmentMode, sourceBasis), basisOrigin),
sourceTransform.yawDegrees,
);
}
const sourceEntrance = draft?.entrance const sourceEntrance = draft?.entrance
?? draft?.spawns?.[0]?.position ?? draft?.spawns?.[0]?.position
?? playerAnchor.position; ?? playerAnchor.position;
@@ -778,6 +839,7 @@ async function compile() {
const environmentMode = inferEnvironmentMode(recipe, assetPackage); const environmentMode = inferEnvironmentMode(recipe, assetPackage);
const sourceBasis = sourceBasisFor(recipe, environmentMode); const sourceBasis = sourceBasisFor(recipe, environmentMode);
const coordinateAlignment = coordinateAlignmentFor(recipe, environmentMode); const coordinateAlignment = coordinateAlignmentFor(recipe, environmentMode);
const sourceTransform = sourceTransformFor(recipe, coordinateAlignment);
const playerAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "player"); const playerAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "player");
const trashAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "trash"); const trashAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "trash");
const bossAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "boss"); const bossAnchor = assetPackage.anchors.find((anchor) => anchor.kind === "boss");
@@ -788,7 +850,7 @@ async function compile() {
trashAnchor.position[0] - playerAnchor.position[0], trashAnchor.position[0] - playerAnchor.position[0],
trashAnchor.position[2] - playerAnchor.position[2], trashAnchor.position[2] - playerAnchor.position[2],
); );
const entranceYaw = Number.isFinite(playerAnchor.yaw) let entranceYaw = Number.isFinite(playerAnchor.yaw)
? playerAnchor.yaw ? playerAnchor.yaw
: inferredEntranceYaw; : inferredEntranceYaw;
@@ -809,6 +871,7 @@ async function compile() {
playerAnchor, playerAnchor,
sourceBasis, sourceBasis,
coordinateAlignment, coordinateAlignment,
sourceTransform,
); );
const entrancePosition = mapPosition( const entrancePosition = mapPosition(
draft?.entrance draft?.entrance
@@ -896,16 +959,49 @@ async function compile() {
const entry = Number(spawn.entityId.replace("entry-", "")); const entry = Number(spawn.entityId.replace("entry-", ""));
if (!bossCandidatesByEntry.has(entry)) bossCandidatesByEntry.set(entry, spawn); if (!bossCandidatesByEntry.has(entry)) bossCandidatesByEntry.set(entry, spawn);
} }
const mappedNativeRoutePositions = coordinateAlignment !== "player-anchor"
? (draft?.spawns ?? [])
.map((spawn) => mapPosition(spawn.position))
.filter((position) => position.every(Number.isFinite))
.sort((left, right) => (
horizontalDistanceSquared(left, entrancePosition)
- horizontalDistanceSquared(right, entrancePosition)
))
: [];
const entranceDirectionTarget = mappedNativeRoutePositions.find((position) => (
Math.abs(position[1] - entrancePosition[1]) <= 3
&& horizontalDistanceSquared(position, entrancePosition) >= 16
));
if (entranceDirectionTarget) {
entranceYaw = Math.atan2(
entranceDirectionTarget[0] - entrancePosition[0],
entranceDirectionTarget[2] - entrancePosition[2],
);
}
const entranceLevelRoutePositions = mappedNativeRoutePositions.filter(
(position) => Math.abs(position[1] - entrancePosition[1]) <= 2.5,
);
const nativeRoutePositions = (
bossCandidatesByEntry.size === 0
&& entranceLevelRoutePositions.length >= encounters.length
)
? entranceLevelRoutePositions
: mappedNativeRoutePositions;
const usedBossSpawnIds = new Set(); const usedBossSpawnIds = new Set();
const bossObjectives = encounters.map((encounter, index) => { const bossObjectives = encounters.map((encounter, index) => {
const candidate = bossCandidatesByEntry.get(Number(encounter.creatureId)); const candidate = bossCandidatesByEntry.get(Number(encounter.creatureId));
const alpha = encounters.length <= 1 ? 1 : index / (encounters.length - 1); const alpha = encounters.length <= 1 ? 1 : index / (encounters.length - 1);
const routePosition = interpolate(trashAnchor.position, bossAnchor.position, 0.18 + alpha * 0.82); const routeAlpha = 0.18 + alpha * 0.82;
const nativeRoutePosition = nativeRoutePositions.length
? nativeRoutePositions[Math.round(routeAlpha * (nativeRoutePositions.length - 1))]
: undefined;
const routePosition = nativeRoutePosition
?? interpolate(trashAnchor.position, bossAnchor.position, routeAlpha);
const position = encounter.eventOnly const position = encounter.eventOnly
? [-151.27, -102.82, 252.26] ? [-151.27, -102.82, 252.26]
: candidate : candidate
? mapPosition(candidate.position) ? mapPosition(candidate.position)
: offsetPosition(routePosition, index % 5, 2.4); : nativeRoutePosition ?? offsetPosition(routePosition, index % 5, 2.4);
const id = encounter.eventOnly const id = encounter.eventOnly
? "mutanus-spawn" ? "mutanus-spawn"
: candidate?.id ?? `encounter-${encounter.encounterId}`; : candidate?.id ?? `encounter-${encounter.encounterId}`;
@@ -1000,8 +1096,9 @@ async function compile() {
const allPoints = [ const allPoints = [
entrancePosition, entrancePosition,
trashAnchor.position, ...(coordinateAlignment === "player-anchor" || syntheticTrash
bossAnchor.position, ? [trashAnchor.position, bossAnchor.position]
: []),
...staticSpawns.map((spawn) => spawn.position), ...staticSpawns.map((spawn) => spawn.position),
...roamingPacks.flatMap((pack) => pack.waypoints), ...roamingPacks.flatMap((pack) => pack.waypoints),
]; ];
@@ -1032,6 +1129,8 @@ async function compile() {
? ["Trash identities and placements are procedural; boss identities come from the installed Ascension encounter catalog."] ? ["Trash identities and placements are procedural; boss identities come from the installed Ascension encounter catalog."]
: coordinateAlignment === "source" : coordinateAlignment === "source"
? [`Server positions use the packaged ${environmentMode} environment's native world coordinates.`] ? [`Server positions use the packaged ${environmentMode} environment's native world coordinates.`]
: coordinateAlignment === "source-transform"
? [`Server positions use the packaged ${environmentMode} environment's authoritative WDT placement transform.`]
: [`Server positions were aligned to the packaged ${environmentMode} environment at its reviewed player anchor.`]), : [`Server positions were aligned to the packaged ${environmentMode} environment at its reviewed player anchor.`]),
]; ];
@@ -1078,6 +1177,7 @@ async function compile() {
serverGameObjects: draft?.gameObjects ?? [], serverGameObjects: draft?.gameObjects ?? [],
provenance: { provenance: {
clientBuild: recipe.clientBuild, clientBuild: recipe.clientBuild,
coordinateAlignment,
clientArchiveHashes: assetPackage.source.checksums ?? {}, clientArchiveHashes: assetPackage.source.checksums ?? {},
databaseAdapter: databaseKind, databaseAdapter: databaseKind,
databaseRevision: draft?.spawns?.length databaseRevision: draft?.spawns?.length
@@ -1090,6 +1190,8 @@ async function compile() {
? sourceBasis === "z-y-negative-x" ? sourceBasis === "z-y-negative-x"
? "three(x,y,z)=(wow.y,wow.z,wow.x)" ? "three(x,y,z)=(wow.y,wow.z,wow.x)"
: "three(x,y,z)=(-wow.y,wow.z,wow.x)" : "three(x,y,z)=(-wow.y,wow.z,wow.x)"
: coordinateAlignment === "source-transform"
? `three(x,y,z)=rotate-y(${sourceBasis === "flip-x" ? "(-draft.x,draft.y,draft.z)" : "draft(x,y,z)"}-[${sourceTransform.origin.join(",")}],${sourceTransform.yawDegrees}deg)`
: coordinateAlignment === "source" : coordinateAlignment === "source"
? sourceBasis === "flip-x" ? sourceBasis === "flip-x"
? "three(x,y,z)=(-draft.x,draft.y,draft.z)" ? "three(x,y,z)=(-draft.x,draft.y,draft.z)"
+164 -2
View File
@@ -5,6 +5,61 @@ import generated from "./generated/dungeonCampaignCatalog.json";
import manastormPackages from "./generated/manastormAssetPackages.json"; import manastormPackages from "./generated/manastormAssetPackages.json";
import { DUNGEON_DEFINITIONS, requireDungeonDefinition } from "./dungeonRegistry"; import { DUNGEON_DEFINITIONS, requireDungeonDefinition } from "./dungeonRegistry";
const SOURCE_NATIVE_DUNGEON_IDS = [
"ahnkahet-old-kingdom",
"arcatraz",
"auchenai-crypts",
"azjol-nerub",
"black-morass",
"blackfathom-deeps",
"blackrock-depths",
"blackrock-spire",
"blood-furnace",
"botanica",
"culling-of-stratholme",
"draktharon-keep",
"escape-from-durnholde",
"forge-of-souls",
"gnomeregan",
"gundrak",
"halls-of-lightning",
"halls-of-reflection",
"halls-of-stone",
"magisters-terrace",
"mana-tombs",
"maraudon",
"mechanar",
"pit-of-saron",
"ragefire-chasm",
"scarlet-monastery",
"sethekk-halls",
"shadow-labyrinth",
"shadowfang-keep",
"shattered-halls",
"slave-pens",
"steamvault",
"stormwind-stockade",
"sunken-temple",
"the-nexus",
"the-oculus",
"trial-of-the-champion",
"uldaman",
"underbog",
"utgarde-keep",
"utgarde-pinnacle",
"violet-hold",
"zulfarrak",
] as const;
const WDT_PLACEMENT_DUNGEON_IDS = [
"dire-maul",
"hellfire-ramparts",
"razorfen-downs",
"razorfen-kraul",
"scholomance",
"stratholme",
] as const;
describe("generated dungeon campaign catalog", () => { describe("generated dungeon campaign catalog", () => {
it("covers only reviewed five-player instances with loadable assets and combat content", () => { it("covers only reviewed five-player instances with loadable assets and combat content", () => {
expect(generated.definitions).toHaveLength(54); expect(generated.definitions).toHaveLength(54);
@@ -240,17 +295,124 @@ describe("generated dungeon campaign catalog", () => {
expect(targorr?.position).toEqual([-159.582, -25.6062, 1.2531]); expect(targorr?.position).toEqual([-159.582, -25.6062, 1.2531]);
}); });
it("starts Ragefire Chasm in the dungeon instead of the Orgrimmar portal annex", () => {
const ragefire = requireDungeonDefinition("ragefire-chasm");
const firstSpawn = ragefire.staticSpawns.find(
(spawn) => spawn.id === "creature-38041",
);
const jergosh = ragefire.staticSpawns.find(
(spawn) => spawn.id === "creature-48740",
);
expect(ragefire.environmentMode).toBe("global-wmo");
expect(ragefire.provenance.coordinateTransform)
.toBe("three(x,y,z)=draft(x,y,z)");
expect(ragefire.entrance.footPosition).toEqual([-3.81, -17.84, -14.82]);
expect(firstSpawn?.position).toEqual([45.0298, -21.2917, -27.7645]);
expect(jergosh?.position).toEqual([376.811, -21.801, 209.224]);
});
it("keeps every navigation-audited dungeon in its native source coordinates", () => {
const sourceAligned = generated.definitions
.filter((dungeon) => dungeon.provenance.coordinateAlignment === "source")
.map((dungeon) => dungeon.id)
.sort();
expect(sourceAligned).toEqual([...SOURCE_NATIVE_DUNGEON_IDS].sort());
for (const dungeonId of SOURCE_NATIVE_DUNGEON_IDS) {
const dungeon = requireDungeonDefinition(dungeonId);
expect(dungeon.provenance.coordinateAlignment, dungeonId).toBe("source");
expect(dungeon.provenance.coordinateTransform, dungeonId)
.not.toContain("package-anchor-translation");
expect(
dungeon.validation.warnings.some((warning) => (
warning.includes("native world coordinates")
)),
dungeonId,
).toBe(true);
}
});
it("pins representative global-WMO and ADT entrances to their source basis", () => {
const expectedEntrances = {
"blackfathom-deeps": [151.89, -39.87, 106.96],
"blackrock-depths": [-456.929, -68.0896, 34.0923],
"blood-furnace": [3.9967, -44.8009, 14.6363],
"the-nexus": [-145.87, -16.636, -10.554],
"violet-hold": [803.93, 44.364, 1808.82],
"black-morass": [7034.7, 32.5619, -1496.24],
"culling-of-stratholme": [556.92, 36.69, 1431.1],
} as const;
for (const [dungeonId, expected] of Object.entries(expectedEntrances)) {
expect(requireDungeonDefinition(dungeonId).entrance.footPosition, dungeonId)
.toEqual(expected);
}
});
it("keeps scripted Trial of the Champion objectives on the native arena floor", () => {
const trial = requireDungeonDefinition("trial-of-the-champion");
const [entranceX, , entranceZ] = trial.entrance.footPosition;
expect(trial.objectiveOrder).toHaveLength(5);
for (const objective of trial.objectiveOrder) {
expect(objective.position[1], objective.name).toBeGreaterThanOrEqual(411);
expect(objective.position[1], objective.name).toBeLessThanOrEqual(413);
expect(
Math.hypot(objective.position[0] - entranceX, objective.position[2] - entranceZ),
objective.name,
).toBeLessThan(150);
}
});
it("uses client WDT placement records for rotated or translated root WMOs", () => {
for (const dungeonId of WDT_PLACEMENT_DUNGEON_IDS) {
expect(
requireDungeonDefinition(dungeonId).provenance.coordinateAlignment,
dungeonId,
).toBe("source-transform");
expect(
requireDungeonDefinition(dungeonId).provenance.coordinateTransform,
dungeonId,
).toContain("rotate-y");
expect(
requireDungeonDefinition(dungeonId).provenance.coordinateTransform,
dungeonId,
).not.toContain("package-anchor-translation");
}
});
it("pins every map found by the portal-map coordinate audit to its dungeon entrance", () => {
const expectedEntrances = {
arcatraz: [1.2316, -0.2043, 0.0143],
"dire-maul": [44.4499, -2.712, 154.822],
"hellfire-ramparts": [5.7204, 129.1393, -94.4661],
"razorfen-downs": [-190.2691, -10.71, -100.8219],
"razorfen-kraul": [-37.901, -5.684, 22.7908],
"scarlet-monastery": [1053.48, 18.6775, 1688.99],
scholomance: [-55.0407, -13.1583, 20.4141],
"shadowfang-keep": [2109.18, 76.8898, -229.135],
stratholme: [-143.4892, -5.8848, -266.8634],
zulfarrak: [841.59, 8.93, 1213.52],
} as const;
for (const [dungeonId, expected] of Object.entries(expectedEntrances)) {
expect(requireDungeonDefinition(dungeonId).entrance.footPosition, dungeonId)
.toEqual(expected);
}
});
it("starts Razorfen Kraul inside the portal and maps its first pack into the WMO", () => { it("starts Razorfen Kraul inside the portal and maps its first pack into the WMO", () => {
const razorfenKraul = requireDungeonDefinition("razorfen-kraul"); const razorfenKraul = requireDungeonDefinition("razorfen-kraul");
const firstPackSpawn = razorfenKraul.staticSpawns.find( const firstPackSpawn = razorfenKraul.staticSpawns.find(
(spawn) => spawn.id === "creature-87284", (spawn) => spawn.id === "creature-87284",
); );
expect(razorfenKraul.entrance.footPosition).toEqual([-33.81, -5.2481, 21.522]); expect(razorfenKraul.entrance.footPosition).toEqual([-37.901, -5.684, 22.7908]);
expect(firstPackSpawn).toBeTruthy(); expect(firstPackSpawn).toBeTruthy();
expect(firstPackSpawn!.position[0]).toBeGreaterThan(razorfenKraul.entrance.footPosition[0]); expect(firstPackSpawn!.position[0]).toBeGreaterThan(razorfenKraul.entrance.footPosition[0]);
expect(firstPackSpawn!.position[0]).toBeLessThan(100); expect(firstPackSpawn!.position[0]).toBeLessThan(100);
expect(razorfenKraul.provenance.coordinateTransform) expect(razorfenKraul.provenance.coordinateTransform)
.toBe("three(x,y,z)=(-draft.x,draft.y,draft.z)+package-anchor-translation"); .toBe("three(x,y,z)=rotate-y(draft(x,y,z)-[-1952.1803,87.684,1587.8923],-133deg)");
}); });
}); });
+1
View File
@@ -191,6 +191,7 @@ export interface DungeonPresentation {
export interface DungeonSourceProvenance { export interface DungeonSourceProvenance {
readonly clientBuild: string; readonly clientBuild: string;
readonly coordinateAlignment?: "player-anchor" | "source" | "source-transform";
readonly clientArchiveHashes: Readonly<Record<string, string>>; readonly clientArchiveHashes: Readonly<Record<string, string>>;
readonly databaseAdapter: string; readonly databaseAdapter: string;
readonly databaseRevision?: string; readonly databaseRevision?: string;
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff