fix: lobby music volume will be changed on options change without restart (also lobby music not looped anymore) (#25530)

* fix: lobby music volume will be changed on options change without restart (also lobby music not looped anymore)

* refactor: now lobby music is part of ContentAudioSystem. Lobby playlist is used instead of single track. Client now selects next lobby soundtrack after previous finished.

* refactor: incapsulated info on current lobby track in simple record

* refactor: fixed inconsistent naming between song and soundtrack for lobbymusic

* refactor: xml-doc for LobbyPlaylistChangedEvent

* fix: inverted invalid _audio.PlayGlobal check to return only if lobby soundtrack play call failed

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
Fildrance
2024-03-02 23:40:04 +03:00
committed by GitHub
parent 4f7facbd73
commit 4c87dcd3cb
13 changed files with 402 additions and 270 deletions

View File

@@ -1,156 +0,0 @@
using Content.Client.GameTicking.Managers;
using Content.Client.Lobby;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
using Robust.Client;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
namespace Content.Client.Audio;
[UsedImplicitly]
public sealed class BackgroundAudioSystem : EntitySystem
{
/*
* TODO: Nuke this system and merge into contentaudiosystem
*/
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f);
private readonly AudioParams _roundEndParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
public EntityUid? LobbyMusicStream;
public EntityUid? LobbyRoundRestartAudioStream;
public override void Initialize()
{
base.Initialize();
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
_stateManager.OnStateChanged += StateManagerOnStateChanged;
_client.PlayerLeaveServer += OnLeave;
_gameTicker.LobbySongUpdated += LobbySongUpdated;
SubscribeNetworkEvent<RoundRestartCleanupEvent>(PlayRestartSound);
}
public override void Shutdown()
{
base.Shutdown();
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
_client.PlayerLeaveServer -= OnLeave;
_gameTicker.LobbySongUpdated -= LobbySongUpdated;
EndLobbyMusic();
}
private void StateManagerOnStateChanged(StateChangedEventArgs args)
{
switch (args.NewState)
{
case LobbyState:
StartLobbyMusic();
break;
default:
EndLobbyMusic();
break;
}
}
private void OnLeave(object? sender, PlayerEventArgs args)
{
EndLobbyMusic();
}
private void LobbyMusicVolumeCVarChanged(float volume)
{
if (_stateManager.CurrentState is LobbyState)
{
RestartLobbyMusic();
}
}
private void LobbyMusicCVarChanged(bool musicEnabled)
{
if (!musicEnabled)
{
EndLobbyMusic();
}
else if (_stateManager.CurrentState is LobbyState)
{
StartLobbyMusic();
}
else
{
EndLobbyMusic();
}
}
private void LobbySongUpdated()
{
RestartLobbyMusic();
}
public void RestartLobbyMusic()
{
EndLobbyMusic();
StartLobbyMusic();
}
public void StartLobbyMusic()
{
if (LobbyMusicStream != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled))
return;
var file = _gameTicker.LobbySong;
if (file == null) // We have not received the lobby song yet.
{
return;
}
LobbyMusicStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_lobbyParams.WithVolume(_lobbyParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))))?.Entity;
}
private void EndLobbyMusic()
{
LobbyMusicStream = _audio.Stop(LobbyMusicStream);
}
private void PlayRestartSound(RoundRestartCleanupEvent ev)
{
if (!_configManager.GetCVar(CCVars.RestartSoundsEnabled))
return;
var file = _gameTicker.RestartSound;
if (string.IsNullOrEmpty(file))
{
return;
}
LobbyRoundRestartAudioStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_roundEndParams.WithVolume(_roundEndParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
)?.Entity;
}
}

View File

@@ -0,0 +1,283 @@
using System.Linq;
using Content.Client.GameTicking.Managers;
using Content.Client.Lobby;
using Content.Shared.Audio.Events;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Robust.Client;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Audio;
// Part of ContentAudioSystem that is responsible for lobby music playing/stopping and round-end sound-effect.
public sealed partial class ContentAudioSystem
{
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
/// <summary>
/// EntityUid of lobby restart sound component.
/// </summary>
private EntityUid? _lobbyRoundRestartAudioStream;
/// <summary>
/// Shuffled list of soundtrack file-names.
/// </summary>
private string[]? _lobbyPlaylist;
/// <summary>
/// Short info about lobby soundtrack currently playing. Is null if soundtrack is not playing.
/// </summary>
private LobbySoundtrackInfo? _lobbySoundtrackInfo;
private Action<LobbySoundtrackChangedEvent>? _lobbySoundtrackChanged;
/// <summary>
/// Event for subscription on lobby soundtrack changes.
/// </summary>
public event Action<LobbySoundtrackChangedEvent>? LobbySoundtrackChanged
{
add
{
if (value != null)
{
if (_lobbySoundtrackInfo != null)
{
value(new LobbySoundtrackChangedEvent(_lobbySoundtrackInfo.Filename));
}
_lobbySoundtrackChanged += value;
}
}
remove => _lobbySoundtrackChanged -= value;
}
/// <summary>
/// Initializes subscriptions that are related to lobby music.
/// </summary>
private void InitializeLobbyMusic()
{
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
_stateManager.OnStateChanged += StateManagerOnStateChanged;
_client.PlayerLeaveServer += OnLeave;
SubscribeNetworkEvent<LobbyMusicStopEvent>(OnLobbySongStopped);
SubscribeNetworkEvent<LobbyPlaylistChangedEvent>(OnLobbySongChanged);
}
private void OnLobbySongStopped(LobbyMusicStopEvent ev)
{
EndLobbyMusic();
}
private void StateManagerOnStateChanged(StateChangedEventArgs args)
{
switch (args.NewState)
{
case LobbyState:
StartLobbyMusic();
break;
default:
EndLobbyMusic();
break;
}
}
private void OnLeave(object? sender, PlayerEventArgs args)
{
EndLobbyMusic();
}
private void LobbyMusicVolumeCVarChanged(float volume)
{
if (_lobbySoundtrackInfo != null)
{
_audio.SetVolume(
_lobbySoundtrackInfo.MusicStreamEntityUid,
_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))
);
}
}
private void LobbyMusicCVarChanged(bool musicEnabled)
{
if (musicEnabled && _stateManager.CurrentState is LobbyState)
{
StartLobbyMusic();
}
else
{
EndLobbyMusic();
}
}
private void OnLobbySongChanged(LobbyPlaylistChangedEvent playlistChangedEvent)
{
var playlist = playlistChangedEvent.Playlist;
//playlist is already playing, no need to restart it
if (_lobbySoundtrackInfo != null
&& _lobbyPlaylist != null
&& _lobbyPlaylist.SequenceEqual(playlist)
)
{
return;
}
EndLobbyMusic();
StartLobbyMusic(playlistChangedEvent.Playlist);
}
/// <summary>
/// Re-starts playing lobby music from playlist, last sent from server. if there is currently none - does nothing.
/// </summary>
private void StartLobbyMusic()
{
if (_lobbyPlaylist == null || _lobbyPlaylist.Length == 0)
{
return;
}
StartLobbyMusic(_lobbyPlaylist);
}
/// <summary>
/// Starts playing lobby music from playlist. If playlist is empty, or lobby music setting is turned off - does nothing.
/// </summary>
/// <param name="playlist">Array of soundtrack filenames for lobby playlist.</param>
private void StartLobbyMusic(string[] playlist)
{
if (_lobbySoundtrackInfo != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled))
return;
_lobbyPlaylist = playlist;
if (_lobbyPlaylist.Length == 0)
{
return;
}
PlaySoundtrack(playlist[0]);
}
private void PlaySoundtrack(string soundtrackFilename)
{
if (!_resourceCache.TryGetResource(new ResPath(soundtrackFilename), out AudioResource? audio))
{
return;
}
var playResult = _audio.PlayGlobal(
soundtrackFilename,
Filter.Local(),
false,
_lobbySoundtrackParams.WithVolume(_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
);
if (playResult.Value.Entity == default)
{
_sawmill.Warning(
$"Tried to play lobby soundtrack '{{Filename}}' using {nameof(SharedAudioSystem)}.{nameof(SharedAudioSystem.PlayGlobal)} but it returned default value of EntityUid!",
soundtrackFilename);
return;
}
var nextTrackOn = _timing.CurTime + audio.AudioStream.Length;
_lobbySoundtrackInfo = new LobbySoundtrackInfo(soundtrackFilename, nextTrackOn, playResult.Value.Entity);
var lobbySongChangedEvent = new LobbySoundtrackChangedEvent(soundtrackFilename);
_lobbySoundtrackChanged?.Invoke(lobbySongChangedEvent);
}
private void EndLobbyMusic()
{
if (_lobbySoundtrackInfo == null)
{
return;
}
_audio.Stop(_lobbySoundtrackInfo.MusicStreamEntityUid);
_lobbySoundtrackInfo = null;
var lobbySongChangedEvent = new LobbySoundtrackChangedEvent();
_lobbySoundtrackChanged?.Invoke(lobbySongChangedEvent);
}
private void PlayRestartSound(RoundRestartCleanupEvent ev)
{
if (!_configManager.GetCVar(CCVars.RestartSoundsEnabled))
return;
var file = _gameTicker.RestartSound;
if (string.IsNullOrEmpty(file))
{
return;
}
_lobbyRoundRestartAudioStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_roundEndSoundEffectParams.WithVolume(_roundEndSoundEffectParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
)?.Entity;
}
private void ShutdownLobbyMusic()
{
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
_client.PlayerLeaveServer -= OnLeave;
EndLobbyMusic();
}
private void UpdateLobbyMusic()
{
if (
_lobbySoundtrackInfo != null
&& _timing.CurTime >= _lobbySoundtrackInfo.NextTrackOn
&& _lobbyPlaylist?.Length > 0
)
{
var nextSoundtrackFilename = GetNextSoundtrackFromPlaylist(_lobbySoundtrackInfo.Filename, _lobbyPlaylist);
PlaySoundtrack(nextSoundtrackFilename);
}
}
private static string GetNextSoundtrackFromPlaylist(string currentSoundtrackFilename, string[] playlist)
{
var indexOfCurrent = Array.IndexOf(playlist, currentSoundtrackFilename);
var nextTrackIndex = indexOfCurrent + 1;
if (nextTrackIndex > playlist.Length - 1)
{
nextTrackIndex = 0;
}
return playlist[nextTrackIndex];
}
/// <summary> Container for lobby soundtrack information. </summary>
/// <param name="Filename">Soundtrack filename.</param>
/// <param name="NextTrackOn">Time (based on <see cref="IGameTiming.CurTime"/>) when this track is going to finish playing and next track have to be started.</param>
/// <param name="MusicStreamEntityUid">
/// EntityUid of launched soundtrack (from <see cref="SharedAudioSystem.PlayGlobal(string,Robust.Shared.Player.Filter,bool,System.Nullable{Robust.Shared.Audio.AudioParams})"/>).
/// </param>
private sealed record LobbySoundtrackInfo(string Filename, TimeSpan NextTrackOn, EntityUid MusicStreamEntityUid);
}
/// <summary>
/// Event of changing lobby soundtrack (or stopping lobby music - will pass null for <paramref name="SoundtrackFilename"/> in that case).
/// Is used by <see cref="ContentAudioSystem.LobbySoundtrackChanged"/> and <see cref="LobbyState.UpdateLobbySoundtrackInfo"/>.
/// </summary>
/// <param name="SoundtrackFilename">Filename of newly set soundtrack, or null if soundtrack playback is stopped.</param>
public sealed record LobbySoundtrackChangedEvent(string? SoundtrackFilename = null);

View File

@@ -29,12 +29,14 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
public const float AmbientMusicMultiplier = 3f;
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
public override void Initialize()
{
base.Initialize();
UpdatesOutsidePrediction = true;
InitializeAmbientMusic();
InitializeLobbyMusic();
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
}
@@ -43,11 +45,11 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
_fadingOut.Clear();
// Preserve lobby music but everything else should get dumped.
var lobbyMusic = EntityManager.System<BackgroundAudioSystem>().LobbyMusicStream;
var lobbyMusic = _lobbySoundtrackInfo?.MusicStreamEntityUid;
TryComp(lobbyMusic, out AudioComponent? lobbyMusicComp);
var oldMusicGain = lobbyMusicComp?.Gain;
var restartAudio = EntityManager.System<BackgroundAudioSystem>().LobbyRoundRestartAudioStream;
var restartAudio = _lobbyRoundRestartAudioStream;
TryComp(restartAudio, out AudioComponent? restartComp);
var oldAudioGain = restartComp?.Gain;
@@ -62,12 +64,14 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
{
Audio.SetGain(restartAudio, oldAudioGain.Value, restartComp);
}
PlayRestartSound(ev);
}
public override void Shutdown()
{
base.Shutdown();
ShutdownAmbientMusic();
ShutdownLobbyMusic();
}
public override void Update(float frameTime)
@@ -78,6 +82,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
return;
UpdateAmbientMusic();
UpdateLobbyMusic();
UpdateFades(frameTime);
}

View File

@@ -1,16 +1,11 @@
using Content.Client.Gameplay;
using Content.Client.Lobby;
using Content.Client.RoundEnd;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.GameWindow;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Client.GameTicking.Managers
@@ -32,7 +27,6 @@ namespace Content.Client.GameTicking.Managers
[ViewVariables] public bool AreWeReady { get; private set; }
[ViewVariables] public bool IsGameStarted { get; private set; }
[ViewVariables] public string? LobbySong { get; private set; }
[ViewVariables] public string? RestartSound { get; private set; }
[ViewVariables] public string? LobbyBackground { get; private set; }
[ViewVariables] public bool DisallowedLateJoin { get; private set; }
@@ -45,7 +39,6 @@ namespace Content.Client.GameTicking.Managers
public event Action? InfoBlobUpdated;
public event Action? LobbyStatusUpdated;
public event Action? LobbySongUpdated;
public event Action? LobbyLateJoinStatusUpdated;
public event Action<IReadOnlyDictionary<NetEntity, Dictionary<string, uint?>>>? LobbyJobsAvailableUpdated;
@@ -70,16 +63,6 @@ namespace Content.Client.GameTicking.Managers
_initialized = true;
}
public void SetLobbySong(string? song, bool forceUpdate = false)
{
var updated = song != LobbySong;
LobbySong = song;
if (updated || forceUpdate)
LobbySongUpdated?.Invoke();
}
private void LateJoinStatus(TickerLateJoinStatusEvent message)
{
DisallowedLateJoin = message.Disallowed;
@@ -120,7 +103,6 @@ namespace Content.Client.GameTicking.Managers
RoundStartTimeSpan = message.RoundStartTimeSpan;
IsGameStarted = message.IsRoundStarted;
AreWeReady = message.YouAreReady;
SetLobbySong(message.LobbySong);
LobbyBackground = message.LobbyBackground;
Paused = message.Paused;
@@ -148,7 +130,6 @@ namespace Content.Client.GameTicking.Managers
private void RoundEnd(RoundEndMessageEvent message)
{
// Force an update in the event of this song being the same as the last.
SetLobbySong(message.LobbySong, true);
RestartSound = message.RestartSound;
// Don't open duplicate windows (mainly for replays).

View File

@@ -1,3 +1,4 @@
using Content.Client.Audio;
using Content.Client.GameTicking.Managers;
using Content.Client.LateJoin;
using Content.Client.Lobby.UI;
@@ -34,6 +35,7 @@ namespace Content.Client.Lobby
[ViewVariables] private CharacterSetupGui? _characterSetup;
private ClientGameTicker _gameTicker = default!;
private ContentAudioSystem _contentAudioSystem = default!;
protected override Type? LinkedScreenType { get; } = typeof(LobbyGui);
private LobbyGui? _lobby;
@@ -49,6 +51,8 @@ namespace Content.Client.Lobby
var chatController = _userInterfaceManager.GetUIController<ChatUIController>();
_gameTicker = _entityManager.System<ClientGameTicker>();
_contentAudioSystem = _entityManager.System<ContentAudioSystem>();
_contentAudioSystem.LobbySoundtrackChanged += UpdateLobbySoundtrackInfo;
_characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager,
_prototypeManager, _configurationManager);
LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide);
@@ -93,6 +97,7 @@ namespace Content.Client.Lobby
_gameTicker.InfoBlobUpdated -= UpdateLobbyUi;
_gameTicker.LobbyStatusUpdated -= LobbyStatusUpdated;
_gameTicker.LobbyLateJoinStatusUpdated -= LobbyLateJoinStatusUpdated;
_contentAudioSystem.LobbySoundtrackChanged -= UpdateLobbySoundtrackInfo;
_voteManager.ClearPopupContainer();
@@ -207,22 +212,28 @@ namespace Content.Client.Lobby
{
_lobby!.ServerInfo.SetInfoBlob(_gameTicker.ServerInfoBlob);
}
}
if (_gameTicker.LobbySong == null)
private void UpdateLobbySoundtrackInfo(LobbySoundtrackChangedEvent ev)
{
if (ev.SoundtrackFilename == null)
{
_lobby!.LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text"));
}
else if (_resourceCache.TryGetResource<AudioResource>(_gameTicker.LobbySong, out var lobbySongResource))
else if (
ev.SoundtrackFilename != null
&& _resourceCache.TryGetResource<AudioResource>(ev.SoundtrackFilename, out var lobbySongResource)
)
{
var lobbyStream = lobbySongResource.AudioStream;
var title = string.IsNullOrEmpty(lobbyStream.Title) ?
Loc.GetString("lobby-state-song-unknown-title") :
lobbyStream.Title;
var title = string.IsNullOrEmpty(lobbyStream.Title)
? Loc.GetString("lobby-state-song-unknown-title")
: lobbyStream.Title;
var artist = string.IsNullOrEmpty(lobbyStream.Artist) ?
Loc.GetString("lobby-state-song-unknown-artist") :
lobbyStream.Artist;
var artist = string.IsNullOrEmpty(lobbyStream.Artist)
? Loc.GetString("lobby-state-song-unknown-artist")
: lobbyStream.Artist;
var markup = Loc.GetString("lobby-state-song-text",
("songTitle", title),

View File

@@ -1,5 +1,6 @@
using Content.Client.Chat.UI;
using Content.Client.Info;
using Content.Client.Message;
using Content.Client.Preferences;
using Content.Client.Preferences.UI;
using Content.Client.UserInterface.Screens;
@@ -33,6 +34,8 @@ namespace Content.Client.Lobby.UI
SetAnchorPreset(MainContainer, LayoutPreset.Wide);
SetAnchorPreset(Background, LayoutPreset.Wide);
LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text"));
LeaveButton.OnPressed += _ => _consoleHost.ExecuteCommand("disconnect");
OptionsButton.OnPressed += _ => _userInterfaceManager.GetUIController<OptionsUIController>().ToggleWindow();
}

View File

@@ -1,19 +1,37 @@
using System.Linq;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Shared.Audio;
using Content.Shared.Audio.Events;
using Content.Shared.GameTicking;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Audio;
public sealed class ContentAudioSystem : SharedContentAudioSystem
{
[ValidatePrototypeId<SoundCollectionPrototype>]
private const string LobbyMusicCollection = "LobbyMusic";
[Dependency] private readonly AudioSystem _serverAudio = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private SoundCollectionPrototype _lobbyMusicCollection = default!;
private string[]? _lobbyPlaylist;
public override void Initialize()
{
base.Initialize();
_lobbyMusicCollection = _prototypeManager.Index<SoundCollectionPrototype>(LobbyMusicCollection);
_lobbyPlaylist = ShuffleLobbyPlaylist();
SubscribeLocalEvent<RoundEndMessageEvent>(OnRoundEnd);
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
@@ -36,4 +54,33 @@ public sealed class ContentAudioSystem : SharedContentAudioSystem
// yeah it's whacky af.
_serverAudio.ReloadPresets();
}
private void OnPlayerJoinedLobby(PlayerJoinedLobbyEvent ev)
{
if (_lobbyPlaylist != null)
{
var session = ev.PlayerSession;
RaiseNetworkEvent(new LobbyPlaylistChangedEvent(_lobbyPlaylist), session);
}
}
private void OnRoundEnd(RoundEndMessageEvent ev)
{
// The lobby song is set here instead of in RestartRound,
// because ShowRoundEndScoreboard triggers the start of the music playing
// at the end of a round, and this needs to be set before RestartRound
// in order for the lobby song status display to be accurate.
_lobbyPlaylist = ShuffleLobbyPlaylist();
RaiseNetworkEvent(new LobbyPlaylistChangedEvent(_lobbyPlaylist));
}
private string[] ShuffleLobbyPlaylist()
{
var playlist = _lobbyMusicCollection.PickFiles
.Select(x => x.ToString())
.ToArray();
_robustRandom.Shuffle(playlist);
return playlist;
}
}

View File

@@ -94,7 +94,7 @@ namespace Content.Server.GameTicking
private TickerLobbyStatusEvent GetStatusMsg(ICommonSession session)
{
_playerGameStatuses.TryGetValue(session.UserId, out var status);
return new TickerLobbyStatusEvent(RunLevel != GameRunLevel.PreRoundLobby, LobbySong, LobbyBackground, status == PlayerGameStatus.ReadyToPlay, _roundStartTime, RoundPreloadTime, RoundStartTimeSpan, Paused);
return new TickerLobbyStatusEvent(RunLevel != GameRunLevel.PreRoundLobby, LobbyBackground, status == PlayerGameStatus.ReadyToPlay, _roundStartTime, RoundPreloadTime, RoundStartTimeSpan, Paused);
}
private void SendStatusToAll()

View File

@@ -1,68 +0,0 @@
using Robust.Shared.Audio;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.GameTicking
{
public sealed partial class GameTicker
{
[ValidatePrototypeId<SoundCollectionPrototype>]
private const string LobbyMusicCollection = "LobbyMusic";
[ViewVariables]
private bool _lobbyMusicInitialized = false;
[ViewVariables]
private SoundCollectionPrototype _lobbyMusicCollection = default!;
[ViewVariables]
public string? LobbySong { get; private set; }
private void InitializeLobbyMusic()
{
DebugTools.Assert(!_lobbyMusicInitialized);
_lobbyMusicCollection = _prototypeManager.Index<SoundCollectionPrototype>(LobbyMusicCollection);
// Now that the collection is set, the lobby music has been initialized and we can choose a random song.
_lobbyMusicInitialized = true;
ChooseRandomLobbySong();
}
/// <summary>
/// Sets the current lobby song, or stops it if null.
/// </summary>
/// <param name="song">The lobby song to play, or null to stop any lobby songs.</param>
public void SetLobbySong(string? song)
{
DebugTools.Assert(_lobbyMusicInitialized);
if (song == null)
{
LobbySong = null;
return;
// TODO GAMETICKER send song stop event
}
LobbySong = song;
// TODO GAMETICKER send song change event
}
/// <summary>
/// Plays a random song from the LobbyMusic sound collection.
/// </summary>
public void ChooseRandomLobbySong()
{
DebugTools.Assert(_lobbyMusicInitialized);
SetLobbySong(_robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString());
}
/// <summary>
/// Stops the current lobby song being played.
/// </summary>
public void StopLobbySong()
{
SetLobbySong(null);
}
}
}

View File

@@ -301,12 +301,6 @@ namespace Content.Server.GameTicking
RunLevel = GameRunLevel.PostRound;
// The lobby song is set here instead of in RestartRound,
// because ShowRoundEndScoreboard triggers the start of the music playing
// at the end of a round, and this needs to be set before RestartRound
// in order for the lobby song status display to be accurate.
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
ShowRoundEndScoreboard(text);
SendRoundEndDiscordMessage();
}
@@ -394,8 +388,17 @@ namespace Content.Server.GameTicking
var listOfPlayerInfoFinal = listOfPlayerInfo.OrderBy(pi => pi.PlayerOOCName).ToArray();
var sound = RoundEndSoundCollection == null ? null : _audio.GetSound(new SoundCollectionSpecifier(RoundEndSoundCollection));
RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, RoundId,
listOfPlayerInfoFinal.Length, listOfPlayerInfoFinal, LobbySong, sound));
var roundEndMessageEvent = new RoundEndMessageEvent(
gamemodeTitle,
roundEndText,
roundDuration,
RoundId,
listOfPlayerInfoFinal.Length,
listOfPlayerInfoFinal,
sound
);
RaiseNetworkEvent(roundEndMessageEvent);
RaiseLocalEvent(roundEndMessageEvent);
_replayRoundPlayerInfo = listOfPlayerInfoFinal;
_replayRoundText = roundEndText;

View File

@@ -93,7 +93,6 @@ namespace Content.Server.GameTicking
InitializeStatusShell();
InitializeCVars();
InitializePlayer();
InitializeLobbyMusic();
InitializeLobbyBackground();
InitializeGamePreset();
DebugTools.Assert(_prototypeManager.Index<JobPrototype>(FallbackOverflowJob).Name == FallbackOverflowJobName,

View File

@@ -0,0 +1,29 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Audio.Events;
/// <summary>
/// Event of changing lobby music playlist (on server).
/// </summary>
[Serializable, NetSerializable]
public sealed class LobbyPlaylistChangedEvent : EntityEventArgs
{
/// <inheritdoc />
public LobbyPlaylistChangedEvent(string[] playlist)
{
Playlist = playlist;
}
/// <summary>
/// List of soundtrack filenames for lobby playlist.
/// </summary>
public string[] Playlist;
}
/// <summary>
/// Event of stopping lobby music.
/// </summary>
[Serializable, NetSerializable]
public sealed class LobbyMusicStopEvent : EntityEventArgs
{
}

View File

@@ -78,7 +78,6 @@ namespace Content.Shared.GameTicking
public sealed class TickerLobbyStatusEvent : EntityEventArgs
{
public bool IsRoundStarted { get; }
public string? LobbySong { get; }
public string? LobbyBackground { get; }
public bool YouAreReady { get; }
// UTC.
@@ -86,10 +85,9 @@ namespace Content.Shared.GameTicking
public TimeSpan RoundStartTimeSpan { get; }
public bool Paused { get; }
public TickerLobbyStatusEvent(bool isRoundStarted, string? lobbySong, string? lobbyBackground, bool youAreReady, TimeSpan startTime, TimeSpan preloadTime, TimeSpan roundStartTimeSpan, bool paused)
public TickerLobbyStatusEvent(bool isRoundStarted, string? lobbyBackground, bool youAreReady, TimeSpan startTime, TimeSpan preloadTime, TimeSpan roundStartTimeSpan, bool paused)
{
IsRoundStarted = isRoundStarted;
LobbySong = lobbySong;
LobbyBackground = lobbyBackground;
YouAreReady = youAreReady;
StartTime = startTime;
@@ -185,7 +183,6 @@ namespace Content.Shared.GameTicking
public int RoundId { get; }
public int PlayerCount { get; }
public RoundEndPlayerInfo[] AllPlayersEndInfo { get; }
public string? LobbySong;
/// <summary>
/// Sound gets networked due to how entity lifecycle works between client / server and to avoid clipping.
@@ -199,7 +196,6 @@ namespace Content.Shared.GameTicking
int roundId,
int playerCount,
RoundEndPlayerInfo[] allPlayersEndInfo,
string? lobbySong,
string? restartSound)
{
GamemodeTitle = gamemodeTitle;
@@ -208,7 +204,6 @@ namespace Content.Shared.GameTicking
RoundId = roundId;
PlayerCount = playerCount;
AllPlayersEndInfo = allPlayersEndInfo;
LobbySong = lobbySong;
RestartSound = restartSound;
}
}