63 lines
2.9 KiB
C#
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<uint>) 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)");
|
|
}
|
|
}
|