Misc replay related changes (#13250)
This commit is contained in:
@@ -40,6 +40,7 @@ public sealed class ChatUIController : UIController
|
|||||||
[Dependency] private readonly IClientNetManager _net = default!;
|
[Dependency] private readonly IClientNetManager _net = default!;
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
[Dependency] private readonly IStateManager _state = default!;
|
[Dependency] private readonly IStateManager _state = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
[UISystemDependency] private readonly ExamineSystem? _examine = default;
|
[UISystemDependency] private readonly ExamineSystem? _examine = default;
|
||||||
[UISystemDependency] private readonly GhostSystem? _ghost = default;
|
[UISystemDependency] private readonly GhostSystem? _ghost = default;
|
||||||
@@ -122,7 +123,7 @@ public sealed class ChatUIController : UIController
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<ChatChannel, int> _unreadMessages = new();
|
private readonly Dictionary<ChatChannel, int> _unreadMessages = new();
|
||||||
|
|
||||||
public readonly List<ChatMessage> History = new();
|
public readonly List<(GameTick, ChatMessage)> History = new();
|
||||||
|
|
||||||
// Maintains which channels a client should be able to filter (for showing in the chatbox)
|
// Maintains which channels a client should be able to filter (for showing in the chatbox)
|
||||||
// and select (for attempting to send on).
|
// and select (for attempting to send on).
|
||||||
@@ -639,12 +640,12 @@ public sealed class ChatUIController : UIController
|
|||||||
|
|
||||||
private void OnChatMessage(MsgChatMessage message) => ProcessChatMessage(message.Message);
|
private void OnChatMessage(MsgChatMessage message) => ProcessChatMessage(message.Message);
|
||||||
|
|
||||||
public void ProcessChatMessage(ChatMessage msg)
|
public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true)
|
||||||
{
|
{
|
||||||
// Log all incoming chat to repopulate when filter is un-toggled
|
// Log all incoming chat to repopulate when filter is un-toggled
|
||||||
if (!msg.HideChat)
|
if (!msg.HideChat)
|
||||||
{
|
{
|
||||||
History.Add(msg);
|
History.Add((_timing.CurTick, msg));
|
||||||
MessageAdded?.Invoke(msg);
|
MessageAdded?.Invoke(msg);
|
||||||
|
|
||||||
if (!msg.Read)
|
if (!msg.Read)
|
||||||
@@ -660,7 +661,7 @@ public sealed class ChatUIController : UIController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Local messages that have an entity attached get a speech bubble.
|
// Local messages that have an entity attached get a speech bubble.
|
||||||
if (msg.SenderEntity == default)
|
if (!speechBubble || msg.SenderEntity == default)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (msg.Channel)
|
switch (msg.Channel)
|
||||||
@@ -711,6 +712,14 @@ public sealed class ChatUIController : UIController
|
|||||||
_typingIndicator?.ClientChangedChatText();
|
_typingIndicator?.ClientChangedChatText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Repopulate()
|
||||||
|
{
|
||||||
|
foreach (var chat in _chats)
|
||||||
|
{
|
||||||
|
chat.Repopulate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly record struct SpeechBubbleData(string Message, SpeechBubble.SpeechType Type);
|
private readonly record struct SpeechBubbleData(string Message, SpeechBubble.SpeechType Type);
|
||||||
|
|
||||||
private sealed class SpeechBubbleQueueData
|
private sealed class SpeechBubbleQueueData
|
||||||
|
|||||||
@@ -71,13 +71,23 @@ public partial class ChatBox : UIWidget
|
|||||||
UpdateSelectedChannel();
|
UpdateSelectedChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Repopulate()
|
||||||
|
{
|
||||||
|
Contents.Clear();
|
||||||
|
|
||||||
|
foreach (var message in _controller.History)
|
||||||
|
{
|
||||||
|
OnMessageAdded(message.Item2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnChannelFilter(ChatChannel channel, bool active)
|
private void OnChannelFilter(ChatChannel channel, bool active)
|
||||||
{
|
{
|
||||||
Contents.Clear();
|
Contents.Clear();
|
||||||
|
|
||||||
foreach (var message in _controller.History)
|
foreach (var message in _controller.History)
|
||||||
{
|
{
|
||||||
OnMessageAdded(message);
|
OnMessageAdded(message.Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ using Content.Shared.Administration;
|
|||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Replays;
|
||||||
|
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||||
|
|
||||||
namespace Content.Server.Administration;
|
namespace Content.Server.Administration;
|
||||||
|
|
||||||
@@ -11,6 +13,7 @@ namespace Content.Server.Administration;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
|
public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IReplayRecordingManager _replay = default!;
|
||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
@@ -18,11 +21,22 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
|
|||||||
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
|
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
|
||||||
|
|
||||||
private readonly List<string> _loadedPrototypes = new();
|
private readonly List<string> _loadedPrototypes = new();
|
||||||
|
public IReadOnlyList<string> LoadedPrototypes => _loadedPrototypes;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(ClientLoadsPrototype);
|
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(ClientLoadsPrototype);
|
||||||
_netManager.Connected += NetManagerOnConnected;
|
_netManager.Connected += NetManagerOnConnected;
|
||||||
|
_replay.OnRecordingStarted += OnStartReplayRecording;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)
|
||||||
|
{
|
||||||
|
// replays will need information about currently loaded prototypes
|
||||||
|
foreach (var prototype in _loadedPrototypes)
|
||||||
|
{
|
||||||
|
initReplayData.Item2.Add(new ReplayPrototypeUploadMsg { PrototypeData = prototype });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendGamePrototype(string prototype)
|
public void SendGamePrototype(string prototype)
|
||||||
@@ -47,6 +61,9 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
|
|||||||
private void LoadPrototypeData(string prototypeData)
|
private void LoadPrototypeData(string prototypeData)
|
||||||
{
|
{
|
||||||
_loadedPrototypes.Add(prototypeData);
|
_loadedPrototypes.Add(prototypeData);
|
||||||
|
|
||||||
|
_replay.QueueReplayMessage(new ReplayPrototypeUploadMsg { PrototypeData = prototypeData });
|
||||||
|
|
||||||
var msg = new GamePrototypeLoadMessage
|
var msg = new GamePrototypeLoadMessage
|
||||||
{
|
{
|
||||||
PrototypeData = prototypeData
|
PrototypeData = prototypeData
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using Content.Shared.CCVar;
|
|||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Replays;
|
||||||
|
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||||
|
|
||||||
namespace Content.Server.Administration;
|
namespace Content.Server.Administration;
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
|
|||||||
[Dependency] private readonly IServerNetManager _serverNetManager = default!;
|
[Dependency] private readonly IServerNetManager _serverNetManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
||||||
[Dependency] private readonly IServerDbManager _serverDb = default!;
|
[Dependency] private readonly IServerDbManager _serverDb = default!;
|
||||||
|
[Dependency] private readonly IReplayRecordingManager _replay = default!;
|
||||||
|
|
||||||
[ViewVariables] public bool Enabled { get; private set; } = true;
|
[ViewVariables] public bool Enabled { get; private set; } = true;
|
||||||
[ViewVariables] public float SizeLimit { get; private set; } = 0f;
|
[ViewVariables] public float SizeLimit { get; private set; } = 0f;
|
||||||
@@ -30,6 +33,16 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
|
|||||||
_cfgManager.OnValueChanged(CCVars.ResourceUploadingStoreEnabled, value => StoreUploaded = value, true);
|
_cfgManager.OnValueChanged(CCVars.ResourceUploadingStoreEnabled, value => StoreUploaded = value, true);
|
||||||
|
|
||||||
AutoDelete(_cfgManager.GetCVar(CCVars.ResourceUploadingStoreDeletionDays));
|
AutoDelete(_cfgManager.GetCVar(CCVars.ResourceUploadingStoreDeletionDays));
|
||||||
|
_replay.OnRecordingStarted += OnStartReplayRecording;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartReplayRecording((MappingDataNode, List<object>) initReplayData)
|
||||||
|
{
|
||||||
|
// replays will need information about currently loaded extra resources
|
||||||
|
foreach (var (path, data) in ContentRoot.GetAllFiles())
|
||||||
|
{
|
||||||
|
initReplayData.Item2.Add(new ReplayResourceUploadMsg { RelativePath = path, Data = data });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -63,6 +76,8 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
|
|||||||
channel.SendMessage(msg);
|
channel.SendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_replay.QueueReplayMessage(new ReplayResourceUploadMsg { RelativePath = msg.RelativePath, Data = msg.Data });
|
||||||
|
|
||||||
if (!StoreUploaded)
|
if (!StoreUploaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public sealed class SpraySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
[Dependency] private readonly VaporSystem _vaporSystem = default!;
|
[Dependency] private readonly VaporSystem _vaporSystem = default!;
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ public sealed class SpraySystem : EntitySystem
|
|||||||
_vaporSystem.Start(vaporComponent, vaporXform, impulseDirection, component.SprayVelocity, target, component.SprayAliveTime, args.User);
|
_vaporSystem.Start(vaporComponent, vaporXform, impulseDirection, component.SprayVelocity, target, component.SprayAliveTime, args.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundSystem.Play(component.SpraySound.GetSound(), Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.125f));
|
_audio.PlayPvs(component.SpraySound, uid, component.SpraySound.Params.WithVariation(0.125f));
|
||||||
|
|
||||||
RaiseLocalEvent(uid,
|
RaiseLocalEvent(uid,
|
||||||
new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(component.CooldownTime)), true);
|
new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(component.CooldownTime)), true);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Administration;
|
namespace Content.Shared.Administration;
|
||||||
|
|
||||||
public interface IGamePrototypeLoadManager
|
public interface IGamePrototypeLoadManager
|
||||||
@@ -5,3 +8,12 @@ public interface IGamePrototypeLoadManager
|
|||||||
public void Initialize();
|
public void Initialize();
|
||||||
public void SendGamePrototype(string prototype);
|
public void SendGamePrototype(string prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO REPLAYS
|
||||||
|
// Figure out a way to just directly save NetMessage objects to replays. This just uses IRobustSerializer as a crutch.
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ReplayPrototypeUploadMsg
|
||||||
|
{
|
||||||
|
public string PrototypeData = default!;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Robust.Shared.ContentPack;
|
using Robust.Shared.ContentPack;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Administration;
|
namespace Content.Shared.Administration;
|
||||||
@@ -38,4 +39,14 @@ public abstract class SharedNetworkResourceManager : IDisposable
|
|||||||
// MemoryContentRoot uses a ReaderWriterLockSlim, which we need to dispose of.
|
// MemoryContentRoot uses a ReaderWriterLockSlim, which we need to dispose of.
|
||||||
ContentRoot.Dispose();
|
ContentRoot.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO REPLAYS
|
||||||
|
// Figure out a way to just directly save NetMessage objects to replays. This just uses IRobustSerializer as a crutch.
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ReplayResourceUploadMsg
|
||||||
|
{
|
||||||
|
public byte[] Data = default!;
|
||||||
|
public ResourcePath RelativePath = default!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ public abstract partial class SharedHandsSystem : EntitySystem
|
|||||||
if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? component))
|
if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? component))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!_actionBlocker.CanInteract(session.AttachedEntity.Value, null))
|
||||||
|
return;
|
||||||
|
|
||||||
if (component.ActiveHand == null || component.Hands.Count < 2)
|
if (component.ActiveHand == null || component.Hands.Count < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace Content.Shared.Projectiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NetSerializable, Serializable]
|
[NetSerializable, Serializable]
|
||||||
protected sealed class ProjectileComponentState : ComponentState
|
public sealed class ProjectileComponentState : ComponentState
|
||||||
{
|
{
|
||||||
public ProjectileComponentState(EntityUid shooter, bool ignoreShooter)
|
public ProjectileComponentState(EntityUid shooter, bool ignoreShooter)
|
||||||
{
|
{
|
||||||
@@ -45,7 +45,7 @@ namespace Content.Shared.Projectiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
protected sealed class ImpactEffectEvent : EntityEventArgs
|
public sealed class ImpactEffectEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
public string Prototype;
|
public string Prototype;
|
||||||
public EntityCoordinates Coordinates;
|
public EntityCoordinates Coordinates;
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ public abstract class SharedTimedDespawnSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
UpdatesOutsidePrediction = true;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
|||||||
/// Used for animated effects on the client.
|
/// Used for animated effects on the client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
protected sealed class HitscanEvent : EntityEventArgs
|
public sealed class HitscanEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
public List<(EntityCoordinates coordinates, Angle angle, SpriteSpecifier Sprite, float Distance)> Sprites = new();
|
public List<(EntityCoordinates coordinates, Angle angle, SpriteSpecifier Sprite, float Distance)> Sprites = new();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user