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 : IPipeline where T : IBytable { Func onRequest; Action onRecv; public Pipeline(Func onRequest, Action 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(); instance.Deserialize(bytes); onRecv.Invoke(instance); } } TcpServerClient client; uint ownerUserID; Dictionary pipeLines = new(); public event Action OnRecvRequestEvent; public RemoteDataPipelines(TcpServerClient client, uint ownerUserID) { this.client = client; this.ownerUserID = ownerUserID; } public void AddPipeline(uint eventID, Func onRequest, Action onRecv) where T : IBytable { if (!pipeLines.ContainsKey(eventID)) { var recvEvent = new Pipeline(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 remoteCommandTypeMap = new Dictionary() { { 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; } }