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/internal/gameserver/routers/game_router_scene_devices.go
T

178 lines
9.9 KiB
Go
Raw Normal View History

package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// Scene devices — doors, vending machines, fridges, arcades, signs.
// Why "the fridge does nothing": an Ask* device INVOKE is only a REQUEST. The client's
// device-state manager waits for the server to echo the transition before it runs the
// presentation (door animation, fridge open, vending purchase). The donor handoff
// (HANDOFF-2026-09-18) walked exactly this path: round 13 added the echo, 13A removed it on a
// test that never happened, and 15D restored it from the one session whose log proved it worked
// (03:50 — the countdown door ran 9→6 cleanly with check=0 throughout; without the echo the same
// door re-fired 23× with the state DECREASING and the checkIndex escalating). Our logs show the
// very same signature today: AskSceneDeviceChangeState ×333 and AskSceneDeviceRecordValue ×364,
// all of them still on the generic neutral fallback.
// Wire (all CSharpOnly: raw fields, ZERO markers):
// <code>
// C2S AskSceneDeviceChangeState 67226162 (22b) = u8 type | u64 id | i32 stateType | i32 state
// | i32 checkIndex | u8 trailing
// C2S AskSceneDeviceRecordValue 67703474 (21b) = u8 type | u64 id | i32 valueName
// | string value (BIASED len + UTF-8)
// | i32 checkIndex | trailing
// reply (both) = SceneDeviceCheckIndexCallback { int CheckIndex; uint Error; } = 8 bytes
// S2C SyncSceneDeviceStateChange 68165561 (21b) = u8 type | u64 id | i32 stateType | i32 state
// | i32 checkIndex
// S2C SyncSceneDeviceValueChange 68332775 = u8 type | u64 id | i32 valueName
// | string value | i32 checkIndex
// </code>
// Two traps baked into the code below:
// 1. String bias is asymmetric. C2S device strings are BIASED (len+1 — a 9-char
// "StartMind" arrives as 0x0A); S2C strings are RAW (ReadStringOrNull @0x189AAB3D0).
// 2. Never push SyncSceneDeviceSignalSend(68477555). The client relays a server signal
// echo back as its own request — 13A measured 14×/s. That one echo is a real loop.
//
// AskSceneDeviceChangeState(67226162) / AskSceneDeviceRecordValue(67703474).
func GameRouter_SceneDevices_OnAskSceneDeviceChangeState(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskSceneDeviceChangeState
var zero any; return zero
}
// AskSceneDeviceRecordValue(67703474) — value records (vending count, sign text).
func GameRouter_SceneDevices_OnAskSceneDeviceRecordValue(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskSceneDeviceRecordValue
var zero any; return zero
}
// CheckCanOccupySceneDevice(67063877) / ReleaseOccupySceneDevice(67244136): void.
func GameRouter_SceneDevices_OnSceneDeviceOccupy(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnSceneDeviceOccupy
var zero any; return zero
}
//
// AskCheckSpoonConditionByType(67709054) — "may I run this device script?".
// ⛔⛔ **2026-09-28 实机订正(用户验证)—— 下面这段旧说法是错的,已改写,别再改回去:**
// 旧文:"The generated neutral default is 0x00 = false, which is precisely what makes an
// interaction appear dead: the client asks, we say no, and nothing plays. Donor round 13
// answers 0x01." —— donor 那条从未实测,只是推断;对**衣柜这一族实测结果完全相反**。
// 实测(塔菲公寓衣柜 uid 14013633775178039662):
// · 答 0x01(true):F 提示一闪即没、换装打不开,`[SPOON] action` 只发 2 次就停
// (packets-20260928-204201.log 21:03:18.961 S2C hex=01)。
// · 答 0x00(false):F 常驻,22:46:44 `[SPOON] action` 触发,payload 与能换装的对照组
// v1.5 逐字节相同(console-20260928-224215.log)。
// 对照组 v1.5 没有本 handler,走 DefaultReturnCatalog4229938 兜底 0x00 ⇒ 衣柜一直可用。
// ⇒ **true 才是让交互挂死的那个值**:客户端拿到 true 就把交互交给服务端 spoon 脚本流程,
// 而 AskDoSpoonServerActionByType 我们只回空 OK、给不出任何脚本输出 ⇒ 卡死、提示被撤。
// 答 false 时客户端走本地表现,脚本照跑。
// 开关:Drmk.Server.Configuration.SceneDeviceSettings.SpoonConditionTrue
// (默认已改为 false;配置里 `world.content.sceneDevices.spoonConditionTrue` 显式 false)。
// 另见 `PrivateServerConfig.cs` 该字段的完整实测记录。
//
func GameRouter_SceneDevices_OnAskCheckSpoonConditionByType(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskCheckSpoonConditionByType
var zero any; return zero
}
// AskGetSpoonServerOutputPortIndexByType(67346473): raw u32, always 0.
func GameRouter_SceneDevices_OnAskGetSpoonServerOutputPortIndexByType(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskGetSpoonServerOutputPortIndexByType
var zero any; return zero
}
// AskDoSpoonServerActionByType(67863523): void. Logged — the payload carries the port.
func GameRouter_SceneDevices_OnAskDoSpoonServerActionByType(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskDoSpoonServerActionByType
var zero any; return zero
}
// --- wire helpers ------------------------------------------------------------------------
// SceneDeviceCheckIndexCallback { int CheckIndex; uint Error; } — 8 bytes, Error = 0.
func GameRouter_SceneDevices_SceneDeviceOkReply(ctx context.Context, checkIndex int32) []byte {
// Router implementation for GameRouter_SceneDevices_SceneDeviceOkReply
return nil
}
func GameRouter_SceneDevices_EchoOff(ctx context.Context, cfg any, id uint64) bool {
// Router implementation for GameRouter_SceneDevices_EchoOff
return true
}
// SyncSceneDeviceStateChange(68165561) — 21 raw bytes, no markers.
func GameRouter_SceneDevices_PushDeviceStateAsync(ctx context.Context, conn any, typeVal byte, id uint64, stateType int32, state int32, checkIndex int32) any {
// Router implementation for GameRouter_SceneDevices_PushDeviceStateAsync
var zero any; return zero
}
// SyncSceneDeviceValueChange(68332775) — S2C strings are RAW-length, not biased.
func GameRouter_SceneDevices_PushDeviceValueAsync(ctx context.Context, conn any, typeVal byte, id uint64, valueName int32, value []byte, checkIndex int32) any {
// Router implementation for GameRouter_SceneDevices_PushDeviceValueAsync
var zero any; return zero
}
// Raw 7-bit varint (no +1 bias) — the S2C string length encoding.
func GameRouter_SceneDevices_WriteRaw7(ctx context.Context, sink []byte, value int32) any {
// Router implementation for GameRouter_SceneDevices_WriteRaw7
var zero any; return zero
}
// --------------------------------------------------------------------------------------
// AskSceneDeviceSendSignal (67144566) — 2026-09-27,桌面清单 T1-44 P0。
//
// 为什么排 P0:**它是 `unknown-methods.log` 里出现最多的 INVOKE**(全量 249 次,09-25 以后 74 次),
// 而且解出来的 `signalName` 不是设备状态,是**玩法/任务/特效信号** —— 服务端此前一条都收不到:
//
// | signalName | 次数 | 含义(按名字推断) |
// |---|---|---|
// | `FinishMind` | 238 | 心智/意志玩法结束(集中在两个固定 gadget uid) |
// | `StartMind` | 4 | 同上,开始 |
// | `BowlingInviteTimelinePlay` | 2 | 保龄球邀请时间轴播放 |
// | `TaskFinish60001155` | 2 | **任务 60001155 完成**(gadget 上触发) |
// | `SmokeFX Off` | 2 | 烟雾特效关闭 |
// | `carshop` | 1 | 车店 |
//
// ⛑ `TaskFinish60001155` 值得盯:服务端一直不知道任务什么时候完成(T2-9 任务面板那条线
// 缺的就是"真实达成"的事件钩子),这条是客户端唯一主动上报任务完成的通道之一。
//
// 方向:**INVOKE**(`ClientToGameSceneDelegate.lua:899` 是 `self.Invoke(...)`)。
// 返回:`UXRPCTask`(void,`RPCDeserializeAuto.lua:14968` 的 reader 函数体为空)⇒ **空 OK 即正解**。
//
// Wire(与 `AskSceneDeviceRecordValue` 同族,**raw,零 marker**):
// `u8 type | u64 id | string signalName`
// type = `SceneDeviceEntityType`(dump.cs:1749290 **只有两个值**:`Gadget = 0` / `Destructible = 1`;
// 观测到的 249 条全部是 **0 = Gadget**)
// signalName = **偏置** 7-bit varint 长度 + UTF-8(与本文件 RecordValue 的 C2S 字符串同规则,
// ⛑ 不是 S2C 的 raw —— 见本文件头"陷阱 1:字符串偏置是不对称的")
//
// ⛑⛑ **绝对不要在这个 handler 里推 `SyncSceneDeviceSignalSend`(68477555)**:本文件头已记录,
// 客户端会把服务端推的信号**当自己的请求再发回来**(donor 13A 实测 **14 次/秒**)⇒ 真回环。
// 这里只回空 OK + 打日志。将来真要驱动玩法,另开一条不会回环的路。
//
// ⛑ 硬规则 94:id 必须进 `GameRouter.cs` 的 `Enabled4229938MethodIds`,否则编译过但不注册。
// --------------------------------------------------------------------------------------
func GameRouter_SceneDevices_OnAskSceneDeviceSendSignal(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_SceneDevices_OnAskSceneDeviceSendSignal
var zero any; return zero
}
func GameRouter_SceneDevices_TypeName(ctx context.Context, typeVal byte) string {
// Router implementation for GameRouter_SceneDevices_TypeName
return ""
}
//
// C2S 设备字符串的**有偏** 7-bit varint 长度:线上是 `len + 1`,返回时已减回。
// 同时给出消耗的字节数(观测到的信号名都 &lt; 127 字节,但保龄球那条 25 字符也走同一路径,
// 不做多字节解析将来迟早踩到)。
//
func GameRouter_SceneDevices_ReadBiasedLen7(ctx context.Context, span []byte) any {
// Router implementation for GameRouter_SceneDevices_ReadBiasedLen7
var zero any; return zero
}