From 1b32c0c5500293c440539fc771881c5f5153cb28 Mon Sep 17 00:00:00 2001 From: teascade Date: Tue, 9 May 2017 17:15:21 +0300 Subject: [PATCH] Add basic syncing. Has no actual effect yet. --- Assets/Scripts/Entities/Character.cs | 33 ++++- Assets/Scripts/Entities/SyncBase.cs | 33 ++++- Assets/Scripts/Entities/SyncDB.cs | 30 ++++- Assets/Scripts/Entities/SyncHandletype.cs | 33 +++++ .../Scripts/Entities/SyncHandletype.cs.meta | 12 ++ .../Scripts/Networking/Clientside/Client.cs | 114 ++++++++++-------- .../Networking/Clientside/SyncHandler.cs | 43 +++++++ .../Networking/Clientside/SyncHandler.cs.meta | 12 ++ Assets/Scripts/Networking/Messages/SyncPkt.cs | 88 ++++++++++++++ .../Networking/Messages/SyncPkt.cs.meta | 12 ++ Assets/Scripts/Networking/NetworkChannelID.cs | 24 ++++ .../Networking/NetworkChannelID.cs.meta | 12 ++ Assets/Scripts/Networking/PktType.cs | 6 + .../Scripts/Networking/Serverside/Server.cs | 26 +++- .../Scripts/Networking/Serverside/Syncer.cs | 95 +++++++++++++++ .../Networking/Serverside/Syncer.cs.meta | 12 ++ 16 files changed, 521 insertions(+), 64 deletions(-) create mode 100644 Assets/Scripts/Entities/SyncHandletype.cs create mode 100644 Assets/Scripts/Entities/SyncHandletype.cs.meta create mode 100644 Assets/Scripts/Networking/Clientside/SyncHandler.cs create mode 100644 Assets/Scripts/Networking/Clientside/SyncHandler.cs.meta create mode 100644 Assets/Scripts/Networking/Messages/SyncPkt.cs create mode 100644 Assets/Scripts/Networking/Messages/SyncPkt.cs.meta create mode 100644 Assets/Scripts/Networking/NetworkChannelID.cs create mode 100644 Assets/Scripts/Networking/NetworkChannelID.cs.meta create mode 100644 Assets/Scripts/Networking/Serverside/Syncer.cs create mode 100644 Assets/Scripts/Networking/Serverside/Syncer.cs.meta diff --git a/Assets/Scripts/Entities/Character.cs b/Assets/Scripts/Entities/Character.cs index d98d470..b347f92 100644 --- a/Assets/Scripts/Entities/Character.cs +++ b/Assets/Scripts/Entities/Character.cs @@ -1,4 +1,6 @@ -using UnityEngine; +using System; +using UnityEngine; +using UnityEngine.Networking; namespace Cyber.Entities { @@ -75,6 +77,35 @@ namespace Cyber.Entities { transform.localEulerAngles.y, Head.localEulerAngles.z); } + /// + /// Gets the Sync Handletype for Character, which doesn't require hash differences and syncs every tick. + /// + /// + public override SyncHandletype GetSyncHandletype() { + return new SyncHandletype(false, 1); + } + + /// + /// Deserializes the character. + /// + /// + public override void Deserialize(NetworkReader reader) { + Vector3 pos = reader.ReadVector3(); + transform.position.Set(pos.x, pos.y, pos.z); + Move(reader.ReadVector3()); + Vector3 rot = reader.ReadVector3(); + } + + /// + /// Serializes the character. + /// + /// + public override void Serialize(NetworkWriter writer) { + writer.Write(transform.position); + writer.Write(MovementDirection); + writer.Write(GetRotation()); + } + private void FixedUpdate() { CharacterController.Move(MovementDirection * MovementSpeed * Time.fixedDeltaTime); } diff --git a/Assets/Scripts/Entities/SyncBase.cs b/Assets/Scripts/Entities/SyncBase.cs index 9b0bc5d..3a7b875 100644 --- a/Assets/Scripts/Entities/SyncBase.cs +++ b/Assets/Scripts/Entities/SyncBase.cs @@ -1,6 +1,5 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; +using UnityEngine; +using UnityEngine.Networking; namespace Cyber.Entities { @@ -8,12 +7,38 @@ namespace Cyber.Entities { /// A base class for all syncable components. An instance of /// will contain all of the game's synced components. /// - public class SyncBase : MonoBehaviour { + public abstract class SyncBase : MonoBehaviour { /// /// The ID this syncable component can be found with from its parent /// . /// public int ID; + + /// + /// Return the Sync Handletype information for . + /// + /// Sync Handletype containing sync information. + public abstract SyncHandletype GetSyncHandletype(); + + /// + /// Deserializes this SyncBase for further use. + /// + /// + public abstract void Deserialize(NetworkReader reader); + + /// + /// Serialize this SyncBase into a sync packet. + /// + /// + public abstract void Serialize(NetworkWriter writer); + + /// + /// Generates a checksum of the contents, or 0 if no checksum is overriden. + /// + /// The integer checksum. + public virtual int GenerateChecksum() { + return 0; + } } } \ No newline at end of file diff --git a/Assets/Scripts/Entities/SyncDB.cs b/Assets/Scripts/Entities/SyncDB.cs index 2866fc7..9eb2f6f 100644 --- a/Assets/Scripts/Entities/SyncDB.cs +++ b/Assets/Scripts/Entities/SyncDB.cs @@ -1,7 +1,7 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System; using UnityEngine; +using Cyber.Networking.Serverside; namespace Cyber.Entities { @@ -17,6 +17,8 @@ namespace Cyber.Entities { private int IDCounter = 0; private Dictionary Database = new Dictionary(); + private Dictionary> CategorizedDatabase = new Dictionary>(); + private Dictionary SyncHandletypes = new Dictionary(); /// /// Add an entity to the database with the given IDs. @@ -31,6 +33,14 @@ namespace Cyber.Entities { if (Syncable != null) { Syncable.ID = ids[Index]; Database[ids[Index++]] = Syncable; + if (Server.IsRunning()) { + Type Type = Syncable.GetType(); + if (!CategorizedDatabase.ContainsKey(Type)) { + CategorizedDatabase.Add(Type, new List()); + SyncHandletypes.Add(Type, Syncable.GetSyncHandletype()); + } + CategorizedDatabase[Type].Add(Syncable.ID); + } } } } @@ -83,6 +93,22 @@ namespace Cyber.Entities { return Database[id]; } + /// + /// Gives the database categorized into lists of their types. + /// + /// A dictionary of categorized SyncBases. + public Dictionary> GetCategorizedDatabase() { + return CategorizedDatabase; + } + + /// + /// Gets the Sync Handletypes currently known by the SyncDB. + /// + /// The Sync Handletypes by Type. + public Dictionary GetSyncHandletypes() { + return SyncHandletypes; + } + /// /// Creates a new ID which isn't in use yet. /// diff --git a/Assets/Scripts/Entities/SyncHandletype.cs b/Assets/Scripts/Entities/SyncHandletype.cs new file mode 100644 index 0000000..29b0924 --- /dev/null +++ b/Assets/Scripts/Entities/SyncHandletype.cs @@ -0,0 +1,33 @@ + +namespace Cyber.Entities { + + /// + /// A struct that gives the following information to Syncer about a SyncBase type: + /// Does it require a hash difference when syncing? + /// How often should this sync be done? + /// + public struct SyncHandletype { + + /// + /// Weather hash difference should be checked before this sync can be done. + /// If true, will override . + /// + public bool RequireHash; + + /// + /// How often in ticks should the syncer sync this. + /// + public int TickInterval; + + /// + /// A one-liner to create this struct. + /// + /// Weather the SyncBase requires a hash to be synced. + /// How often should this be synced. + public SyncHandletype(bool requireHash, int tickInterval) { + RequireHash = requireHash; + TickInterval = tickInterval; + } + + } +} \ No newline at end of file diff --git a/Assets/Scripts/Entities/SyncHandletype.cs.meta b/Assets/Scripts/Entities/SyncHandletype.cs.meta new file mode 100644 index 0000000..4e4f002 --- /dev/null +++ b/Assets/Scripts/Entities/SyncHandletype.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: df50627e354741e4295b8da5ba13aa29 +timeCreated: 1494329035 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Clientside/Client.cs b/Assets/Scripts/Networking/Clientside/Client.cs index 7b5db31..8a40e6f 100644 --- a/Assets/Scripts/Networking/Clientside/Client.cs +++ b/Assets/Scripts/Networking/Clientside/Client.cs @@ -27,6 +27,8 @@ namespace Cyber.Networking.Clientside { private Spawner Spawner; + private SyncHandler SyncHandler; + /// /// The player of this client /// @@ -92,6 +94,7 @@ namespace Cyber.Networking.Clientside { private void Start() { Spawner = GetComponent(); + SyncHandler = new SyncHandler(Spawner.SyncDB); } private bool LaunchClient(string ip, int port) { @@ -100,8 +103,9 @@ namespace Cyber.Networking.Clientside { } ConnectionConfig Config = new ConnectionConfig(); - Config.AddChannel(QosType.ReliableSequenced); - Config.AddChannel(QosType.UnreliableSequenced); + NetworkChannelID.ReliableSequenced = Config.AddChannel(QosType.ReliableSequenced); + NetworkChannelID.UnreliableSequenced = Config.AddChannel(QosType.UnreliableSequenced); + NetworkChannelID.Unreliable = Config.AddChannel(QosType.Unreliable); NetworkServer.Configure(Config, 10); NetClient = new NetworkClient(); @@ -114,6 +118,7 @@ namespace Cyber.Networking.Clientside { NetClient.RegisterHandler(PktType.MassIdentity, HandlePacket); NetClient.RegisterHandler(PktType.SpawnEntity, HandlePacket); NetClient.RegisterHandler(PktType.MoveCreature, HandlePacket); + NetClient.RegisterHandler(PktType.SyncPacket, HandlePacket); NetClient.RegisterHandler(MsgType.Connect, OnConnected); NetClient.RegisterHandler(MsgType.Disconnect, OnDisconnected); @@ -129,60 +134,63 @@ namespace Cyber.Networking.Clientside { private void HandlePacket(NetworkMessage msg) { switch (msg.msgType) { - case (PktType.TextMessage): - TextMessagePkt TextMsg = new TextMessagePkt(); - TextMsg.Deserialize(msg.reader); - Term.Println(TextMsg.Message); - break; - case (PktType.Identity): - IdentityPkt Identity = new IdentityPkt(); - Identity.Deserialize(msg.reader); - var Conn = new CConnectedPlayer(Identity.ConnectionID); - if (Identity.Owned) { - Player = Conn; - } else { - Debug.Log(Conn.ConnectionID + " connected!"); - Term.Println(Conn.ConnectionID + " connected!"); - } - Players.Add(Conn.ConnectionID, Conn); - break; - case (PktType.MassIdentity): - MassIdentityPkt Identities = new MassIdentityPkt(); - Identities.Deserialize(msg.reader); - foreach (int currId in Identities.IdList) { - Players.Add(currId, new CConnectedPlayer(currId)); - } - break; - case (PktType.SpawnEntity): - SpawnEntityPkt SpawnPkt = new SpawnEntityPkt(); - SpawnPkt.Deserialize(msg.reader); + case (PktType.TextMessage): + TextMessagePkt TextMsg = new TextMessagePkt(); + TextMsg.Deserialize(msg.reader); + Term.Println(TextMsg.Message); + break; + case (PktType.Identity): + IdentityPkt Identity = new IdentityPkt(); + Identity.Deserialize(msg.reader); + var Conn = new CConnectedPlayer(Identity.ConnectionID); + if (Identity.Owned) { + Player = Conn; + } else { + Debug.Log(Conn.ConnectionID + " connected!"); + Term.Println(Conn.ConnectionID + " connected!"); + } + Players.Add(Conn.ConnectionID, Conn); + break; + case (PktType.MassIdentity): + MassIdentityPkt Identities = new MassIdentityPkt(); + Identities.Deserialize(msg.reader); + foreach (int currId in Identities.IdList) { + Players.Add(currId, new CConnectedPlayer(currId)); + } + break; + case (PktType.SpawnEntity): + SpawnEntityPkt SpawnPkt = new SpawnEntityPkt(); + SpawnPkt.Deserialize(msg.reader); - EntityType EntityType = SpawnPkt.EntityType; - // Check if you are the owner and if they are spawning an NPC - if (SpawnPkt.OwnerID == Player.ConnectionID && EntityType == EntityType.NPC) { - // Change it into a PC instead. - EntityType = EntityType.PC; - } - Spawner.Spawn(EntityType, SpawnPkt.Position, SpawnPkt.SyncBaseIDList); - break; - case (PktType.MoveCreature): - MoveCreaturePkt MoveCreature = new MoveCreaturePkt(); - MoveCreature.Deserialize(msg.reader); + EntityType EntityType = SpawnPkt.EntityType; + // Check if you are the owner and if they are spawning an NPC + if (SpawnPkt.OwnerID == Player.ConnectionID && EntityType == EntityType.NPC) { + // Change it into a PC instead. + EntityType = EntityType.PC; + } + Spawner.Spawn(EntityType, SpawnPkt.Position, SpawnPkt.SyncBaseIDList); + break; + case (PktType.MoveCreature): + MoveCreaturePkt MoveCreature = new MoveCreaturePkt(); + MoveCreature.Deserialize(msg.reader); - SyncBase SyncBase = Spawner.SyncDB.Get(MoveCreature.SyncBaseID); - if (SyncBase != null || SyncBase is Character ) { - Character Character = (Character) SyncBase; - Character.Move(MoveCreature.Direction); - } else { - Debug.LogError("SyncBase " + MoveCreature.SyncBaseID + " is not a Creature"); - Term.Println("SyncBase " + MoveCreature.SyncBaseID + " is not a Creature"); - } + SyncBase SyncBase = Spawner.SyncDB.Get(MoveCreature.SyncBaseID); + if (SyncBase != null || SyncBase is Character ) { + Character Character = (Character) SyncBase; + Character.Move(MoveCreature.Direction); + } else { + Debug.LogError("SyncBase " + MoveCreature.SyncBaseID + " is not a Creature"); + Term.Println("SyncBase " + MoveCreature.SyncBaseID + " is not a Creature"); + } - break; - default: - Debug.LogError("Received an unknown packet, id: " + msg.msgType); - Term.Println("Received an unknown packet, id: " + msg.msgType); - break; + break; + case (PktType.SyncPacket): + SyncHandler.HandleSyncPkt(msg); + break; + default: + Debug.LogError("Received an unknown packet, id: " + msg.msgType); + Term.Println("Received an unknown packet, id: " + msg.msgType); + break; } } diff --git a/Assets/Scripts/Networking/Clientside/SyncHandler.cs b/Assets/Scripts/Networking/Clientside/SyncHandler.cs new file mode 100644 index 0000000..b070508 --- /dev/null +++ b/Assets/Scripts/Networking/Clientside/SyncHandler.cs @@ -0,0 +1,43 @@ + +using Cyber.Entities; +using Cyber.Networking.Messages; +using UnityEngine; +using UnityEngine.Networking; + +namespace Cyber.Networking.Clientside { + + /// + /// A Short clientside class for handling sync packages. + /// It simply keeps track of sync-packages and will not apply them if they are too old. + /// + public class SyncHandler { + + private SyncDB SyncDB; + private int LatestSyncID = -1; + + /// + /// Creates the SyncHandler with SyncDB. + /// + /// + public SyncHandler(SyncDB syncDB) { + SyncDB = syncDB; + } + + /// + /// Handle a given Network message. Must be checked to be first. + /// + /// + public void HandleSyncPkt(NetworkMessage message) { + SyncPkt SyncPacket = new SyncPkt(SyncDB); + SyncPacket.Deserialize(message.reader); + if (LatestSyncID < SyncPacket.SyncPacketID) { + LatestSyncID = SyncPacket.SyncPacketID; + SyncPacket.ApplySync(message.reader); + Debug.Log("Applied Sync " + LatestSyncID); + } + // Otherwise disregard the sync. + + } + + } +} diff --git a/Assets/Scripts/Networking/Clientside/SyncHandler.cs.meta b/Assets/Scripts/Networking/Clientside/SyncHandler.cs.meta new file mode 100644 index 0000000..f485756 --- /dev/null +++ b/Assets/Scripts/Networking/Clientside/SyncHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6377ec5e92cc97c48aa26423059e4b3a +timeCreated: 1494337627 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Messages/SyncPkt.cs b/Assets/Scripts/Networking/Messages/SyncPkt.cs new file mode 100644 index 0000000..9e41fe3 --- /dev/null +++ b/Assets/Scripts/Networking/Messages/SyncPkt.cs @@ -0,0 +1,88 @@ + +using Cyber.Entities; +using UnityEngine.Networking; + +namespace Cyber.Networking.Messages { + + /// + /// Contains sync data to sync stuff with. + /// + public class SyncPkt : MessageBase { + + /// + /// The Sync Packet ID of this packet. + /// + public int SyncPacketID; + + /// + /// The Array of SyncID added in this SyncPkt + /// + public int[] SyncedSyncBases; + + private SyncDB SyncDB; + + /// + /// Creates a SyncPkt on the serverside. + /// + /// SyncDB to sync from. + /// The ID's of the SyncBases to sync. + /// ID of the sync packet itself. + public SyncPkt(SyncDB syncDB, int[] syncBases, int syncPacketID) { + SyncPacketID = syncPacketID; + SyncDB = syncDB; + SyncedSyncBases = syncBases; + } + + /// + /// Creates SyncPkt for deserializing. + /// + /// SyncBase to sync to. + public SyncPkt(SyncDB syncDB) { + SyncDB = syncDB; + } + + /// + /// Deserializes the SynkPkt with ONLY the Sync Packet ID. + /// + /// + public override void Deserialize(NetworkReader reader) { + SyncPacketID = reader.ReadInt32(); + } + + /// + /// Applies the SyncPkt. + /// + /// + public void ApplySync(NetworkReader reader) { + byte[][] ByteArray = new byte[4][]; + ByteArray[0] = reader.ReadBytesAndSize(); + ByteArray[1] = reader.ReadBytesAndSize(); + ByteArray[2] = reader.ReadBytesAndSize(); + ByteArray[3] = reader.ReadBytesAndSize(); + SyncedSyncBases = NetworkHelper.DeserializeIntArray(ByteArray); + + foreach (int syncId in SyncedSyncBases) { + SyncDB.Get(syncId).Deserialize(reader); + } + } + + /// + /// Serializes the SyncPkt and writes everything it needs. + /// + /// + public override void Serialize(NetworkWriter writer) { + writer.Write(SyncPacketID); + + byte[][] ByteArray = NetworkHelper.SerializeIntArray(SyncedSyncBases); + writer.WriteBytesFull(ByteArray[0]); + writer.WriteBytesFull(ByteArray[1]); + writer.WriteBytesFull(ByteArray[2]); + writer.WriteBytesFull(ByteArray[3]); + + foreach (int syncId in SyncedSyncBases) { + SyncDB.Get(syncId).Serialize(writer); + } + } + + } +} diff --git a/Assets/Scripts/Networking/Messages/SyncPkt.cs.meta b/Assets/Scripts/Networking/Messages/SyncPkt.cs.meta new file mode 100644 index 0000000..696575a --- /dev/null +++ b/Assets/Scripts/Networking/Messages/SyncPkt.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b17a30eca8d025d47aa9738d5eaa9b61 +timeCreated: 1494336224 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/NetworkChannelID.cs b/Assets/Scripts/Networking/NetworkChannelID.cs new file mode 100644 index 0000000..2a90947 --- /dev/null +++ b/Assets/Scripts/Networking/NetworkChannelID.cs @@ -0,0 +1,24 @@ + +namespace Cyber.Networking { + + /// + /// Networked channel ID's to be used. + /// + public class NetworkChannelID { + + /// + /// The default channel which is reliable and sequenced. True TCP! + /// + public static byte ReliableSequenced; + + /// + /// Another channel which is unreliable (like UDP) but always in correct sending order (like TCP). + /// + public static byte UnreliableSequenced; + + /// + /// Very unreliable, true UDP! + /// + public static byte Unreliable; + } +} diff --git a/Assets/Scripts/Networking/NetworkChannelID.cs.meta b/Assets/Scripts/Networking/NetworkChannelID.cs.meta new file mode 100644 index 0000000..223477c --- /dev/null +++ b/Assets/Scripts/Networking/NetworkChannelID.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: daf9802139051fb4eab0348011f699af +timeCreated: 1494338663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/PktType.cs b/Assets/Scripts/Networking/PktType.cs index 2bd1db5..9909872 100644 --- a/Assets/Scripts/Networking/PktType.cs +++ b/Assets/Scripts/Networking/PktType.cs @@ -32,5 +32,11 @@ namespace Cyber.Networking { /// to inform actual movement. /// public const short MoveCreature = 204; + + /// + /// Packet containing sync data. + /// + public const short SyncPacket = 205; + } } \ No newline at end of file diff --git a/Assets/Scripts/Networking/Serverside/Server.cs b/Assets/Scripts/Networking/Serverside/Server.cs index 6d3e9ef..1d845c2 100644 --- a/Assets/Scripts/Networking/Serverside/Server.cs +++ b/Assets/Scripts/Networking/Serverside/Server.cs @@ -40,6 +40,23 @@ namespace Cyber.Networking.Serverside { return Singleton.LaunchServer(port); } + /// + /// Sends Message to all clients using specified channel. + /// defaults to . + /// + /// Message type being sent. + /// Message contents. + /// Channel being used. + /// + public static bool SendToAllByChannel(short msgType, MessageBase message, byte channel) { + if (NetworkServer.active) { + NetworkServer.SendByChannelToAll(msgType, message, channel); + return true; + } else { + return false; + } + } + /// /// Attempts to send a message to all clients who are listening. /// Returns false if server wasn't active, true otherwise. @@ -91,8 +108,9 @@ namespace Cyber.Networking.Serverside { Spawner = GetComponent(); ConnectionConfig Config = new ConnectionConfig(); - Config.AddChannel(QosType.ReliableSequenced); - Config.AddChannel(QosType.UnreliableSequenced); + NetworkChannelID.ReliableSequenced = Config.AddChannel(QosType.ReliableSequenced); + NetworkChannelID.UnreliableSequenced = Config.AddChannel(QosType.UnreliableSequenced); + NetworkChannelID.Unreliable = Config.AddChannel(QosType.Unreliable); NetworkServer.Configure(Config, 10); NetworkServer.Listen(port); @@ -112,6 +130,8 @@ namespace Cyber.Networking.Serverside { SendToAll(PktType.TextMessage, new TextMessagePkt("Server: " + args[0])); }); + gameObject.AddComponent(); + return true; } @@ -129,8 +149,6 @@ namespace Cyber.Networking.Serverside { // Check if the player is allowed to move this character Character Controlled = Players[msg.conn.connectionId].Character.GetComponent(); - Debug.Log(Controlled.ID); - Debug.Log(MoveCreature.SyncBaseID); if (Controlled.ID != MoveCreature.SyncBaseID) { break; } diff --git a/Assets/Scripts/Networking/Serverside/Syncer.cs b/Assets/Scripts/Networking/Serverside/Syncer.cs new file mode 100644 index 0000000..44eda17 --- /dev/null +++ b/Assets/Scripts/Networking/Serverside/Syncer.cs @@ -0,0 +1,95 @@ + +using Cyber.Entities; +using Cyber.Networking.Messages; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Cyber.Networking.Serverside { + + /// + /// Keeps stuff in-sync over at clients. Periodically collects stuff that needs to be synced and then sends them on the next 'tick.' + /// + public class Syncer : MonoBehaviour { + + private SyncDB Database; + + private int TickCounter = 0; + private const float TickInterval = 1f / 10; + + private float TimeSinceLastTick = TickInterval; + + private List QueuedSyncs = new List(); + private List DirtySyncBases = new List(); + + private int SyncPacketID = 0; + + /// + /// Mark a SyncBase "Dirty", which makes it eligible to sync. + /// + /// The ID of the SyncBase. See + public void DirtSyncBase(int syncBaseID) { + DirtySyncBases.Add(syncBaseID); + } + + /// + /// Queue a SyncBase directly, so it will be synced next time a sync tick is called. + /// + /// The ID of the SyncBase. See + public void QueueSyncBase(int SyncBaseID) { + QueuedSyncs.Add(SyncBaseID); + } + + private void Start() { + Database = GetComponent(); + } + + private void Update() { + TimeSinceLastTick += Time.deltaTime; + if (TimeSinceLastTick >= TickInterval) { + + var Categorized = Database.GetCategorizedDatabase(); + + foreach (Type type in Categorized.Keys) { + SyncHandletype Handletype = Database.GetSyncHandletypes()[type]; + if (Handletype.RequireHash) { + foreach (int SyncBaseID in Categorized[type]) { + if (DirtySyncBases.Contains(SyncBaseID)) { + QueueSyncBase(SyncBaseID); + } + } + } else { + if (TickCounter % Handletype.TickInterval == 0) { + foreach (int SyncBaseID in Categorized[type]) { + if (DirtySyncBases.Contains(SyncBaseID)) { + QueueSyncBase(SyncBaseID); + } + } + } + } + } + + TickCounter++; + TimeSinceLastTick -= TickInterval; + + if (QueuedSyncs.Count > 0) { + int[] SyncIDs = QueuedSyncs.ToArray(); + SyncPkt SyncPacket = new SyncPkt(Database, SyncIDs, SyncPacketID++); + Server.SendToAllByChannel(PktType.SyncPacket, SyncPacket, NetworkChannelID.Unreliable); + + QueuedSyncs.Clear(); + DirtySyncBases.Clear(); + } + + if (Categorized.ContainsKey(typeof(Character))) { + foreach (int i in Categorized[typeof(Character)]) { + DirtSyncBase(i); + } + } + } + + + } + + } +} diff --git a/Assets/Scripts/Networking/Serverside/Syncer.cs.meta b/Assets/Scripts/Networking/Serverside/Syncer.cs.meta new file mode 100644 index 0000000..d46e4d0 --- /dev/null +++ b/Assets/Scripts/Networking/Serverside/Syncer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 36a5eba300b7514419b2a8df64f8e7df +timeCreated: 1494327632 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: