using System; using System.Collections.Generic; using Robust.Client.Interfaces.GameStates; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Network.Messages; using Robust.Shared.Utility; namespace Robust.Client.GameObjects { /// /// The client implementation of the Entity Network Manager. /// public class ClientEntityNetworkManager : IEntityNetworkManager { #pragma warning disable 649 [Dependency] private readonly IClientNetManager _networkManager; [Dependency] private readonly IClientGameStateManager _gameStateManager; [Dependency] private readonly IGameTiming _gameTiming; #pragma warning restore 649 /// public event EventHandler ReceivedComponentMessage; /// public event EventHandler ReceivedSystemMessage; private readonly PriorityQueue _queue = new PriorityQueue(new MessageTickComparer()); /// public void SetupNetworking() { _networkManager.RegisterNetMessage(MsgEntity.NAME, HandleEntityNetworkMessage); } public void Update() { while (_queue.Count != 0 && _queue.Peek().SourceTick <= _gameStateManager.CurServerTick) { DispatchMsgEntity(_queue.Take()); } } /// public void SendSystemNetworkMessage(EntitySystemMessage message) { SendSystemNetworkMessage(message, default(uint)); } public void SendSystemNetworkMessage(EntitySystemMessage message, uint sequence) { var msg = _networkManager.CreateNetMessage(); msg.Type = EntityMessageType.SystemMessage; msg.SystemMessage = message; msg.SourceTick = _gameTiming.CurTick; msg.Sequence = sequence; _networkManager.ClientSendMessage(msg); } /// public void SendSystemNetworkMessage(EntitySystemMessage message, INetChannel channel) { throw new NotSupportedException(); } /// public void SendComponentNetworkMessage(INetChannel channel, IEntity entity, IComponent component, ComponentMessage message) { if (!component.NetID.HasValue) throw new ArgumentException($"Component {component.Name} does not have a NetID.", nameof(component)); var msg = _networkManager.CreateNetMessage(); msg.Type = EntityMessageType.ComponentMessage; msg.EntityUid = entity.Uid; msg.NetId = component.NetID.Value; msg.ComponentMessage = message; msg.SourceTick = _gameTiming.CurTick; _networkManager.ClientSendMessage(msg); } private void HandleEntityNetworkMessage(MsgEntity message) { if (message.SourceTick <= _gameStateManager.CurServerTick) { DispatchMsgEntity(message); return; } _queue.Add(message); } private void DispatchMsgEntity(MsgEntity message) { switch (message.Type) { case EntityMessageType.ComponentMessage: ReceivedComponentMessage?.Invoke(this, new NetworkComponentMessage(message)); return; case EntityMessageType.SystemMessage: ReceivedSystemMessage?.Invoke(this, message.SystemMessage); return; } } private sealed class MessageTickComparer : IComparer { public int Compare(MsgEntity x, MsgEntity y) { DebugTools.AssertNotNull(x); DebugTools.AssertNotNull(y); return y.SourceTick.CompareTo(x.SourceTick); } } } }