bug反馈7,8 ¶
问题1:
状态:未处理
测试服:账号:fafa ID:390697
现象:领取通行证奖励后 皮肤显示领取成功 但是武将皮肤界面未解锁 无法穿戴
预期:皮肤正常到账 可正常穿戴
截图:



问题2:
状态:已修复 验收不通过
备注:收车时和发车时奖励不一致 获取的奖励还是固定的
截图:
现象:俱乐部赛车内黄金赛车发车奖励和收车奖励不一致 (发车奖励ui改为区间了 但是收车还是保底奖励)
预期:发车时奖励是什么收车时奖励就是什么
根因:服务端未发车的金车/超级车会被默认车数据补齐为配置区间下限奖励;发车时只判断 rewards 非空并直接保留,导致这类默认下限被当作最终奖励,收车仍发保底。
修复:发车时识别“未刷新且奖励等于区间下限”的默认奖励,重新按金车/超级车配置随机一次;已刷新出的奖励继续原样保留。
验证:新增回归测试 TestRuntimeSend_RollsGoldenDefaultMinimumRewards,并通过赛车奖励范围、刷新预览、发车保留刷新奖励、完整发车收车流相关测试。
截图:


问题3:
状态:已修复 验收通过
正式服:facaizzz ID:100316514
现象:俱乐部赛车内 排行榜每次点击都会卡死
预期:点击俱乐部排行榜不会卡顿卡死 应正常流畅
根因:俱乐部排行榜服务端先对所有俱乐部加载 Mongo 元信息,再排序截断前 50;prod-1 当时有 8648 个赛车角色、2510 个俱乐部,car_getgrouprank 日志显示单次 9-11 秒,客户端一直停留 loading。
修复:服务端先按已聚合分数/战力/俱乐部 ID 排序并截断前 50,再只加载前 50 和自己俱乐部的元信息,避免每次点击串行查询所有俱乐部。
验证:新增 TestRuntimeGroupRankBoardLoadsMetaOnlyForVisibleRanks,并通过俱乐部榜排序、缓存、统计相关测试。
截图:

问题4:
状态:已修复 待同步正式服周一验证
正式服:facai005 ID:500229114
facaizzz ID:100316514
现象:俱乐部赛车内 每日排行榜结算奖励不发放 以至于最强车手榜没有榜单
预期:每日排行榜每天结算 奖励最强车手积分正常发放 最强车手榜根据最强车手积分高低进行排名
根因:每日榜结算在发奖前全量加载并逐个回写所有有 cargoRaid 的角色;prod-1 有 8648 条赛车角色,接口日志显示 car_getrolerank 打满 30 秒并报 daily settlement failed ... context deadline exceeded,导致每日奖励邮件未发送。生产确认每日赛车奖励邮件数为 0,最强车手积分道具 35010 持有人为 0。
修复:每日结算只加载上一日窗口内有 dailyScore 的候选角色,发奖和重置只处理候选角色,避免全量扫描/回写超时;每日奖励正常发出后会发放最强车手积分道具,最强车手榜即可产生数据。
验证:新增 TestCargoRaidDailyRankCandidateQueryUsesPreviousDayWindow,并通过每日榜结算/最强车手榜相关测试。
截图:


问题5:
状态:已修复 验收通过
正式服:facaizzz ID:100316514 7.7号14:03
现象:俱乐部赛车掠夺他人时 跳过战斗 战斗胜利 但是不显示对面全部死亡
预期:跳过战斗 失败方显示全部死亡
根因:赛车掠夺接入 battle-service 后,服务端只把胜负/统计写入 battleData.result,没有调用通用 PVP 的结果队伍补齐逻辑;battle-service 结果缺少 accept.teamInfo 最终血量时,客户端跳过战斗后无法把失败方统一显示为死亡。
修复:runCargoRaidBattle 对 battle-service 和本地 fallback 结果统一调用 EnsurePVPResultTeams,胜利时补齐防守方 teamInfo[].hp=0 和 ext.curHP=0。
验证:新增 TestRunCargoRaidBattle_FillsDeadDefenderTeamOnBattleServiceWin,并通过 battle-service 统计保留、PVP 结果队伍补齐相关测试。
截图:


问题6:
状态:已修复 待周期结束验证
现象:俱乐部赛车内 赛车改装 周期时间到期后 改装服务」内容的升级未重置 零件也未重置
预期:「改装服务」内容的升级会在每期重置一次,未使用的「赛车零件」也会被回收兑换为金砖奖励,重置周期为28天。
根因:客户端改装页直接读取 roleCarInfo.research 显示改装等级、读取全局 ROLE.items[35009] 显示赛车零件;服务端 normalizeRoleCar 跨 28 天 phase 时只重置了 partItemConsumeCnt 和 partConsumeRewardMap,没有清空 research,也没有读取/执行 CarPartsExpireRewardNum、CarPartsExpireRewardType 的零件回收配置。car_getrolecar 入口跨期后也未保存和同步资源变化。该问题未提供角色 ID,本地历史日志无 7 月 8 日可关联记录,根因由截图、客户端读取链路、服务端重置逻辑和配置缺口闭环确认。
修复:服务端配置加载补齐零件过期回收字段;跨期重置时清空 research、清空本期消耗进度/领取记录,并按配置把未使用 35009 赛车零件兑换为金砖后清零;car_getrolecar 检测到 phase 变化时保存角色、刷新缓存,并通过 syncresp 同步零件数量和金砖变化。
验证:新增 TestRuntimeStateAtResearchPhaseResetClearsUpgradesAndRecoversUnusedParts,并通过跨期重置、改装升级、改装消耗奖励、主包赛车战斗/每日榜相关编译测试。
截图:


问题7:
状态:已修复 验收通过
测试服账号:LZBN2 ID:100089014 时间:17:00-17:01
现象:游戏内切磋战斗和竞技场战斗血量不一致 竞技场内血量低 (是否是哪里加成竞技场不生效 如勋章 阵营光环等)
预期:应所有加成都在竞技场内都正常生效
根因:截图中同一阵容切磋/咸主之争血量为 123754347642,竞技场血量为 107612476213;玩家当前 4 吴阵营光环为血量 +15%、攻击 +15%,107612476213 * 1.15 与切磋血量吻合。服务端代码确认切磋、咸主之争走 buildLeftTeam,会读取 AuraConf;竞技场 fight_startareaarena.buildPlayerTeam 手写队伍数据,只取武将原始 attack/hp,虽处理了勋章、宠物、装备祝福,但遗漏阵营光环,所以竞技场血量/攻击偏低。本地缺少 7 月 8 日 17:00-17:01 对应历史日志,根因由截图数值、客户端战斗数据来源和服务端构建链路闭环确认。
修复:竞技场战斗队伍改为复用通用 buildLeftTeam 构建链路,使阵营光环、勋章、技能属性、皮肤、宠物、装备祝福统一生效;保留竞技场自己的战力快照、武器、宠物和旧 avatar 响应字段。
验证:新增 TestFightStartAreaArena_BuildPlayerTeamAppliesAuraConfig,确认竞技场 4 吴光环会给全队 attack/hp 加 15%;并通过竞技场战力快照、皮肤净化、武器主动等级、装备祝福、失败方死亡补齐和通用 BuildLeftTeam 光环/勋章/皮肤回归测试。
截图:



问题8:
状态:已修复 验收通过
正式服账号:facaizzz ID:100316514 时间:7月8号 20:41
现象:正式服内进入他人客厅 点击咸主挑战 就会很卡 有时候会只有游戏卡死
预期:点击咸主挑战流畅不卡顿
根因:客户端 FeudatoryInfoDialog 点“征服”后会异步刷新目标信息、请求 fight_startconquer、再进入战斗 UI,但按钮没有进行中锁;生产日志确认 2026-07-08 20:41:13-20:41:15,facaizzz 对同一目标 100266906 连续发出 3 次 fight_startconquer(seq=55/58/60),每次服务端耗时只有 170-294ms,单次接口并不慢。服务端已有重复门但窗口只有 900ms,三次点击间隔约 1 秒,刚好全部穿过,导致客户端多个战斗请求和多个进入战斗 UI 流程叠加,表现为点击后卡顿甚至卡死。
修复:客户端征服、反抗、Boss 面板反抗入口共用 _fightPending 锁,在一次挑战请求/战斗 UI 跳转完成前忽略重复点击,并在 Promise finally 中释放;服务端 fight_startconquer/fight_startrevolt 同角色同目标同命令重复门调整为 3 秒,覆盖一次完整点击到战斗转场窗口。
验证:生产日志已确认原问题不是单次服务端慢请求,而是 3 次重复战斗请求叠加;新增 TestPVEBridge_FightStartConquer_DefaultDuplicateGateCoversBattleTransition,复现 1.1 秒间隔重复请求会被拦截;通过 node --check client/assets/game/scripts/FeudatoryInfoDialog.js 和 go test . -run 'TestPVEBridge_FightStartConquer' -count=1。
截图:

问题9:
状态:已修复 验收通过
备注:测试服依然榜单只有自己一个人 测试服账号:rty520520520 ID:100243669
截图:
正式服账号:facaizzz ID:100316514
现象:珍宝阁内消耗排行活动 只显示两个人 而且奖励不发放
预期:珍宝排行:本区内的所有玩家将根据当周道具消耗活动中对应道具的消耗数量或限时玩法进行排名,于消耗活动或限时玩法结束时结算,前 500 名玩家可获得排行奖励(道具消耗活动会于灵贝、白玉消耗中循环开启)
根因:有三个独立问题。第一,珍宝阁前台 collection_getweekactrank 在幽冥/怪异塔排行活动开启或角色有 evoTower.towerScore 时直接使用 evotower_role 排行 key,生产日志显示 2026-07-08 20:45 返回 rankType=evotower_role score=124 list=2,所以珍宝阁消耗排行实际展示成了幽冥榜,只剩 2 人。第二,珍宝阁排行奖励定时任务在周一 00:02 发奖时用 WeekOpenTimeUnixAt(next.Add(-1s)) 计算结算周,next.Add(-1s) 仍是新周周一 00:01:59,导致任务结算刚开始 2 分钟的新周,而不是刚结束的上一周。生产 Mongo 证据:上一周 1782662400 的白玉活动有 3932 人有分,facaizzz 分数 23396400;但 collection_rank_reward 只发了 22 封,邮件 ID 时间均在 2026-06-29 00:02 左右,最高邮件分数仅 44100,正是新周刚开始时的误结算结果。第三,前台周榜读 Redis collection_week_act_{activityId}_{weekOpenTime},但周活动分数写入只落角色 activityRecord.week,没有同步维护 Redis;该 Redis 榜默认 5 分钟 TTL,过期后 collection_getweekactrank 只把当前打开榜单的玩家写入 Redis,再读 top100,所以测试服出现 list=1。测试服日志证据:2026-07-09 17:54:15,roleId 100216517 返回 rankType=collection_week_act_10_1783267200 score=5543 list=1 myRank=1;同一时间 Mongo 当前周活动10有分人数为 524,100243669 分数 1852、Mongo 排名 201/524。生产一区 Mongo 当前周活动10有分人数为 1323,100316514/facaizzz 分数 4512、排名 100/1323。
修复:珍宝阁排行接口固定使用珍宝阁周活动自己的 collection_week_act_{activityId}_{weekOpenTime} key,不再复用 evotower_role;活动 ID 按当前周配置中的 10/11/12 选择。排行奖励定时任务改为在周一 00:02 结算上一周 openTime,避免提前结算新周。新增周活动分数写入后的珍宝阁周榜同步钩子,活动 10/11/12 分数成功写入 activityRecord.week 后同步更新 Redis;同时 collection_getweekactrank 在 Redis 榜为空/稀疏时从 Mongo 权威周活动记录回填 Redis,并在回填后重新查询本人真实排名,避免非 top100 玩家仍显示临时 rank=1。
验证:新增 TestCollectionWeekRankTypeAndScore_UsesCollectionWeekActivityWhenEvoTowerScoreExists,确认角色有幽冥分时仍使用珍宝阁周榜;新增 TestCollectionRankRewardSettleWeekOpenTime_UsesPreviousWeekAtMondayRewardTime,确认 2026-07-06 00:02 结算 2026-06-29 周;新增 TestIncrementWeekActivityProgressFieldized_UpdatesCollectionRank,确认周活动消耗分数写入后同步更新珍宝阁周榜;新增 TestCollectionWeekRankUpdatesFromRoles_UsesAuthoritativeWeekRecords 和 TestCollectionShouldRebuildWeekRank_RebuildsSparseRankOnce,确认 Redis 稀疏榜可从 Mongo 当前周权威记录回填。已通过 go test ./internal/activityx -count=1 和 go test . -run 'TestCollection|TestBuildCollection|TestActivityWeek|TestCollectionRankRewardSettleWeekOpenTime' -count=1。历史 2026-06-29 周漏发的前 500 奖励需要确认后按修正逻辑补发。
截图:


问题10:
状态:已修复 待正式服确认
预期:确保勋章加成 盐场内对战生效 (所都对战加成都生效)
根因:盐场 PvP 构造 battleData 时已经走 buildLeftTeamWithPet,勋章的攻击/血量加成会进入英雄 attack/hp;但随后 mergeSaltFieldTeamStateIntoTeamData 会把盐场快照 TeamInfo 中的 curHp/hp 直接覆盖回 battleData。盐场 TeamInfo 是入场/布阵快照,血量基准没有勋章战斗加成,所以首战会把已加成的 hp 对应 curHp 覆盖成未加成血量,表现为盐场内战斗血量加成不生效。连战时如果简单放大又会重复放大上一场战斗结果,因此需要记录战斗血量基准。
修复:盐场合并持续血量时按 当前 battleData 最大血量 / 快照血量基准 映射 curHp,并在 TeamInfo 中记录 battleMaxHp 作为后续连战基准;复活/重生重置血量时清除该基准,避免下一轮复活状态误用旧战斗基准。勋章攻击/血量加成仍由统一 buildLeftTeamWithPet 入口计算。
验证:新增 TestMergeSaltFieldTeamStateIntoTeamData_MapsInitialCurHpToBattleMaxHp,确认快照基础血量 1000、战斗最大血量 1250 时首战 curHp 映射到 1250;新增 TestMergeSaltFieldTeamStateIntoTeamData_DoesNotRescalePersistedBattleCurHp,确认连战剩余 800 不会二次放大;新增 TestResetRoleTeamCurHpLocked_ClearsBattleMaxHpBaseline,确认复活清理基准。通过 go test . -run 'TestMergeSaltFieldTeamStateIntoTeamData|TestResetRoleTeamCurHpLocked|TestScaleSaltFieldBattleTeamByRoleEnergy' -count=1 和 go test ./domains/core/competitive -run 'TestBuildLeftTeam_AppliesMedallionBattleBonusWithoutMutatingRole|TestBuildLeftTeam_MedallionBonusAggregatedOncePerBuildAndRepeatable' -count=1。
截图:
问题11:
状态:已修复 验收通过
测试服账号:rty520520520 ID:100243669 时间:7.9号 16:54
现象:对站房高级房间内不管是2人场 4人场 3v3场次 只有房主看到的页面正常 队员和观战人员看到的页面都不正常 卡界面 还可以点击跳过
预期:所有玩法房间内 所有人看到的页面一致 页面正常 无法点击跳过
日志证据:2026-07-09 目标测试服日志未命中 100243669/rty520520520,同一截图链路命中 roomId=787009002、battleId=1783587209712、房主 100089014/LZBN2、队员 100316514/facaizzz、观战/进房账号 100216517/rty520520。protocol-164938-004143.log:161-164 显示 100216517 16:53:22 查询房间、16:53:23 加入房间,16:53:31 房主执行 pkroom_startbattle 且 extraPushCount=1;pvp-164949-004152.log:59-61 连续三条 pkroom_fightnotify_payload 都是同一份左侧视角:attackRoleId=100089014 defendRoleId=100316514 attackScore=0 defendScore=1 leftRoleId=100089014 rightRoleId=100316514 view0=100089014 view1=100316514;app-153427-000000.log:456129-456131 证明 battle-worker 对 battleId=1783587209712 返回成功;app-153427-000000.log:456127-456132 显示 BattleSkipTest2 data=[0],跳过不是服务端开关放开。对比生产一区历史日志 prod-1-bugfan-20260629/...json.log.30:247334-247335,正确形态会出现 pkroom_fightnotify: mirrored viewer roleId=100736909 attackRoleId=100736909 defendRoleId=100842467,并给右侧 viewer 下发镜像后的 top-level 攻防视角。
根因:pkroom_fightnotify 的 buildPKFightNotifyPayloadForViewer 只做深拷贝,没有按 viewer 处理右侧参战者的 attackRoleId/defendRoleId/nextAttackRoleId/nextDefendRoleId/attackScore/defendScore,导致非房主收到房主左侧视角的战斗通知;客户端 RoomFightModule._onRoomFightNotify 只要收到带 battleData 的通知就会触发 EventRoomPKNewBattle,RoomFightPanel._onNewBattle 直接 SHOW_BATTLE_UI,UIBattleUIRoom.startNewBattle 的跳过是本地 battle manager 行为,不走 pkroom 网络命令,所以日志里不会出现 skip 命令。
修复:仅改服务端。server/pkroom_runtime.go 恢复 buildPKFightNotifyPayloadForViewer 对右侧 viewer 的 top-level 攻防/分数镜像,并保留 battleData 原始左右队伍,避免改动战斗输入;该逻辑同时覆盖实时 notifyPKRoomFight 和 currentFightNotifyPayloadForRole 重放路径。
验证:先将 TestBuildPKFightNotifyPayloadForViewer_MirrorsTopLevelFightForRightViewer 改为期望右侧 viewer 镜像并确认旧实现失败;修复后通过 env GOCACHE=/tmp/go-build GOTMPDIR=/tmp go test . -run 'TestBuildPKFightNotify|TestPKRuntimeRoom_CurrentFightNotifyPayload' -count=1。
截图:

问题12:
状态:已修复 待测试服复验
正式服账号::facaizzz ID:100316514 时间:7.9号 16:28
现象:对战房间内高级房间3v3玩法规则不对 会每个玩家都出场一次 切存在赢了判定输
预期:例1:玩家A队玩家ABC B队玩家DEF 游戏开启后 AD 对战 A输 第二回合D对战B(D保留上一场的状态) D输 第三回合B对战F B输 第四回合F对战C C输 那么B队胜利
例2:玩家A队玩家ABC B队玩家DEF 游戏开启后AD对战 A胜 第二回合A对战E A胜 第三回合A对战F A胜 那么A组胜利B组失败
对战赢了就是赢了 输了就是输了 不会存在赢了判定输
日志证据:已将生产一区 2026-07-09 pvp/protocol 日志拷到本地 /tmp/prod1-20260709-pvp.log、/tmp/prod1-20260709-protocol.log。/tmp/prod1-20260709-pvp.log:24531 显示 roomId=785144068 是 roomType=1 requestRoleNum=6 appliedClientRoleNum=6 groupType=2 的高级房 3v3 车轮战;:24898 第一场是 100285049 vs 100316514 matchRound=0 matchIndex=0;:25011 第二场却变成 100089014 vs 100892948 matchRound=0 matchIndex=1,说明服务端按普通高级赛树直接跳到另一组,而不是让第一场胜者留场对下一名对手;:25070 第三场又进入 matchRound=1 matchIndex=0 的决赛 100316514 vs 100089014。赢负判定错误也在同一房间复现::25072 第三场 leftRoleId=100316514 rightRoleId=100089014 isWin=false,真实赢家应是右侧 100089014,但 :25084 记录 pkroom_awardwin winnerId=100316514 before=34 after=35,把胜场加给了输家。截图房间 786413070 在 :25273 也显示同样规则参数。
根因:服务端把 roomType=advance && len(FightRoleBase)>=4 统一判成普通高级赛,pkRoomIsAdvanceSeries 没区分 groupType=2 的 3v3 车轮战;ensurePKAdvanceBracket/applyPKRoomBattleOutcome 因此固定生成 0v1 -> 2v3 -> final 的淘汰树,6 人时座位 4/5 被跳过,胜者也不会继续留场。最终战报和胜场统计又从 FightRoleBase[0]/[1] 或默认左右座位取人,而不是按当前 matchRound/matchIndex 的 aIdx/bIdx 取当前对局双方,导致生产日志里右侧赢了却给左侧/旧座位玩家加胜场。
修复:仅改服务端。server/pkroom_runtime.go 新增高级 3v3 车轮战分支:groupType=2 不再进入普通高级赛树;按座位奇偶划分 A/B 队,第一场 0v1,之后胜者留场并追加对阵失败方下一名队员,直到一方没有下一名队员才结算;战斗通知里的 nextAttackRoleId/nextDefendRoleId 按下一场真实双方下发;胜场统计和战报改为按当前 match 的 aIdx/bIdx 取人;同时从 battle result 保存胜者阵容剩余 HP/怒气,下一场构造 battleData 时回填,满足“胜者保留上一场状态”。未改客户端。
验证:新增并通过回归测试 TestApplyPKRoomBattleOutcome_AdvanceGroupWheel_WinnerStaysAgainstNextOpponent、TestApplyPKRoomBattleOutcome_AdvanceGroupWheel_EndsWhenOneTeamOut、TestPKRoomAdvanceGroupWheel_CarriesWinnerHPIntoNextBattleTeam、TestPKRoomWinnerRoleID_AdvanceGroupWheelUsesCurrentMatch、TestBuildPKBattleHistory_AdvanceGroupWheelUsesCurrentMatchRoles。验证命令:env GOCACHE=/tmp/go-build GOTMPDIR=/tmp go test . -run 'TestApplyPKRoomBattleOutcome_Advance(GroupWheel|Series)|TestPKRoomAdvanceGroupWheel_CarriesWinnerHP|TestPKRoomWinnerRoleID_AdvanceGroupWheel|TestBuildPKBattleHistory_AdvanceGroupWheel|TestBuildPKFightNotify_BestOfThree|TestBuildPKFightNotifyPayload|TestPKRuntimeRoom_CurrentFightNotifyPayload|TestPKRoomRuntime_RecordRoomBattle' -count=1;更宽的 env GOCACHE=/tmp/go-build GOTMPDIR=/tmp go test . -run 'PKRoom|pkroom|ApplyPKRoomBattleOutcome|BuildPKFightNotify' -count=1 也通过。
截图:

问题13:
状态:已修复 验收通过
现象:对战房间高级房开启后 其他玩家搜索不到
预期:房间开启对战后 玩家任可以搜索进入 正常观战
截图:

根因:搜索框走 pkroom_getroominfo({roomId})。服务端原来直接用原始 roomId 查运行时房间,未做 TrimSpace;如果输入带不可见空白会 miss。更关键的是 miss 后仍返回 code=0 + roomInfo:{},客户端会按成功打开搜索结果弹窗,但 roomInfo.watchRoles.get(leaderId) 取不到房主,表现为空搜索结果/无法正常加入。
日志证据:测试服 test-runtime/logs/2026-07-09/pvp-164949-004152.log:19 创建高级房 roomId=787009002 roomType=1;:48-51 账号 100216517/rty520520 开战前按房间号查询并加入成功;:53-68 房主开战并结算,房间仍保留为 state=2;:76 后续仍可命中该房间。截图时间点没有对应失败请求日志,因此本次修复锁定服务端可确定的搜索响应契约缺陷。
修复:pkroom_getroominfo 对 roomId 做 trim;明确传入房间号但未命中时返回 code=1,msg=房间不存在 并记录 miss 日志,避免客户端收到成功空房间;只有未传房间号时才 fallback 查询自己的房间。
验证:GOCACHE=/tmp/xianyu-go-build go test ./ -run 'TestPKRoom'
问题14:
状态:已修复 待验收
备注:测试服账号::rty520520 ID:100216517 时间:7月12号 11:48
现象:如截图1 已知我方诸葛亮精准142+进场黄月英专属鱼机神的50 共192精准 对方孙策格挡181 我方精准大于敌方孙策格挡 依然被挂火
预期:我方精准大于对方孙策格挡不会被孙策灼烧
截图:

测试服:账号:rty520520 ID:100216517 时间:7月9号 17:24
现象:对战房间内 切磋内 咸主挑战内 盐场战斗 竞技场内 我方精准大于敌方孙策格挡还会被孙策灼烧挂火
预期:我方精准大于对方孙策格挡不会被孙策灼烧 (是否月英专属鱼专属加成在这几个地方不生效)(确保盐场内不会出现这种情况) 应保证 切磋 对战房间 咸主挑战 盐场内战斗 数据都和竞技场一样
例:我方孙策总格挡 130%
你方精准 80%:剩余格挡 50%,50% 概率格挡 + 挂火
你方精准 140%:精准>格挡,0 格挡概率,永远挂不上灼烧
截图:

日志证据:截图底部 battleId 1783588965568 对应生产一区日志 /tmp/prod1-20260709-pvp.log:26914-26916,时间 2026-07-09 17:22:45.568 +08:00,fight_startpvp roleId=100216517 targetId=100276032 attackerPower=23258077366 defenderPower=25297659794 attackerWeapon=9 defenderWeapon=5;/tmp/prod1-20260709-protocol.log:234022 记录同一请求 trace_id=100216517-rty520520-130-fight_startpvp 成功返回 battleData。现有日志没有逐帧格挡/灼烧/精准明细,不能直接定死根因。
排查结论:战斗引擎格挡公式是 defender.attribute["54"] - attacker.attribute["53"],精准大于格挡时会归零;battle-worker 发送层不删除 53/54。当前高概率问题在各战斗入口构造 battleData 前的角色属性口径不一致:竞技场会按指定阵容/武器/宠物构造;切磋、对战房等入口存在使用缓存/覆盖阵容后未重新计算 bonus 的嫌疑。根因未定死,不修业务逻辑。
诊断:服务端已加低频诊断日志 [battle_precision_diag],仅对 PVP/竞技场/咸主类 mode 3/8/32 且命中黄月英 hero=116、龙鱼机神 artifact=12105/skill=12105 时输出:battleId、mode、左右 roleId、攻击方最大精准 leftMax53、防守方最大格挡 rightMax54、finalRightBlockVsLeft、每个上阵英雄的 hero/artifact/pearl/attr53/attr54/skills。盐场额外加 [saltfield_battle_placeholder_diag] 标识 war_startbattle 即时返回的占位 battleData 不含战斗属性,仅在占位队伍含黄月英时输出;真实 worker 入参仍看 [battle_precision_diag]。
7月11复核证据:截图 battleId 1783773821815 在测试服日志 /root/xianyu/test-runtime/logs/2026-07-11/app.log:39670 已命中 [battle_precision_diag],同一战斗 mode=3 leftRole=100216517 rightRole=100892948 leftMax53=2.3000 rightMax54=2.2185 finalRightBlockVsLeft=0.0000;worker 日志 /root/xianyu/test-runtime/logs/battle_worker/60b95146d9fc.log:8-15 确认 battle-worker 收到并执行同 battleId。该证据说明本次入口 battleData 里精准加成已进入 worker,按入参公式最终格挡率已经归零;暂不能再按“入口漏加黄月英/龙鱼机神精准”修。
新缺口:现有日志仍没有 worker 内部逐次格挡判定和灼烧 buff 来源,不能定死是 worker 结算、回放事件,还是表现误判。已在 server/battle_worker/runner.js 增加 battle worker precision trace 诊断,默认只对 mode 3/8/32 且命中 hero=116 或 skill=12105 的战斗输出;event=block 记录 attackRat/blockRat/finalBlockRate/roll/isBlock/双方英雄,event=buff 记录 buffId/buffType/buffTag/buffAttr/来源技能/来源英雄/目标。7月12复现日志显示原单场 80 条上限被 buff 事件刷满,未抓到 event=block,所以诊断已调整为 block/buff 分桶限流:block 默认最多 300 条,buff 默认最多 80 条,互不挤占,并在战斗结束输出 battle worker precision trace summary 统计 block/buff 抓取和丢弃数量。可用 BATTLE_WORKER_PRECISION_TRACE=off 关闭,可用 BATTLE_WORKER_PRECISION_TRACE_BLOCK_MAX、BATTLE_WORKER_PRECISION_TRACE_BUFF_MAX 单独调整上限。
复现要求:下一次请按 battleId 搜 [battle_precision_diag]、battle worker precision trace 和 battle worker precision trace summary。若 trace 出现 finalBlockRate=0 但 isBlock=true,修 worker 格挡判定/回放读写;若 blockCount=0 或没有 isBlock=true 但出现灼烧 buff,按 buffId/source skillUser/skillId 定位真实挂火来源;若入口和 worker 都正常但客户端显示异常,再查客户端回放表现链路,暂不改客户端。
7月13第一次定因证据:测试服账号 rty520520、roleId 100216517 复现命中 battleId 1783937390832,测试服日志 /root/xianyu/test-runtime/logs/2026-07-13/pvp.log:18 记录 fight_startpvp roleId=100216517 targetId=100892948;/root/xianyu/test-runtime/logs/2026-07-13/app.log:4668 的 [battle_precision_diag] 记录 mode=32 leftRole=100216517 rightRole=100892948 leftMax53=2.5501 rightMax54=2.2185 finalRightBlockVsLeft=0.0000,说明入口 battleData 中我方最高精准已大于孙策格挡;/root/xianyu/test-runtime/logs/battle_worker/2e35add30b12.log:94、:105 记录旧逻辑下孙策 targetHasTongxinAttack=true 时被 source=我方主公/id=0 触发 blocked_trigger,attackRat=0 blockRat=2.2185 finalBlockRate=1。本地高上限回放 /tmp/replay-1783937390832.log 进一步确认该 blocked_trigger 后由孙策 skillId=11171 给我方追加 buffId=11171/11172 灼烧链路。
7月13二次复现证据:测试服账号 rty520520、roleId 100216517 在 20:15:12 复现 battleId 1783944912618;/root/xianyu/test-runtime/logs/2026-07-13/app.log:7173 记录 mode=32 leftRole=100216517 rightRole=100892948 leftMax53=2.1451 rightMax54=2.1185 finalRightBlockVsLeft=0.0000。旧修复回放 /tmp/issue14-red.log 抓到孙策 target id=111 被普通武将来源 source id=104 hero_104 触发 blocked_trigger,attackRat=2.0691 blockRat=2.1185 finalBlockRate=0.0494 suppressed=false targetHasTongxinAttack=true;这说明之前只处理主公来源还不完整,非主公来源也会因同心路径取当前 source 精准而漏按全队最高精准口径判断。
最终根因:不是客户端表现问题,也不是入口漏加黄月英/龙鱼机神精准。真实根因在 battle worker 加载的战斗引擎同心分摊/反击路径:actor-hp-helper.subLife 对带 TONGXIN_ATTACK 的孙策触发 BLOCKED 时,直接取当前 source/r.skillUser 的 ATTACK_RAT 作为攻击方精准;但验收口径是“我方精准大于对方孙策格挡不会被孙策灼烧”,同心路径应按同阵营存活武将最高精准判断。旧逻辑在主公来源时精准为 0,普通武将来源低于全队最高精准时也可能把孙策格挡算成正值,从而错误触发 BLOCKED -> 11171/11172 挂火。
修复:仅改服务端 server/battle_worker/runner.js,不改客户端。battle worker 在 SkillTriggerHelper.triggerSkills 包装层统一处理 triggerType=BLOCKED 且目标带 TONGXIN_ATTACK 的场景:用同阵营存活武将最高 ATTACK_RAT 重新计算孙策格挡率,若最高精准已覆盖目标格挡,则返回 false 压掉这次错误的 BLOCKED 触发。目标没有同心反击、找不到同阵营存活武将、或最高精准仍不足时全部保留原逻辑。
验证:本地 node --check server/battle_worker/runner.js 通过;同一 replay 1783944912618-32.json 修复前 source=hero_104 attackRat=2.0691 blockRat=2.1185 finalBlockRate=0.0494 suppressed=false,修复后 /tmp/issue14-verify-positive.log 记录同一触发 effectiveSource=赵云 effectiveAttackRat=2.64511 effectiveFinalBlockRate=0 suppressed=true,且孙策 id=111 的 suppressed=false 记录为 0。PVP replay 1783948014719-32.json 与盐场 replay 1783948109524-3.json 均验证孙策 id=111 的同心 BLOCKED 按运行态最高精准压制。已执行 deploy/bin/update.sh test 更新测试服;测试服 health/ready 均正常,4 个 xianyu-test-battle-worker-* 容器内 node --check /app/server/battle_worker/runner.js 均通过,worker-1 启动日志有 tongxinBlockedGuard:true,更新后实际请求 battleId=1783948499432 已记录孙策 id=111 的 tongxin blocked suppressed。
问题15
状态:已修复 验收通过
测试服:账号:rty520520 ID:100216517 时间:7月9号 20:21
现象:游戏内先换玩具后上阵武将 武将速度会按照上一个速度 不会立即刷新最新玩具的速度(图一为先换玩具后上阵 图二先上阵后换玩具正常的)
预期:玩具更换后 所有武将面板立即刷新新玩具的数值 不会残留上个武将的数值
截图:

日志证据:测试服日志 /root/xianyu/test-runtime/logs/2026-07-09/protocol-164938-004143.log:673 记录 20:21:23.467 先请求 lordweapon_changedefaultweapon,trace 100216517-rty520520-40-lordweapon_changedefaultweapon;rolepower.log:73-74 记录同次换玩具 oldWeaponId=3 newWeaponId=8,触发 lordweapon_reset 并返回 heroes=1。随后 /root/xianyu/test-runtime/logs/2026-07-09/protocol-164938-004143.log:676-678 记录三次 hero_gointobattle,trace 100216517-rty520520-43/44/45-hero_gointobattle,rolepower.log:75-80 记录每次上阵都按新阵容重算战力,队伍从 heroes=2 到 heroes=4。
根因:客户端阵容详情速度只读 ROLE.heroes[heroId].speed,不会按玩具本地重算;服务端 hero_gointobattle 虽然写入新 battleTeam 并重算 power,但回包 role.heroes 只包含 battleTeamSlot,没有包含按当前玩具/阵容重算后的 speed/attribute/attack/hp/defense 等英雄面板字段。先上阵后换玩具正常,是因为 lordweapon_changedefaultweapon 在已有阵容时会通过 BuildHeroesDataFromBonus 返回阵上英雄面板属性;先换玩具后再上阵时,新上阵武将缺少这次面板属性同步,客户端继续显示旧缓存速度。
修复:服务端 server/internal/gameplay/herox/gointobattle_fieldized.go 在 hero_gointobattle 写入新阵容并计算战力后,使用同一份新 battleTeam 构建当前阵上英雄的面板数据,并合并原有 slot 变更返回;不修改客户端,不把动态面板属性写入 Mongo。
验证:新增回归测试 TestHeroGoIntoBattleFieldized_ReturnsRecalculatedBattleTeamHeroPanelData,先确认旧逻辑失败于 speed=<nil>,修复后通过。已执行 GOCACHE=/tmp/xianyu-go-build go test ./internal/gameplay/herox -run TestHeroGoIntoBattleFieldized -count=1 和 GOCACHE=/tmp/xianyu-go-build go test ./internal/gameplay/herox -count=1 通过。
问题16:
状态:已修复 验收通过
备注:测试服账号:nm480189 ID:100892948 时间:7月11 20:52
现象:竞技场挑战时还是按照防守阵容的宠物上阵 不按照当前主线阵容上阵的宠物
预期:当前主线阵容上阵的宠物是什么 竞技场内挑战他人时就是什么宠物
测试服账号:LZBN2 ID:100089014 时间:7.9号 20:46
现象:当竞技场防守阵容和主线阵容宠物上阵不一致时 竞技场挑战他人时 显示的是防守阵容设置的宠物
预期:主线阵容当前上阵是什么宠物 挑战他人时就是什么宠物 不跟着防守阵容走
截图:


日志证据:测试服 /root/xianyu/test-runtime/logs/2026-07-09/app-153427-000000.log:559899 在 20:46:32.414 记录 hero_calcpowerbyteam 战力 24392898154,宠物 100089014-1781560443486022636,对应主线截图 243.9亿;:559900 在 20:46:34.467 记录另一次 hero_calcpowerbyteam 战力 25135564951,宠物 100089014-1780858069577070064,对应竞技场防守截图 251.3亿。protocol-164938-004143.log:800 记录 20:46:38.529 执行 fight_startareaarena,trace 100089014-LZBN2-59-fight_startareaarena;app-153427-000000.log:559904 明确攻击方使用主线阵容 BattleTeam,但 :559906 显示攻击方入战宠物是 100089014-1780858069577070064,即竞技场防守宠物。
根因:客户端 ArenaBattleDialog 发起竞技场挑战只传 targetId/battleVersion,不传宠物;战斗 UI 只读服务端回包 battleData.leftTeam.petId/petActiveSkillId。服务端 fight_startareaarena 的攻击方队伍和武器已经走主线来源:BuildArenaAttackTeam(attackerRole) / BuildArenaAttackWeaponID(attackerRole);但攻击方宠物使用 firstNonEmpty(req.PetUId, attackerRole.ArenaPetUId),当客户端不传 petUId 时错误回退到竞技场防守宠物。防守方 resolveArenaDefenseEquipment(targetRole) 继续使用对手 Arena 防守宠物是正确行为。
修复:服务端 server/compat_ws_bridge.go 新增 resolveArenaAttackPetUId,竞技场挑战攻击方在请求未带 petUId 时回退到 role.PetData.pets[-1] 当前主线上阵宠物,不再回退 ArenaPetUId;防守方逻辑不变。不修改客户端。
验证:新增回归测试 TestResolveArenaAttackPetUIdFallsBackToEquippedMainPet,先确认旧代码缺失/无法满足该合同,修复后通过。已执行 GOCACHE=/tmp/xianyu-go-build go test ./ -run TestResolveArenaAttackPetUIdFallsBackToEquippedMainPet -count=1 和 GOCACHE=/tmp/xianyu-go-build go test ./ -run 'Test(FightStartAreaArena|ArenaStartArea|ResolveArenaAttackPetUId)' -count=1 通过。
7月11验收不通过复核:本地测试服日志 /root/xianyu/test-runtime/logs/2026-07-11/*.log 没有 100892948/nm480189 在 20:52 的 fight_startareaarena 请求;同时间窗只有 100216517/rty520520 的普通关卡 fight_startlevel 和系统健康/监控请求,不能证明本次复现打到了竞技场挑战入口。只读 Mongo 查询显示 100892948/nm480189 当前 petData.pets["-1"].uId 与 arenaPetUId 均为 100892948-1780768555262838447,即主线已装备宠和竞技场防守宠本身相同,用该账号无法验收“主线宠与防守宠不一致时是否取主线宠”。客户端 ArenaBattleDialog 仍只传 targetId/battleVersion,没有 petUId,不改客户端。
7月12复验通过:测试服账号 facaizzz/100316514 在 2026-07-12 08:27:47 执行 fight_startareaarena,/root/xianyu/test-runtime/logs/2026-07-12/protocol.log:754 命中 trace 100316514-facaizzz-94-fight_startareaarena;/root/xianyu/test-runtime/logs/2026-07-12/app.log:8753 显示攻击方 petUId=100316514-1782319616121773149。同号只读 Mongo 确认当前主线上阵宠为 100316514-1782319616121773149,竞技场防守宠为 100316514-1780861860974273176,两者不同,复验符合“攻击方使用当前主线宠,不跟随防守宠”的预期;防守方仍使用对手 Arena 防守宠,逻辑正确。
复验判定口径:使用主线宠和防守宠不同的账号,复现后按 fight_startareaarena battle_team side=attacker roleId=<roleId> ... petUId=<uid> 查日志;若 attacker petUId 等于 petData.pets["-1"].uId 则通过,若等于 arenaPetUId 再查部署版本或服务端逻辑。
问题17:
状态:已修复 待正式服验收
现象:怪异塔内俱乐部目标内属性加成无法领取 点击领取无反应
预期:点击领取可正常领取
截图:

日志证据:截图对应怪异塔主界面和“俱乐部目标/俱乐部特权”页,第二张图显示参与人数 25/25 且第一档特权红点。测试服 2026-07-10 日志中,/root/xianyu/test-runtime/logs/2026-07-10/protocol-004143-170935.log:321 记录角色 100216517/rty520520 在 15:12:35.850 成功执行 evotower_getinfo;:327、:328 分别在 15:12:38.720、15:12:39.945 成功执行 evotower_getlegionjoinmembers,返回成员列表。精确搜索同日日志无 evotower_claimlegionprivilege,说明点击没有形成服务端 claim 请求,而不是 claim handler 返回失败。Mongo 只读查询角色 100216517 显示 activityRecord.evoTower.legionPrivilege: {}、towerId:644、legionId:216517,与怪异塔俱乐部目标链路一致。
根因:客户端俱乐部特权页不从服务端 level/claimedLevel 字段取等级,而是遍历 SERVER_DATA.evoTower.legionPrivilege 的 Map key 当作当前已激活等级;只有 s == 当前行 && 可激活等级 > s 时才绑定 m_activeBtn.onClick 并发送 EvoTowerService.claimLegionPrivilege({})。服务端旧实现有三个不匹配点:evotower_getinfo/getlegionprivilege 把 legionPrivilege 保存/返回为 {level, claimedLevel, memberCount, totalScore, legionId} 元数据对象,污染客户端等级 Map;可激活档位硬编码为 1/5/10 人三档,而配置 EvoTowerClubPrivilegeConf 是 10/15/20/25 人四档;claim 成功只写 claimedLevel,没有发放/同步 PrivilegeConf 301-304 的 role.privilege。因此客户端会出现红点/状态异常且不发 claim,或 claim 后看起来无变化。
修复:仅改服务端。server/domains/activity/evotower 统一把 legionPrivilege 规范为客户端可消费的等级 key map,例如未激活 {}、已激活第一档 {"1":1};evotower_getinfo 会迁移旧 {level, claimedLevel} 结构,避免旧数据继续污染客户端。claim 按“下一档”逐档激活,按配置发放 301-304 到 role.privilege,并在响应里返回 role.privilege delta。server/internal/evotowercfg 新增加载 EvoTowerClubPrivilegeConf,按配置读取四档门槛并映射到 301-304;无配置时回落 10/15/20/25 默认值。不修改客户端。
验证:先新增 TestHandleGetLegionPrivilege_AndClaim 红灯,旧代码失败于返回 level/claimedLevel/memberCount 元数据;修复后通过,并断言首次领取只激活 {"1":1} 且返回 role.privilege.301。新增 TestHandleGetInfo_NormalizesLegacyLegionPrivilegeForClientLevelMap 覆盖 evotower_getinfo 历史数据迁移;TestLoadConfig_UsesKnownKeys 覆盖 EvoTowerClubPrivilegeConf 加载。已执行 GOCACHE=/tmp/xianyu-go-build go test ./domains/activity/evotower ./internal/evotowercfg ./entry/activity/activityentry -count=1 通过。
问题18:
状态:已修复 待正式服验收
预期:确保俱乐部赛车内俱乐部奖励每周五结算发放到账 最强赛车手排行奖励每4周结算一次奖励发放到账
每日奖励每天结算一次 奖励发放到账
截图:


日志证据:测试服 2026-07-12 赛车结算日志 /root/xianyu/test-runtime/logs/2026-07-12/cargoraid-114248-121004.log 显示 group_dan 周结算任务有执行并完成;Mongo 只读核对 mails 中已有 cargoraid_daily_rank_reward,但没有 cargoraid_group_rank_reward/俱乐部排行奖励来源邮件,说明不是邮件展示问题,而是俱乐部奖励链路未发。
根因:服务端俱乐部段位结算 settleCargoRaidGroupDan 只更新 cargo_raid_group_dan_settlements、legion.dan 和角色 cargoRaid,没有加载/使用 CarLegionRankReward,也没有生成俱乐部排行奖励邮件;同时历史实现按当前 role.LegionId 聚合本周俱乐部分,玩家换俱乐部后会把旧贡献错误归到当前俱乐部,不能满足截图规则中“奖励发放时不在俱乐部内仍可获得奖励”。
修复:仅改服务端。domains/legion/cargoraid 加载 CarLegionRankReward 并按段位+排名取奖;本周俱乐部分新增 groupScoreLegionId 贡献归属快照,周重置时清空,换俱乐部后旧贡献不挪到新俱乐部;settleCargoRaidGroupDan 在更新段位后按结算 entry 生成 cargoraid_group_rank_reward 邮件,带 dedupeKey 幂等防重,按贡献归属给成员发奖。
验证:新增并通过 TestLegionRankRewardForRankUsesLegionDan、TestBuildGroupDanSettlementUsesContributionLegionSnapshot、TestBuildCargoRaidGroupRankRewardRequestsRewardsCurrentLegionMembers,覆盖按段位取奖、换俱乐部贡献归属、俱乐部奖励邮件请求。已执行 GOCACHE=/tmp/xianyu-go-build go test ./domains/legion/cargoraid -run 'TestLegionRankRewardForRankUsesLegionDan|TestBuildGroupDanSettlementUsesContributionLegionSnapshot|TestPhaseRankRewardForRankIncludesMedallion' 和 GOCACHE=/tmp/xianyu-go-build go test . -run 'TestBuildCargoRaidGroupRankRewardRequestsRewardsCurrentLegionMembers|TestDecorateRecruitChatMessageIncludesLegionPayload|TestSystemGetChatMessageHandlerReturnsRecentRecruitMessages|TestSystemSendChatMessageHandler' 通过。
问题19:
状态:已修复 验收通过
测试服:账号:rty520520 ID:100216517 时间:7.12 10:52-53
现象:俱乐部邀请信息至世界招募频道后 招募频道不显示 且点击招募频道游戏直接卡死
预期:发送俱乐部邀请信息后所有人可以在招募频道看到 且可点击信息申请俱乐部 点击招募频道游戏不会卡死
截图:


日志证据:测试服复现窗口内 /root/xianyu/test-runtime/logs/2026-07-12/protocol-120841-121003.log:934 记录角色 100216517/rty520520 的 system_sendchatmessage 成功;/root/xianyu/test-runtime/logs/2026-07-12/app-121013-121002.log:11578 记录广播 payload 为 channel:3,msgType:3,extra:{extType:1},但缺少客户端招募消息必读的顶层 legion 和 legionMember;同窗口 system_getchatmessage 返回只有空 messageMap,导致招募频道历史也取不到。
根因:客户端 ChatPanel._dealRecruitMsg 对招募消息直接读取 e.legion.level/name/id 和 e.legionMember,但服务端 BuildChatMessage/HandleSystemChatBroadcast 只构造 roleId/roleName/channel/msgType/msg/extra,不会为招募频道补俱乐部数据;system_getchatmessageHandler 也固定返回空数组,所以招募实时消息和历史消息都不满足协议。
修复:仅改服务端。广播封包前对招募频道消息补齐 legion{id,name,level,dan,logo,serverId} 与 legionMember;无俱乐部角色禁止发送招募消息;服务端记录世界/招募最近消息,system_getchatmessage 返回招募历史,保持其他非公共频道不从该缓存返回,避免可见性扩大。
验证:新增并通过 TestDecorateRecruitChatMessageIncludesLegionPayload、TestSystemGetChatMessageHandlerReturnsRecentRecruitMessages,并回归 TestSystemSendChatMessageHandler* 和 go test ./internal/app/wsruntime,覆盖招募实时 payload、招募历史 payload 和广播接口兼容。
问题20:
状态:未处理
测试服:账号:rty520520 ID:100216517 时间:7.12 16:35-36
现象:竞技场内战斗赢了判定输
预期:赢了就是赢了 输了就是输了 不会出现赢了判定输的情况
截图:
评论
请登录后发表评论。
暂无评论。成为第一个评论者!