Files
Ananta-ps/Ananta.Server/Ananta.Handlers/Game/GameRouter.NpcPhoneDrop.cs
T

118 lines
5.5 KiB
C#
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.
using Ananta.SDK.Network;
using Ananta.SDK.Rpc;
using Ananta.Server.Configuration;
using Ananta.Server.Protocol.Client4229938;
using GameMethods = Ananta.Server.RpcTypes.Client4229938.Methods.Game;
namespace Ananta.Server.Handlers.Game;
/// <summary>
/// 掉落物拾取的两个回执 —— 2026-09-25 接入。
///
/// <b>起因</b>:用户回报「路人 NPC 手里的手机能打落拾取,但他们的 BBChat 点不开」。
/// 掉手机这件事客户端本地就能做(GM 命令 <c>DebugEnableDropPhoneWhenDeath</c>,
/// <c>补丁和工具/ClientGmCommands.txt:320</c>),掉出来的手机是客户端自己生成的 SceneItem;
/// 但拾取时它发了两个 <b>INVOKE</b> 给服务端:
/// <code>
/// AskPickUpSceneItemTransferToItem (67297154) u64 sceneitemuid
/// AskEnemyItemPickUp (67453017) u64 enemyinstanceid + i32 binditemsindex
/// </code>
/// 这两个 MethodId 在本服务端<b>零 handler、也不在白名单</b>(全项目 grep 只命中 MethodId.cs),
/// ⇒ 走 <c>DefaultUnknownInvoke</c> 兜底或直接 await 挂起(硬规则 94)。
///
/// <b>本文件只回空 OK,不做内容</b>。理由(见 2026-09-25 记忆 §路人手机调研):
/// NPC 手机里的聊天<b>一个字节都不走服务端</b> ——
/// <c>GUI/Chat/RandomChatManager.lua:13 GetChatId(npcId, itemId)</c> 用
/// <c>AgentConfig.GetConfig(npcId)</c> 的 AppearanceTag / BodyTag / SexType / JobTag 去匹配
/// 35 行 <c>NPCChatAtmosphereNewConfig</c>(84028000-84028034),按 <c>60/Weight</c> 加权
/// 随机挑 1 条 <c>NPCChatConfig</c> 聊天链,然后打开面板。
/// ⇒ 想让"每个人手机不一样",要动的是 <b>npcId(AgentConfig id)</b>,不是往服务端塞文本。
///
/// ⛑ 注册的 kind 用 <c>Both</c>:按 AskControlAgent 那次的教训,同族 RPC 会有 NOTIFY 变体,
/// 只注册 Invoke 就是静默丢包;<c>ReturnEmptyOkAsync</c> 对 NOTIFY 是 no-op。
/// </summary>
internal sealed partial class GameRouter
{
/// <summary>per-session:本局拾取过的掉落物 uid(去重后只用于日志计数)。</summary>
private const string SceneItemPickupStateKey = "client4229938-sceneitem-pickup";
/// <summary>
/// AskPickUpSceneItemTransferToItem(67297154) —— 把场景里的掉落物收进背包。
///
/// 客户端本地掉落、本地回收,服务端没有 SceneItem 账本(我们从未推过
/// <c>SyncEnemyBeginSceneItemDrop</c> 68357238 / <c>SyncDropBelonging</c> 68316751),
/// 所以这里能做的只有<a href="硬规则 94">放行</a>:不回执,拾取动作 await 到超时。
/// </summary>
[Handler(MethodId.AskPickUpSceneItemTransferToItem, HandlerPacketKind.Both)]
private async Task OnAskPickUpSceneItemTransferToItem(Connection conn, UxRpcMessage msg)
{
ulong uid = 0;
try
{
var args = msg.GetArgs<GameMethods.AskPickUpSceneItemTransferToItem4229938>();
if (args is not null)
uid = args.sceneitemuid;
}
catch (Exception ex)
{
// ⛑ 不 throw:这是 INVOKE,抛异常等于不回执 ⇒ 客户端卡死。解析不出 uid 也要放行。
conn.Log.Warn($"[PICKUP] AskPickUpSceneItemTransferToItem 解析失败(按 uid=0 处理): {ex.Message}");
}
await conn.ReturnEmptyOkAsync(msg);
if (!PrivateServerConfigStore.Current.Gameplay.SceneItemPickupEnabled)
return;
var items = msg.Context.Session.Items;
if (items.TryGetValue(SceneItemPickupStateKey, out var raw) is false || raw is not HashSet<ulong> set)
{
set = [];
items[SceneItemPickupStateKey] = set;
}
bool fresh;
lock (set)
fresh = set.Add(uid);
conn.Log.Info($"[PICKUP] sceneitem uid={uid} kind={(msg.IsInvoke ? "invoke" : "notify")} " +
$"{(fresh ? "new" : "repeat")} — 本局已拾取 {set.Count} 件(服务端无 SceneItem 账本,只回执)");
}
/// <summary>
/// AskEnemyItemPickUp(67453017) —— 从敌人/NPC 身上拿走第 N 件携带物(belonging)。
///
/// 官方完整链是 <c>SyncAgentBelongings</c> → <c>SyncDropBelonging</c>(68316751) →
/// <c>SyncEnemyBeginSceneItemDrop</c>(68357238) → 本包。我们只发过第一步
/// (<c>GameRouter.HackNpc.cs</c> 给路人递手机),后两步是 T3-9 的整块待办。
/// 客户端仍会自发这个包 ⇒ 同样只放行。
/// </summary>
[Handler(MethodId.AskEnemyItemPickUp, HandlerPacketKind.Both)]
private async Task OnAskEnemyItemPickUp(Connection conn, UxRpcMessage msg)
{
ulong enemy = 0;
int index = -1;
try
{
var args = msg.GetArgs<GameMethods.AskEnemyItemPickUp4229938>();
if (args is not null)
{
enemy = args.enemyinstanceid;
index = args.binditemsindex;
}
}
catch (Exception ex)
{
conn.Log.Warn($"[PICKUP] AskEnemyItemPickUp 解析失败(按 0/-1 处理): {ex.Message}");
}
await conn.ReturnEmptyOkAsync(msg);
if (!PrivateServerConfigStore.Current.Gameplay.SceneItemPickupEnabled)
return;
conn.Log.Info($"[PICKUP] belonging from enemy={enemy} index={index} " +
$"kind={(msg.IsInvoke ? "invoke" : "notify")}(belongings 是 HackNpc 递的手机,服务端无掉落账本)");
}
}