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

63 lines
2.9 KiB
C#

using Ananta.SDK.Network;
using Ananta.SDK.Rpc;
using Ananta.SDK.Serialization;
using Ananta.Server.Protocol.Client4229938;
using SceneMethods = Ananta.Server.RpcTypes.Client4229938.Methods.GameScene;
namespace Ananta.Server.Handlers.Game;
/// <summary>
/// Spoon server-action output ports. The client's spoon task graph asks the SERVER which
/// output port to take (AskGetSpoonServerOutputPortIndexByType, UXRPCTask&lt;uint&gt;) or to
/// perform an action (AskDoSpoonServerActionByType). We answer port 0 — byte-identical to
/// the typed-default fallback — and, for do-action, push the nearest repair shop's
/// inventory so the mechanic's "assortment" dialog branch opens with content.
/// Full param decoding (SpoonServerActionParam) is deferred: the raw body is logged.
/// </summary>
internal sealed partial class GameRouter
{
[Handler(MethodId.AskGetSpoonServerOutputPortIndexByType, HandlerPacketKind.Invoke)]
private Task SpoonOutputPortProbe(Connection conn, UxRpcMessage msg)
{
conn.Log.Info($"[SPOON] output-port probe bytes={msg.Body.Length} -> port 0");
return conn.ReturnAsync(msg, 0u);
}
[Handler(MethodId.AskDoSpoonServerActionByType, HandlerPacketKind.Invoke)]
private async Task SpoonServerAction(Connection conn, UxRpcMessage msg)
{
conn.Log.Info($"[SPOON] do-action bytes={msg.Body.Length} -> ok (port 0)");
await conn.ReturnEmptyOkAsync(msg);
// Push the nearest repair shop's inventory when the player is close to one —
// the mechanic's assortment dialog opens empty without this push.
var state = GetStateIfExists(conn.Session);
if (state is null || !state.HasLastReportedPlayerTransform)
return;
var px = state.LastReportedPlayerPosition.X;
var pz = state.LastReportedPlayerPosition.Z;
var west = ShopInteriors[0];
var seaside = ShopInteriors[1];
float D2(SceneMethods.UxVector3 e) => (px - e.X) * (px - e.X) + (pz - e.Z) * (pz - e.Z);
var (shopId, dist2) = D2(west.Entrance) <= D2(seaside.Entrance) ? (94100069u, D2(west.Entrance)) : (94100070u, D2(seaside.Entrance));
if (dist2 > 60f * 60f)
return;
ShopCommodityCache.Value.TryGetValue(shopId, out var ids);
var items = (ids ?? []).Select(id => new RpcTypes.Client4229938.Methods.Game.ShopCommodityItem
{
TemplateId = id,
Count = 1,
Status = 0,
Discount = 100,
MaxBuyCount = 0,
}).ToList();
await conn.Session.NotifyAsync(MethodId.IGameToClient_SyncFullCommodityInfos, UxSerializer.Serialize(
new RpcTypes.Client4229938.Methods.Game.SyncFullCommodityInfos
{
shopId = shopId,
infos = items,
}), CancellationToken.None);
conn.Log.Info($"[SPOON] do-action -> pushed {items.Count} commodities shop={shopId} (dist={MathF.Sqrt(dist2):F0}m)");
}
}