diff --git a/Assets/Scripts/Controls/PlayerController.cs b/Assets/Scripts/Controls/PlayerController.cs index e7f35e6..300a8b5 100644 --- a/Assets/Scripts/Controls/PlayerController.cs +++ b/Assets/Scripts/Controls/PlayerController.cs @@ -57,6 +57,9 @@ namespace Cyber.Controls { Interactable LookingAt = LookedAtObject.GetComponent(); if (LookingAt != null && (LookingAt.transform.position - Character.GetPosition()).magnitude < Character.InteractionDistance) { LookingAt.Interact(); + if (LookingAt.GetInteractableSyncdata().PublicInteractions) { + Client.Send(PktType.InteractPkt, new InteractionPkt(LookingAt.ID)); + } } } } diff --git a/Assets/Scripts/Entities/InteractableSyncdata.cs b/Assets/Scripts/Entities/InteractableSyncdata.cs new file mode 100644 index 0000000..3928cb7 --- /dev/null +++ b/Assets/Scripts/Entities/InteractableSyncdata.cs @@ -0,0 +1,26 @@ + +namespace Cyber.Entities { + public struct InteractableSyncdata { + + /// + /// Weather this interactable requires syncing or not. + /// + public bool RequiresSyncing; + + /// + /// Weather interacting with this should send a TCP-packet or not. + /// + public bool PublicInteractions; + + /// + /// Creates an InteractibleSyncdata struct. + /// + /// Weather this interactible requires syncing (like a door) or not (like a bell). + /// Weather interacting with this interactible should send a TCP-packet (like a bell or a door) or not (like opening a screen where you can type). + public InteractableSyncdata(bool requiresSyncing, bool publicInteractions) { + RequiresSyncing = requiresSyncing; + PublicInteractions = publicInteractions; + } + + } +} diff --git a/Assets/Scripts/Entities/InteractableSyncdata.cs.meta b/Assets/Scripts/Entities/InteractableSyncdata.cs.meta new file mode 100644 index 0000000..83bd2b7 --- /dev/null +++ b/Assets/Scripts/Entities/InteractableSyncdata.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b02b5449859d14f4784a47e5663a1d3c +timeCreated: 1494455790 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Entities/SyncBases/Button.cs b/Assets/Scripts/Entities/SyncBases/Button.cs index 5e30330..b155775 100644 --- a/Assets/Scripts/Entities/SyncBases/Button.cs +++ b/Assets/Scripts/Entities/SyncBases/Button.cs @@ -4,6 +4,7 @@ using UnityEngine; using UnityEngine.Networking; using Cyber.Networking; using Cyber.Console; +using System; namespace Cyber.Entities.SyncBases { @@ -55,19 +56,22 @@ namespace Cyber.Entities.SyncBases { } /// - /// Buttons only act as triggers, so only interact is sent to the server. + /// Does nothing, because it doesn't need to synced. /// /// - public override void Deserialize(NetworkReader reader) { - } + public override void Deserialize(NetworkReader reader) {} /// - /// Buttons only act as triggers, so only interact is sent to the server. + /// Does nothing, because it doesn't need to synced. /// /// public override void Serialize(NetworkWriter writer) { } + public override InteractableSyncdata GetInteractableSyncdata() { + return new InteractableSyncdata(false, true); + } + /// /// Buttons only act as triggers, so only interact is sent to the server. /// diff --git a/Assets/Scripts/Entities/SyncBases/Door.cs b/Assets/Scripts/Entities/SyncBases/Door.cs index 1aa2605..1d4ffa8 100644 --- a/Assets/Scripts/Entities/SyncBases/Door.cs +++ b/Assets/Scripts/Entities/SyncBases/Door.cs @@ -51,6 +51,10 @@ namespace Cyber.Entities.SyncBases { return new SyncHandletype(false, 10); } + public override InteractableSyncdata GetInteractableSyncdata() { + return new InteractableSyncdata(true, true); + } + private void Update() { float DoorScale = IsOpen ? 0.01f : 1; if (DoorRoot.localScale.x != DoorScale) { diff --git a/Assets/Scripts/Entities/SyncBases/Interactable.cs b/Assets/Scripts/Entities/SyncBases/Interactable.cs index 4819eb1..4269b9e 100644 --- a/Assets/Scripts/Entities/SyncBases/Interactable.cs +++ b/Assets/Scripts/Entities/SyncBases/Interactable.cs @@ -1,6 +1,8 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Networking; namespace Cyber.Entities.SyncBases { @@ -13,6 +15,12 @@ namespace Cyber.Entities.SyncBases { /// All interactables should implement their interactions by overriding this. /// public abstract void Interact(); + + /// + /// Get Interaction information about this interactible. + /// + /// The Interaction information. + public abstract InteractableSyncdata GetInteractableSyncdata(); } } \ No newline at end of file diff --git a/Assets/Scripts/Entities/SyncDB.cs b/Assets/Scripts/Entities/SyncDB.cs index 4debfed..8c7b761 100644 --- a/Assets/Scripts/Entities/SyncDB.cs +++ b/Assets/Scripts/Entities/SyncDB.cs @@ -13,7 +13,8 @@ namespace Cyber.Entities { public class SyncDB : MonoBehaviour { private static readonly Type[] SyncableClasses = new Type[] { - typeof(Character) + typeof(Character), + typeof(Button) }; private int IDCounter = 0; @@ -21,6 +22,8 @@ namespace Cyber.Entities { private Dictionary> CategorizedDatabase = new Dictionary>(); private Dictionary SyncHandletypes = new Dictionary(); + private List StaticSyncBaseIDList = new List(); + /// /// Add an entity to the database with the given IDs. /// @@ -32,16 +35,8 @@ namespace Cyber.Entities { for (int i = 0; i < SyncableClasses.Length; i++) { SyncBase Syncable = (SyncBase)gameObject.GetComponent(SyncableClasses[i]); 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); - } + Syncable.ID = ids[Index++]; + AddSyncBaseToDatabase(Syncable); } } } @@ -134,5 +129,49 @@ namespace Cyber.Entities { } return ID; } + + /// + /// Sets static objects for all objects in the world. This method should be called once per game launch ever. + /// + /// The list of id's to be set. If null, will create new ids. + public void SetStaticObjectsIDs(int[] idList = null) { + SyncBase[] SyncBases = FindObjectsOfType(); + Array.Sort(SyncBases, (a, b) => { + Vector3 APos = a.gameObject.transform.position; + float AComparison = APos.x + APos.y + APos.z + Array.IndexOf(SyncableClasses, a); + Vector3 BPos = b.gameObject.transform.position; + float BComparison = BPos.x + BPos.y + BPos.z + Array.IndexOf(SyncableClasses, b); + + return AComparison.CompareTo(BComparison); + }); + if (idList == null) { + foreach (SyncBase SyncBase in SyncBases) { + SyncBase.ID = CreateID(); + AddSyncBaseToDatabase(SyncBase); + StaticSyncBaseIDList.Add(SyncBase.ID); + } + } else { + for (int i = 0; i < Math.Min(SyncBases.Length, idList.Length); i++) { + SyncBases[i].ID = idList[i]; + AddSyncBaseToDatabase(SyncBases[i]); + } + } + } + + public int[] GetStaticSyncBaseIDList() { + return StaticSyncBaseIDList.ToArray(); + } + + private void AddSyncBaseToDatabase(SyncBase syncBase) { + Database[syncBase.ID] = syncBase; + if (Server.IsRunning()) { + Type Type = syncBase.GetType(); + if (!CategorizedDatabase.ContainsKey(Type)) { + CategorizedDatabase.Add(Type, new List()); + SyncHandletypes.Add(Type, syncBase.GetSyncHandletype()); + } + CategorizedDatabase[Type].Add(syncBase.ID); + } + } } } \ No newline at end of file diff --git a/Assets/Scripts/Networking/Clientside/Client.cs b/Assets/Scripts/Networking/Clientside/Client.cs index 1c48e32..3aa8b36 100644 --- a/Assets/Scripts/Networking/Clientside/Client.cs +++ b/Assets/Scripts/Networking/Clientside/Client.cs @@ -127,6 +127,8 @@ namespace Cyber.Networking.Clientside { NetClient.RegisterHandler(PktType.SpawnEntity, HandlePacket); NetClient.RegisterHandler(PktType.MoveCreature, HandlePacket); NetClient.RegisterHandler(PktType.SyncPacket, HandlePacket); + NetClient.RegisterHandler(PktType.InteractPkt, HandlePacket); + NetClient.RegisterHandler(PktType.StaticObjectIdsPkt, HandlePacket); NetClient.RegisterHandler(MsgType.Connect, OnConnected); NetClient.RegisterHandler(MsgType.Disconnect, OnDisconnected); @@ -160,7 +162,7 @@ namespace Cyber.Networking.Clientside { Players.Add(Conn.ConnectionID, Conn); break; case (PktType.MassIdentity): - MassIdentityPkt Identities = new MassIdentityPkt(); + IntListPkt Identities = new IntListPkt(); Identities.Deserialize(msg.reader); foreach (int currId in Identities.IdList) { Players.Add(currId, new CConnectedPlayer(currId)); @@ -194,10 +196,29 @@ namespace Cyber.Networking.Clientside { Term.Println("SyncBase " + MoveCreature.SyncBaseID + " is not a Creature"); } + break; + case (PktType.InteractPkt): + InteractionPkt Interaction = new InteractionPkt(); + Interaction.Deserialize(msg.reader); + if (Interaction.OwnerSyncBaseID == Player.Character.ID) { + break; + } + + SyncBase Target = Spawner.SyncDB.Get(Interaction.InteractSyncBaseID); + if (Target != null && Target is Interactable) { + ((Interactable) Target).Interact(); + } else { + Term.Println("Server has sent an erroneus SyncBase ID!"); + } break; case (PktType.SyncPacket): SyncHandler.HandleSyncPkt(msg); break; + case (PktType.StaticObjectIdsPkt): + IntListPkt StaticIds = new IntListPkt(); + StaticIds.Deserialize(msg.reader); + Spawner.SyncDB.SetStaticObjectsIDs(StaticIds.IdList); + break; default: Debug.LogError("Received an unknown packet, id: " + msg.msgType); Term.Println("Received an unknown packet, id: " + msg.msgType); diff --git a/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs b/Assets/Scripts/Networking/Messages/IntListPkt.cs similarity index 81% rename from Assets/Scripts/Networking/Messages/MassIdentityPkt.cs rename to Assets/Scripts/Networking/Messages/IntListPkt.cs index e9a4940..6adf626 100644 --- a/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs +++ b/Assets/Scripts/Networking/Messages/IntListPkt.cs @@ -4,27 +4,27 @@ using UnityEngine.Networking; namespace Cyber.Networking.Messages { /// - /// Packet containing a list of ID's of players currently connected. + /// Packet containing integers, used in many packet types, such as and . /// - public class MassIdentityPkt : MessageBase { + public class IntListPkt : MessageBase { /// - /// List of Connection ID's to send + /// List of Integers. /// public int[] IdList; /// - /// Create a Mass Identity packet used to send a list of currently online connections. + /// Create a packet containing integers. /// /// - public MassIdentityPkt(int[] idList) { + public IntListPkt(int[] idList) { IdList = idList; } /// /// Parameter-less constructor using when deserializing the message. /// - public MassIdentityPkt() { + public IntListPkt() { } diff --git a/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs.meta b/Assets/Scripts/Networking/Messages/IntListPkt.cs.meta similarity index 100% rename from Assets/Scripts/Networking/Messages/MassIdentityPkt.cs.meta rename to Assets/Scripts/Networking/Messages/IntListPkt.cs.meta diff --git a/Assets/Scripts/Networking/Messages/InteractionPkt.cs b/Assets/Scripts/Networking/Messages/InteractionPkt.cs new file mode 100644 index 0000000..aa1af53 --- /dev/null +++ b/Assets/Scripts/Networking/Messages/InteractionPkt.cs @@ -0,0 +1,53 @@ + +using UnityEngine.Networking; + +namespace Cyber.Networking.Messages { + + /// + /// Includes information about interacting an interactible. Applicable only for some interactibles. + /// + public class InteractionPkt : MessageBase { + + /// + /// ID of the interactible. + /// + public int InteractSyncBaseID; + + /// + /// Id of the interactor. + /// + public int OwnerSyncBaseID; + + /// + /// Creates an InteraktionPkt, which contains the message "someone interacted". + /// + /// + public InteractionPkt(int syncBaseID) { + InteractSyncBaseID = syncBaseID; + } + + /// + /// Empty constructor for deserialization. + /// + public InteractionPkt() {} + + /// + /// Deserializes SyncBaseID for the recipent. + /// + /// + public override void Deserialize(NetworkReader reader) { + InteractSyncBaseID = reader.ReadInt32(); + OwnerSyncBaseID = reader.ReadInt32(); + } + + /// + /// Serializes the SyncBaseID for sending. + /// + /// + public override void Serialize(NetworkWriter writer) { + writer.Write(InteractSyncBaseID); + writer.Write(OwnerSyncBaseID); + } + + } +} diff --git a/Assets/Scripts/Networking/Messages/InteractionPkt.cs.meta b/Assets/Scripts/Networking/Messages/InteractionPkt.cs.meta new file mode 100644 index 0000000..61e9463 --- /dev/null +++ b/Assets/Scripts/Networking/Messages/InteractionPkt.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ee7d568a49719d248910f19e26d82051 +timeCreated: 1494453893 +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 9909872..ee5704a 100644 --- a/Assets/Scripts/Networking/PktType.cs +++ b/Assets/Scripts/Networking/PktType.cs @@ -18,6 +18,7 @@ namespace Cyber.Networking { /// /// Packet containing the identification details about everyone on the server before the client connected. + /// This packet contains an . /// public const short MassIdentity = 202; @@ -38,5 +39,16 @@ namespace Cyber.Networking { /// public const short SyncPacket = 205; + /// + /// Packet telling that someone has made an interactive remark. + /// + public const short InteractPkt = 206; + + /// + /// Packet containing an id list of static objects existing in the ready game. + /// This packet contains an . + /// + public const short StaticObjectIdsPkt = 207; + } } \ No newline at end of file diff --git a/Assets/Scripts/Networking/Serverside/Server.cs b/Assets/Scripts/Networking/Serverside/Server.cs index 69a7d0d..17077a5 100644 --- a/Assets/Scripts/Networking/Serverside/Server.cs +++ b/Assets/Scripts/Networking/Serverside/Server.cs @@ -20,6 +20,11 @@ namespace Cyber.Networking.Serverside { private Spawner Spawner; + /// + /// The Syncer which syncs. + /// + public Syncer Syncer; + /// /// Creates the server-component, and sets the singleton as itself. /// @@ -108,6 +113,8 @@ namespace Cyber.Networking.Serverside { Spawner = GetComponent(); + Spawner.SyncDB.SetStaticObjectsIDs(); + ConnectionConfig Config = new ConnectionConfig(); NetworkChannelID.ReliableSequenced = Config.AddChannel(QosType.ReliableSequenced); NetworkChannelID.UnreliableSequenced = Config.AddChannel(QosType.UnreliableSequenced); @@ -118,6 +125,7 @@ namespace Cyber.Networking.Serverside { NetworkServer.RegisterHandler(PktType.TextMessage, HandlePacket); NetworkServer.RegisterHandler(PktType.MoveCreature, HandlePacket); + NetworkServer.RegisterHandler(PktType.InteractPkt, HandlePacket); NetworkServer.RegisterHandler(MsgType.Connect, OnConnected); NetworkServer.RegisterHandler(MsgType.Disconnect, OnDisconnected); @@ -139,35 +147,60 @@ namespace Cyber.Networking.Serverside { private void HandlePacket(NetworkMessage msg) { switch (msg.msgType) { - case PktType.TextMessage: - TextMessagePkt TextMsg = new TextMessagePkt(); - TextMsg.Deserialize(msg.reader); - Term.Println(TextMsg.Message); + case PktType.TextMessage: + TextMessagePkt TextMsg = new TextMessagePkt(); + TextMsg.Deserialize(msg.reader); + Term.Println(TextMsg.Message); + break; + case PktType.MoveCreature: + MoveCreaturePkt MoveCreature = new MoveCreaturePkt(); + MoveCreature.Deserialize(msg.reader); + + // Check if the player is allowed to move this character + Character Controlled = Players[msg.conn.connectionId].Character.GetComponent(); + if (Controlled.ID != MoveCreature.SyncBaseID) { break; - case PktType.MoveCreature: - MoveCreaturePkt MoveCreature = new MoveCreaturePkt(); - MoveCreature.Deserialize(msg.reader); + } - // Check if the player is allowed to move this character - Character Controlled = Players[msg.conn.connectionId].Character.GetComponent(); - if (Controlled.ID != MoveCreature.SyncBaseID) { - break; + Controlled.Move(MoveCreature.Direction); + + foreach (var Player in Players) { + if (Player.Value.ConnectionID == msg.conn.connectionId) { + continue; } + MoveCreature.Timestamp = NetworkHelper.GetCurrentSystemTime(); + NetworkServer.SendToClient(Player.Value.ConnectionID, PktType.MoveCreature, MoveCreature); + } + break; + case PktType.InteractPkt: + InteractionPkt Interaction = new InteractionPkt(); + Interaction.Deserialize(msg.reader); - Controlled.Move(MoveCreature.Direction); + Character Sender = Players[msg.conn.connectionId].Character; + SyncBase Target = Spawner.SyncDB.Get(Interaction.InteractSyncBaseID); - foreach (var Player in Players) { - if (Player.Value.ConnectionID == msg.conn.connectionId) { - continue; + Interaction.OwnerSyncBaseID = Sender.ID; + + if (Target != null && Target is Interactable) { + Interactable Interacted = (Interactable) Target; + Vector3 Delta = Interacted.gameObject.transform.position - Sender.gameObject.transform.position; + float ServerInteractionDistance = Sender.InteractionDistance + Sender.MovementSpeed * 0.5f; + if (Delta.magnitude <= ServerInteractionDistance) { + Interacted.Interact(); + NetworkServer.SendToAll(PktType.InteractPkt, Interaction); + if (Interacted.GetInteractableSyncdata().RequiresSyncing) { + Syncer.DirtSyncBase(Interacted.ID); } - MoveCreature.Timestamp = NetworkHelper.GetCurrentSystemTime(); - NetworkServer.SendToClient(Player.Value.ConnectionID, PktType.MoveCreature, MoveCreature); } - break; - default: - Debug.LogError("Received an unknown packet, id: " + msg.msgType); - Term.Println("Received an unknown packet, id: " + msg.msgType); - break; + } else { + Term.Println("Client has reported an erronous SyncBase ID!"); + } + + break; + default: + Debug.LogError("Received an unknown packet, id: " + msg.msgType); + Term.Println("Received an unknown packet, id: " + msg.msgType); + break; } } @@ -189,7 +222,7 @@ namespace Cyber.Networking.Serverside { } // Then send the client a list of all other clients - NetworkServer.SendToClient(Id, PktType.MassIdentity, new MassIdentityPkt(IdList)); + NetworkServer.SendToClient(Id, PktType.MassIdentity, new IntListPkt(IdList)); // Add the player to the list SConnectedPlayer Player = new SConnectedPlayer(msg.conn.connectionId); @@ -199,7 +232,7 @@ namespace Cyber.Networking.Serverside { NetworkServer.SendToClient(msg.conn.connectionId, PktType.Identity, new IdentityPkt(msg.conn.connectionId, true)); - // Spawn the player and collet it's IDs + // Spawn the player and collect it's IDs Vector3 Position = new Vector3(0, 0, 0); GameObject Obj = Spawner.Spawn(EntityType.NPC, Position); int[] EntityIdList = Spawner.SyncDB.GetEntityIDs(Obj); @@ -207,6 +240,9 @@ namespace Cyber.Networking.Serverside { NetworkServer.SendToAll(PktType.SpawnEntity, new SpawnEntityPkt(EntityType.NPC, Position, EntityIdList, Id)); + // Send ID's of every existing static SyncBase object in the world. + NetworkServer.SendToClient(Id, PktType.StaticObjectIdsPkt, new IntListPkt(Spawner.SyncDB.GetStaticSyncBaseIDList())); + // Send every entity to the player who just connected. foreach (var Entry in Players) { if (Entry.Key == Id) { diff --git a/Assets/Scripts/Util/TextTextureApplier.cs b/Assets/Scripts/Util/TextTextureApplier.cs index 42cfa59..48d3172 100644 --- a/Assets/Scripts/Util/TextTextureApplier.cs +++ b/Assets/Scripts/Util/TextTextureApplier.cs @@ -36,7 +36,6 @@ namespace Cyber.Util { /// public float Brightness = 1f; - private TextTextureProperties LastText = new TextTextureProperties(""); private Material Material; private bool Dirty = true;