122 lines
4.5 KiB
C#
122 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using FastArena.Network.Packets;
|
|
using UnityEngine;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace FastArena.Network
|
|
{
|
|
public enum ClientStatus
|
|
{
|
|
Initialized, Connected, Disconnected
|
|
}
|
|
|
|
public class ServerConnection
|
|
{
|
|
public IPAddress Ip;
|
|
public short PortFirst;
|
|
public Guid SessionId;
|
|
public byte[] ServerKey;
|
|
}
|
|
|
|
public static class Client
|
|
{
|
|
private static TcpClient _tcp;
|
|
private static UdpClient _udp;
|
|
private static byte[] _clientKey;
|
|
private static ServerConnection _serverConnection;
|
|
|
|
public static ClientStatus Status { get; private set; } = ClientStatus.Initialized;
|
|
|
|
public static void SendUserAction()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public static void Connect(IPAddress ip, short portFirst)
|
|
{
|
|
_tcp = new TcpClient();
|
|
_udp = new UdpClient();
|
|
_serverConnection = new ServerConnection()
|
|
{
|
|
Ip = ip, PortFirst = portFirst
|
|
};
|
|
_udp.Connect(ip, portFirst + 1);
|
|
_tcp.BeginConnect(ip, portFirst, TCPConnectCallback, null);
|
|
}
|
|
|
|
private static void ReadExactly(this TcpClient tcp, byte[] buffer, int offset, int exactSize, int timeoutMs = 5000)
|
|
{
|
|
int msPassed = 0;
|
|
while (tcp.Available < exactSize)
|
|
{
|
|
Thread.Sleep(1);
|
|
msPassed += 1;
|
|
if (msPassed > timeoutMs)
|
|
{
|
|
throw new TimeoutException(
|
|
$"couldn't get {exactSize} bytes from socket, {tcp.Available} avaliable");
|
|
}
|
|
}
|
|
|
|
int readN = _tcp.GetStream().Read(buffer, offset, exactSize);
|
|
if (readN != exactSize)
|
|
throw new Exception($"expected to read {exactSize} bytes, got {readN}");
|
|
}
|
|
|
|
private static void TCPConnectCallback(IAsyncResult ar)
|
|
{
|
|
_tcp.EndConnect(ar);
|
|
|
|
// receive first response from server
|
|
byte[] buffer = new byte[4096];
|
|
_tcp.ReadExactly(buffer, 0, Marshal.SizeOf<ConnectionResponseTCP>());
|
|
//TODO: implement decryption
|
|
var firstResponse = StructBinaryConverter.ReadStruct<ConnectionResponseTCP>(buffer);
|
|
firstResponse.ValidateResponseCode();
|
|
_serverConnection.SessionId = firstResponse.sessionId;
|
|
_serverConnection.ServerKey = firstResponse.serverKey;
|
|
|
|
// connect udp socket associated with current session
|
|
byte[] byteMessage = StructBinaryConverter.GetBytes(new ConnectionRequestUDP(_serverConnection.SessionId));
|
|
//TODO: implement encryption
|
|
_udp.Send(byteMessage, byteMessage.Length);
|
|
|
|
// receive second response from server
|
|
IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.None, 0);
|
|
byteMessage = _udp.Receive(ref remoteEndpoint);
|
|
//TODO: implement decryption
|
|
var secondResponse = StructBinaryConverter.ReadStruct<ConnectionResponseUDP>(byteMessage);
|
|
secondResponse.ValidateResponseCode();
|
|
|
|
//TODO: start tcp read loop
|
|
//TODO: start udp read loop
|
|
}
|
|
|
|
|
|
private static readonly Dictionary<int, SyncTransform> _syncTransforms = new Dictionary<int, SyncTransform>();
|
|
|
|
private static void CreateGameObject(ref CreateObjectPacket packet)
|
|
{
|
|
var prefab = Resources.Load(packet.prefabPath, typeof(GameObject));
|
|
var go = (GameObject)Object.Instantiate(prefab);
|
|
var idComponent = go.AddComponent<GameObjectId>();
|
|
idComponent._SetId(packet.gameObjectId);
|
|
if (go.TryGetComponent(out SyncTransform syncTransform))
|
|
{
|
|
_syncTransforms.Add(packet.gameObjectId, syncTransform);
|
|
}
|
|
}
|
|
|
|
private static void UpdateObjectTransform(ref TransformUpdatePacket packet)
|
|
{
|
|
if(!_syncTransforms.TryGetValue(packet.gameObjectId, out var component))
|
|
return;
|
|
component.UpdateTransform(ref packet);
|
|
}
|
|
}
|
|
} |