package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // 搜打撤「武器轮盘」的武器实体化 —— 把轮盘 bag 里的枪变成 gWeaponManager 认得的武器。 // 为什么必须有这一层:搜打撤里有两套互不相干的武器系统。 // · 轮盘 bag(99952004)= 物品存储。客户端 BackCircleAnantarkovStore 用 // gExtractionShooterManager:GetItemInfoBySlot(slotIndex, wheel) 读它,只负责「画格子」。 // · 实体化武器 = gWeaponManager.CurrWeaponSlots,由 SyncSpiritWeaponDetail / // SyncSpiritAddWeaponAction 灌进来,只管「切枪」。 // 把物品挪进轮盘 bag 只动了第一套。Tab / 滚轮切枪走的是 // WeaponManager:GetNextCircleWeapon → 只遍历 CurrWeaponSlots, // 而且 BackCircleAnantarkovStore.OnCircleButtonClick 是空的(点格子不切枪), // 所以第二套没跟上时,不管往轮盘里放了多少把枪,Tab 永远只在拳头和角色自带那把之间转。 // 下标口径(三处证据一致,见 ExtractionShooterRuntime4229938.WheelHomeOffset4229938): // CurrWeaponSlots 下标 0 = 拳头、1 = 私有武器、2 + k = 轮盘 CellX k。 // 下发策略:整表(SyncSpiritWeaponDetail)最稳、增量(Add/RemoveWeaponAction)最省, // 两种都留着并由配置切换(world.content.extraction.wheelSync)。 // 增量一旦发现「当前武器要被摘掉」就自动退回整表,免得客户端 OnSwitchCurrentWeapon // 找不到人而打 "Not Find Current Weapon"。 // // // 让 gWeaponManager 跟上轮盘 bag 的当前内容。轮盘 bag 每变动一次、进图、切角色都要调。 // 静默跳过的三种情况(都不是错误): // · 模式为 Off; // · state.Ready 还没置起 —— 世界还没起,客户端 gWeaponManager 还没建, // 这时候发过去会被丢掉,等世界就绪时那次调用才是有效的; // · 当前不在搜打撤图里 —— 轮盘 bag 属于搜打撤玩法,主城里没有这套 UI, // 乱发 SyncSpiritWeaponDetail 会把城镇的 16 槽武器盘覆盖成搜打撤的 9 槽。 // func GameRouter_ExtractionWeapons_PushExtractionWheelSyncAsync(ctx context.Context, session *GameSession, state any, phase string) any { // Router implementation for GameRouter_ExtractionWeapons_PushExtractionWheelSyncAsync var zero any; return zero } // // 整表重发:SyncSpiritWeaponDetail(68255545)。客户端把它整体灌进 // CurrWeaponSlots 并按 CurrentWeaponUid 切当前武器,所以顺带就能自愈 // 「客户端已经把 WeaponManager 重建过」这类状态漂移。 // func GameRouter_ExtractionWeapons_PushExtractionWheelSnapshotAsync(ctx context.Context, session *GameSession, state any, phase string) any { // Router implementation for GameRouter_ExtractionWeapons_PushExtractionWheelSnapshotAsync var zero any; return zero } // // 把「此刻轮盘的内容」记成增量基线。整表下发之后必须调一次,否则下一次增量会拿着 // 过期的镜像做差,把已经变过的格当成没变。 // func GameRouter_ExtractionWeapons_RecordExtractionWheelPublished(ctx context.Context, session *GameSession, state any) any { // Router implementation for GameRouter_ExtractionWeapons_RecordExtractionWheelPublished var zero any; return zero } // // 搜打撤版的武器表:[拳头, 私有武器, 轮盘 CellX 0..N-1]。 // 城镇的 CombatCodec.SpiritWeaponSnapshot 用的是角色 16 槽配装,进图后要换成这一张 —— // PublishWeaponSnapshot(切场景后首次移动也会走一次)必须按同一口径发, // 否则城镇那张 16 槽表会把刚补好的轮盘覆盖掉,轮盘枪又从 CurrWeaponSlots 里消失。 // func GameRouter_ExtractionWeapons_BuildExtractionWheelSnapshot(ctx context.Context, session *GameSession, state any, unitId uint64, templateId uint32, currentWeaponInstanceId uint64) any { // Router implementation for GameRouter_ExtractionWeapons_BuildExtractionWheelSnapshot var zero any; return zero } // // 搜打撤里 AskSwitchWeapon(index) 的解析:下标 0/1 取角色配装的拳头 / 私有武器, // 下标 ≥ 2 取轮盘 bag 里 CellX = index - 2 那把。 // 只有这一条路径能把轮盘枪切成手上这把 —— 客户端轮盘界面的点击是空的 // (BackCircleAnantarkovStore.OnCircleButtonClick 什么都不做),切枪全靠 // Tab / 滚轮走 GetNextCircleWeapon 遍历 CurrWeaponSlots 后发这条请求, // 所以这里必须能把它按位置还原成袋子里那把枪。 // func GameRouter_ExtractionWeapons_ExtractionSwitchWeaponAt(ctx context.Context, session *GameSession, state any, index int32) any { // Router implementation for GameRouter_ExtractionWeapons_ExtractionSwitchWeaponAt var zero any; return zero } // // 增量:把「服务端镜像」和「轮盘 bag 现状」做差,只发变了的格。 // 有一个必须退整表的情形:当前武器被摘掉了。增量只发 Remove 的话客户端会把那一格置空, // 但手上还拿着已不存在的 instance,之后所有技能请求都会解析失败。 // 整表里带着合法的 CurrentWeaponUid,客户端自己会切过去,所以这里直接改走整表。 // func GameRouter_ExtractionWeapons_PushExtractionWheelDeltaAsync(ctx context.Context, session *GameSession, state any, phase string) any { // Router implementation for GameRouter_ExtractionWeapons_PushExtractionWheelDeltaAsync var zero any; return zero } // 把轮盘 bag 的现状按 CurrWeaponSlots 下标排成表。 func GameRouter_ExtractionWeapons_WheelWeaponsByIndex(ctx context.Context, session *GameSession) map[string]any { // Router implementation for GameRouter_ExtractionWeapons_WheelWeaponsByIndex return nil } // 一次快照下发要用到的三件东西:角色模板、单位 id、当前武器实例。 func GameRouter_ExtractionWeapons_WheelSyncTarget(ctx context.Context, state any) any { // Router implementation for GameRouter_ExtractionWeapons_WheelSyncTarget var zero any; return zero } // // CurrWeaponSlots[0](拳头)和 [1](私有武器)—— 这两个位置不属于轮盘, // 直接取角色自己的配装 Slots[0] / Slots[1],它们的流派 / 技能是作者配好的。 // func GameRouter_ExtractionWeapons_WheelHeadWeapons(ctx context.Context, state any, templateId uint32) any { // Router implementation for GameRouter_ExtractionWeapons_WheelHeadWeapons var zero any; return zero } // // 序列化前给一件实体化武器盖上真实的弹药 / 耐久 / 流派 / 子弹。 // 轮盘武器的这些值活在 WorldEntryState(Handler 层)里,和城镇 // PublishWeaponSnapshot 用的是同一套状态,所以两边口径天然一致: // 一把枪在城镇打完的弹量,进图后接着算,不会因为换了条下发路径就回满。 // ⚠️ 用账号军械库查(CombatCatalogRepository.Weapon(instanceId))而不是只在角色配装里查: // 轮盘里的枪是账号军械库的(PersonalWeapons 之外),查错会静默跳过 ⇒ // 下发出去的枪 Durability/MagazineAmmo 全是模板默认值。 // func GameRouter_ExtractionWeapons_PrepareWheelWeaponDetail(ctx context.Context, state any, templateId uint32, detail any) any { // Router implementation for GameRouter_ExtractionWeapons_PrepareWheelWeaponDetail var zero any; return zero } // 轮盘武器实体化的下发方式。 type ExtractionWheelSyncMode4229938 int32 const ( // 完全不下发(排障用,等价于修复前的行为)。 ExtractionWheelSyncMode4229938_Off ExtractionWheelSyncMode4229938 = iota // 只发变化的格(SyncSpiritAddWeaponAction / SyncSpiritRemoveWeaponAction)。 ExtractionWheelSyncMode4229938_Incremental // 每次变动重发整表(SyncSpiritWeaponDetail)。默认。 ExtractionWheelSyncMode4229938_Full )