Merge branches '2020-05-18-midi' and '20-05-22-midi-update'

This commit is contained in:
Pieter-Jan Briers
2020-05-22 18:02:24 +02:00
6 changed files with 318 additions and 43 deletions

View File

@@ -1,15 +1,25 @@
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects;
using Content.Server.Mobs;
using Content.Shared.GameObjects.Components.Instruments;
using NFluidsynth;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
using Robust.Server.Interfaces.Player;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using Logger = Robust.Shared.Log.Logger;
using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent;
namespace Content.Server.GameObjects.Components.Instruments
{
@@ -18,12 +28,35 @@ namespace Content.Server.GameObjects.Components.Instruments
public class InstrumentComponent : SharedInstrumentComponent,
IDropped, IHandSelected, IHandDeselected, IActivate, IUse, IThrown
{
[Dependency] private IServerNotifyManager _notifyManager;
// These 2 values are quite high for now, and this could be easily abused. Change this if people are abusing it.
public const int MaxMidiEventsPerSecond = 20;
public const int MaxMidiEventsPerBatch = 50;
public const int MaxMidiBatchDropped = 20;
/// <summary>
/// The client channel currently playing the instrument, or null if there's none.
/// </summary>
private ICommonSession _instrumentPlayer;
[ViewVariables]
private IPlayerSession _instrumentPlayer;
private bool _handheld;
[ViewVariables]
private bool _playing = false;
[ViewVariables]
private float _timer = 0f;
[ViewVariables]
private int _batchesDropped = 0;
[ViewVariables]
private uint _lastSequencerTick = 0;
[ViewVariables]
private int _midiEventCount = 0;
[ViewVariables]
private BoundUserInterface _userInterface;
@@ -33,6 +66,43 @@ namespace Content.Server.GameObjects.Components.Instruments
[ViewVariables]
public bool Handheld => _handheld;
/// <summary>
/// Whether the instrument is currently playing or not.
/// </summary>
[ViewVariables]
public bool Playing
{
get => _playing;
set
{
_playing = value;
Dirty();
}
}
public IPlayerSession InstrumentPlayer
{
get => _instrumentPlayer;
private set
{
Playing = false;
if(_instrumentPlayer != null)
_instrumentPlayer.PlayerStatusChanged -= OnPlayerStatusChanged;
_instrumentPlayer = value;
if(value != null)
_instrumentPlayer.PlayerStatusChanged += OnPlayerStatusChanged;
}
}
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
{
if (e.NewStatus == SessionStatus.Disconnected)
InstrumentPlayer = null;
}
public override void Initialize()
{
base.Initialize();
@@ -46,31 +116,52 @@ namespace Content.Server.GameObjects.Components.Instruments
serializer.DataField(ref _handheld, "handheld", false);
}
public override ComponentState GetComponentState()
{
return new InstrumentState(Playing, _lastSequencerTick);
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, channel, session);
// If the client that sent the message isn't the client playing this instrument, we ignore it.
if (session != _instrumentPlayer) return;
switch (message)
{
case InstrumentMidiEventMessage midiEventMsg:
SendNetworkMessage(midiEventMsg);
if (!Playing || session != _instrumentPlayer)
return;
if (++_midiEventCount <= MaxMidiEventsPerSecond &&
midiEventMsg.MidiEvent.Length < MaxMidiEventsPerBatch)
SendNetworkMessage(midiEventMsg);
else
_batchesDropped++; // Batch dropped!
_lastSequencerTick = midiEventMsg.MidiEvent[^1].Timestamp;
break;
case InstrumentStartMidiMessage startMidi:
Playing = true;
break;
case InstrumentStopMidiMessage stopMidi:
Playing = false;
_lastSequencerTick = 0;
break;
}
}
public void Dropped(DroppedEventArgs eventArgs)
{
Playing = false;
SendNetworkMessage(new InstrumentStopMidiMessage());
_instrumentPlayer = null;
InstrumentPlayer = null;
_userInterface.CloseAll();
}
public void Thrown(ThrownEventArgs eventArgs)
{
Playing = false;
SendNetworkMessage(new InstrumentStopMidiMessage());
_instrumentPlayer = null;
InstrumentPlayer = null;
_userInterface.CloseAll();
}
@@ -80,11 +171,12 @@ namespace Content.Server.GameObjects.Components.Instruments
if (session == null) return;
_instrumentPlayer = session;
InstrumentPlayer = session;
}
public void HandDeselected(HandDeselectedEventArgs eventArgs)
{
Playing = false;
SendNetworkMessage(new InstrumentStopMidiMessage());
_userInterface.CloseAll();
}
@@ -94,10 +186,10 @@ namespace Content.Server.GameObjects.Components.Instruments
if (Handheld || !eventArgs.User.TryGetComponent(out IActorComponent actor))
return;
if (_instrumentPlayer != null)
if (InstrumentPlayer != null)
return;
_instrumentPlayer = actor.playerSession;
InstrumentPlayer = actor.playerSession;
OpenUserInterface(actor.playerSession);
}
@@ -106,17 +198,18 @@ namespace Content.Server.GameObjects.Components.Instruments
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
return false;
if(_instrumentPlayer == actor.playerSession)
if(InstrumentPlayer == actor.playerSession)
OpenUserInterface(actor.playerSession);
return false;
}
private void UserInterfaceOnClosed(IPlayerSession player)
{
if (!Handheld && player == _instrumentPlayer)
if (!Handheld && player == InstrumentPlayer)
{
_instrumentPlayer = null;
InstrumentPlayer = null;
SendNetworkMessage(new InstrumentStopMidiMessage());
Playing = false;
}
}
@@ -124,5 +217,35 @@ namespace Content.Server.GameObjects.Components.Instruments
{
_userInterface.Open(session);
}
public override void Update(float delta)
{
base.Update(delta);
if (_instrumentPlayer != null && !ActionBlockerSystem.CanInteract(_instrumentPlayer.AttachedEntity))
InstrumentPlayer = null;
if (_batchesDropped > MaxMidiBatchDropped && InstrumentPlayer != null)
{
_batchesDropped = 0;
var mob = InstrumentPlayer.AttachedEntity;
_userInterface.CloseAll();
if (mob.TryGetComponent(out StunnableComponent stun))
stun.Stun(1);
else
StandingStateHelper.DropAllItemsInHands(mob);
InstrumentPlayer = null;
_notifyManager.PopupMessage(Owner, mob, "Your fingers cramp up from playing!");
}
_timer += delta;
if (_timer < 1) return;
_timer = 0f;
_midiEventCount = 0;
}
}
}