From 11e068893029051315e7251c926b0c17e248b452 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Mon, 14 Sep 2026 13:07:25 +0000 Subject: [PATCH] =?UTF-8?q?feat(packer):=20=E6=8F=90=E5=8F=96=E5=8F=AF?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=20NPC=20=E7=9A=84=E5=9C=B0=E5=9B=BE=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D=E5=B9=B6=E7=8B=AC=E7=AB=8B=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将场景数据生成时对 objectType 的判定粒度细化。保留对普通怪物的忽略过滤,对于包含 baseIsMonsters 标识的命名 NPC 记录,将类型标识拆分为 'npc' 并单独放入 scene.json 的 npcs 数组中打包。 --- scripts/pack-act-assets.ts | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/scripts/pack-act-assets.ts b/scripts/pack-act-assets.ts index e428852..6b10bf1 100644 --- a/scripts/pack-act-assets.ts +++ b/scripts/pack-act-assets.ts @@ -344,14 +344,19 @@ for (const row of objectsTable.rows) { /** Object members grouped by token and mode, built once. */ const objectMembers = new Map>() +const monsterMembers = new Map>() for (const name of allNames) { - if (!name.toLowerCase().startsWith(OBJECT_PREFIX.toLowerCase())) continue - const rest = name.slice(OBJECT_PREFIX.length).split('\\') + const isObj = name.toLowerCase().startsWith(OBJECT_PREFIX.toLowerCase()) + const isMon = name.toLowerCase().startsWith('data\\global\\monsters\\') + if (!isObj && !isMon) continue + const prefixLen = isObj ? OBJECT_PREFIX.length : 22 // 'data\\global\\monsters\\'.length + const rest = name.slice(prefixLen).split('\\') if (rest.length < 3) continue const token = (rest[0] ?? '').toUpperCase() const mode = (rest[1] ?? '').toLowerCase() - if (!objectMembers.has(token)) objectMembers.set(token, new Map()) - const modes = objectMembers.get(token)! + const map = isObj ? objectMembers : monsterMembers + if (!map.has(token)) map.set(token, new Map()) + const modes = map.get(token)! if (!modes.has(mode)) modes.set(mode, []) modes.get(mode)!.push(name) } @@ -378,8 +383,9 @@ function compRank(path: string): number { * @param modeToken - animation mode token the engine places the object in (`NU`/`OP`/…). * @returns the member name and how many candidates there were. */ -function pickObjectMember(token: string, modeToken: string): { member: string; candidates: number } | null { - const dirs = objectMembers.get(token) +function pickObjectMember(token: string, modeToken: string, baseIsMonsters = false): { member: string; candidates: number } | null { + const map = baseIsMonsters ? monsterMembers : objectMembers + const dirs = map.get(token) if (dirs === undefined) return null const all = [...dirs.values()].flat().filter(name => { const lower = name.toLowerCase() @@ -641,6 +647,7 @@ async function bakeDs1Variant( const objectPages = new PageBuilder(palette) const objects: unknown[] = [] + const npcs: unknown[] = [] const missingObjects: string[] = [] let objectsWithArt = 0 const placementByMember = new Map() @@ -655,7 +662,7 @@ async function bakeDs1Variant( } if (resolved.kind === 'monster') continue const row = resolved.row - const pick = resolved.token === '' ? null : pickObjectMember(resolved.token, resolved.mode) + const pick = resolved.token === '' ? null : pickObjectMember(resolved.token, resolved.mode, resolved.kind === 'npc') const orthoX = (object.x - object.y) * ORTHO_SUB_TILE_WIDTH + scene.originX const orthoY = (object.x + object.y) * ORTHO_SUB_TILE_HEIGHT + scene.originY @@ -723,7 +730,8 @@ async function bakeDs1Variant( } } - objects.push({ + const list = resolved.kind === 'npc' ? npcs : objects + list.push({ id: object.id, type: object.type, name: row?.name ?? resolved.token, @@ -793,6 +801,7 @@ async function bakeDs1Variant( walls: scene.walls.map(draw => [draw.frameIndex, draw.x, draw.y, draw.cellX, draw.cellY]), roofs: scene.roofs.map(draw => [draw.frameIndex, draw.x, draw.y, draw.cellX, draw.cellY]), objects, + npcs, collision: { width: scene.gridWidth, height: scene.gridHeight, runs }, spawn: spawn === null ? null : [Math.round(spawn.x), Math.round(spawn.y)], stats: { @@ -804,6 +813,7 @@ async function bakeDs1Variant( missingRefs: scene.missingRefs, walkable: 1 - [...scene.blocked].reduce((sum, value) => sum + value, 0) / scene.blocked.length, objects: objects.length, + npcs: npcs.length, objectsWithArt, objectsUnresolved: missingObjects, objectsArtPending: (objects as any[]).filter(o => o.member !== null && o.frame === null).length, @@ -840,6 +850,7 @@ async function bakeDs1Variant( cells: `${String(scene.cellsX)}x${String(scene.cellsY)}`, frames: scene.frames.length, objects: objects.length, + npcs: npcs.length, pages: pageFiles.length, objectPages: objectFiles.length, missingTiles: scene.missingTiles,