Skip to content

Commit

Permalink
Make ServerAppearanceSystem thread-safe (#1568)
Browse files Browse the repository at this point in the history
* Use locks on ServerAppearanceSystem

* Use a file-scoped namespace
  • Loading branch information
wixoaGit authored Dec 26, 2023
1 parent 1bb067f commit 562f047
Showing 1 changed file with 37 additions and 22 deletions.
59 changes: 37 additions & 22 deletions OpenDreamRuntime/Rendering/ServerAppearanceSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,40 @@
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.Player;

namespace OpenDreamRuntime.Rendering {
public sealed class ServerAppearanceSystem : SharedAppearanceSystem {
private readonly Dictionary<IconAppearance, int> _appearanceToId = new();
private readonly Dictionary<int, IconAppearance> _idToAppearance = new();
private int _appearanceIdCounter;
namespace OpenDreamRuntime.Rendering;

[Dependency] private readonly IPlayerManager _playerManager = default!;
public sealed class ServerAppearanceSystem : SharedAppearanceSystem {
private readonly Dictionary<IconAppearance, int> _appearanceToId = new();
private readonly Dictionary<int, IconAppearance> _idToAppearance = new();
private int _appearanceIdCounter;

public override void Initialize() {
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
}
/// <summary>
/// This system is used by the PVS thread, we need to be thread-safe
/// </summary>
private readonly object _lock = new();

[Dependency] private readonly IPlayerManager _playerManager = default!;

public override void Initialize() {
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
}

public override void Shutdown() {
public override void Shutdown() {
lock (_lock) {
_appearanceToId.Clear();
_idToAppearance.Clear();
_appearanceIdCounter = 0;
}
}

private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) {
if (e.NewStatus == SessionStatus.InGame) {
RaiseNetworkEvent(new AllAppearancesEvent(_idToAppearance), e.Session.ConnectedClient);
}
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) {
if (e.NewStatus == SessionStatus.InGame) {
RaiseNetworkEvent(new AllAppearancesEvent(_idToAppearance), e.Session.ConnectedClient);
}
}

public int AddAppearance(IconAppearance appearance) {
public int AddAppearance(IconAppearance appearance) {
lock (_lock) {
if (!_appearanceToId.TryGetValue(appearance, out int appearanceId)) {
appearanceId = _appearanceIdCounter++;
_appearanceToId.Add(appearance, appearanceId);
Expand All @@ -39,23 +48,29 @@ public int AddAppearance(IconAppearance appearance) {

return appearanceId;
}
}

public IconAppearance MustGetAppearance(int appearanceId) {
public IconAppearance MustGetAppearance(int appearanceId) {
lock (_lock) {
return _idToAppearance[appearanceId];
}
}

public bool TryGetAppearance(int appearanceId, [NotNullWhen(true)] out IconAppearance? appearance) {
public bool TryGetAppearance(int appearanceId, [NotNullWhen(true)] out IconAppearance? appearance) {
lock (_lock) {
return _idToAppearance.TryGetValue(appearanceId, out appearance);
}
}

public bool TryGetAppearanceId(IconAppearance appearance, out int appearanceId) {
public bool TryGetAppearanceId(IconAppearance appearance, out int appearanceId) {
lock (_lock) {
return _appearanceToId.TryGetValue(appearance, out appearanceId);
}
}

public void Animate(NetEntity entity, IconAppearance targetAppearance, TimeSpan duration) {
int appearanceId = AddAppearance(targetAppearance);
public void Animate(NetEntity entity, IconAppearance targetAppearance, TimeSpan duration) {
int appearanceId = AddAppearance(targetAppearance);

RaiseNetworkEvent(new AnimationEvent(entity, appearanceId, duration));
}
RaiseNetworkEvent(new AnimationEvent(entity, appearanceId, duration));
}
}

0 comments on commit 562f047

Please sign in to comment.