mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-03 10:37:05 +02:00
* bubble implementation include contained entities fix line edit crash when clipboard contents are null somehow use CVar for update bubble range remove seenMovers that get NaN'd out of MaxUpdateRange - huge reduction in network traffic from bullets cut default of MaxUpdateRange down to 12.5 for now maybe handle teleported things handle removing player state on disconnect fixed positional audio errors make UpdateEntityTree also update player's last seen ents make net.maxupdaterange cvar tunable at runtime w/o impacting performance back to position nan as means to hide from client revert work pooling as the wrong player was getting the wrong game state ffs needed to think less about *if* something is *seen* and more about *when* it must be *unseen* clean up usings handle parenting and sequencing issues that arise on the client gather needed ents to update recursively applied suggestions from code review fix missing recursively contained ents make assumption that client last saw things on first tick instead of tick zero, as zero would be the "from tick" and first would be he "to tick" add First tick as constant to GameTick due to relevance above renamed includedEnts to checkedEnts to make usage more clear added comments inverted some conditions to flatten parts of the pvs logic fixed sending states when already seen (lastChange < lastSeen to lastChange <= lastSeen) fix sending states when no actual changes (other bugs?) local caching of currentTick, remove priorTick * make TransformComponent's Parent setter call Dirty() to handle replicating network state if AttachParent isn't invoked * fixed parent changed by setting Parent on Transform not updating parent's Children collection and other stuff rotating parent entities now are visible with their orbiting children if one of their children moves into view * break out duplicated code as GetLastSeen * remove unused net.parallelstates introduce net.pvs to configure enabling/disabling PVS
269 lines
9.5 KiB
C#
269 lines
9.5 KiB
C#
using System;
|
|
using Robust.Client.Audio;
|
|
using Robust.Client.Interfaces.ResourceManagement;
|
|
using Robust.Client.ResourceManagement;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.GameObjects.Systems;
|
|
using Robust.Shared.Interfaces.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Client.Interfaces.Graphics;
|
|
using Robust.Shared.Interfaces.Map;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Utility;
|
|
using System.Collections.Generic;
|
|
using JetBrains.Annotations;
|
|
|
|
namespace Robust.Client.GameObjects.EntitySystems
|
|
{
|
|
[UsedImplicitly]
|
|
public class AudioSystem : EntitySystem
|
|
{
|
|
#pragma warning disable 649
|
|
[Dependency] private readonly IResourceCache _resourceCache;
|
|
[Dependency] private readonly IMapManager _mapManager;
|
|
[Dependency] private readonly IClydeAudio _clyde;
|
|
#pragma warning restore 649
|
|
|
|
private readonly List<PlayingStream> _playingClydeStreams = new List<PlayingStream>();
|
|
|
|
/// <inheritdoc />
|
|
public override void Initialize()
|
|
{
|
|
SubscribeNetworkEvent<PlayAudioEntityMessage>(PlayAudioEntityHandler);
|
|
SubscribeNetworkEvent<PlayAudioGlobalMessage>(PlayAudioGlobalHandler);
|
|
SubscribeNetworkEvent<PlayAudioPositionalMessage>(PlayAudioPositionalHandler);
|
|
}
|
|
|
|
private void PlayAudioPositionalHandler(PlayAudioPositionalMessage ev)
|
|
{
|
|
if (!_mapManager.GridExists(ev.Coordinates.GridID))
|
|
{
|
|
Logger.Error($"Server tried to play sound on grid {ev.Coordinates.GridID.Value}, which does not exist. Ignoring.");
|
|
return;
|
|
}
|
|
|
|
Play(ev.FileName, ev.Coordinates, ev.AudioParams);
|
|
}
|
|
|
|
private void PlayAudioGlobalHandler(PlayAudioGlobalMessage ev)
|
|
{
|
|
Play(ev.FileName, ev.AudioParams);
|
|
}
|
|
|
|
private void PlayAudioEntityHandler(PlayAudioEntityMessage ev)
|
|
{
|
|
if (!EntityManager.TryGetEntity(ev.EntityUid, out var entity))
|
|
{
|
|
Logger.Error($"Server tried to play audio file {ev.FileName} on entity {ev.EntityUid} which does not exist.");
|
|
return;
|
|
}
|
|
|
|
Play(ev.FileName, entity, ev.AudioParams);
|
|
}
|
|
|
|
public override void FrameUpdate(float frameTime)
|
|
{
|
|
// Update positions of streams every frame.
|
|
foreach (var stream in _playingClydeStreams)
|
|
{
|
|
if (!stream.Source.IsPlaying)
|
|
{
|
|
stream.Source.Dispose();
|
|
stream.Done = true;
|
|
stream.DoPlaybackDone();
|
|
continue;
|
|
}
|
|
|
|
if (stream.TrackingCoordinates != null)
|
|
{
|
|
if (!stream.Source.SetPosition(stream.TrackingCoordinates.Value.ToMapPos(_mapManager)))
|
|
{
|
|
Logger.Warning("Interrupting positional audio, can't set position.");
|
|
stream.Source.StopPlaying();
|
|
}
|
|
}
|
|
else if (stream.TrackingEntity != null)
|
|
{
|
|
if(!stream.Source.SetPosition(stream.TrackingEntity.Transform.WorldPosition))
|
|
{
|
|
Logger.Warning("Interrupting positional audio, can't set position.");
|
|
stream.Source.StopPlaying();
|
|
}
|
|
}
|
|
}
|
|
|
|
_playingClydeStreams.RemoveAll(p => p.Done);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio file globally, without position.
|
|
/// </summary>
|
|
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
|
|
/// <param name="audioParams"></param>
|
|
public IPlayingAudioStream Play(string filename, AudioParams? audioParams = null)
|
|
{
|
|
if (_resourceCache.TryGetResource<AudioResource>(new ResourcePath(filename), out var audio))
|
|
{
|
|
return Play(audio, audioParams);
|
|
}
|
|
|
|
Logger.Error($"Server tried to play audio file {filename} which does not exist.");
|
|
return default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio stream globally, without position.
|
|
/// </summary>
|
|
/// <param name="stream">The audio stream to play.</param>
|
|
/// <param name="audioParams"></param>
|
|
public IPlayingAudioStream Play(AudioStream stream, AudioParams? audioParams = null)
|
|
{
|
|
var source = _clyde.CreateAudioSource(stream);
|
|
ApplyAudioParams(audioParams, source);
|
|
|
|
source.SetGlobal();
|
|
source.StartPlaying();
|
|
var playing = new PlayingStream
|
|
{
|
|
Source = source
|
|
};
|
|
_playingClydeStreams.Add(playing);
|
|
return playing;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio file following an entity.
|
|
/// </summary>
|
|
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
|
|
/// <param name="entity">The entity "emitting" the audio.</param>
|
|
/// <param name="audioParams"></param>
|
|
public IPlayingAudioStream Play(string filename, IEntity entity, AudioParams? audioParams = null)
|
|
{
|
|
if (_resourceCache.TryGetResource<AudioResource>(new ResourcePath(filename), out var audio))
|
|
{
|
|
return Play(audio, entity, audioParams);
|
|
}
|
|
|
|
Logger.Error($"Server tried to play audio file {filename} which does not exist.");
|
|
return default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio stream following an entity.
|
|
/// </summary>
|
|
/// <param name="stream">The audio stream to play.</param>
|
|
/// <param name="entity">The entity "emitting" the audio.</param>
|
|
/// <param name="audioParams"></param>
|
|
[CanBeNull]
|
|
public IPlayingAudioStream Play(AudioStream stream, IEntity entity, AudioParams? audioParams = null)
|
|
{
|
|
var source = _clyde.CreateAudioSource(stream);
|
|
if (!source.SetPosition(entity.Transform.WorldPosition))
|
|
{
|
|
Logger.Warning("Can't play positional audio, can't set position.");
|
|
return null;
|
|
}
|
|
|
|
ApplyAudioParams(audioParams, source);
|
|
|
|
source.StartPlaying();
|
|
var playing = new PlayingStream
|
|
{
|
|
Source = source,
|
|
TrackingEntity = entity,
|
|
};
|
|
_playingClydeStreams.Add(playing);
|
|
return playing;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio file at a static position.
|
|
/// </summary>
|
|
/// <param name="filename">The resource path to the OGG Vorbis file to play.</param>
|
|
/// <param name="coordinates">The coordinates at which to play the audio.</param>
|
|
/// <param name="audioParams"></param>
|
|
[CanBeNull]
|
|
public IPlayingAudioStream Play(string filename, GridCoordinates coordinates, AudioParams? audioParams = null)
|
|
{
|
|
if(_resourceCache.TryGetResource<AudioResource>(new ResourcePath(filename), out var audio))
|
|
{
|
|
return Play(audio, coordinates, audioParams);
|
|
}
|
|
|
|
Logger.Error($"Server tried to play audio file {filename} which does not exist.");
|
|
return default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Play an audio stream at a static position.
|
|
/// </summary>
|
|
/// <param name="stream">The audio stream to play.</param>
|
|
/// <param name="coordinates">The coordinates at which to play the audio.</param>
|
|
/// <param name="audioParams"></param>
|
|
[CanBeNull]
|
|
public IPlayingAudioStream Play(AudioStream stream, GridCoordinates coordinates,
|
|
AudioParams? audioParams = null)
|
|
{
|
|
var source = _clyde.CreateAudioSource(stream);
|
|
if (!source.SetPosition(coordinates.ToMapPos(_mapManager)))
|
|
{
|
|
Logger.Warning("Can't play positional audio, can't set position.");
|
|
return null;
|
|
}
|
|
|
|
ApplyAudioParams(audioParams, source);
|
|
|
|
source.StartPlaying();
|
|
var playing = new PlayingStream
|
|
{
|
|
Source = source,
|
|
TrackingCoordinates = coordinates,
|
|
};
|
|
_playingClydeStreams.Add(playing);
|
|
return playing;
|
|
}
|
|
|
|
private static void ApplyAudioParams(AudioParams? audioParams, IClydeAudioSource source)
|
|
{
|
|
if (!audioParams.HasValue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
source.SetPitch(audioParams.Value.PitchScale);
|
|
source.SetVolume(audioParams.Value.Volume);
|
|
source.SetPlaybackPosition(audioParams.Value.PlayOffsetSeconds);
|
|
source.IsLooping = audioParams.Value.Loop;
|
|
}
|
|
|
|
private class PlayingStream : IPlayingAudioStream
|
|
{
|
|
public IClydeAudioSource Source;
|
|
public IEntity TrackingEntity;
|
|
public GridCoordinates? TrackingCoordinates;
|
|
public bool Done;
|
|
|
|
public void Stop()
|
|
{
|
|
Source.StopPlaying();
|
|
}
|
|
|
|
public event Action PlaybackDone;
|
|
|
|
public void DoPlaybackDone()
|
|
{
|
|
PlaybackDone?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface IPlayingAudioStream
|
|
{
|
|
void Stop();
|
|
|
|
event Action PlaybackDone;
|
|
}
|
|
}
|