Remap occupied furniture IDs during Catalog Studio imports
This commit is contained in:
1 parent
9f791ba284
commit
9dc6b8a261
6 files changed
+206
-9
No files matched your search
@@ -0,0 +1,56 @@
|
||||
import { sql } from "drizzle-orm";
|
||||
import { db } from "@/lib/db";
|
||||
import { findFurniDataIdConflict } from "./furni-data";
|
||||
|
||||
let reservation: Promise<void> = Promise.resolve();
|
||||
/** Reserve both SQL and client identifiers by inserting while holding the local queue.
|
||||
* The primary key handles competing processes; only duplicate-key failures retry.
|
||||
*/
|
||||
export async function reserveFurnitureId(
|
||||
preferred: number,
|
||||
classname: string,
|
||||
insert: (id: number) => Promise<void>,
|
||||
): Promise<number> {
|
||||
let release!: () => void;
|
||||
const previous = reservation;
|
||||
reservation = new Promise<void>((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
await previous;
|
||||
try {
|
||||
let candidate = preferred;
|
||||
for (let attempt = 0; attempt < 100; attempt++) {
|
||||
if (
|
||||
!Number.isSafeInteger(candidate) ||
|
||||
candidate < 1 ||
|
||||
candidate > 2147483647
|
||||
)
|
||||
throw new Error("No valid furniture ID is available");
|
||||
const [owners] = (await db.execute(
|
||||
sql`SELECT item_name FROM items_base WHERE id = ${candidate} OR sprite_id = ${candidate} LIMIT 1`,
|
||||
)) as unknown as [Array<{ item_name: string }>, unknown];
|
||||
const occupied =
|
||||
owners.length > 0 ||
|
||||
!!(await findFurniDataIdConflict(candidate, classname));
|
||||
if (!occupied) {
|
||||
try {
|
||||
await insert(candidate);
|
||||
return candidate;
|
||||
} catch (error) {
|
||||
const cause =
|
||||
(error as { cause?: { code?: string; errno?: number } }).cause ??
|
||||
(error as { code?: string; errno?: number });
|
||||
if (cause.code !== "ER_DUP_ENTRY" && cause.errno !== 1062)
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const [rows] = (await db.execute(
|
||||
sql`SELECT GREATEST(COALESCE(MAX(id), 0), COALESCE(MAX(sprite_id), 0)) AS maximum FROM items_base`,
|
||||
)) as unknown as [Array<{ maximum: number | string }>, unknown];
|
||||
candidate = Math.max(candidate + 1, Number(rows[0]?.maximum ?? 0) + 1);
|
||||
}
|
||||
throw new Error("Cannot reserve a free furniture ID; retry the import");
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user