mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 04:19:30 +08:00
插件热重载
This commit is contained in:
parent
c4e0b706f9
commit
8ec41d634a
@ -81,79 +81,56 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 热重载脚本编辑及插件编写
|
* 热重载脚本编辑
|
||||||
* @param {string} data
|
* @param {string} data
|
||||||
*/
|
*/
|
||||||
async function reloadScript(data) {
|
async function reloadScript() {
|
||||||
if (data === 'plugins') {
|
// 脚本编辑略微麻烦点
|
||||||
// 插件编写比较好办
|
const before = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a;
|
||||||
const before = plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1;
|
// 这里不能用动态导入,因为动态导入会变成模块,变量就不是全局的了
|
||||||
// 这里不能用动态导入,因为动态导入会变成模块,变量就不是全局的了
|
const script = document.createElement('script');
|
||||||
const script = document.createElement('script');
|
script.src = `/project/functions.js?v=${Date.now()}`;
|
||||||
script.src = `/project/plugins.js?v=${Date.now()}`;
|
document.body.appendChild(script);
|
||||||
document.body.appendChild(script);
|
await new Promise(res => {
|
||||||
await new Promise(res => {
|
script.onload = () => res('success');
|
||||||
script.onload = () => res('success');
|
});
|
||||||
});
|
const after = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a;
|
||||||
const after = plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1;
|
// 找到差异的函数
|
||||||
// 找到差异的函数
|
for (const mod in before) {
|
||||||
for (const id in before) {
|
const fns = before[mod];
|
||||||
const fn = before[id];
|
for (const id in fns) {
|
||||||
if (typeof fn !== 'function') continue;
|
const fn = fns[id];
|
||||||
if (fn.toString() !== after[id]?.toString()) {
|
if (typeof fn !== 'function' || id === 'hasSpecial') continue;
|
||||||
|
const now = after[mod][id];
|
||||||
|
if (fn.toString() !== now.toString()) {
|
||||||
try {
|
try {
|
||||||
core.plugin[id] = after[id];
|
if (mod === 'events') {
|
||||||
core.plugin[id].call(core.plugin);
|
core.events.eventdata[id] = now;
|
||||||
|
} else if (mod === 'enemys') {
|
||||||
|
core.enemys.enemydata[id] = now;
|
||||||
|
} else if (mod === 'actions') {
|
||||||
|
core.actions.actionsdata[id] = now;
|
||||||
|
} else if (mod === 'control') {
|
||||||
|
core.control.controldata[id] = now;
|
||||||
|
} else if (mod === 'ui') {
|
||||||
|
core.ui.uidata[id] = now;
|
||||||
|
}
|
||||||
core.updateStatusBar(true, true);
|
core.updateStatusBar(true, true);
|
||||||
console.log(`plugin hot reload: ${id}`);
|
console.log(`function hot reload: ${mod}.${id}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (data === 'functions') {
|
|
||||||
// 脚本编辑略微麻烦点
|
|
||||||
const before = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a;
|
|
||||||
// 这里不能用动态导入,因为动态导入会变成模块,变量就不是全局的了
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = `/project/functions.js?v=${Date.now()}`;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
await new Promise(res => {
|
|
||||||
script.onload = () => res('success');
|
|
||||||
});
|
|
||||||
const after = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a;
|
|
||||||
// 找到差异的函数
|
|
||||||
for (const mod in before) {
|
|
||||||
const fns = before[mod];
|
|
||||||
for (const id in fns) {
|
|
||||||
const fn = fns[id];
|
|
||||||
if (typeof fn !== 'function' || id === 'hasSpecial')
|
|
||||||
continue;
|
|
||||||
const now = after[mod][id];
|
|
||||||
if (fn.toString() !== now.toString()) {
|
|
||||||
try {
|
|
||||||
if (mod === 'events') {
|
|
||||||
core.events.eventdata[id] = now;
|
|
||||||
} else if (mod === 'enemys') {
|
|
||||||
core.enemys.enemydata[id] = now;
|
|
||||||
} else if (mod === 'actions') {
|
|
||||||
core.actions.actionsdata[id] = now;
|
|
||||||
} else if (mod === 'control') {
|
|
||||||
core.control.controldata[id] = now;
|
|
||||||
} else if (mod === 'ui') {
|
|
||||||
core.ui.uidata[id] = now;
|
|
||||||
}
|
|
||||||
core.updateStatusBar(true, true);
|
|
||||||
console.log(`function hot reload: ${mod}.${id}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function reloadPlugin(data) {
|
||||||
|
// 直接import就完事了
|
||||||
|
await import(`/project/plugin/${data}.js?v=${Date.now()}`);
|
||||||
|
console.log(`plugin hot reload: ${data}.js`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 属性热重载,包括全塔属性等
|
* 属性热重载,包括全塔属性等
|
||||||
* @param {string} data
|
* @param {string} data
|
||||||
@ -239,6 +216,7 @@
|
|||||||
if (type === 'data') reloadData(file);
|
if (type === 'data') reloadData(file);
|
||||||
if (type === 'floor') reloadFloor(file);
|
if (type === 'floor') reloadFloor(file);
|
||||||
if (type === 'script') reloadScript(file);
|
if (type === 'script') reloadScript(file);
|
||||||
|
if (type === 'plugin') reloadPlugin(file);
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ next();
|
|||||||
let repStart;
|
let repStart;
|
||||||
|
|
||||||
const listenedFloors = [];
|
const listenedFloors = [];
|
||||||
|
const listenedPlugins = [];
|
||||||
|
|
||||||
// ----- GET file
|
// ----- GET file
|
||||||
|
|
||||||
@ -172,6 +173,7 @@ async function writeFile(req, res) {
|
|||||||
const value = /&value=[^]+/.exec(data)[0].slice(7);
|
const value = /&value=[^]+/.exec(data)[0].slice(7);
|
||||||
await fs.writeFile(dir, value, { encoding: type });
|
await fs.writeFile(dir, value, { encoding: type });
|
||||||
testWatchFloor(name);
|
testWatchFloor(name);
|
||||||
|
testWatchPlugin(name);
|
||||||
if (name.endsWith('project/events.js')) doDeclaration('events', value);
|
if (name.endsWith('project/events.js')) doDeclaration('events', value);
|
||||||
if (name.endsWith('project/items.js')) doDeclaration('items', value);
|
if (name.endsWith('project/items.js')) doDeclaration('items', value);
|
||||||
if (name.endsWith('project/maps.js')) doDeclaration('maps', value);
|
if (name.endsWith('project/maps.js')) doDeclaration('maps', value);
|
||||||
@ -332,7 +334,7 @@ async function watch() {
|
|||||||
watchOneFloor(v.slice(15));
|
watchOneFloor(v.slice(15));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 脚本编辑 及 插件 热重载
|
// 脚本编辑 热重载
|
||||||
const scripts = await extract('project/functions.js', 'project/plugins.js');
|
const scripts = await extract('project/functions.js', 'project/plugins.js');
|
||||||
scripts.forEach(v => {
|
scripts.forEach(v => {
|
||||||
const dir = path.resolve(__dirname, v);
|
const dir = path.resolve(__dirname, v);
|
||||||
@ -343,6 +345,12 @@ async function watch() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 插件热重载
|
||||||
|
const plugins = await extract('project/plugin/*.js');
|
||||||
|
plugins.forEach(v => {
|
||||||
|
watchOnePlugin(v.slice(15));
|
||||||
|
});
|
||||||
|
|
||||||
// 数据热重载
|
// 数据热重载
|
||||||
const datas = (await extract('project/*.js')).filter(
|
const datas = (await extract('project/*.js')).filter(
|
||||||
v => !v.endsWith('functions.js') && !v.endsWith('plugins.js')
|
v => !v.endsWith('functions.js') && !v.endsWith('plugins.js')
|
||||||
@ -370,6 +378,19 @@ function testWatchFloor(url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测是否是楼层文件并进行监听
|
||||||
|
* @param {string} url 要测试的路径
|
||||||
|
*/
|
||||||
|
function testWatchPlugin(url) {
|
||||||
|
if (/project(\/|\\)plugin(\/|\\).*\.js/.test(url)) {
|
||||||
|
const f = url.slice(15);
|
||||||
|
if (!listenedFloors.includes(f.slice(0, -3))) {
|
||||||
|
watchOnePlugin(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听一个楼层文件
|
* 监听一个楼层文件
|
||||||
* @param {string} file 要监听的文件
|
* @param {string} file 要监听的文件
|
||||||
@ -386,6 +407,22 @@ function watchOneFloor(file) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听一个楼层文件
|
||||||
|
* @param {string} file 要监听的文件
|
||||||
|
*/
|
||||||
|
function watchOnePlugin(file) {
|
||||||
|
if (!/.*\.js/.test(file)) return;
|
||||||
|
const f = file.slice(0, -3);
|
||||||
|
listenedFloors.push(file.slice(0, -3));
|
||||||
|
fss.watchFile(`project/plugin/${file}`, { interval: 500 }, () => {
|
||||||
|
const plugin = f;
|
||||||
|
if (hotReloadData.includes(`@@plugin:${plugin}`)) return;
|
||||||
|
hotReloadData += `@@plugin:${plugin}`;
|
||||||
|
console.log(`plugin hot reload: ${plugin}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改部分文件后重新加载及热重载
|
* 修改部分文件后重新加载及热重载
|
||||||
* @param {http.IncomingMessage} req
|
* @param {http.IncomingMessage} req
|
||||||
@ -411,189 +448,6 @@ function reload(req, res, hot = false) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- replay debugger
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 录像调试
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
function replay(req, res) {
|
|
||||||
req.on('data', async chunk => {
|
|
||||||
if (chunk.toString() === 'test' && !replayed) {
|
|
||||||
replayed = true;
|
|
||||||
try {
|
|
||||||
await fs.mkdir(path.resolve(__dirname, '_replay'));
|
|
||||||
await fs.mkdir(path.resolve(__dirname, '_replay/status'));
|
|
||||||
await fs.mkdir(path.resolve(__dirname, '_replay/save'));
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.readFile(
|
|
||||||
path.resolve(__dirname, '_replay/.info'),
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
await fs.writeFile(
|
|
||||||
path.resolve(__dirname, '_replay/.info'),
|
|
||||||
`{
|
|
||||||
"cnt": 0
|
|
||||||
}`,
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const data = fss.readFileSync(
|
|
||||||
path.resolve(__dirname, '_replay/.info'),
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
repStart = Number(JSON.parse(data).cnt);
|
|
||||||
console.log(`服务器录像调试模块已开始服务`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('end', () => {
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取未占用的状态栏位
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
async function replayCnt() {
|
|
||||||
const data = `{
|
|
||||||
"cnt": ${++repStart}
|
|
||||||
}`;
|
|
||||||
fss.writeFileSync(path.resolve(__dirname, '_replay/.info'), data, 'utf-8');
|
|
||||||
|
|
||||||
return repStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 写入
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
async function replayWrite(req, res) {
|
|
||||||
const data = await getPostData(req);
|
|
||||||
const n = await replayCnt();
|
|
||||||
|
|
||||||
if (isNaN(n)) res.end('@error');
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
fs.writeFile(
|
|
||||||
path.resolve(__dirname, '_replay/.info'),
|
|
||||||
`{
|
|
||||||
"cnt": ${n + 1}
|
|
||||||
}`,
|
|
||||||
'utf-8'
|
|
||||||
),
|
|
||||||
fs.writeFile(
|
|
||||||
path.resolve(__dirname, `_replay/status/${n}.rep`),
|
|
||||||
data,
|
|
||||||
'utf-8'
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
|
|
||||||
res.end(n.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 比对录像与本地数据
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
async function replayCheck(req, res) {
|
|
||||||
const ans = await getPostData(req);
|
|
||||||
const [n, data] = ans.split('@-|-@');
|
|
||||||
|
|
||||||
const local = (
|
|
||||||
await fs.readFile(
|
|
||||||
path.resolve(__dirname, `_replay/status/${n}.rep`),
|
|
||||||
'utf-8'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.split('@---@')
|
|
||||||
.map(v => JSON.parse(v));
|
|
||||||
const rep = data.split('@---@').map(v => JSON.parse(v));
|
|
||||||
|
|
||||||
if (local.length !== rep.length) return res.end('false');
|
|
||||||
|
|
||||||
const check = (a, b) => {
|
|
||||||
if (a === b) return true;
|
|
||||||
if (typeof a !== typeof b) return false;
|
|
||||||
if (typeof a === 'object' && a !== null) {
|
|
||||||
for (const j in a) {
|
|
||||||
if (j === 'statistics' || j === 'timeout') continue; // 忽略统计信息
|
|
||||||
const aa = a[j];
|
|
||||||
const bb = b[j];
|
|
||||||
if (!check(aa, bb)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof a === 'boolean' ||
|
|
||||||
typeof a === 'number' ||
|
|
||||||
typeof a === 'string' ||
|
|
||||||
typeof a === 'symbol' ||
|
|
||||||
typeof a === 'undefined' ||
|
|
||||||
typeof a === 'bigint' ||
|
|
||||||
a === null
|
|
||||||
) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0; i < local.length; i++) {
|
|
||||||
const a = local[i];
|
|
||||||
const b = rep[i];
|
|
||||||
if (!check(a, b)) return res.end('false');
|
|
||||||
}
|
|
||||||
|
|
||||||
res.end('true');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取本地属性
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
async function replayGet(req, res, dir) {
|
|
||||||
const ans = Number(await getPostData(req));
|
|
||||||
|
|
||||||
const data = await fs.readFile(
|
|
||||||
path.resolve(__dirname, `_replay/${dir}/${ans}.rep`)
|
|
||||||
);
|
|
||||||
res.end(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 录像回放存档
|
|
||||||
* @param {http.IncomingMessage} req
|
|
||||||
* @param {http.ServerResponse<http.IncomingMessage> & {req: http.IncomingMessage;}} res
|
|
||||||
*/
|
|
||||||
async function replaySave(req, res) {
|
|
||||||
const data = await getPostData(req);
|
|
||||||
const [cnt, save] = data.split('@-|-@');
|
|
||||||
|
|
||||||
if (isNaN(Number(cnt))) {
|
|
||||||
console.log('Invalid input of save cnt');
|
|
||||||
res.end('@error: 不合法的录像存档信息');
|
|
||||||
}
|
|
||||||
|
|
||||||
await fs.writeFile(
|
|
||||||
path.resolve(__dirname, `_replay/save/${cnt}.rep`),
|
|
||||||
save,
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
|
|
||||||
res.end('success');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- declaration
|
// ----- declaration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user