Misc replay related changes (#13250)

This commit is contained in:
Leon Friedrich
2023-01-08 07:04:09 +13:00
committed by GitHub
parent a9adab88e5
commit f1cb0ca37a
11 changed files with 93 additions and 9 deletions

View File

@@ -40,6 +40,7 @@ public sealed class ChatUIController : UIController
[Dependency] private readonly IClientNetManager _net = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[UISystemDependency] private readonly ExamineSystem? _examine = default;
[UISystemDependency] private readonly GhostSystem? _ghost = default;
@@ -122,7 +123,7 @@ public sealed class ChatUIController : UIController
/// </summary>
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)
// and select (for attempting to send on).
@@ -639,12 +640,12 @@ public sealed class ChatUIController : UIController
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
if (!msg.HideChat)
{
History.Add(msg);
History.Add((_timing.CurTick, msg));
MessageAdded?.Invoke(msg);
if (!msg.Read)
@@ -660,7 +661,7 @@ public sealed class ChatUIController : UIController
}
// Local messages that have an entity attached get a speech bubble.
if (msg.SenderEntity == default)
if (!speechBubble || msg.SenderEntity == default)
return;
switch (msg.Channel)
@@ -711,6 +712,14 @@ public sealed class ChatUIController : UIController
_typingIndicator?.ClientChangedChatText();
}
public void Repopulate()
{
foreach (var chat in _chats)
{
chat.Repopulate();
}
}
private readonly record struct SpeechBubbleData(string Message, SpeechBubble.SpeechType Type);
private sealed class SpeechBubbleQueueData

View File

@@ -71,13 +71,23 @@ public partial class ChatBox : UIWidget
UpdateSelectedChannel();
}
public void Repopulate()
{
Contents.Clear();
foreach (var message in _controller.History)
{
OnMessageAdded(message.Item2);
}
}
private void OnChannelFilter(ChatChannel channel, bool active)
{
Contents.Clear();
foreach (var message in _controller.History)
{
OnMessageAdded(message);
OnMessageAdded(message.Item2);
}
if (active)

View File

@@ -3,6 +3,8 @@ using Content.Shared.Administration;
using Robust.Server.Player;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Markdown.Mapping;
namespace Content.Server.Administration;
@@ -11,6 +13,7 @@ namespace Content.Server.Administration;
/// </summary>
public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
{
[Dependency] private readonly IReplayRecordingManager _replay = default!;
[Dependency] private readonly IServerNetManager _netManager = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
@@ -18,11 +21,22 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
private readonly List<string> _loadedPrototypes = new();
public IReadOnlyList<string> LoadedPrototypes => _loadedPrototypes;
public void Initialize()
{
_netManager.RegisterNetMessage<GamePrototypeLoadMessage>(ClientLoadsPrototype);
_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)
@@ -47,6 +61,9 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
private void LoadPrototypeData(string prototypeData)
{
_loadedPrototypes.Add(prototypeData);
_replay.QueueReplayMessage(new ReplayPrototypeUploadMsg { PrototypeData = prototypeData });
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototypeData

View File

@@ -5,6 +5,8 @@ using Content.Shared.CCVar;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Markdown.Mapping;
namespace Content.Server.Administration;
@@ -15,6 +17,7 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
[Dependency] private readonly IServerNetManager _serverNetManager = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IServerDbManager _serverDb = default!;
[Dependency] private readonly IReplayRecordingManager _replay = default!;
[ViewVariables] public bool Enabled { get; private set; } = true;
[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);
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>
@@ -63,6 +76,8 @@ public sealed class NetworkResourceManager : SharedNetworkResourceManager
channel.SendMessage(msg);
}
_replay.QueueReplayMessage(new ReplayResourceUploadMsg { RelativePath = msg.RelativePath, Data = msg.Data });
if (!StoreUploaded)
return;

View File

@@ -20,6 +20,7 @@ public sealed class SpraySystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = 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);
}
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,
new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(component.CooldownTime)), true);

View File

@@ -1,3 +1,6 @@
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Administration;
public interface IGamePrototypeLoadManager
@@ -5,3 +8,12 @@ public interface IGamePrototypeLoadManager
public void Initialize();
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!;
}

View File

@@ -1,5 +1,6 @@
using Robust.Shared.ContentPack;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Administration;
@@ -38,4 +39,14 @@ public abstract class SharedNetworkResourceManager : IDisposable
// MemoryContentRoot uses a ReaderWriterLockSlim, which we need to dispose of.
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!;
}
}

View File

@@ -77,6 +77,9 @@ public abstract partial class SharedHandsSystem : EntitySystem
if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? component))
return;
if (!_actionBlocker.CanInteract(session.AttachedEntity.Value, null))
return;
if (component.ActiveHand == null || component.Hands.Count < 2)
return;

View File

@@ -32,7 +32,7 @@ namespace Content.Shared.Projectiles
}
[NetSerializable, Serializable]
protected sealed class ProjectileComponentState : ComponentState
public sealed class ProjectileComponentState : ComponentState
{
public ProjectileComponentState(EntityUid shooter, bool ignoreShooter)
{
@@ -45,7 +45,7 @@ namespace Content.Shared.Projectiles
}
[Serializable, NetSerializable]
protected sealed class ImpactEffectEvent : EntityEventArgs
public sealed class ImpactEffectEvent : EntityEventArgs
{
public string Prototype;
public EntityCoordinates Coordinates;

View File

@@ -7,6 +7,12 @@ public abstract class SharedTimedDespawnSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
base.Initialize();
UpdatesOutsidePrediction = true;
}
public override void Update(float frameTime)
{
base.Update(frameTime);

View File

@@ -404,7 +404,7 @@ public abstract partial class SharedGunSystem : EntitySystem
/// Used for animated effects on the client.
/// </summary>
[Serializable, NetSerializable]
protected sealed class HitscanEvent : EntityEventArgs
public sealed class HitscanEvent : EntityEventArgs
{
public List<(EntityCoordinates coordinates, Angle angle, SpriteSpecifier Sprite, float Distance)> Sprites = new();
}