You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
6.3 KiB
235 lines
6.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
|
|
public interface IBytable
|
|
{
|
|
byte[] Serialize();
|
|
void Deserialize(byte[] bytes);
|
|
}
|
|
|
|
public class RemoteDataPipelines
|
|
{
|
|
interface IPipeline
|
|
{
|
|
void OnRequest(TcpServerClient server, uint ownerUserID);
|
|
void OnRecv(byte[] bytes);
|
|
}
|
|
|
|
class Pipeline<T> : IPipeline where T : IBytable
|
|
{
|
|
Func<T> onRequest;
|
|
Action<T> onRecv;
|
|
|
|
public Pipeline(Func<T> onRequest, Action<T> onRecv)
|
|
{
|
|
this.onRequest = onRequest;
|
|
this.onRecv = onRecv;
|
|
}
|
|
|
|
public void OnRequest(TcpServerClient server, uint ownerUserID)
|
|
{
|
|
var instance = onRequest.Invoke();
|
|
byte[] bytes = instance.Serialize();
|
|
|
|
// TODO : Send bytes to server
|
|
ByteStream stream = new ByteStream();
|
|
//stream.Write(ownerUserID);
|
|
stream.Write(bytes);
|
|
|
|
var toBytes = stream.Bytes;
|
|
int dataSize = toBytes.Length;
|
|
|
|
Packet packet = new Packet();
|
|
//packet.header.code = HeaderCode.?;
|
|
packet.header.size = dataSize;
|
|
packet.body.data = toBytes;
|
|
|
|
server.Send(packet);
|
|
}
|
|
|
|
public void OnRecv(byte[] bytes)
|
|
{
|
|
var instance = Activator.CreateInstance<T>();
|
|
instance.Deserialize(bytes);
|
|
onRecv.Invoke(instance);
|
|
}
|
|
}
|
|
|
|
TcpServerClient client;
|
|
uint ownerUserID;
|
|
Dictionary<uint, IPipeline> pipeLines = new();
|
|
|
|
public event Action<uint, uint> OnRecvRequestEvent;
|
|
|
|
public RemoteDataPipelines(TcpServerClient client, uint ownerUserID)
|
|
{
|
|
this.client = client;
|
|
this.ownerUserID = ownerUserID;
|
|
}
|
|
|
|
public void AddPipeline<T>(uint eventID, Func<T> onRequest, Action<T> onRecv) where T : IBytable
|
|
{
|
|
if (!pipeLines.ContainsKey(eventID))
|
|
{
|
|
var recvEvent = new Pipeline<T>(onRequest, onRecv);
|
|
pipeLines.Add(eventID, recvEvent);
|
|
}
|
|
}
|
|
|
|
public void RemovePipeline(uint eventID)
|
|
{
|
|
pipeLines.Remove(eventID);
|
|
}
|
|
|
|
public void RequestEvent(uint eventID)
|
|
{
|
|
if (pipeLines.TryGetValue(eventID, out var pipeline))
|
|
{
|
|
pipeline.OnRequest(client, ownerUserID);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class RemoteTrasnfrom : IBytable
|
|
{
|
|
Vector3 position;
|
|
Vector3 scale;
|
|
Vector3 rotation;
|
|
|
|
public Vector3 Position => position;
|
|
public Vector3 Scale => scale;
|
|
public Vector3 Rotation => rotation;
|
|
|
|
public byte[] Serialize()
|
|
{
|
|
byte[] bytes = new byte[sizeof(float) * 3 * 3];
|
|
BitConverter.GetBytes(position.x).CopyTo(bytes, 0);
|
|
BitConverter.GetBytes(position.y).CopyTo(bytes, sizeof(float));
|
|
BitConverter.GetBytes(position.z).CopyTo(bytes, sizeof(float) * 2);
|
|
BitConverter.GetBytes(scale.x).CopyTo(bytes, sizeof(float) * 3);
|
|
BitConverter.GetBytes(scale.y).CopyTo(bytes, sizeof(float) * 4);
|
|
BitConverter.GetBytes(scale.z).CopyTo(bytes, sizeof(float) * 5);
|
|
BitConverter.GetBytes(rotation.x).CopyTo(bytes, sizeof(float) * 6);
|
|
BitConverter.GetBytes(rotation.y).CopyTo(bytes, sizeof(float) * 7);
|
|
BitConverter.GetBytes(rotation.z).CopyTo(bytes, sizeof(float) * 8);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
public void Deserialize(byte[] bytes)
|
|
{
|
|
position.x = BitConverter.ToSingle(bytes, 0);
|
|
position.y = BitConverter.ToSingle(bytes, sizeof(float));
|
|
position.z = BitConverter.ToSingle(bytes, sizeof(float) * 2);
|
|
scale.x = BitConverter.ToSingle(bytes, sizeof(float) * 3);
|
|
scale.y = BitConverter.ToSingle(bytes, sizeof(float) * 4);
|
|
scale.z = BitConverter.ToSingle(bytes, sizeof(float) * 5);
|
|
rotation.x = BitConverter.ToSingle(bytes, sizeof(float) * 6);
|
|
rotation.y = BitConverter.ToSingle(bytes, sizeof(float) * 7);
|
|
rotation.z = BitConverter.ToSingle(bytes, sizeof(float) * 8);
|
|
}
|
|
}
|
|
|
|
public class TestTcpClient : TcpServerClient
|
|
{
|
|
static Dictionary<HeaderCode, Type> remoteCommandTypeMap = new Dictionary<HeaderCode, Type>()
|
|
{
|
|
{ HeaderCode.JoinGame, typeof(UserJoinToServerPacket) },
|
|
};
|
|
|
|
protected override void OnDataReceived(in Packet packet)
|
|
{
|
|
if(TryCreateRemoteCommand(packet, out var command))
|
|
{
|
|
command.Execute();
|
|
}
|
|
}
|
|
|
|
private bool TryCreateRemoteCommand(in Packet packet, out RemoteCommand command)
|
|
{
|
|
command = null;
|
|
|
|
if (remoteCommandTypeMap.TryGetValue(packet.header.code, out var type))
|
|
{
|
|
command = Activator.CreateInstance(type) as RemoteCommand;
|
|
command.SetData(packet);
|
|
}
|
|
|
|
return command != null;
|
|
}
|
|
}
|
|
|
|
public abstract class RemoteCommand
|
|
{
|
|
public abstract void SetData(in Packet packet);
|
|
public abstract void Execute();
|
|
}
|
|
|
|
public class UserState
|
|
{
|
|
public int userID;
|
|
public Vector3 position;
|
|
|
|
public static int GetSize() => sizeof(int) + sizeof(float) * 3;
|
|
}
|
|
|
|
public class UserJoinToServerPacket : RemoteCommand
|
|
{
|
|
UserState userState;
|
|
|
|
public override void SetData(in Packet packet)
|
|
{
|
|
Debug.Assert(packet.header.code == HeaderCode.JoinGame, "Invalid packet code");
|
|
Debug.Assert(packet.header.size == UserState.GetSize(), "Invalid packet size");
|
|
|
|
userState = new UserState();
|
|
userState.userID = BitConverter.ToInt32(packet.body.data, 0);
|
|
userState.position.x = BitConverter.ToSingle(packet.body.data, sizeof(int));
|
|
}
|
|
|
|
public override void Execute()
|
|
{
|
|
GameObject user = new GameObject("User");
|
|
user.transform.position = userState.position;
|
|
|
|
Logger.Log("user " + userState.userID + " joined to server at " + userState.position.ToString());
|
|
}
|
|
}
|
|
|
|
public abstract class Monster : ICloneable
|
|
{
|
|
public abstract object Clone();
|
|
}
|
|
|
|
public class Orc : Monster
|
|
{
|
|
public override object Clone()
|
|
{
|
|
return new Orc();
|
|
}
|
|
}
|
|
|
|
public class Goblin : Monster
|
|
{
|
|
public override object Clone()
|
|
{
|
|
return new Goblin();
|
|
}
|
|
}
|
|
|
|
public class MonsterSpawner
|
|
{
|
|
Monster prototype;
|
|
|
|
public MonsterSpawner(Monster prototype)
|
|
{
|
|
this.prototype = prototype;
|
|
}
|
|
|
|
public Monster SpawnMonster()
|
|
{
|
|
return prototype.Clone() as Monster;
|
|
}
|
|
}
|