You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
47 KiB

3 weeks ago
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.unload = exports.load = exports.methods = void 0;
const path_1 = __importDefault(require("path"));
const Fs = require('fs');
// ── 属性映射:标记 → MapGrid 组件全部 8 个属性的完整值 ──
const MARKER_PROPS = {
'': { _isCanWalk: true, _isCanPutGrid: true, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'CanWalk': { _isCanWalk: true, _isCanPutGrid: true, _isBestPlace: true, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'CanBeDig': { _isCanWalk: false, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: true, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'CanPut': { _isCanWalk: false, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: true, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'spawnPoint_1': { _isCanWalk: true, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'spawnPoint_2': { _isCanWalk: true, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'spawnPoint_3': { _isCanWalk: true, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'wallTarget1': { _isCanWalk: true, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'wallTarget2': { _isCanWalk: true, _isCanPutGrid: false, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: false },
'isFreePlace': { _isCanWalk: true, _isCanPutGrid: true, _isBestPlace: false, _isCanBeDig: false, _isCanPutText: false, _isCanRemove: false, _isCanBeThunder: false, _isFreePlace: true },
};
const SPAWN_MARKERS = ['spawnPoint_1', 'spawnPoint_2', 'spawnPoint_3'];
const MAPGRID_FILE_ID = 'a5Czjqnj1DIa/1qXv6uwzF';
const CELL_SIZE = 93;
const ORIGIN_X = -325.5;
const ORIGIN_Y = 418.5;
const COLS = 8;
const ROWS = 10;
function cellToWorld(index) {
const col = index % COLS;
const row = Math.floor(index / COLS);
return { x: ORIGIN_X + col * CELL_SIZE, y: ORIGIN_Y - row * CELL_SIZE };
}
/** 在 JSON 数组中按 _name 查找节点,返回索引 */
function findNodeIndex(data, name) {
for (let i = 0; i < data.length; i++) {
if (data[i] && data[i]._name === name)
return i;
}
return -1;
}
/** 获取格子的 PrefabInstance 对象 */
function getGridInstance(data, geziIdx, gridIndex) {
const gezi = data[geziIdx];
if (!gezi || !gezi._children || gridIndex >= gezi._children.length)
return null;
const gridRef = gezi._children[gridIndex];
const gridNode = data[gridRef.__id__];
if (!gridNode || !gridNode._prefab)
return null;
const prefabInfo = data[gridNode._prefab.__id__];
if (!prefabInfo || !prefabInfo.instance)
return null;
return data[prefabInfo.instance.__id__];
}
/** 清除指定格子中所有 MapGrid 组件的属性覆盖 */
function clearGridOverrides(data, geziIdx, gridIndex) {
const instance = getGridInstance(data, geziIdx, gridIndex);
if (!instance || !instance.propertyOverrides)
return;
instance.propertyOverrides = instance.propertyOverrides.filter((ref) => {
const po = data[ref.__id__];
if (!po || !po.targetInfo)
return true; // 保留非 targetInfo 的条目
const ti = data[po.targetInfo.__id__];
if (!ti || !ti.localID)
return true;
// 删除 targetInfo.localID 匹配 MapGrid 组件的覆盖
return ti.localID[0] !== MAPGRID_FILE_ID;
});
}
/** 向指定格子的 PrefabInstance 追加一条 MapGrid 属性覆盖 */
function addGridOverride(data, geziIdx, gridIndex, propName, value) {
const instance = getGridInstance(data, geziIdx, gridIndex);
if (!instance || !instance.propertyOverrides)
return;
const targetInfoId = data.length;
data.push({ __type__: 'cc.TargetInfo', localID: [MAPGRID_FILE_ID] });
const overrideId = data.length;
data.push({
__type__: 'CCPropertyOverrideInfo',
targetInfo: { __id__: targetInfoId },
propertyPath: [propName],
value: value,
});
instance.propertyOverrides.push({ __id__: overrideId });
}
/** 移动/设置指定父节点下某个子节点的坐标 */
function setChildPos(data, parentName, childName, x, y) {
const parentIdx = findNodeIndex(data, parentName);
if (parentIdx < 0)
return false;
const parent = data[parentIdx];
if (!parent._children)
return false;
for (const ref of parent._children) {
const child = data[ref.__id__];
if (child && child._name === childName) {
child._lpos = { __type__: 'cc.Vec3', x, y, z: 0 };
return true;
}
}
return false;
}
/** 从父节点中删除指定名称的子节点 */
function removeChildByName(data, parentName, childName) {
const parentIdx = findNodeIndex(data, parentName);
if (parentIdx < 0)
return;
const parent = data[parentIdx];
if (!parent._children)
return;
parent._children = parent._children.filter((ref) => {
const child = data[ref.__id__];
return !(child && child._name === childName);
});
}
/** 向父节点添加一个浅拷贝自模板的子节点(用于补充缺失的 spawnPoint) */
function copyChildFromTemplate(data, template, parentName, childName) {
const parentIdx = findNodeIndex(data, parentName);
if (parentIdx < 0)
return;
// 从模板中找到同名子节点引用
const tplParentIdx = findNodeIndex(template, parentName);
if (tplParentIdx < 0)
return;
const tplParent = template[tplParentIdx];
for (const ref of tplParent._children || []) {
const child = template[ref.__id__];
if (child && child._name === childName) {
// 将子节点及其组件深克隆追加到 data 末尾,并在父节点 _children 中引用
const cloneStartIdx = data.length;
const cloned = JSON.parse(JSON.stringify(child));
data.push(cloned);
data[parentIdx]._children.push({ __id__: cloneStartIdx });
return;
}
}
}
/**
* 应用格子数据到预制体 JSON(新增和更新共用)
*/
function applyGridData(data, template, grids) {
const geziIdx = findNodeIndex(data, '格子');
if (geziIdx < 0)
return;
// 1. 收集 spawn 位置映射 + 遍历格子清除旧覆盖 / 添加新覆盖
const spawnPositions = new Map();
for (let i = 0; i < 80; i++) {
clearGridOverrides(data, geziIdx, i);
const marker = grids[i] || '';
const props = MARKER_PROPS[marker];
if (props) {
for (const [prop, value] of Object.entries(props)) {
addGridOverride(data, geziIdx, i, prop, value);
}
}
if (SPAWN_MARKERS.includes(marker)) {
spawnPositions.set(marker, cellToWorld(i));
}
}
// 2. wallTarget1/wallTarget2 配对
const t1 = grids.indexOf('wallTarget1');
const t2 = grids.indexOf('wallTarget2');
if (t1 >= 0 && t2 >= 0) {
const p1 = cellToWorld(t1), p2 = cellToWorld(t2);
const r1 = Math.floor(t1 / COLS), c1 = t1 % COLS;
const r2 = Math.floor(t2 / COLS), c2 = t2 % COLS;
let mx, my;
if (r1 === r2) {
mx = (p1.x + p2.x) / 2;
my = p1.y;
} // 横连
else if (c1 === c2) {
mx = p1.x;
my = (p1.y + p2.y) / 2;
} // 竖连
else {
mx = (p1.x + p2.x) / 2;
my = (p1.y + p2.y) / 2;
} // 斜角
setChildPos(data, '目标点', 'wallTarget1', mx, my);
}
else if (t1 >= 0) {
const pos = cellToWorld(t1);
setChildPos(data, '目标点', 'wallTarget1', pos.x, pos.y);
}
// 3. 同步 spawn 节点:删除多余 → 补回缺失 → 设置坐标
const allSpawns = ['spawnPoint_1', 'spawnPoint_2', 'spawnPoint_3', 'spawnPoint_4', 'spawnPoint_5', 'spawnPoint_6', 'spawnPoint_7'];
for (const spName of allSpawns) {
if (spawnPositions.has(spName))
continue;
removeChildByName(data, '出怪口', spName);
}
for (const [spName, pos] of spawnPositions) {
const parentIdx = findNodeIndex(data, '出怪口');
const exists = parentIdx >= 0 && (data[parentIdx]._children || []).some((ref) => {
const child = data[ref.__id__];
return child && child._name === spName;
});
if (!exists) {
copyChildFromTemplate(data, template, '出怪口', spName);
}
setChildPos(data, '出怪口', spName, pos.x, pos.y);
}
}
// ── 扩展入口 ──
exports.methods = {
async generateMapLayers() {
try {
const projectPath = Editor.Project.path;
// 1. 读取 Excel
const excelPath = path_1.default.join(projectPath, 'assets/res/地图/地图.xls');
if (!Fs.existsSync(excelPath)) {
console.error('[地图生成] Excel 文件不存在:', excelPath);
return;
}
const xlsxPath = path_1.default.join(__dirname, '../../excel-to-json-ts/lib/xlsx.js');
const XLSX = require(xlsxPath);
const buffer = Fs.readFileSync(excelPath);
const workbook = XLSX.read(buffer, { type: 'buffer' });
// 2. 读取模板
const templatePath = path_1.default.join(projectPath, 'assets/bundles/battleMap/prefab/地图/mapLayerTemplate.prefab');
if (!Fs.existsSync(templatePath)) {
console.error('[地图生成] 模板预制体不存在:', templatePath);
return;
}
const templateJson = Fs.readFileSync(templatePath, 'utf-8');
const templateData = JSON.parse(templateJson);
const prefabDir = path_1.default.join(projectPath, 'assets/bundles/battleMap/prefab/地图');
console.log(`[地图生成] 开始处理 ${workbook.SheetNames.length} 个工作表...`);
// 3. 遍历每个工作表
for (const sheetName of workbook.SheetNames) {
const worksheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
const grids = [];
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
const raw = (rows[r] || [])[c];
grids.push((raw !== undefined && raw !== null && raw !== '') ? String(raw).trim() : '');
}
}
const prefabPath = path_1.default.join(prefabDir, `${sheetName}.prefab`);
const exists = Fs.existsSync(prefabPath);
let prefabData;
if (exists) {
// 已有预制体 → 读取后原地修改
const existingJson = Fs.readFileSync(prefabPath, 'utf-8');
prefabData = JSON.parse(existingJson);
applyGridData(prefabData, templateData, grids);
}
else {
// 新预制体 → 从模板克隆生成
prefabData = JSON.parse(JSON.stringify(templateData));
prefabData[0]._name = sheetName;
prefabData[1]._name = sheetName;
applyGridData(prefabData, templateData, grids);
}
const jsonStr = JSON.stringify(prefabData, null, 2);
const url = `db://assets/bundles/battleMap/prefab/地图/${sheetName}.prefab`;
await Editor.Message.request('asset-db', 'create-asset', url, jsonStr, { overwrite: true });
const stats = {};
for (const m of grids) {
const k = m || '(空白)';
stats[k] = (stats[k] || 0) + 1;
}
const statStr = Object.entries(stats).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}:${v}`).join(', ');
console.log(`[地图生成] ${exists ? '~' : '+'} ${sheetName}.prefab (${statStr})`);
}
console.log('[地图生成] 全部完成!');
}
catch (err) {
console.error('[地图生成] 错误:', err);
}
},
};
function load() { }
exports.load = load;
function unload() { }
exports.unload = unload;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NvdXJjZS9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGdEQUF3QjtBQUV4QixNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFekIseUNBQXlDO0FBQ3pDLE1BQU0sWUFBWSxHQUE0QztJQUMxRCxFQUFFLEVBQWUsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFHLGFBQWEsRUFBRSxJQUFJLEVBQUcsWUFBWSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUU7SUFDN0wsU0FBUyxFQUFRLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRyxhQUFhLEVBQUUsSUFBSSxFQUFHLFlBQVksRUFBRSxJQUFJLEVBQUcsV0FBVyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFO0lBQzdMLFVBQVUsRUFBTyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUcsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRTtJQUM3TCxRQUFRLEVBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUcsWUFBWSxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUU7SUFDN0wsY0FBYyxFQUFHLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRyxhQUFhLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFO0lBQzdMLGNBQWMsRUFBRyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUcsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRTtJQUM3TCxjQUFjLEVBQUcsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFHLGFBQWEsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUU7SUFDN0wsYUFBYSxFQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRyxhQUFhLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFO0lBQzdMLGFBQWEsRUFBSSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUcsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRTtJQUM3TCxhQUFhLEVBQUksRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFHLGFBQWEsRUFBRSxJQUFJLEVBQUcsWUFBWSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUc7Q0FDaE0sQ0FBQztBQUVGLE1BQU0sYUFBYSxHQUFHLENBQUMsY0FBYyxFQUFFLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQztBQUN2RSxNQUFNLGVBQWUsR0FBRyx3QkFBd0IsQ0FBQztBQUVqRCxNQUFNLFNBQVMsR0FBRyxFQUFFLENBQUM7QUFDckIsTUFBTSxRQUFRLEdBQUcsQ0FBQyxLQUFLLENBQUM7QUFDeEIsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDO0FBQ3ZCLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQztBQUNmLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUVoQixTQUFTLFdBQVcsQ0FBQyxLQUFhO0lBQzlCLE1BQU0sR0FBRyxHQUFHLEtBQUssR0FBRyxJQUFJLENBQUM7SUFDekIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDckMsT0FBTyxFQUFFLENBQUMsRUFBRSxRQUFRLEdBQUcsR0FBRyxHQUFHLFNBQVMsRUFBRSxDQUFDLEVBQUUsUUFBUSxHQUFHLEdBQUcsR0FBRyxTQUFTLEVBQUUsQ0FBQztBQUM1RSxDQUFDO0FBRUQsa0NBQWtDO0FBQ2xDLFNBQVMsYUFBYSxDQUFDLElBQVcsRUFBRSxJQUFZO0lBQzVDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ2xDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssSUFBSTtZQUFFLE9BQU8sQ0FBQyxDQUFDO0tBQ25EO0lBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUNkLENBQUM7QUFFRCw4QkFBOEI7QUFDOUIsU0FBUyxlQUFlLENBQUMsSUFBVyxFQUFFLE9BQWUsRUFBRSxTQUFpQjtJQUNwRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDM0IsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksU0FBUyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2hGLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQ