Skip to content

Commit

Permalink
Merge pull request #1877 from space-syndicate/upstream-sync
Browse files Browse the repository at this point in the history
Upstream sync
  • Loading branch information
Morb0 authored Feb 17, 2024
2 parents 8ed4939 + 92aae19 commit f7a6c76
Show file tree
Hide file tree
Showing 107 changed files with 791 additions and 106 deletions.
84 changes: 84 additions & 0 deletions Content.Client/Options/OptionsVisualizerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Content.Shared.CCVar;

namespace Content.Client.Options;

/// <summary>
/// Allows specifying sprite alternatives depending on the client's accessibility options.
/// </summary>
/// <remarks>
/// A list of layer mappings is given that the component applies to,
/// and it will pick one entry to apply based on the settings configuration. Example:
///
/// <code>
/// - type: Sprite
/// sprite: Effects/optionsvisualizertest.rsi
/// layers:
/// - state: none
/// map: [ "layer" ]
/// - type: OptionsVisualizer
/// visuals:
/// layer:
/// - options: Default
/// data: { state: none }
/// - options: Test
/// data: { state: test }
/// - options: ReducedMotion
/// data: { state: motion }
/// - options: [Test, ReducedMotion]
/// data: { state: both }
/// </code>
/// </remarks>
/// <seealso cref="OptionsVisualizerSystem"/>
/// <seealso cref="OptionVisualizerOptions"/>
[RegisterComponent]
public sealed partial class OptionsVisualizerComponent : Component
{
/// <summary>
/// A mapping storing data about which sprite layer keys should be controlled.
/// </summary>
/// <remarks>
/// Each layer stores an array of possible options. The last entry with a
/// <see cref="LayerDatum.Options"/> matching the active user preferences will be picked.
/// This allows choosing a priority if multiple entries are matched.
/// </remarks>
[DataField(required: true)]
public Dictionary<string, LayerDatum[]> Visuals = default!;

/// <summary>
/// A single option for a layer to be selected.
/// </summary>
[DataDefinition]
public sealed partial class LayerDatum
{
/// <summary>
/// Which options must be set by the user to make this datum match.
/// </summary>
[DataField]
public OptionVisualizerOptions Options { get; set; }

/// <summary>
/// The sprite layer data to set on the sprite when this datum matches.
/// </summary>
[DataField]
public PrototypeLayerData Data { get; set; }
}
}

[Flags]
public enum OptionVisualizerOptions
{
/// <summary>
/// Corresponds to no special options being set, can be used as a "default" state.
/// </summary>
Default = 0,

/// <summary>
/// Corresponds to the <see cref="CCVars.DebugOptionVisualizerTest"/> CVar being set.
/// </summary>
Test = 1 << 0,

/// <summary>
/// Corresponds to the <see cref="CCVars.ReducedMotion"/> CVar being set.
/// </summary>
ReducedMotion = 1 << 1,
}
97 changes: 97 additions & 0 deletions Content.Client/Options/OptionsVisualizerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Content.Shared.CCVar;
using Robust.Client.GameObjects;
using Robust.Shared.Configuration;
using Robust.Shared.Reflection;

namespace Content.Client.Options;

/// <summary>
/// Implements <see cref="OptionsVisualizerComponent"/>.
/// </summary>
public sealed class OptionsVisualizerSystem : EntitySystem
{
private static readonly (OptionVisualizerOptions, CVarDef<bool>)[] OptionVars =
{
(OptionVisualizerOptions.Test, CCVars.DebugOptionVisualizerTest),
(OptionVisualizerOptions.ReducedMotion, CCVars.ReducedMotion),
};

[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IReflectionManager _reflection = default!;

private OptionVisualizerOptions _currentOptions;

public override void Initialize()
{
base.Initialize();

foreach (var (_, cvar) in OptionVars)
{
Subs.CVar(_cfg, cvar, _ => CVarChanged());
}

UpdateActiveOptions();

SubscribeLocalEvent<OptionsVisualizerComponent, ComponentStartup>(OnComponentStartup);
}

private void CVarChanged()
{
UpdateActiveOptions();
UpdateAllComponents();
}

private void UpdateActiveOptions()
{
_currentOptions = OptionVisualizerOptions.Default;

foreach (var (value, cVar) in OptionVars)
{
if (_cfg.GetCVar(cVar))
_currentOptions |= value;
}
}

private void UpdateAllComponents()
{
var query = EntityQueryEnumerator<OptionsVisualizerComponent, SpriteComponent>();
while (query.MoveNext(out _, out var component, out var sprite))
{
UpdateComponent(component, sprite);
}
}

private void OnComponentStartup(EntityUid uid, OptionsVisualizerComponent component, ComponentStartup args)
{
if (!TryComp(uid, out SpriteComponent? sprite))
return;

UpdateComponent(component, sprite);
}

private void UpdateComponent(OptionsVisualizerComponent component, SpriteComponent sprite)
{
foreach (var (layerKeyRaw, layerData) in component.Visuals)
{
object layerKey = _reflection.TryParseEnumReference(layerKeyRaw, out var @enum)
? @enum
: layerKeyRaw;

OptionsVisualizerComponent.LayerDatum? matchedDatum = null;
foreach (var datum in layerData)
{
if ((datum.Options & _currentOptions) != datum.Options)
continue;

matchedDatum = datum;
}

if (matchedDatum == null)
continue;

var layerIndex = sprite.LayerMapReserveBlank(layerKey);
sprite.LayerSetData(layerIndex, matchedDatum.Data);
}
}
}

1 change: 1 addition & 0 deletions Content.Server/Botany/Systems/PlantHolderSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@ public void Update(EntityUid uid, PlantHolderComponent? component = null)
RemovePlant(uid, component);
component.ForceUpdate = true;
Update(uid, component);
return;
}

CheckHealth(uid, component);
Expand Down
1 change: 1 addition & 0 deletions Content.Server/Entry/IgnoredComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public static class IgnoredComponents
"InventorySlots",
"LightFade",
"HolidayRsiSwap",
"OptionsVisualizer",
};
}
}
14 changes: 11 additions & 3 deletions Content.Server/Explosion/EntitySystems/TriggerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Player;
using Content.Shared.Coordinates;

namespace Content.Server.Explosion.EntitySystems
{
Expand Down Expand Up @@ -103,9 +105,15 @@ public override void Initialize()

private void OnSoundTrigger(EntityUid uid, SoundOnTriggerComponent component, TriggerEvent args)
{
_audio.PlayPvs(component.Sound, uid);
if (component.RemoveOnTrigger)
RemCompDeferred<SoundOnTriggerComponent>(uid);
if (component.RemoveOnTrigger) // if the component gets removed when it's triggered
{
var xform = Transform(uid);
_audio.PlayPvs(component.Sound, xform.Coordinates); // play the sound at its last known coordinates
}
else // if the component doesn't get removed when triggered
{
_audio.PlayPvs(component.Sound, uid); // have the sound follow the entity itself
}
}

private void OnAnchorTrigger(EntityUid uid, AnchorOnTriggerComponent component, TriggerEvent args)
Expand Down
21 changes: 21 additions & 0 deletions Content.Server/GameTicking/GameTicker.Replays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
using Robust.Shared;
using Robust.Shared.ContentPack;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;

namespace Content.Server.GameTicking;
Expand All @@ -10,12 +14,15 @@ public sealed partial class GameTicker
{
[Dependency] private readonly IReplayRecordingManager _replays = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly ISerializationManager _serialman = default!;


private ISawmill _sawmillReplays = default!;

private void InitializeReplays()
{
_replays.RecordingFinished += ReplaysOnRecordingFinished;
_replays.RecordingStopped += ReplaysOnRecordingStopped;
}

/// <summary>
Expand Down Expand Up @@ -108,6 +115,20 @@ private void ReplaysOnRecordingFinished(ReplayRecordingFinished data)
data.Directory.Rename(data.Path, state.MoveToPath.Value);
}

private void ReplaysOnRecordingStopped(MappingDataNode metadata)
{
// Write round info like map and round end summery into the replay_final.yml file. Useful for external parsers.

metadata["map"] = new ValueDataNode(_gameMapManager.GetSelectedMap()?.MapName);
metadata["gamemode"] = new ValueDataNode(CurrentPreset != null ? Loc.GetString(CurrentPreset.ModeTitle) : string.Empty);
metadata["roundEndPlayers"] = _serialman.WriteValue(_replayRoundPlayerInfo);
metadata["roundEndText"] = new ValueDataNode(_replayRoundText);
metadata["server_id"] = new ValueDataNode(_configurationManager.GetCVar(CCVars.ServerId));
// These should be set to null to prepare them for the next round.
_replayRoundPlayerInfo = null;
_replayRoundText = null;
}

private ResPath GetAutoReplayPath()
{
var cfgValue = _cfg.GetCVar(CCVars.ReplayAutoRecordName);
Expand Down
10 changes: 10 additions & 0 deletions Content.Server/GameTicking/GameTicker.RoundFlow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public sealed partial class GameTicker
[ViewVariables]
private GameRunLevel _runLevel;

private RoundEndMessageEvent.RoundEndPlayerInfo[]? _replayRoundPlayerInfo;

private string? _replayRoundText;

[ViewVariables]
public GameRunLevel RunLevel
{
Expand Down Expand Up @@ -373,11 +377,14 @@ public void ShowRoundEndScoreboard(string text = "")
PlayerOOCName = contentPlayerData?.Name ?? "(IMPOSSIBLE: REGISTERED MIND WITH NO OWNER)",
// Character name takes precedence over current entity name
PlayerICName = playerIcName,
PlayerGuid = userId,
PlayerNetEntity = GetNetEntity(entity),
Role = antag
? roles.First(role => role.Antagonist).Name
: roles.FirstOrDefault().Name ?? Loc.GetString("game-ticker-unknown-role"),
Antag = antag,
JobPrototypes = roles.Where(role => !role.Antagonist).Select(role => role.Prototype).ToArray(),
AntagPrototypes = roles.Where(role => role.Antagonist).Select(role => role.Prototype).ToArray(),
Observer = observer,
Connected = connected
};
Expand All @@ -391,6 +398,9 @@ public void ShowRoundEndScoreboard(string text = "")
RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, RoundId,
listOfPlayerInfoFinal.Length, listOfPlayerInfoFinal, LobbySong, sound));
RaiseLocalEvent(new RoundEndedEvent(RoundId, roundDuration)); // Corvax

_replayRoundPlayerInfo = listOfPlayerInfoFinal;
_replayRoundText = roundEndText;
}

private async void SendRoundEndDiscordMessage()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using Content.Server.Mind;
using Content.Shared.Species.Components;
using Content.Shared.Body.Events;
using Content.Shared.Mind;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Shared.Species;
namespace Content.Server.Species.Systems;

public sealed partial class NymphSystem : EntitySystem
{
[Dependency] protected readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
[Dependency] private readonly IPrototypeManager _protoManager= default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;

public override void Initialize()
Expand All @@ -31,11 +31,11 @@ private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, RemovedFromPa
return;

var coords = Transform(uid).Coordinates;
var nymph = EntityManager.SpawnEntity(entityProto.ID, coords);
var nymph = EntityManager.SpawnAtPosition(entityProto.ID, coords);

if (comp.TransferMind == true && _mindSystem.TryGetMind(args.OldBody, out var mindId, out var mind))
_mindSystem.TransferTo(mindId, nymph, mind: mind);

EntityManager.QueueDeleteEntity(uid);
QueueDel(uid);
}
}
3 changes: 0 additions & 3 deletions Content.Server/Wagging/WaggingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ private void OnWaggingToggle(EntityUid uid, WaggingComponent component, ref Togg

private void OnMobStateChanged(EntityUid uid, WaggingComponent component, MobStateChangedEvent args)
{
if (args.NewMobState != MobState.Dead)
return;

if (component.Wagging)
TryToggleWagging(uid, wagging: component);
}
Expand Down
5 changes: 5 additions & 0 deletions Content.Shared/Administration/AdminFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public enum AdminFlags : uint
/// </summary>
EditNotes = 1 << 14,

/// <summary>
/// Lets you Massban, on SS14.Admin
/// </summary>
MassBan = 1 << 15,

/// <summary>
/// Dangerous host permissions like scsi.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2011,5 +2011,15 @@ public static readonly CVarDef<float>

public static readonly CVarDef<bool> GatewayGeneratorEnabled =
CVarDef.Create("gateway.generator_enabled", true);

/*
* DEBUG
*/

/// <summary>
/// A simple toggle to test <c>OptionsVisualizerComponent</c>.
/// </summary>
public static readonly CVarDef<bool> DebugOptionVisualizerTest =
CVarDef.Create("debug.option_visualizer_test", false, CVar.CLIENTONLY);
}
}
Loading

0 comments on commit f7a6c76

Please sign in to comment.