Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions tools/generate-prefab-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ async function buildHtmls(labels: Map<LabelId, Label>) {
console.warn("Abort a prefab HTML: ", e.message);
return;
}
console.warn("Abort a prefab HTML: ", e);
return;
throw e;
}
if (++successCount % 50 === 0) {
console.log("Build HTML files: %d/%d", successCount, xmlFiles.length);
Expand Down
16 changes: 10 additions & 6 deletions tools/lib/prefab-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,9 @@ export function buildSleeperVolumes(
if (groupIds === undefined) {
throw new Error("SleeperVolumeGroupId is not found");
}
// HACK: pad SleeperVolumeGameStageAdjust with empty strings when it is absent or shorter than SleeperVolumeGroup.
// WHY: vanilla prefabs omit trailing falses/empties on optional properties.
// WHY: IsLoot/IsQuestExclude/Flags fallbacks match the 7DTD binary bounds-checks.
// WHY: GameStageAdjust and IsBoss are absent from the binary model.
const gameStageAdjusts =
parseCsvField(propMap, "SleeperVolumeGameStageAdjust", (s) => s.trim()) ??
Array.from(groups, () => "");
Expand All @@ -311,7 +313,6 @@ export function buildSleeperVolumes(
(s) => parseInt(s, 10),
);
if (flags === undefined) throw new Error("SleeperVolumeFlags is not found");
// HACK: default SleeperIsBoss/Loot/QuestExclude arrays to all-false when the property is absent or shorter than groups.
const parseBool = (s: string) => s === "True";
const isBosses = parseCsvField(propMap, "SleeperIsBossVolume", parseBool) ??
Array.from(groups, () => false);
Expand Down Expand Up @@ -342,11 +343,14 @@ export function buildSleeperVolumes(
groupIds[i],
() => `Unexpected state: groupId is not found: index=${String(i)}`,
),
// WHY: trailing empty entries are omitted in vanilla prefabs for optional string arrays.
gameStageAdjust: gameStageAdjusts[i] ?? "",
flags: requireNonnull(
flags[i],
() => `Unexpected state: flags is not found: index=${String(i)}`,
),
// WHY: the 7DTD binary (Assembly-CSharp.dll, PrefabVolumes.PrefabSleeperVolumeList::ReadFromProperties)
// WHY: falls back to 0 when SleeperVolumeFlags is shorter than SleeperVolumeGroup.
flags: flags[i] ?? 0,
// WHY: the 7DTD binary falls back to false when SleeperIsLootVolume and
// WHY: SleeperIsQuestExclude are shorter than SleeperVolumeGroup.
// WHY: isBoss is not part of the binary model; kept here for HTML display.
isBoss: isBosses[i] ?? false,
isLoot: isLoots[i] ?? false,
isQuestExclude: isQuestExcludes[i] ?? false,
Expand Down
15 changes: 15 additions & 0 deletions tools/test/prefab-html.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,19 @@ describe("buildSleeperVolumes", () => {
"SleeperVolumeFlags is not found",
);
});

it("defaults flags to 0 when the property is shorter than groups", () => {
// WHY: the 7DTD binary also falls back to 0 for missing flags entries.
const props: PrefabProperty[] = [
{ name: "SleeperVolumeGroup", value: "groupA,1,2,groupB,3,4" },
{ name: "SleeperVolumeGroupId", value: "0,1" },
{ name: "SleeperVolumeFlags", value: "1" },
{ name: "SleeperVolumeSize", value: "1,2,3#4,5,6" },
{ name: "SleeperVolumeStart", value: "0,0,0#1,1,1" },
];
const volumes = buildSleeperVolumes(props);
expect(volumes.length).toBe(2);
expect(volumes[0].flags).toBe(1);
expect(volumes[1].flags).toBe(0);
});
});