Files
AIC-Project/Client/Assets/Script/xmain/MiniGame/MiniGameNetChannel.cs
T
2026-07-10 10:24:29 +08:00

116 lines
4.2 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 System;
using System.Collections.Generic;
using UnityEngine;
using XWorld.Framework;
using XWorld.Framework.Protocol;
namespace XGame.MiniGame
{
// 客户端到服务端的帧通道。每帧轮询底层 socket,解码出的帧分发:
// Game 帧 -> OnGameMessage(NetMessage)(交给 IGameClient.OnNetMessage
// Framework 帧 -> OnFrameworkFrame(Frame)(宿主处理 MatchFound/RoomEnd 等)
public sealed class MiniGameNetChannel
{
private readonly XWebSocket _sock;
private readonly List<byte> _recvBuffer = new List<byte>(4096);
public Action<NetMessage> OnGameMessage;
public Action<Frame> OnFrameworkFrame;
public MiniGameNetChannel(XWebSocket sock) { _sock = sock; }
public bool IsConnected => _sock != null && _sock.IsConected();
// 业务输入:IGameClient 调 ctx.Send(NetMessage) -> 这里包成 Game 帧发出
public void SendGame(NetMessage msg)
{
byte[] frame = FrameCodec.Encode(new Frame(Channel.Game, msg.Opcode, msg.Payload));
SendRaw(frame);
}
public void SendFramework(FrameworkOpcode op, byte[] payload)
{
byte[] frame = FrameCodec.Encode(new Frame(Channel.Framework, (ushort)op, payload));
SendRaw(frame);
}
private void SendRaw(byte[] frame)
{
string err = null;
_sock.send(frame, null, ref err);
if (!string.IsNullOrEmpty(err)) Debug.LogError("[MiniGameNetChannel] send err: " + err);
}
// 每帧由宿主调用:把底层收到的字节解出并分发。
// XWebSocket 会把多条 WS 消息追加到同一个 bufferFrame 自带 payloadLen
// 所以这里按 FrameCodec 的线网格式从累计字节流中拆出 0..N 帧。
public void Pump()
{
if (_sock == null) return;
string err = null;
while (_sock.isDataRecv())
{
byte[] data = _sock.recv(ref err);
if (!string.IsNullOrEmpty(err)) { Debug.LogError("[MiniGameNetChannel] recv err: " + err); break; }
if (data == null || data.Length == 0) break;
_recvBuffer.AddRange(data);
}
while (TryPopFrame(out var frameBytes))
{
Frame f;
try { f = FrameCodec.Decode(frameBytes); }
catch (FormatException) { Debug.LogWarning("[MiniGameNetChannel] 畸形帧,丢弃"); continue; }
if (f.Channel == Channel.Game) OnGameMessage?.Invoke(new NetMessage(f.Opcode, f.Payload));
else OnFrameworkFrame?.Invoke(f);
}
}
private bool TryPopFrame(out byte[] frameBytes)
{
frameBytes = null;
if (_recvBuffer.Count < 4) return false; // channel + opcode + at least 1-byte payload len
int pos = 3;
uint payloadLen = 0;
int shift = 0;
while (true)
{
if (pos >= _recvBuffer.Count) return false;
if (shift > 28)
{
Debug.LogWarning("[MiniGameNetChannel] payloadLen varuint too long, clear buffer");
_recvBuffer.Clear();
return false;
}
byte b = _recvBuffer[pos++];
if (shift == 28 && (b & 0x70) != 0)
{
Debug.LogWarning("[MiniGameNetChannel] payloadLen overflow, clear buffer");
_recvBuffer.Clear();
return false;
}
payloadLen |= (uint)(b & 0x7F) << shift;
if ((b & 0x80) == 0) break;
shift += 7;
}
if (payloadLen > 1024 * 1024)
{
Debug.LogWarning("[MiniGameNetChannel] frame too large, clear buffer");
_recvBuffer.Clear();
return false;
}
int totalLen = pos + (int)payloadLen;
if (_recvBuffer.Count < totalLen) return false;
frameBytes = _recvBuffer.GetRange(0, totalLen).ToArray();
_recvBuffer.RemoveRange(0, totalLen);
return true;
}
}
}