package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// 五子棋**单机**(人机 / 残局)—— EnterGomokuZoneDoubleAI(67614971) 与
// EnterGomokuZoneEndGame(67341006)。
// ★ 现象与根因链(四刀,每一刀都有本机取证)
//
// - R153 入口未登记:这两条从未进白名单 ⇒ 走 DefaultReturnCatalog4229938
// 兜底(:1611 / :1710)回 8 个 0x00 = **裸 u64 = 0**。客户端
// [warning]StartGomoke AI: TryGetLogicAgent fail, uid=0 /
// StartGomoke EndGame: TryGetLogicAgent fail, uid=0。
// ⇒ 必须登记并回一个**真实存在的**实体 uid。
// - R155 只有 uid 装不下身份:SyncLogicAgentEnter 的 interop 签名只有一个 ulong,
// 而 LogicAgent.AgentConfigId 是 uint ⇒ 只注册 uid 会让客户端报
// 创建AgentUnit失败!AgentConfigId为0!。
// 唯一能送 AgentConfig 的通道是 **Aether 静态 NPC**(NpcFormworkId 就是 AgentConfig id),
// 而客户端在请求体第 2 个字段 agentid 里**自己把该填哪个告诉我们了**。
// - R156 缺棋局状态推送(本轮真正卡住落子的那一刀):
// 客户端点子链是 TryRayIntersectBoard → PlaceGomokuPiece →
// AskPlaceGomokuPiece,而闸门是 GomokuManager.get_NowMyTurn();
// 唯一能置起"我的回合"的输入就是 SyncGameGroundZoneInfo(68004609)。
// 实测 AskPlaceGomokuPiece / PlaceGomokuPiece / SyncGameGroundZoneInfo
// 在全部历史日志里 **0 命中** ⇒ 客户端从没收到过 ⇒ 闸门恒关 ⇒ **一条落子包都不发**。
// - R185 参与方列表不能为空:客户端靠 ipairs(zoneInfo.ParticipantInfos) 拿到
// pendingOpponentAgentId。推空列表 ⇒ 它永远是 0 ⇒ 闸门还是不开。
// 且列表元素是**多态**的,每个元素自带 1B tag = GomokuWire.ParticipantTagGomoku(12);
// 若用裸 [UxContract](默认 0xFF)会被 Dispatch 判成 undefined 分支全部丢弃。
//
// ★ 三步法与主线自己的 GameRouter.ChineseChess.cs(SpawnChineseChessAiAsync)
// **完全同形**(那里注释原话:"与五子棋 R153/R155/R157 三步完全同形"):
// ① SyncLogicAgentEnter 注册 uid → ② SendCivilianAsync 送 AgentConfig + 站位
// → ③ 把同一个 uid 回给客户端 / 写进 ParticipantInfos[].AgentInstanceId。
// ⛑⛑ 不要加"等 NPC 落地"的延迟:象棋的实测证据是客户端
// TryGetOrConvertToUnit 查不到时**会等待**(10 秒后才打"等待服务器对手 NPC 单位超时"),
// 不是立刻失败 ⇒ 时序不是问题,缺的是状态推送。曾按"时序"假设加过延迟,方向是错的。
// 契约 DTO 见 Drmk.RpcTypes/Client4229938/GomokuWireContracts.cs(文件头有逐字段的本机复核)。
//
// ─────────────────────────────────────────────────────────────────────
// 两条单机入口
// ─────────────────────────────────────────────────────────────────────
//
// EnterGomokuZoneDoubleAI(67614971) 人机对战。
// C2S = u64 gadgetuid + u32 agentid + bool useblackpiece + byte difficulty + bool canuseskill。
// RET = **裸 u64**(对手实体的真实 uid)。
//
func GameRouter_GomokuSolo_EnterGomokuZoneDoubleAI4229938(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_GomokuSolo_EnterGomokuZoneDoubleAI4229938
var zero any; return zero
}
//
// EnterGomokuZoneEndGame(67341006) 残局。
// C2S = u64 gadgetuid + u32 agentid + u32 endgameid。RET = **裸 u64**(同上)。
// ⛑ 与 DoubleAI 的差别只有:请求里**没有** useBlack 字段 ⇒ 按残局约定「玩家先手 = 黑」。
//
func GameRouter_GomokuSolo_EnterGomokuZoneEndGame4229938(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_GomokuSolo_EnterGomokuZoneEndGame4229938
var zero any; return zero
}
// 把对手 uid 按「裸 u64」拼成 8 字节小端回给客户端。
func GameRouter_GomokuSolo_ReturnGomokuUidAsync(ctx context.Context, conn any, msg any, uid uint64) any {
// Router implementation for GameRouter_GomokuSolo_ReturnGomokuUidAsync
var zero any; return zero
}
// ─────────────────────────────────────────────────────────────────────
// ★★★ R156 核心:把「棋局已开始、现在轮到谁、对手是谁」推给客户端
// ─────────────────────────────────────────────────────────────────────
//
// 推 SyncGameGroundZoneInfo(68004609) + GomokuZoneInfo(多态 tag 13)。
// 这是「点棋盘没反应」与「能落子」之间缺的那一刀 —— 客户端 get_NowMyTurn()
// 的置位只有这一个输入来源。
// ★ 座位/先手(别与象棋的「颜色」混淆):五子棋 CurrentTurn 是 **SeatIndex 座位号**。
// GomokuWire.SeatIndexBlack = 0;客户端两个单机入口都 useBlack=true
// ⇒ 玩家 mySeatIndex = 0、黑棋先手 ⇒ CurrentTurn 必须是 0。
// 玩家 SeatIndex=0 / AI SeatIndex=1 / CurrentTurn=玩家座位 —— **三者必须自洽**,
// 写错任一个都是「点不动」。
// 回滚 = 删两个 handler 里对本方法的调用(两行)。
//
func GameRouter_GomokuSolo_PushGomokuZoneInfoAsync(ctx context.Context, conn any, gadgetUid uint64, gameType byte, aiUid uint64, playerUsesBlack bool) any {
// Router implementation for GameRouter_GomokuSolo_PushGomokuZoneInfoAsync
var zero any; return zero
}
// ─────────────────────────────────────────────────────────────────────
// 造对手 —— 三步法,与 GameRouter.ChineseChess.cs 的 SpawnChineseChessAiAsync 同形
// ─────────────────────────────────────────────────────────────────────
//
// 建一个「客户端查得到的 AI 对手」,返回它的**真实 uid**。三步:
// ① SyncLogicAgentEnter 注册 uid(客户端 TryGetLogicAgent 查的就是这张表);
// ② 用**客户端给的 agentId** 走 Aether 静态 NPC 通道(NpcFormworkId = AgentConfig id,
// 不送的话客户端建 Unit 时报 创建AgentUnit失败!AgentConfigId为0!);
// ③ 把同一个 uid 交回调用方(回包 + 写进 ParticipantInfos)。
// ★ R157 复用:**同一会话同一张桌只 spawn 一次**。理由(象棋同源注释原话):
// 「旧的那个删不掉(本版客户端无可靠删除通道)⇒ 场上越来越多」。
// 实测本仓 MethodId 里没有 SyncAetherAIStaticNpcRemove*;
// SyncRemoveNpc(68446556) 的 reader 是 Int32 ⇒ 装不下 830… 段的 u64。
// ⇒ 与其猜"怎么删",不如**根本不重复建**。
// 缓存键带 gadgetUid(庙会区有多张 WuZiQi 桌,要各有一个对手,不能互相顶掉)。
// 作用域用 TcpSession.Items —— 断线即弃,不会泄漏到别的会话。
//
func GameRouter_GomokuSolo_SpawnGomokuOpponentAsync(ctx context.Context, conn any, gadgetUid uint64, agentId uint32, playerUsesBlack bool, tag string, endGameId uint32) any {
// Router implementation for GameRouter_GomokuSolo_SpawnGomokuOpponentAsync
var zero any; return zero
}
//
// 挑对手模板:优先用客户端请求里带来的 agentId(实测 40131483「廖永强」),
// 它不在 NpcCatalog 里时才退回通用市民(骰子 PickDiceOpponentItem 同款挑法)。
//
func GameRouter_GomokuSolo_PickGomokuOpponentItem(ctx context.Context, agentId uint32) any {
// Router implementation for GameRouter_GomokuSolo_PickGomokuOpponentItem
var zero any; return zero
}
// 摊位表里离玩家最近的那个五子棋机关;表为空时返回 null。
func GameRouter_GomokuSolo_FindGomokuStall(ctx context.Context, px float32, pz float32) any {
// Router implementation for GameRouter_GomokuSolo_FindGomokuStall
var zero any; return zero
}
//
// 造 NPC 失败时的兜底 uid(骰子 FallbackUid 同款)。刻意不是 0 ——
// 0 会被客户端当成「进场失败」(套圈注释的判据),至少让它走到
// 「等待 Agent 实体同步」而不是当场判死,日志里也好区分。
//
func GameRouter_GomokuSolo_GomokuFallbackUid(ctx context.Context, ) uint64 {
// Router implementation for GameRouter_GomokuSolo_GomokuFallbackUid
return 0
}