feat(noknockback): 新增拒绝击退开关,中弹不再被推开
在本地坦克实体的 kz7 事件派发处丢弃外力事件(ODt:作用点/方向/强度),坦克物理收不到就不产生位移与旋转;悬挂与行驶仍走 m9k 直调,不受影响。面板新增「拒绝击退」开关。字段名走 hornet_schema。
This commit is contained in:
1 parent
692b812e58
commit
bea22bb5f9
6 files changed
+480
-11
No files matched your search
@@ -280,6 +280,12 @@
|
|||||||
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
||||||
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
||||||
|
|
||||||
|
// ---- 实体事件总线 / 外力事件(ODt)----
|
||||||
|
'Entity.Dispatch': 'kz7()', // 向实体内所有订阅者派发事件
|
||||||
|
'Event.PushPoint': 'o13i_1', // 外力事件:作用点(O$ 向量)
|
||||||
|
'Event.PushDir': 'p13i_1', // 外力事件:方向(O$ 向量)
|
||||||
|
'Event.PushStrength': 'q13i_1', // 外力事件:强度(坦克物理交给 m9k)
|
||||||
|
|
||||||
// ---- 血量组件(Vkt)----
|
// ---- 血量组件(Vkt)----
|
||||||
'Health.Max': 'p12o_1',
|
'Health.Max': 'p12o_1',
|
||||||
'Health.Current': 'q12o_1',
|
'Health.Current': 'q12o_1',
|
||||||
@@ -6348,6 +6354,156 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// ===== hornet_noknockback.js =====
|
||||||
|
// hornet_noknockback.js — 拒绝击退(中弹不再被推着走)
|
||||||
|
// 放在控制面板「拒绝击退」开关里,只作用于**本地坦克**。
|
||||||
|
//
|
||||||
|
// 引擎里「被打中弹开」的完整链路(module_87072 / module_55088):
|
||||||
|
// 碰撞/武器命中 → 目标坦克实体派发 ODt 事件(外力事件):
|
||||||
|
// ODt.o13i_1 = 作用点,ODt.p13i_1 = 方向,ODt.q13i_1 = 强度
|
||||||
|
// → 坦克物理组件 ejt 在 oz4() 里订阅它(callableName = "applyForce"):
|
||||||
|
// t.pbk().m9k(点, 方向, 强度) // m9k = 在点处施加力,直接进速度/角速度
|
||||||
|
// → 车体被推开 / 被弹得转圈
|
||||||
|
//
|
||||||
|
// 为什么在「事件派发」这一层拦:
|
||||||
|
// m9k 同时被悬挂/弹簧(Gbt.s151)和自身开炮后座使用,直接封 m9k 会把悬挂也废掉;
|
||||||
|
// 而 ODt 只承载外力(炮弹/地雷/撞击),拦掉它 → 只失去被推动,悬挂与驾驶完全不受影响。
|
||||||
|
//
|
||||||
|
// 拦法:给本地坦克实体实例的 kz7(事件派发方法)套一层,遇到外力事件直接丢弃。
|
||||||
|
// 只影响本客户端本地坦克;自己的开炮后座走的是直接 m9k 调用,不受影响。
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Lib = window.__hornetLib__;
|
||||||
|
if (!Lib) {
|
||||||
|
console.error('[拒绝击退] 请先加载 hornet_lib.js');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 字段抽象层(语义名 → 匿名字段,总表在 hornet_schema.js)=====
|
||||||
|
var Schema = window.__hornetSchema__ || null;
|
||||||
|
function Fld(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.FieldName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
function Mth(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.MethodName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
var FPushPoint = Fld('Event.PushPoint', 'o13i_1'); // 外力作用点
|
||||||
|
var FPushDir = Fld('Event.PushDir', 'p13i_1'); // 外力方向
|
||||||
|
var FPushStrength = Fld('Event.PushStrength', 'q13i_1'); // 外力强度
|
||||||
|
var MDispatch = Mth('Entity.Dispatch', 'kz7'); // 实体事件派发
|
||||||
|
|
||||||
|
var Stat = {
|
||||||
|
running: false,
|
||||||
|
blocked: 0, // 累计拦下的外力事件数
|
||||||
|
tankId: -1
|
||||||
|
};
|
||||||
|
|
||||||
|
var PatchedTank = null; // 当前已接管的坦克实体
|
||||||
|
var OrigDispatch = null; // 该实体原来的派发方法
|
||||||
|
|
||||||
|
// 外力事件识别(ODt):作用点 + 方向 + 强度 + r13i 写入方法
|
||||||
|
// ⚠ 不能用 instanceof:ODt 类没有对外导出,且每版类对象都会重建
|
||||||
|
function IsPushEvent(Event) {
|
||||||
|
if (!Event || typeof Event !== 'object') return false;
|
||||||
|
if (typeof Event[FPushStrength] !== 'number') return false;
|
||||||
|
var Point = Event[FPushPoint];
|
||||||
|
var Dir = Event[FPushDir];
|
||||||
|
if (!Point || !Dir) return false;
|
||||||
|
if (typeof Point.f20_1 !== 'number' || typeof Dir.f20_1 !== 'number') return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地坦克:拥有中的优先;死亡时退回观察目标(此时不参与战斗,影响可忽略)
|
||||||
|
function GetLocalTank() {
|
||||||
|
var Gm = window.__gameMode__;
|
||||||
|
if (!Gm) return null;
|
||||||
|
try { if (Gm.u10b_1) return Gm.u10b_1; } catch (e) {}
|
||||||
|
try { if (Gm.t10b_1) return Gm.t10b_1; } catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Unpatch() {
|
||||||
|
if (PatchedTank && OrigDispatch) {
|
||||||
|
try { PatchedTank[MDispatch] = OrigDispatch; } catch (e) {}
|
||||||
|
}
|
||||||
|
PatchedTank = null;
|
||||||
|
OrigDispatch = null;
|
||||||
|
Stat.tankId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Patch(Tank) {
|
||||||
|
if (!Tank) return;
|
||||||
|
if (PatchedTank === Tank) return;
|
||||||
|
Unpatch();
|
||||||
|
var Orig = Tank[MDispatch];
|
||||||
|
if (typeof Orig !== 'function') return;
|
||||||
|
OrigDispatch = Orig;
|
||||||
|
Tank[MDispatch] = function (Event) {
|
||||||
|
// 外力事件:直接吞掉(坦克物理收不到 → 不产生位移/旋转)
|
||||||
|
if (Stat.running && IsPushEvent(Event)) {
|
||||||
|
Stat.blocked++;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return OrigDispatch.apply(this, arguments);
|
||||||
|
};
|
||||||
|
PatchedTank = Tank;
|
||||||
|
Stat.tankId = (Tank.iz1_1 !== undefined) ? Tank.iz1_1 : -1;
|
||||||
|
console.log('[拒绝击退] 已接管本地坦克事件派发 id=' + Stat.tankId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Loop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
try {
|
||||||
|
var Tank = GetLocalTank();
|
||||||
|
if (Tank && Tank !== PatchedTank) Patch(Tank); // 换车/重生:实体换了要重新套
|
||||||
|
if (!Tank && PatchedTank) Unpatch(); // 离开战局:还原
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start() {
|
||||||
|
if (Stat.running) return;
|
||||||
|
Stat.running = true;
|
||||||
|
Stat.blocked = 0;
|
||||||
|
Patch(GetLocalTank());
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
console.log('[拒绝击退] 已启动(中弹/撞击不再推动本地坦克;悬挂、行驶、自身后座不受影响)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
Stat.running = false;
|
||||||
|
Unpatch();
|
||||||
|
console.log('[拒绝击退] 已停止,事件派发已还原');
|
||||||
|
}
|
||||||
|
|
||||||
|
var Tool = {
|
||||||
|
Start: function () { _start(); },
|
||||||
|
Stop: function () { _stop(); },
|
||||||
|
GetRunning: function () { return Stat.running; },
|
||||||
|
Status: function () {
|
||||||
|
if (!Stat.running) return '已停止';
|
||||||
|
return PatchedTank ? ('拦截 ' + Stat.blocked + ' 次') : '等待坦克';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__hornetTools__ = window.__hornetTools__ || {};
|
||||||
|
window.__hornetTools__.NoKnockback = Tool;
|
||||||
|
window.__hornetNoKnockback__ = {
|
||||||
|
IsPushEvent: IsPushEvent,
|
||||||
|
GetStat: function () {
|
||||||
|
return { running: Stat.running, blocked: Stat.blocked, tankId: Stat.tankId };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('[3DTank] 拒绝击退模块已加载');
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
// ===== hornet_panel.js =====
|
// ===== hornet_panel.js =====
|
||||||
// ===== 3DTank 控制面板 =====
|
// ===== 3DTank 控制面板 =====
|
||||||
// 功能:Alt+T 切换面板显示,控制各工具开关
|
// 功能:Alt+T 切换面板显示,控制各工具开关
|
||||||
@@ -6501,14 +6657,15 @@
|
|||||||
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
||||||
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
||||||
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
||||||
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip }
|
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip },
|
||||||
|
{ key: 'NoKnockback', label: '拒绝击退', obj: tools.NoKnockback }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 工具启用状态(持久化 + 默认启用)=====
|
// ===== 工具启用状态(持久化 + 默认启用)=====
|
||||||
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
||||||
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip'];
|
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip', 'NoKnockback'];
|
||||||
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false };
|
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false, NoKnockback: false };
|
||||||
var ToolEnabled = {};
|
var ToolEnabled = {};
|
||||||
try {
|
try {
|
||||||
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
||||||
|
|||||||
+160
-3
@@ -280,6 +280,12 @@
|
|||||||
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
||||||
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
||||||
|
|
||||||
|
// ---- 实体事件总线 / 外力事件(ODt)----
|
||||||
|
'Entity.Dispatch': 'kz7()', // 向实体内所有订阅者派发事件
|
||||||
|
'Event.PushPoint': 'o13i_1', // 外力事件:作用点(O$ 向量)
|
||||||
|
'Event.PushDir': 'p13i_1', // 外力事件:方向(O$ 向量)
|
||||||
|
'Event.PushStrength': 'q13i_1', // 外力事件:强度(坦克物理交给 m9k)
|
||||||
|
|
||||||
// ---- 血量组件(Vkt)----
|
// ---- 血量组件(Vkt)----
|
||||||
'Health.Max': 'p12o_1',
|
'Health.Max': 'p12o_1',
|
||||||
'Health.Current': 'q12o_1',
|
'Health.Current': 'q12o_1',
|
||||||
@@ -6348,6 +6354,156 @@
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// ===== hornet_noknockback.js =====
|
||||||
|
// hornet_noknockback.js — 拒绝击退(中弹不再被推着走)
|
||||||
|
// 放在控制面板「拒绝击退」开关里,只作用于**本地坦克**。
|
||||||
|
//
|
||||||
|
// 引擎里「被打中弹开」的完整链路(module_87072 / module_55088):
|
||||||
|
// 碰撞/武器命中 → 目标坦克实体派发 ODt 事件(外力事件):
|
||||||
|
// ODt.o13i_1 = 作用点,ODt.p13i_1 = 方向,ODt.q13i_1 = 强度
|
||||||
|
// → 坦克物理组件 ejt 在 oz4() 里订阅它(callableName = "applyForce"):
|
||||||
|
// t.pbk().m9k(点, 方向, 强度) // m9k = 在点处施加力,直接进速度/角速度
|
||||||
|
// → 车体被推开 / 被弹得转圈
|
||||||
|
//
|
||||||
|
// 为什么在「事件派发」这一层拦:
|
||||||
|
// m9k 同时被悬挂/弹簧(Gbt.s151)和自身开炮后座使用,直接封 m9k 会把悬挂也废掉;
|
||||||
|
// 而 ODt 只承载外力(炮弹/地雷/撞击),拦掉它 → 只失去被推动,悬挂与驾驶完全不受影响。
|
||||||
|
//
|
||||||
|
// 拦法:给本地坦克实体实例的 kz7(事件派发方法)套一层,遇到外力事件直接丢弃。
|
||||||
|
// 只影响本客户端本地坦克;自己的开炮后座走的是直接 m9k 调用,不受影响。
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Lib = window.__hornetLib__;
|
||||||
|
if (!Lib) {
|
||||||
|
console.error('[拒绝击退] 请先加载 hornet_lib.js');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 字段抽象层(语义名 → 匿名字段,总表在 hornet_schema.js)=====
|
||||||
|
var Schema = window.__hornetSchema__ || null;
|
||||||
|
function Fld(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.FieldName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
function Mth(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.MethodName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
var FPushPoint = Fld('Event.PushPoint', 'o13i_1'); // 外力作用点
|
||||||
|
var FPushDir = Fld('Event.PushDir', 'p13i_1'); // 外力方向
|
||||||
|
var FPushStrength = Fld('Event.PushStrength', 'q13i_1'); // 外力强度
|
||||||
|
var MDispatch = Mth('Entity.Dispatch', 'kz7'); // 实体事件派发
|
||||||
|
|
||||||
|
var Stat = {
|
||||||
|
running: false,
|
||||||
|
blocked: 0, // 累计拦下的外力事件数
|
||||||
|
tankId: -1
|
||||||
|
};
|
||||||
|
|
||||||
|
var PatchedTank = null; // 当前已接管的坦克实体
|
||||||
|
var OrigDispatch = null; // 该实体原来的派发方法
|
||||||
|
|
||||||
|
// 外力事件识别(ODt):作用点 + 方向 + 强度 + r13i 写入方法
|
||||||
|
// ⚠ 不能用 instanceof:ODt 类没有对外导出,且每版类对象都会重建
|
||||||
|
function IsPushEvent(Event) {
|
||||||
|
if (!Event || typeof Event !== 'object') return false;
|
||||||
|
if (typeof Event[FPushStrength] !== 'number') return false;
|
||||||
|
var Point = Event[FPushPoint];
|
||||||
|
var Dir = Event[FPushDir];
|
||||||
|
if (!Point || !Dir) return false;
|
||||||
|
if (typeof Point.f20_1 !== 'number' || typeof Dir.f20_1 !== 'number') return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地坦克:拥有中的优先;死亡时退回观察目标(此时不参与战斗,影响可忽略)
|
||||||
|
function GetLocalTank() {
|
||||||
|
var Gm = window.__gameMode__;
|
||||||
|
if (!Gm) return null;
|
||||||
|
try { if (Gm.u10b_1) return Gm.u10b_1; } catch (e) {}
|
||||||
|
try { if (Gm.t10b_1) return Gm.t10b_1; } catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Unpatch() {
|
||||||
|
if (PatchedTank && OrigDispatch) {
|
||||||
|
try { PatchedTank[MDispatch] = OrigDispatch; } catch (e) {}
|
||||||
|
}
|
||||||
|
PatchedTank = null;
|
||||||
|
OrigDispatch = null;
|
||||||
|
Stat.tankId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Patch(Tank) {
|
||||||
|
if (!Tank) return;
|
||||||
|
if (PatchedTank === Tank) return;
|
||||||
|
Unpatch();
|
||||||
|
var Orig = Tank[MDispatch];
|
||||||
|
if (typeof Orig !== 'function') return;
|
||||||
|
OrigDispatch = Orig;
|
||||||
|
Tank[MDispatch] = function (Event) {
|
||||||
|
// 外力事件:直接吞掉(坦克物理收不到 → 不产生位移/旋转)
|
||||||
|
if (Stat.running && IsPushEvent(Event)) {
|
||||||
|
Stat.blocked++;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return OrigDispatch.apply(this, arguments);
|
||||||
|
};
|
||||||
|
PatchedTank = Tank;
|
||||||
|
Stat.tankId = (Tank.iz1_1 !== undefined) ? Tank.iz1_1 : -1;
|
||||||
|
console.log('[拒绝击退] 已接管本地坦克事件派发 id=' + Stat.tankId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Loop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
try {
|
||||||
|
var Tank = GetLocalTank();
|
||||||
|
if (Tank && Tank !== PatchedTank) Patch(Tank); // 换车/重生:实体换了要重新套
|
||||||
|
if (!Tank && PatchedTank) Unpatch(); // 离开战局:还原
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start() {
|
||||||
|
if (Stat.running) return;
|
||||||
|
Stat.running = true;
|
||||||
|
Stat.blocked = 0;
|
||||||
|
Patch(GetLocalTank());
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
console.log('[拒绝击退] 已启动(中弹/撞击不再推动本地坦克;悬挂、行驶、自身后座不受影响)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
Stat.running = false;
|
||||||
|
Unpatch();
|
||||||
|
console.log('[拒绝击退] 已停止,事件派发已还原');
|
||||||
|
}
|
||||||
|
|
||||||
|
var Tool = {
|
||||||
|
Start: function () { _start(); },
|
||||||
|
Stop: function () { _stop(); },
|
||||||
|
GetRunning: function () { return Stat.running; },
|
||||||
|
Status: function () {
|
||||||
|
if (!Stat.running) return '已停止';
|
||||||
|
return PatchedTank ? ('拦截 ' + Stat.blocked + ' 次') : '等待坦克';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__hornetTools__ = window.__hornetTools__ || {};
|
||||||
|
window.__hornetTools__.NoKnockback = Tool;
|
||||||
|
window.__hornetNoKnockback__ = {
|
||||||
|
IsPushEvent: IsPushEvent,
|
||||||
|
GetStat: function () {
|
||||||
|
return { running: Stat.running, blocked: Stat.blocked, tankId: Stat.tankId };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('[3DTank] 拒绝击退模块已加载');
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
// ===== hornet_panel.js =====
|
// ===== hornet_panel.js =====
|
||||||
// ===== 3DTank 控制面板 =====
|
// ===== 3DTank 控制面板 =====
|
||||||
// 功能:Alt+T 切换面板显示,控制各工具开关
|
// 功能:Alt+T 切换面板显示,控制各工具开关
|
||||||
@@ -6501,14 +6657,15 @@
|
|||||||
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
||||||
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
||||||
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
||||||
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip }
|
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip },
|
||||||
|
{ key: 'NoKnockback', label: '拒绝击退', obj: tools.NoKnockback }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 工具启用状态(持久化 + 默认启用)=====
|
// ===== 工具启用状态(持久化 + 默认启用)=====
|
||||||
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
||||||
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip'];
|
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip', 'NoKnockback'];
|
||||||
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false };
|
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false, NoKnockback: false };
|
||||||
var ToolEnabled = {};
|
var ToolEnabled = {};
|
||||||
try {
|
try {
|
||||||
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
||||||
|
|||||||
+3
-2
@@ -26,8 +26,9 @@ FILES = [
|
|||||||
"hornet_warsandbox.js", # 9. 战争沙盘模块 -> __hornetTools__.WarSandbox
|
"hornet_warsandbox.js", # 9. 战争沙盘模块 -> __hornetTools__.WarSandbox
|
||||||
"hornet_mouse.js", # 10. 鼠标输入稳定器 -> __hornetTools__.Mouse
|
"hornet_mouse.js", # 10. 鼠标输入稳定器 -> __hornetTools__.Mouse
|
||||||
"hornet_noclip.js", # 11. 穿坦克(忽略玩家碰撞)-> __hornetTools__.NoClip
|
"hornet_noclip.js", # 11. 穿坦克(忽略玩家碰撞)-> __hornetTools__.NoClip
|
||||||
"hornet_panel.js", # 12. 控制面板(Alt+T + HUD)
|
"hornet_noknockback.js", # 12. 拒绝击退(中弹不再被推开)-> __hornetTools__.NoKnockback
|
||||||
"hornet_prefetch.js", # 13. 车库资源预热(战局空闲时后台加载车库所需资源)
|
"hornet_panel.js", # 13. 控制面板(Alt+T + HUD)
|
||||||
|
"hornet_prefetch.js", # 14. 车库资源预热(战局空闲时后台加载车库所需资源)
|
||||||
]
|
]
|
||||||
|
|
||||||
HEADER = """// ============================================================
|
HEADER = """// ============================================================
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
// hornet_noknockback.js — 拒绝击退(中弹不再被推着走)
|
||||||
|
// 放在控制面板「拒绝击退」开关里,只作用于**本地坦克**。
|
||||||
|
//
|
||||||
|
// 引擎里「被打中弹开」的完整链路(module_87072 / module_55088):
|
||||||
|
// 碰撞/武器命中 → 目标坦克实体派发 ODt 事件(外力事件):
|
||||||
|
// ODt.o13i_1 = 作用点,ODt.p13i_1 = 方向,ODt.q13i_1 = 强度
|
||||||
|
// → 坦克物理组件 ejt 在 oz4() 里订阅它(callableName = "applyForce"):
|
||||||
|
// t.pbk().m9k(点, 方向, 强度) // m9k = 在点处施加力,直接进速度/角速度
|
||||||
|
// → 车体被推开 / 被弹得转圈
|
||||||
|
//
|
||||||
|
// 为什么在「事件派发」这一层拦:
|
||||||
|
// m9k 同时被悬挂/弹簧(Gbt.s151)和自身开炮后座使用,直接封 m9k 会把悬挂也废掉;
|
||||||
|
// 而 ODt 只承载外力(炮弹/地雷/撞击),拦掉它 → 只失去被推动,悬挂与驾驶完全不受影响。
|
||||||
|
//
|
||||||
|
// 拦法:给本地坦克实体实例的 kz7(事件派发方法)套一层,遇到外力事件直接丢弃。
|
||||||
|
// 只影响本客户端本地坦克;自己的开炮后座走的是直接 m9k 调用,不受影响。
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Lib = window.__hornetLib__;
|
||||||
|
if (!Lib) {
|
||||||
|
console.error('[拒绝击退] 请先加载 hornet_lib.js');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 字段抽象层(语义名 → 匿名字段,总表在 hornet_schema.js)=====
|
||||||
|
var Schema = window.__hornetSchema__ || null;
|
||||||
|
function Fld(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.FieldName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
function Mth(Key, Fallback) {
|
||||||
|
var N = Schema ? Schema.MethodName(Key) : null;
|
||||||
|
return N || Fallback;
|
||||||
|
}
|
||||||
|
var FPushPoint = Fld('Event.PushPoint', 'o13i_1'); // 外力作用点
|
||||||
|
var FPushDir = Fld('Event.PushDir', 'p13i_1'); // 外力方向
|
||||||
|
var FPushStrength = Fld('Event.PushStrength', 'q13i_1'); // 外力强度
|
||||||
|
var MDispatch = Mth('Entity.Dispatch', 'kz7'); // 实体事件派发
|
||||||
|
|
||||||
|
var Stat = {
|
||||||
|
running: false,
|
||||||
|
blocked: 0, // 累计拦下的外力事件数
|
||||||
|
tankId: -1
|
||||||
|
};
|
||||||
|
|
||||||
|
var PatchedTank = null; // 当前已接管的坦克实体
|
||||||
|
var OrigDispatch = null; // 该实体原来的派发方法
|
||||||
|
|
||||||
|
// 外力事件识别(ODt):作用点 + 方向 + 强度 + r13i 写入方法
|
||||||
|
// ⚠ 不能用 instanceof:ODt 类没有对外导出,且每版类对象都会重建
|
||||||
|
function IsPushEvent(Event) {
|
||||||
|
if (!Event || typeof Event !== 'object') return false;
|
||||||
|
if (typeof Event[FPushStrength] !== 'number') return false;
|
||||||
|
var Point = Event[FPushPoint];
|
||||||
|
var Dir = Event[FPushDir];
|
||||||
|
if (!Point || !Dir) return false;
|
||||||
|
if (typeof Point.f20_1 !== 'number' || typeof Dir.f20_1 !== 'number') return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地坦克:拥有中的优先;死亡时退回观察目标(此时不参与战斗,影响可忽略)
|
||||||
|
function GetLocalTank() {
|
||||||
|
var Gm = window.__gameMode__;
|
||||||
|
if (!Gm) return null;
|
||||||
|
try { if (Gm.u10b_1) return Gm.u10b_1; } catch (e) {}
|
||||||
|
try { if (Gm.t10b_1) return Gm.t10b_1; } catch (e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Unpatch() {
|
||||||
|
if (PatchedTank && OrigDispatch) {
|
||||||
|
try { PatchedTank[MDispatch] = OrigDispatch; } catch (e) {}
|
||||||
|
}
|
||||||
|
PatchedTank = null;
|
||||||
|
OrigDispatch = null;
|
||||||
|
Stat.tankId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Patch(Tank) {
|
||||||
|
if (!Tank) return;
|
||||||
|
if (PatchedTank === Tank) return;
|
||||||
|
Unpatch();
|
||||||
|
var Orig = Tank[MDispatch];
|
||||||
|
if (typeof Orig !== 'function') return;
|
||||||
|
OrigDispatch = Orig;
|
||||||
|
Tank[MDispatch] = function (Event) {
|
||||||
|
// 外力事件:直接吞掉(坦克物理收不到 → 不产生位移/旋转)
|
||||||
|
if (Stat.running && IsPushEvent(Event)) {
|
||||||
|
Stat.blocked++;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return OrigDispatch.apply(this, arguments);
|
||||||
|
};
|
||||||
|
PatchedTank = Tank;
|
||||||
|
Stat.tankId = (Tank.iz1_1 !== undefined) ? Tank.iz1_1 : -1;
|
||||||
|
console.log('[拒绝击退] 已接管本地坦克事件派发 id=' + Stat.tankId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Loop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
try {
|
||||||
|
var Tank = GetLocalTank();
|
||||||
|
if (Tank && Tank !== PatchedTank) Patch(Tank); // 换车/重生:实体换了要重新套
|
||||||
|
if (!Tank && PatchedTank) Unpatch(); // 离开战局:还原
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start() {
|
||||||
|
if (Stat.running) return;
|
||||||
|
Stat.running = true;
|
||||||
|
Stat.blocked = 0;
|
||||||
|
Patch(GetLocalTank());
|
||||||
|
requestAnimationFrame(Loop);
|
||||||
|
console.log('[拒绝击退] 已启动(中弹/撞击不再推动本地坦克;悬挂、行驶、自身后座不受影响)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _stop() {
|
||||||
|
if (!Stat.running) return;
|
||||||
|
Stat.running = false;
|
||||||
|
Unpatch();
|
||||||
|
console.log('[拒绝击退] 已停止,事件派发已还原');
|
||||||
|
}
|
||||||
|
|
||||||
|
var Tool = {
|
||||||
|
Start: function () { _start(); },
|
||||||
|
Stop: function () { _stop(); },
|
||||||
|
GetRunning: function () { return Stat.running; },
|
||||||
|
Status: function () {
|
||||||
|
if (!Stat.running) return '已停止';
|
||||||
|
return PatchedTank ? ('拦截 ' + Stat.blocked + ' 次') : '等待坦克';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__hornetTools__ = window.__hornetTools__ || {};
|
||||||
|
window.__hornetTools__.NoKnockback = Tool;
|
||||||
|
window.__hornetNoKnockback__ = {
|
||||||
|
IsPushEvent: IsPushEvent,
|
||||||
|
GetStat: function () {
|
||||||
|
return { running: Stat.running, blocked: Stat.blocked, tankId: Stat.tankId };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('[3DTank] 拒绝击退模块已加载');
|
||||||
|
})();
|
||||||
@@ -150,14 +150,15 @@
|
|||||||
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
{ key: 'FreeLook', label: '自由视角', obj: tools.FreeLook },
|
||||||
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
{ key: 'WarSandbox', label: '战争沙盘', obj: tools.WarSandbox },
|
||||||
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
{ key: 'Mouse', label: '鼠标稳定', obj: tools.Mouse },
|
||||||
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip }
|
{ key: 'NoClip', label: '穿坦克', obj: tools.NoClip },
|
||||||
|
{ key: 'NoKnockback', label: '拒绝击退', obj: tools.NoKnockback }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 工具启用状态(持久化 + 默认启用)=====
|
// ===== 工具启用状态(持久化 + 默认启用)=====
|
||||||
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
// 默认除「自由视角」外全部开启:自由视角会直接接管相机,默认开启过于突兀
|
||||||
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip'];
|
var ToolKeys = ['Radar', 'Wireframe', 'Rearview', 'AimWarning', 'FreeLook', 'WarSandbox', 'Mouse', 'NoClip', 'NoKnockback'];
|
||||||
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false };
|
var ToolDefaults = { Radar: true, Wireframe: true, Rearview: true, AimWarning: true, FreeLook: false, WarSandbox: true, Mouse: true, NoClip: false, NoKnockback: false };
|
||||||
var ToolEnabled = {};
|
var ToolEnabled = {};
|
||||||
try {
|
try {
|
||||||
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
var __savedEnabled = JSON.parse(localStorage.getItem('hornet_tool_enabled') || '{}');
|
||||||
|
|||||||
@@ -65,6 +65,12 @@
|
|||||||
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
||||||
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
'Shape.Ghost': 'g9k_1', // true = 只探测不产生碰撞响应
|
||||||
|
|
||||||
|
// ---- 实体事件总线 / 外力事件(ODt)----
|
||||||
|
'Entity.Dispatch': 'kz7()', // 向实体内所有订阅者派发事件
|
||||||
|
'Event.PushPoint': 'o13i_1', // 外力事件:作用点(O$ 向量)
|
||||||
|
'Event.PushDir': 'p13i_1', // 外力事件:方向(O$ 向量)
|
||||||
|
'Event.PushStrength': 'q13i_1', // 外力事件:强度(坦克物理交给 m9k)
|
||||||
|
|
||||||
// ---- 血量组件(Vkt)----
|
// ---- 血量组件(Vkt)----
|
||||||
'Health.Max': 'p12o_1',
|
'Health.Max': 'p12o_1',
|
||||||
'Health.Current': 'q12o_1',
|
'Health.Current': 'q12o_1',
|
||||||
|
|||||||
Reference in new issue
Block a user