Preserve furniture revisions when downloading source assets

This commit is contained in:
Simo committed 2026-09-05 14:29:48 +02:00
1 parent 7880d5d5df
commit 8a919f85b2
5 files changed
+32 -4

No files matched your search

+1 -1
View File
@@ -391,7 +391,7 @@ export const GET = withAdmin(
type: item.itemType === "i" ? "wallitem" : "flooritem",
name: item.name,
description: item.description,
revision: 0,
revision: Number(item.revision) || 0,
category: String(item.category ?? ""),
...presence,
nitroExists,
+11
View File
@@ -304,3 +304,14 @@ describe("fetchSourceFurnidata", () => {
).rejects.toThrow(/Cloudflare challenge/);
});
});
it("preserves numeric source revisions for asset downloads", () => {
const [entry] = parseFurnidata({
roomitemtypes: {
furnitype: [
{ id: 16940, classname: "recycler_kintsugiB", revision: "73706" },
],
},
});
expect(entry.revision).toBe(73706);
});
+4
View File
@@ -69,6 +69,10 @@ function toSourceFurni(
return {
...raw,
id: Number(raw.id ?? 0),
revision:
Number.isSafeInteger(Number(raw.revision)) && Number(raw.revision) > 0
? Number(raw.revision)
: 0,
classname: String(raw.classname ?? ""),
name: String(raw.name ?? raw.classname ?? ""),
description: String(raw.description ?? ""),
+15 -2
View File
@@ -4,6 +4,8 @@ import { MySqlDialect } from "drizzle-orm/mysql-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
official: vi.fn(),
download: vi.fn(),
execute: vi.fn(),
select: vi.fn(),
stat: vi.fn(),
@@ -43,14 +45,14 @@ vi.mock("@/lib/services/furni-data", () => ({
appendFurniEntry: mocks.append,
}));
vi.mock("@/lib/services/habbo-furnidata-cache", () => ({
lookupOfficialHabboFurni: async () => null,
lookupOfficialHabboFurni: mocks.official,
}));
vi.mock("@/lib/services/habbo-gamedata-hotel", () => ({
getHabboGamedataHotel: async () => "it",
}));
vi.mock("@/lib/services/import/core/download", () => ({
downloadFile: vi.fn(),
tryDownloadCandidates: async () => false,
tryDownloadCandidates: mocks.download,
}));
vi.mock("@/lib/services/swf-to-nitro", () => ({
parseNitroBundle: () => ({ json: {} }),
@@ -76,6 +78,8 @@ function queries() {
describe("completion of existing furniture", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.official.mockResolvedValue(null);
mocks.download.mockResolvedValue(false);
const rows = [
[{ id: 2000037257, spriteId: 9001, type: "s" }],
[{ itemName: input.classname }],
@@ -140,13 +144,22 @@ it("imports recycler_kintsugiB with an allocated ID throughout SQL and furnidata
return [[{ id: 123, page_id: "15" }], []];
return [[], []];
});
mocks.official.mockResolvedValue({ revision: 73706, xdim: 1, ydim: 1 });
const result = await importSingleFurni({
...input,
revision: 0,
id: 16940,
classname: "recycler_kintsugiB",
});
expect(result.ok).toBe(true);
expect(result.itemId).toBe(2000037258);
expect(mocks.download).toHaveBeenCalledWith(
expect.arrayContaining([
"https://images.habbo.com/dcr/hof_furni/73706/recycler_kintsugiB.swf",
]),
expect.any(String),
"swf",
);
expect(mocks.build).toHaveBeenCalledWith(
expect.objectContaining({
id: 2000037258,
+1 -1
View File
@@ -659,7 +659,7 @@ export async function importSingleFurni(params: {
}
// ── Derive file-safe names ────────────────────────────────────────
const rev = revision || 0;
const rev = bestRevision;
const assetTargets = await getFurniAssetWriteTargets();
const { swfDir, iconDir, nitroDir } = assetTargets;
const starIdx = classname.indexOf("*");