mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 11:40:52 +01:00
148 lines
5.2 KiB
C#
148 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Prometheus;
|
|
using Robust.Client.GameStates;
|
|
using Robust.Client.Player;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Network.Messages;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Robust.Client.GameObjects
|
|
{
|
|
/// <summary>
|
|
/// Manager for entities -- controls things like template loading and instantiation
|
|
/// </summary>
|
|
public sealed class ClientEntityManager : EntityManager, IClientEntityManagerInternal
|
|
{
|
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
[Dependency] private readonly IClientNetManager _networkManager = default!;
|
|
[Dependency] private readonly IClientGameStateManager _gameStateManager = default!;
|
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
|
|
protected override int NextEntityUid { get; set; } = EntityUid.ClientUid + 1;
|
|
|
|
public override void Initialize()
|
|
{
|
|
SetupNetworking();
|
|
ReceivedSystemMessage += (_, systemMsg) => EventBus.RaiseEvent(EventSource.Network, systemMsg);
|
|
|
|
base.Initialize();
|
|
}
|
|
|
|
EntityUid IClientEntityManagerInternal.CreateEntity(string? prototypeName, EntityUid uid)
|
|
{
|
|
return base.CreateEntity(prototypeName, uid);
|
|
}
|
|
|
|
void IClientEntityManagerInternal.InitializeEntity(EntityUid entity, MetaDataComponent? meta)
|
|
{
|
|
base.InitializeEntity(entity, meta);
|
|
}
|
|
|
|
void IClientEntityManagerInternal.StartEntity(EntityUid entity)
|
|
{
|
|
base.StartEntity(entity);
|
|
}
|
|
|
|
#region IEntityNetworkManager impl
|
|
|
|
public override IEntityNetworkManager EntityNetManager => this;
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<object>? ReceivedSystemMessage;
|
|
|
|
private readonly PriorityQueue<(uint seq, MsgEntity msg)> _queue = new(new MessageTickComparer());
|
|
private uint _incomingMsgSequence = 0;
|
|
|
|
/// <inheritdoc />
|
|
public void SetupNetworking()
|
|
{
|
|
_networkManager.RegisterNetMessage<MsgEntity>(HandleEntityNetworkMessage);
|
|
}
|
|
|
|
public override void TickUpdate(float frameTime, bool noPredictions, Histogram? histogram)
|
|
{
|
|
using (histogram?.WithLabels("EntityNet").NewTimer())
|
|
{
|
|
while (_queue.Count != 0 && _queue.Peek().msg.SourceTick <= _gameStateManager.CurServerTick)
|
|
{
|
|
var (_, msg) = _queue.Take();
|
|
// Logger.DebugS("net.ent", "Dispatching: {0}: {1}", seq, msg);
|
|
DispatchMsgEntity(msg);
|
|
}
|
|
}
|
|
|
|
base.TickUpdate(frameTime, noPredictions, histogram);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SendSystemNetworkMessage(EntityEventArgs message)
|
|
{
|
|
SendSystemNetworkMessage(message, default(uint));
|
|
}
|
|
|
|
public void SendSystemNetworkMessage(EntityEventArgs message, uint sequence)
|
|
{
|
|
var msg = new MsgEntity();
|
|
msg.Type = EntityMessageType.SystemMessage;
|
|
msg.SystemMessage = message;
|
|
msg.SourceTick = _gameTiming.CurTick;
|
|
msg.Sequence = sequence;
|
|
|
|
_networkManager.ClientSendMessage(msg);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SendSystemNetworkMessage(EntityEventArgs message, INetChannel channel)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
private void HandleEntityNetworkMessage(MsgEntity message)
|
|
{
|
|
if (message.SourceTick <= _gameStateManager.CurServerTick)
|
|
{
|
|
DispatchMsgEntity(message);
|
|
return;
|
|
}
|
|
|
|
// MsgEntity is sent with ReliableOrdered so Lidgren guarantees ordering of incoming messages.
|
|
// We still need to store a sequence input number to ensure ordering remains consistent in
|
|
// the priority queue.
|
|
_queue.Add((++_incomingMsgSequence, message));
|
|
}
|
|
|
|
private void DispatchMsgEntity(MsgEntity message)
|
|
{
|
|
switch (message.Type)
|
|
{
|
|
case EntityMessageType.SystemMessage:
|
|
var msg = message.SystemMessage;
|
|
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
|
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(_playerManager.LocalPlayer!.Session), msg)!;
|
|
ReceivedSystemMessage?.Invoke(this, msg);
|
|
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private sealed class MessageTickComparer : IComparer<(uint seq, MsgEntity msg)>
|
|
{
|
|
public int Compare((uint seq, MsgEntity msg) x, (uint seq, MsgEntity msg) y)
|
|
{
|
|
var cmp = y.msg.SourceTick.CompareTo(x.msg.SourceTick);
|
|
if (cmp != 0)
|
|
{
|
|
return cmp;
|
|
}
|
|
|
|
return y.seq.CompareTo(x.seq);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|