6
2026-01-24 12:49:55 +03:00

235 lines
7.5 KiB
C#

using System.Linq;
using Content.Shared._Horizon.MediaPlayer;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server._Horizon.MediaPlayer;
public sealed class MediaPlayerSystem : SharedMediaPlayerSystem
{
[Dependency] private readonly IPrototypeManager _protoManager = null!;
private List<MediaFilePrototype> _mediaFilePrototypes = [];
private readonly Dictionary<EntityUid, string> _mediaById = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MediaPlayerComponent, MediaPlayMessage>(OnMediaPlay);
SubscribeLocalEvent<MediaPlayerComponent, MediaPauseMessage>(OnMediaPause);
SubscribeLocalEvent<MediaPlayerComponent, MediaStopMessage>(Stop);
SubscribeLocalEvent<MediaPlayerComponent, MediaSetTimeMessage>(OnMediaSetTime);
SubscribeLocalEvent<MediaPlayerComponent, MediaRepeatMessage>(SetRepeatState);
SubscribeLocalEvent<MediaPlayerComponent, MediaVolumeMessage>(SetMediaVolume);
//SubscribeLocalEvent<MediaPlayerComponent, PowerChangedEvent>(OnPowerChanged);
//SubscribeLocalEvent<MediaPlayerComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<MediaPlayerComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<MediaPlayerComponent, MediaSelectedMessage>(OnMediaSelected);
_mediaFilePrototypes = _protoManager.EnumeratePrototypes<MediaFilePrototype>()
.OrderBy(x => x.ID)
.ToList();
_protoManager.PrototypesReloaded += _ =>
{
_mediaFilePrototypes = _protoManager.EnumeratePrototypes<MediaFilePrototype>()
.OrderBy(x => x.ID)
.ToList();
};
}
#region Apperance
private void OnComponentShutdown(EntityUid uid, MediaPlayerComponent component, ComponentShutdown args)
{
component.AudioStream = Audio.Stop(component.AudioStream);
_mediaById.Remove(uid);
}
/*
private void OnComponentInit(EntityUid uid, MediaPlayerComponent component, ComponentInit args)
{
if (HasComp<ApcPowerReceiverComponent>(uid))
{
TryUpdateVisualState(uid, component);
}
}
private void OnPowerChanged(Entity<MediaPlayerComponent> entity, ref PowerChangedEvent args)
{
TryUpdateVisualState(entity);
if (!this.IsPowered(entity.Owner, EntityManager))
{
Stop(entity);
}
}
private void DirectSetVisualState(EntityUid uid, MediaPlayerVisualStates state)
{
_appearanceSystem.SetData(uid, MediaPlayerVisuals.VisualState, state);
}
private void TryUpdateVisualState(EntityUid uid, MediaPlayerComponent? mediaComponent = null)
{
if (!Resolve(uid, ref mediaComponent))
return;
var finalState = MediaPlayerVisualStates.On;
if (!this.IsPowered(uid, EntityManager))
{
finalState = MediaPlayerVisualStates.Off;
}
_appearanceSystem.SetData(uid, MediaPlayerVisuals.VisualState, finalState);
}
*/
private void Stop(EntityUid uid, MediaPlayerComponent comp, MediaStopMessage args)
{
Audio.Stop(comp.AudioStream);
comp.SelectedSongId = null;
comp.AudioStream = null;
if (!args.Repeat)
_mediaById.Remove(uid);
Dirty(uid, comp);
}
#endregion
#region Audio
private void OnMediaPlay(EntityUid uid, MediaPlayerComponent component, MediaPlayMessage args = null!)
{
if (Exists(component.AudioStream))
{
Audio.SetState(component.AudioStream, AudioState.Playing); //Stop(new Entity<MediaPlayerComponent>(uid, component));
return;
}
if (string.IsNullOrEmpty(component.SelectedSongId))
{
return;
}
var param = new AudioParams
{
Volume = component.Volume,
Pitch = 1,
MaxDistance = 15f + component.Volume, // По умолчанию это расстояние будет равно 5f
RolloffFactor = 1,
ReferenceDistance = 1,
Loop = false,
PlayOffsetSeconds = 0f,
};
component.AudioStream = Audio.PlayPvs(component.AudioPath, uid, param)?.Entity;
Dirty(uid, component);
}
private void SetMediaVolume(EntityUid uid, MediaPlayerComponent component, ref MediaVolumeMessage args)
{
component.Volume = args.Volume;
Dirty(uid, component);
if (!Exists(component.AudioStream))
return;
Audio.SetVolume(component.AudioStream, args.Volume);
}
private void SetRepeatState(EntityUid uid, MediaPlayerComponent component, ref MediaRepeatMessage args)
{
component.Repeat = args.Type;
Dirty(uid, component);
}
private void OnMediaPause(Entity<MediaPlayerComponent> ent, ref MediaPauseMessage _)
{
Audio.SetState(ent.Comp.AudioStream, AudioState.Paused);
}
private void OnMediaSetTime(EntityUid uid, MediaPlayerComponent component, ref MediaSetTimeMessage args)
{
if (!TryComp(args.Actor, out ActorComponent? actorComp))
return;
var offset = actorComp.PlayerSession.Channel.Ping * 2 / 1000f;
Audio.SetPlaybackPosition(component.AudioStream, args.SongTime + offset);
}
private void OnMediaSelected(EntityUid uid, MediaPlayerComponent component, ref MediaSelectedMessage args)
{
if (args.AudioPath is null)
return;
if (Audio.IsPlaying(component.AudioStream))
Stop(uid, component, new MediaStopMessage(false));
// Sound settings
if (args.SongId is null)
return;
component.Volume = args.Volume;
component.SelectedSongId = args.SongId;
component.AudioPath = args.AudioPath;
_mediaById[uid] = args.SongId;
//DirectSetVisualState(uid, MediaPlayerVisualStates.Select);
OnMediaPlay(uid, component);
Dirty(uid, component);
}
private void HandleRepeat()
{
foreach (var (uid, id) in _mediaById)
{
if (!TryComp(uid, out MediaPlayerComponent? component))
continue;
if (Exists(component.AudioStream) || component.Repeat == RepeatType.None)
continue;
using var enumerator = _mediaFilePrototypes.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (current.ID != id)
continue;
switch (component.Repeat)
{
case RepeatType.Playlist:
current = enumerator.MoveNext() ? enumerator.Current : _mediaFilePrototypes.First();
_mediaById[uid] = current.ID;
break;
case RepeatType.Single:
break;
case RepeatType.None:
default:
return;
}
component.SelectedSongId = current.ID;
component.AudioPath = current.SoundPath;
OnMediaPlay(uid, component);
Dirty(uid, component);
RaiseNetworkEvent(new RepeatMessage(GetNetEntity(uid), current.ID));
break;
}
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
HandleRepeat();
}
#endregion
}