This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Ananta-ps/pkg/protocol/methods/vehicle_methods4229938.go
T

169 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package methods
//
// Vehicle summon/ownership wire contracts for client 4229938. Field order is the wire
// order, verified 1:1 against lua/LuaGen/AutoGen/RPCSerializeAuto.lua
// (WriteVehicleClientInfo, WriteLogicVehicleClientInfo, WriteSummonVehicleResult,
// WritePlayerVehicleClientDetail, WriteRaidVehicleSeatInfo, WriteNewClientBoardingInfo,
// WriteBoardingExtInfo, WritePlayerVehicleDriveStateInfo, WriteRaidVehicleSyncData,
// WriteVehicleClientPart) and ClientToGameSceneDelegate.lua arg serializers.
// New-vs-4091149 deltas already applied: LogicVehicleClientInfo.VehicleSpoonName (tail)
// and PlayerVehicleClientDetail.IsPersistent (tail).
//
//
// Stock vehicle HP notification; normal SyncUnitHp only handles BaseUnit.
// Ported from donor_7k (T1-16 载具骇入): CanHack() requires CurrentHp > 0, and
// SyncSpawnVehicle carries no HP fields, so this packet is mandatory for hackability.
//
//
// Server notify body: SyncUnitBoardingInfo (68699595) — NPC 的座位挂载句柄
// (客户端 LogicAgentAttachVehicleHandle.Setup:原生座位偏移/旋转 + attach 句柄每帧跟随车辆)。
// <para>★ 字段顺序 = wire 顺序,2026-09-30 逐字段对照客户端
// ux_game_all.dump.cs:22762 ClientBoardingInfo 核过:<br/>
// ulong EntityId / ulong VehicleUId / byte SeatIndex / UXVector3 PositionOffset /
// UXVector3 RotationOffset / bool CanBeEjected / bool UseSpecificAction /
// uint ActionGroup / uint ActionId。<br/>
// 根签名是 SyncUnitBoardingInfo(ClientBoardingInfo info, bool force)
// ⇒ 见 SyncUnitBoardingInfo4229938。</para>
// <para>⛑ 客户端把这个 mid 标成 CSharpOnly(RPCDeserializeAuto.lua:1153),
// Lua 侧没有明文 Reader ⇒ 只能按 dump.cs 字段布局核(规则 239 的客户端取证走 C# 侧)。
// 1(FF) + 8 + 8 + 1 + 12 + 12 + 1 + 1 + 4 + 4 = 52 B。</para>
//
//
// Server notify: SyncUnitBoardingInfo (68699595) 全包 = info + force。
// 合计 53 B。⛑ 捐赠端 v0.5-2 PoliceVehicle.cs:82-91 是手写字节
// (U8(255) + U64 + U64 + U8 + F32×6 + Bool×2 + U32×2 + Bool(true)),
// 与这里序列化出来的结果逐字节相同(已核)。
// ⛑ 解除挂载时 VehicleUId = 0 ⇒ 客户端同时清掉 attach 与原生座位注册。
//
// Server notify: SyncPlayerMoveToDriveSeat (68778293).
// Server notify: SyncPlayerExitVehicle (exit leg).
//
// 上下车驱动状态。C2S:AskPlayerStartEnterOrExitVehicle(67225310) /
// AskPlayerFinishEnterOrExitVehicle(67211905);S2C:
// SyncPlayerStartEnterOrExitVehicl / SyncPlayerVehicleStateChange /
// SyncPlayerFinishEnterOrExitVehic(GameRouter.VehicleStory.cs 的强制上下车)。
// ⛑⛑ 2026-10-03:**不是 Inline**。客户端
// ClientToGameSceneDelegate.lua:1317 / :1352 用的是
// SerializeBase.WriteComplex(writer, syncdata, WritePlayerVehicleDriveStateInfo, "syncdata", false)
// ⇒ 顶层 struct 前面有一个 presence 字节(0xFF)。
// 实机包体(14:46:43 上车,35B)逐字节对齐:
// <code>
// FF presence(有值)
// 64 00 00 00 00 00 00 00 Pid = 100
// 01 EnterOrLeave(上车=1 / 下车=0)
// 01 00 34 F6 8D 40 CC 71 VehicleEntityId = 8200000000000000001
// 00 00 00 00 SeatIndex = 0
// 00 IfForce
// 00 00 00 00 OpenDoorTypeId
// 00 00 00 00 OpenDoorActionSpeed
// 00 00 00 00 OpenDoorActionClipLength
// </code>
// 以前标 Inline = true ⇒ 少读那 1 字节 ⇒ 尾部剩 1 字节 ⇒ TryGetArgs 失败,
// 日志常年 AskPlayerStartEnterOrExitVehicle undecodable bytes=35,后果是
// **服务端根本没处理过上下车**(CurrentVehicleId / LastDrivenVehicleId /
// 「车流车坐进去先摘出车道流」这些后续逻辑全没跑)。
// ⛑ 同步影响:S2C 那三包也用这个 DTO,改后它们同样带 presence 字节 —— 这是按
// 「C2S 与 S2C 由同一份契约生成」的对称性推断,需要实机确认强制上下车按钮仍正常。
// 回滚:还原 .bak-20261003-drivestate。
//
// Client invoke arg: AskPublicSwitchToPublicScene (63491547).
// Client invoke arg: AskEnterRaidByMapEntrance (63510026).
// Aether vehicle init (SyncAetherAIInitDatas, 68704070). Lists stay empty.
// Never serialized (all Aether init lists are empty); satisfies the serializer.
// --- ClientTrafficIntersectionInitInfo (dump.cs:1743618) ------------------------------------
//
// ★ 这是 AetherAIInitData.Intersections 的真实元素类型。我们此前一直用上面的空 stub,
// 等于永远发「零个路口」—— 客户端的路口/信号灯系统从来没有拿到过初始化数据。
//
// dump 内存布局:基类 TrafficIntersectionPeriodInfo 在 0x10/0x11/0x12,派生在 0x18/0x20/0x24
// (即内存里基类在前)。但历史笔记记的 wire 顺序是「派生先、基类后」。
// 两者可能不一致(UxSerializer 按声明顺序写,与内存布局无关),所以两个版本都留着,
// 由配置 `initVariants` 选哪一个 —— 探测阶段两边都试,看客户端日志哪边有反应。
//
// MassTrafficIntersectionState: Start=0 / Transition=1 / Finishing=2。
// 派生字段在前:InstanceId, ZoneIndex, CurrentState, 然后基类三个周期 byte。
// 基类字段在前(照 dump 内存偏移 0x10/0x11/0x12 排)。
// top-int7 framing + 真路口(派生先)。
// top-int7 framing + 真路口(基类先)。
//
// Same four fields, but NOT Inline: UxSerializer emits the single-argument 0xFF object
// marker first. The 4229938 reader consumes that marker before RaidId (see the note on
// AetherAIInitData4229938), so this is the framing to use.
//
//
// ★★ 唯一实测正确的 SyncAetherAIInitDatas(68704070) 线格式(2026-09-20 客户端验证)。
// 0xFF 对象标记 + u32 RaidId + bool HasZoneGraph + i32 ZoneStorageDataHandle
// + 0xFF list presence + Int7(count+1)。空路口表 ⇒ 共 12 字节:
// `FF 188B6301 01 611ABBC1 FF 01`(donor `--probe-aether` 输出一致)。
// 别换成 Int32 count 版(AetherAIInitDataTop4229938),客户端会 capacity 负数崩溃。
//
// Bool-first field order, no object marker (diagnostic variant).
// Client notify arg: AskInteractCmd (67390408). Logged + accepted.
// Client notify: ReportDrivingVehicle (67528706).
// Client notify: AskVehicleNitroValue (67533682).
// Client invoke: AskVehicleNitro (67037029).
// Client notify: AskModifyVehicleTopSpeed (67920147).
// Client notify: AskVehicleHorn (67983272).
// Client notify: AskVehicleContactDamage (67589692).
// Full contact-damage struct (WriteVehicleContactDamageData order).
// Client invoke: AskGetVehicleRadioContent (67725622).
//
// AskGetVehicleRadioContent(67725622) 的返回体 = UX.Game.RadioRandomContent
// (TypeDefIndex 33514,字段顺序取自 il2cpp dump,与 DefaultReturnCatalog 的既有 15 字节
// 全零回包 FF 00 00 00 00 00 … 完全对齐 —— 1 字节 complex 标记 + 1+4+4+4+1)。
// 所以这里不能 Inline = true:inline 会省掉那个 0xFF,客户端
// Base.ReadComplex(reader, Auto.Reader[594]) 就会把 ContentType 当成标记字节读掉。
// 字段语义(RadioPlayerManager.GetVoicesByContent):
// ContentType 1=Ad 2=News 3=Chat 4=Comment(3/4 都查 RadioContentDJs)5=SpecialNews
// ContentId 主内容 id(按 ContentType 查对应表拿 SoundId)
// StartContentId 开场口播 id(查 RadioContentDJs;广告/新闻为 0)
// EndContentId 收尾口播 id(同上)
// MarkType 1=Middle 2=End —— 决定串词插在歌的哪个 cue 上
//
//
// Client notify: AskSwitchVehicleRadio (67959772),参数一个 u32(电台序号)。
// 客户端 RadioPlayerManager.SwitchRadio / SwitchTargetRadio 本地已经切完了才发这帧,
// 服务端只做记录(切台本身没有任何服务端权威状态)。
//
// Client notify: SyncChangeSafeArea (63310118).
// Client invoke: SyncChangeBuilding (63495099).
// Client invoke: SyncChangeIndoor (63927817).
// --- 路口相位更新 SyncAetherAIIntersectionUpdateDa (68819947) -------------------------------
//
// ★★ 2026-10-02 从捐赠端 PrivateServerPor 移植(`VehicleAiTaskMethods.cs`)。这是「让红绿灯真的亮」
// 的那一半:init 只把路口表交给客户端,灯柱要按相位变色还得周期发这条包。
//
// ⛑⛑ 契约来源(与 init 那对类型同源,互相印证):
// dump.cs TypeDefIndex 32648/32650:
// class TrafficIntersectionPeriodInfo { byte CurrentPeriodIndex; byte NextPeriodIndex; byte RailPeriodIndex; }
// class ClientTrafficIntersectionPeriodUpdateInfo : TrafficIntersectionPeriodInfo
// { ulong IntersectionIndex /*0x18*/; MassTrafficIntersectionState CurrentState /*0x20*/; }
// 声明顺序 = **派生字段在前、基类三 byte 在后**,与主线 `TrafficIntersectionInitInfoDerived4229938`
// 完全同构(后者是 InstanceId/ZoneIndex/CurrentState 在前 + 三个周期 byte)。
//
// ⛑ 这条包在 `RPCDeserializeAuto.lua` 里是 `CSharpOnly`(第 1157 行 `midToExportOption[68819947]`)
// ⇒ **lua 侧没有 Reader 可对照**(硬规则 209/239 在这里不适用),只能按 dump 定序。
//
// 客户端消费方:`AetherCity.Common.AetherIntersectionManager.OnSyncIntersectionPeriodUpdateInfo`。
// MassTrafficIntersectionState: Start=0 / Transition=1 / Finishing=2。
type MassTrafficIntersectionState4229938 byte
const (
MassTrafficIntersectionState4229938_Start MassTrafficIntersectionState4229938 = 0
MassTrafficIntersectionState4229938_Transition MassTrafficIntersectionState4229938 = 1
MassTrafficIntersectionState4229938_Finishing MassTrafficIntersectionState4229938 = 2
)
//
// 68819947 的顶层:只有一个 data(与捐赠端逐字一致)。
// ⛑⛑ **必须 Inline**:捐赠端 `VehicleAiTaskMethods.cs:18` 就是 `[UxContract(Inline = true)]`,
// 顶**不写**对象标记;`data` 字段自己是 `[UxContract]`(非 Inline)⇒ 由它写那一个 `FF`。
// 我第一版漏了 Inline ⇒ 变成 `FF FF …`,整包偏移 1 字节,客户端会解歪。
// 与 init 的 `AetherAIInitData`(非 Inline,根上写一个 FF)**总标记数都是 1**,互相印证。
//
//
// 68819947 的载荷。**字段顺序 = wire 顺序,别动。**
// IntersectionIndex 取 CSV 第一列 zone_index(配置 intersectionIndexSource)。
//