在本地坦克实体的 kz7 事件派发处丢弃外力事件(ODt:作用点/方向/强度),坦克物理收不到就不产生位移与旋转;悬挂与行驶仍走 m9k 直调,不受影响。面板新增「拒绝击退」开关。字段名走 hornet_schema。
257 lines
10 KiB
JavaScript
257 lines
10 KiB
JavaScript
// hornet_schema.js — 引擎匿名字段抽象层(字段映射总表)
|
||
//
|
||
// 为什么需要它:
|
||
// 游戏每个构建版本都会把类的字段名整体平移(如 ejt 的 zzq_1 / bzr_1),
|
||
// 工具里到处硬编码 `comp.zzq_1`、`tank.qz1_1.s2a_1` 这类匿名名,
|
||
// 版本一换就要全局搜替换,还容易改错(同名复用极严重)。
|
||
// 这里把「语义名 → 匿名字段路径」集中成一张表:
|
||
// · 工具只用语义名(Schema.Get(tank, 'Tank.StateValue'))
|
||
// · 换版本时只改这张表,并跑一次 SelfCheck() 看哪几项失配
|
||
//
|
||
// 路径语法:
|
||
// 'a.b.c' 属性链
|
||
// 'lz4()' 方法调用(末尾带括号即调用,中间也可混用,如 'm10b_1.j11y()')
|
||
//
|
||
// 用法:
|
||
// var S = window.__hornetSchema__;
|
||
// S.Get(gm, 'GameMode.TankList')
|
||
// S.Get(tank, 'Tank.StateValue')
|
||
// S.Check(gm, 'GameMode') // → { Ok: [...], Missing: [...] }
|
||
// S.SelfCheck() // 用当前战局对象自检并打印
|
||
//
|
||
// 版本:main.7cfa4058(字段核对自 module_87072 / 61378 / 92980 / 55088)
|
||
|
||
(function () {
|
||
'use strict';
|
||
|
||
// ===== 字段映射总表 =====
|
||
// 命名规则:<对象类型>.<语义名>
|
||
var Fields = {
|
||
// ---- 战斗实体基类(fe / BattleEntity)----
|
||
'Entity.Id': 'iz1_1', // 实体 ID(坦克/战场唯一)
|
||
'Entity.Components': 'qz1_1.s2a_1', // Map<组件标识, 组件列表>,取值要 valueList.g1(0)
|
||
|
||
// ---- GameMode(ght,window.__gameMode__)----
|
||
'GameMode.Scene': 'lz4()', // 场景实体
|
||
'GameMode.TankList': 'm10b_1.j11y()', // 坦克列表(e1() 数量 / g1(i) 取)
|
||
'GameMode.OwnedTank': 'u10b_1', // 本地玩家拥有的坦克(onTankPossessed)
|
||
'GameMode.ObservedTank': 't10b_1', // 当前观察目标(死亡/观战时可能指向敌人)
|
||
'GameMode.LocalTeam': 'v10b_1', // 本地队伍(与 u10b_1 同生命周期)
|
||
|
||
// ---- 坦克组件(lxt,含状态机)----
|
||
'Tank.Fsm': 'p10c_1', // 状态机字段(组件识别用)
|
||
'Tank.State': 'k10c_1', // 状态枚举对象
|
||
'Tank.StateValue': 'k10c_1.k3_1', // 状态数值:0=DEAD 1=DEAD_PHANTOM 2=SEMI_ACTIVE 3=ACTIVE 4=DISABLED 5=TELEPORT
|
||
'Tank.IsAlive': 's14j()', // 引擎可见性判定(2/3/5)
|
||
'Tank.TeamSource': 'l10c_1', // 状态机里下发的队伍对象
|
||
|
||
// ---- 队伍组件(GIt)与队伍对象 ----
|
||
'Team.Field': 'b135_1', // 队伍组件上保存队伍对象的字段
|
||
'Team.Id': 'k3_1', // 队伍编号:0 / 1 / 2(2 = 中立)
|
||
'Team.NeutralId': 2,
|
||
|
||
// ---- 坦克物理组件(ejt,组件名 tankPhysics)----
|
||
'Physics.Position': 'bzr_1', // 世界位置向量(f20_1/g20_1/h20_1)
|
||
'Physics.Size': 'xzq_1', // 车体半尺寸(**不是位置**)
|
||
'Physics.Hull': 'zzq_1', // 车体主碰撞形状(x9j_1 === 'hull-main')
|
||
'Physics.Body': 'pbk()', // 物理刚体(jM)
|
||
'Physics.AddMask': 'n155()', // z9j_1 |= t
|
||
'Physics.RemoveMask': 'm155()', // z9j_1 &= ~t
|
||
'Physics.BodyShapes': 'pbk().y9i_1', // 刚体上的形状列表(e1()/g1(i))
|
||
|
||
// ---- 碰撞形状(yi)----
|
||
'Shape.Name': 'x9j_1',
|
||
'Shape.Category': 'y9j_1', // bit0=坦克(1) bit3=地雷(8) bit4=地形(16)
|
||
'Shape.Mask': 'z9j_1', // 愿意碰撞的分类位
|
||
'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)----
|
||
'Health.Max': 'p12o_1',
|
||
'Health.Current': 'q12o_1',
|
||
|
||
// ---- 用户信息组件(yot)----
|
||
'User.Name': 'c12n_1',
|
||
'User.Clan': 'e12n_1',
|
||
|
||
// ---- 装备分组件(BattleGearScoreCC)----
|
||
'Gear.Score': 'cjf_1',
|
||
|
||
// ---- 皮肤组件(eUt)----
|
||
'Skin.HullSkin': 'g159_1', // 皮肤对象
|
||
'Skin.HullRoot': 'h159_1', // 车身渲染树根(BP 节点)
|
||
'Skin.Parts': 'g159_1.g17r_1', // 部件表
|
||
'Skin.PartNode': 'j17r_1', // 部件 → BP 节点
|
||
|
||
// ---- 炮塔皮肤组件(LUt)----
|
||
'Turret.Wrapper': 'a11p_1', // 组件首字段(包装对象)
|
||
'Turret.Root': 'e11p_1.a17q_1', // 炮塔 BP 根节点
|
||
'Turret.GetRoot': 'u11p()',
|
||
|
||
// ---- BP 场景节点(zl)----
|
||
'Node.Name': 'g35_1',
|
||
'Node.Matrix': 'p35_1', // 世界矩阵(列主序,[12][13][14] = 平移)
|
||
'Node.Children': 'r35_1',
|
||
'Node.Mesh': 'v3m_1',
|
||
'Node.Lod': 'u4x_1',
|
||
|
||
// ---- 相机(场景实体 .jz1_1.iyx_1)----
|
||
'Camera.SceneRef': 'jz1_1',
|
||
'Camera.Main': 'jz1_1.iyx_1',
|
||
'Camera.Position': 'jz1_1.iyx_1.t35_1',
|
||
'Camera.ViewMatrix': 'jz1_1.iyx_1.d37_1',
|
||
'Camera.ClipMatrix': 'jz1_1.iyx_1.g37_1',
|
||
'Camera.Fov': 'jz1_1.iyx_1.b37_1'
|
||
};
|
||
|
||
// ===== module_87072 的导出键($_.xx),每版都可能平移 =====
|
||
// 队伍:vd = WIt(t) 取实体队伍;dl = R7(a,b) 同队且非中立
|
||
// ⚠ 旧版是 kd / rk;新版 kd 已指向无关构造器
|
||
var Exports = {
|
||
'Export.TeamOf': ['vd', 'kd'],
|
||
'Export.TeamSame': ['dl', 'rk']
|
||
};
|
||
|
||
// ===== 路径解析 =====
|
||
function IsCall(Token) {
|
||
var N = Token.length;
|
||
return N > 2 && Token.charAt(N - 1) === ')' && Token.charAt(N - 2) === '(';
|
||
}
|
||
|
||
function ResolvePath(Target, Path) {
|
||
if (Target === null || Target === undefined || !Path) return undefined;
|
||
var Tokens = String(Path).split('.');
|
||
var Cur = Target;
|
||
for (var i = 0; i < Tokens.length; i++) {
|
||
if (Cur === null || Cur === undefined) return undefined;
|
||
var Tok = Tokens[i];
|
||
if (IsCall(Tok)) {
|
||
var Name = Tok.slice(0, -2);
|
||
if (typeof Cur[Name] !== 'function') return undefined;
|
||
try { Cur = Cur[Name](); } catch (e) { return undefined; }
|
||
} else {
|
||
Cur = Cur[Tok];
|
||
}
|
||
}
|
||
return Cur;
|
||
}
|
||
|
||
// 取字段值:Key 是总表键(如 'Tank.StateValue'),未命中则把 Key 当字面路径
|
||
function Get(Target, Key) {
|
||
var Path = Fields[Key];
|
||
return ResolvePath(Target, Path !== undefined ? Path : Key);
|
||
}
|
||
|
||
// 取字段路径(字符串),用于打印/自检
|
||
function PathOf(Key) {
|
||
return Fields[Key] !== undefined ? Fields[Key] : String(Key);
|
||
}
|
||
|
||
// 取单段属性名:'Node.Matrix' → 'p35_1';带方法或多段时返回 null
|
||
// 工具里写成 `Node[FieldName('Node.Matrix') || 'p35_1']`,即「优先用总表,缺表时用字面名」
|
||
function FieldName(Key) {
|
||
var P = Fields[Key];
|
||
if (!P || P.indexOf('.') >= 0 || IsCall(P)) return null;
|
||
return P;
|
||
}
|
||
|
||
// 取单段方法名:'Physics.RemoveMask' → 'm155'
|
||
function MethodName(Key) {
|
||
var P = Fields[Key];
|
||
if (!P || !IsCall(P) || P.indexOf('.') >= 0) return null;
|
||
return P.slice(0, -2);
|
||
}
|
||
|
||
// 自检:按前缀检查某对象上哪些语义字段能解析
|
||
function Check(Target, Prefix) {
|
||
var Out = { Ok: [], Missing: [] };
|
||
Object.keys(Fields).forEach(function (Key) {
|
||
if (Prefix && Key.indexOf(Prefix + '.') !== 0) return;
|
||
if (typeof Fields[Key] !== 'string') return; // 常量项(如 Team.NeutralId)不参与自检
|
||
var V = Get(Target, Key);
|
||
if (V === undefined) Out.Missing.push(Key + ' → ' + Fields[Key]);
|
||
else Out.Ok.push(Key + ' → ' + Fields[Key]);
|
||
});
|
||
return Out;
|
||
}
|
||
|
||
// 用当前战局对象做一次全量自检(控制台调用 __hornetSchema__.SelfCheck())
|
||
function SelfCheck() {
|
||
var Gm = window.__gameMode__;
|
||
var Report = { HasGameMode: !!Gm, Groups: {}, Missing: [] };
|
||
if (!Gm) return Report;
|
||
|
||
var Scene = Get(Gm, 'GameMode.Scene');
|
||
var TankList = Get(Gm, 'GameMode.TankList');
|
||
var Tank = null;
|
||
try {
|
||
Tank = Get(Gm, 'GameMode.OwnedTank');
|
||
if (!Tank && TankList && typeof TankList.e1 === 'function' && TankList.e1() > 0) Tank = TankList.g1(0);
|
||
} catch (e) {}
|
||
|
||
var Targets = {
|
||
Entity: Tank || Scene,
|
||
GameMode: Gm,
|
||
Tank: Tank,
|
||
Physics: Tank ? FindPhysics(Tank) : null,
|
||
Shape: null,
|
||
Skin: Tank,
|
||
Turret: Tank,
|
||
Node: null,
|
||
Camera: Scene
|
||
};
|
||
|
||
Object.keys(Targets).forEach(function (Prefix) {
|
||
if (!Targets[Prefix]) { Report.Groups[Prefix] = '无样本对象'; return; }
|
||
var R = Check(Targets[Prefix], Prefix);
|
||
Report.Groups[Prefix] = R;
|
||
R.Missing.forEach(function (M) { Report.Missing.push(Prefix + '.' + M); });
|
||
});
|
||
|
||
if (Report.Missing.length) {
|
||
console.warn('[字段抽象] 失配 ' + Report.Missing.length + ' 项:', Report.Missing);
|
||
} else {
|
||
console.log('[字段抽象] 全部语义字段解析正常');
|
||
}
|
||
return Report;
|
||
}
|
||
|
||
// 找坦克物理组件(与工具内实现同源,放这里方便自检)
|
||
function FindPhysics(Tank) {
|
||
if (!Tank) return null;
|
||
var Map = Get(Tank, 'Entity.Components');
|
||
if (!Map || typeof Map.forEach !== 'function') return null;
|
||
var Found = null;
|
||
Map.forEach(function (ValueList) {
|
||
if (Found) return;
|
||
var Comp = (ValueList && typeof ValueList.g1 === 'function') ? ValueList.g1(0) : ValueList;
|
||
if (!Comp) return;
|
||
var Hull = Get(Comp, 'Physics.Hull');
|
||
if (Hull && Get(Hull, 'Shape.Name') === 'hull-main') Found = Comp;
|
||
});
|
||
return Found;
|
||
}
|
||
|
||
// ===== 导出 =====
|
||
window.__hornetSchema__ = {
|
||
Version: 'main.7cfa4058',
|
||
Fields: Fields,
|
||
Exports: Exports,
|
||
Get: Get,
|
||
PathOf: PathOf,
|
||
FieldName: FieldName,
|
||
MethodName: MethodName,
|
||
Check: Check,
|
||
SelfCheck: SelfCheck,
|
||
ResolvePath: ResolvePath,
|
||
FindPhysics: FindPhysics
|
||
};
|
||
|
||
console.log('[3DTank] 字段抽象层已加载(版本 main.7cfa4058,语义字段 ' + Object.keys(Fields).length + ' 项)');
|
||
})();
|