Adds playable instruments, IDropped, IHandSelected and IHandDese… (#368)
* Instrument test. * Midi stuff * Some more work * This actually works now! * update * Midi Audio works! * Lots of stuff, and cool interfaces for items * Update * Fix a few things * It just works * Move textures to another folder, remove placeholder description from instruments * Fix warning * Use renderer enum * Instruments now use DisposeRenderer method, and send MidiEvents as they receive them. Deletes InstrumentSystem whoo. * Fix incorrect sprite paths * Instruments take midi file size check into account when enabling/disabling midi playback buttons * Fix crash when pressing drop on empty hand. * Use new renderer return values for midi/input * Xylophones are no longer handheld instruments, fix their sprites. * Use new API * Remove nfluidsynth from solution * Timing information * Use IGameTiming.CurTime for timestamps instead
This commit is contained in:
committed by
Pieter-Jan Briers
parent
ce54c489eb
commit
fedc0ad71c
@@ -145,6 +145,8 @@ namespace Content.Server.GameObjects
|
||||
item.Owner.Transform.LocalPosition = Vector2.Zero;
|
||||
}
|
||||
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().HandSelectedInteraction(Owner, item.Owner);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Components.Instruments;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Instruments
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
public class InstrumentComponent : SharedInstrumentComponent,
|
||||
IDropped, IHandSelected, IHandDeselected, IActivate, IUse, IThrown
|
||||
{
|
||||
/// <summary>
|
||||
/// The client channel currently playing the instrument, or null if there's none.
|
||||
/// </summary>
|
||||
private INetChannel _instrumentPlayer;
|
||||
private bool _handheld;
|
||||
|
||||
[ViewVariables]
|
||||
private BoundUserInterface _userInterface;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the instrument is an item which can be held or not.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Handheld => _handheld;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(InstrumentUiKey.Key);
|
||||
_userInterface.OnClosed += UserInterfaceOnClosed;
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _handheld, "handheld", false);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||
{
|
||||
base.HandleMessage(message, netChannel, component);
|
||||
// If the client that sent the message isn't the client playing this instrument, we ignore it.
|
||||
if (netChannel != _instrumentPlayer) return;
|
||||
switch (message)
|
||||
{
|
||||
case InstrumentMidiEventMessage midiEventMsg:
|
||||
SendNetworkMessage(midiEventMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dropped(DroppedEventArgs eventArgs)
|
||||
{
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_instrumentPlayer = null;
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
|
||||
public void Thrown(ThrownEventArgs eventArgs)
|
||||
{
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_instrumentPlayer = null;
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
|
||||
public void HandSelected(HandSelectedEventArgs eventArgs)
|
||||
{
|
||||
var session = eventArgs.User?.GetComponent<BasicActorComponent>()?.playerSession;
|
||||
|
||||
if (session == null) return;
|
||||
|
||||
_instrumentPlayer = session.ConnectedClient;
|
||||
}
|
||||
|
||||
public void HandDeselected(HandDeselectedEventArgs eventArgs)
|
||||
{
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
|
||||
public void Activate(ActivateEventArgs eventArgs)
|
||||
{
|
||||
if (Handheld || !eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||
return;
|
||||
|
||||
if (_instrumentPlayer != null)
|
||||
return;
|
||||
|
||||
_instrumentPlayer = actor.playerSession.ConnectedClient;
|
||||
OpenUserInterface(actor.playerSession);
|
||||
}
|
||||
|
||||
public bool UseEntity(UseEntityEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||
return false;
|
||||
|
||||
if(_instrumentPlayer == actor.playerSession.ConnectedClient)
|
||||
OpenUserInterface(actor.playerSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UserInterfaceOnClosed(ServerBoundUserInterfaceMessage obj)
|
||||
{
|
||||
if (!Handheld && obj.Session.ConnectedClient == _instrumentPlayer)
|
||||
{
|
||||
_instrumentPlayer = null;
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenUserInterface(IPlayerSession session)
|
||||
{
|
||||
_userInterface.Open(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,11 @@ namespace Content.Server.GameObjects
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanDrop()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanEmote()
|
||||
{
|
||||
return true;
|
||||
@@ -103,6 +108,11 @@ namespace Content.Server.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanDrop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanEmote()
|
||||
{
|
||||
return false;
|
||||
@@ -169,6 +179,11 @@ namespace Content.Server.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanDrop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanEmote()
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -101,6 +101,11 @@ namespace Content.Server.GameObjects
|
||||
bool IActionBlocker.CanSpeak()
|
||||
{
|
||||
return CurrentDamageState.CanSpeak();
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanDrop()
|
||||
{
|
||||
return CurrentDamageState.CanDrop();
|
||||
}
|
||||
|
||||
bool IActionBlocker.CanEmote()
|
||||
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.GameObjects;
|
||||
namespace Content.Server.GameObjects.Components.Research
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class TechnologyDatabaseComponent : SharedTechnologyDatabaseComponent
|
||||
public class TechnologyDatabaseComponent : SharedTechnologyDatabaseComponent
|
||||
{
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
bool CanSpeak();
|
||||
|
||||
bool CanDrop();
|
||||
|
||||
bool CanEmote();
|
||||
}
|
||||
|
||||
@@ -70,6 +72,16 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return canspeak;
|
||||
}
|
||||
|
||||
public static bool CanDrop(IEntity entity)
|
||||
{
|
||||
bool candrop = true;
|
||||
foreach (var actionblockercomponents in entity.GetAllComponents<IActionBlocker>())
|
||||
{
|
||||
candrop &= actionblockercomponents.CanDrop();
|
||||
}
|
||||
return candrop;
|
||||
}
|
||||
|
||||
public static bool CanEmote(IEntity entity)
|
||||
{
|
||||
bool canemote = true;
|
||||
|
||||
@@ -183,6 +183,60 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
public GridCoordinates ClickLocation { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when they're held on the selected hand.
|
||||
/// </summary>
|
||||
public interface IHandSelected
|
||||
{
|
||||
void HandSelected(HandSelectedEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class HandSelectedEventArgs : EventArgs
|
||||
{
|
||||
public HandSelectedEventArgs(IEntity user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
|
||||
public IEntity User { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when they're held on a deselected hand.
|
||||
/// </summary>
|
||||
public interface IHandDeselected
|
||||
{
|
||||
void HandDeselected(HandDeselectedEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class HandDeselectedEventArgs : EventArgs
|
||||
{
|
||||
public HandDeselectedEventArgs(IEntity user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
|
||||
public IEntity User { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when they're dropped by a mob.
|
||||
/// </summary>
|
||||
public interface IDropped
|
||||
{
|
||||
void Dropped(DroppedEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class DroppedEventArgs : EventArgs
|
||||
{
|
||||
public DroppedEventArgs(IEntity user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
|
||||
public IEntity User { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Governs interactions during clicking on entities
|
||||
/// </summary>
|
||||
@@ -512,8 +566,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the Use behavior of an object
|
||||
/// Verifies that the user is capable of doing the use interaction first
|
||||
/// Activates the Throw behavior of an object
|
||||
/// Verifies that the user is capable of doing the throw interaction first
|
||||
/// </summary>
|
||||
public bool TryThrowInteraction(IEntity user, IEntity item)
|
||||
{
|
||||
@@ -568,6 +622,86 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the Dropped behavior of an object
|
||||
/// Verifies that the user is capable of doing the drop interaction first
|
||||
/// </summary>
|
||||
public bool TryDroppedInteraction(IEntity user, IEntity item)
|
||||
{
|
||||
if (user == null || item == null || !ActionBlockerSystem.CanDrop(user)) return false;
|
||||
|
||||
DroppedInteraction(user, item);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls Dropped on all components that implement the IDropped interface
|
||||
/// on an entity that has been dropped.
|
||||
/// </summary>
|
||||
public void DroppedInteraction(IEntity user, IEntity item)
|
||||
{
|
||||
var dropMsg = new DroppedMessage(user, item);
|
||||
RaiseEvent(dropMsg);
|
||||
if (dropMsg.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var comps = item.GetAllComponents<IDropped>().ToList();
|
||||
|
||||
// Call Land on all components that implement the interface
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
comp.Dropped(new DroppedEventArgs(user));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls HandSelected on all components that implement the IHandSelected interface
|
||||
/// on an item entity on a hand that has just been selected.
|
||||
/// </summary>
|
||||
public void HandSelectedInteraction(IEntity user, IEntity item)
|
||||
{
|
||||
var dropMsg = new HandSelectedMessage(user, item);
|
||||
RaiseEvent(dropMsg);
|
||||
if (dropMsg.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var comps = item.GetAllComponents<IHandSelected>().ToList();
|
||||
|
||||
// Call Land on all components that implement the interface
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
comp.HandSelected(new HandSelectedEventArgs(user));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls HandDeselected on all components that implement the IHandDeselected interface
|
||||
/// on an item entity on a hand that has just been deselected.
|
||||
/// </summary>
|
||||
public void HandDeselectedInteraction(IEntity user, IEntity item)
|
||||
{
|
||||
var dropMsg = new HandDeselectedMessage(user, item);
|
||||
RaiseEvent(dropMsg);
|
||||
if (dropMsg.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var comps = item.GetAllComponents<IHandDeselected>().ToList();
|
||||
|
||||
// Call Land on all components that implement the interface
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
comp.HandDeselected(new HandDeselectedEventArgs(user));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will have two behaviors, either "uses" the weapon at range on the entity if it is capable of accepting that action
|
||||
/// Or it will use the weapon itself on the position clicked, regardless of what was there
|
||||
@@ -883,6 +1017,90 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when an entity that was thrown lands.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class DroppedMessage : EntitySystemMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// If this message has already been "handled" by a previous system.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that dropped the item.
|
||||
/// </summary>
|
||||
public IEntity User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Item that was dropped.
|
||||
/// </summary>
|
||||
public IEntity Dropped { get; }
|
||||
|
||||
public DroppedMessage(IEntity user, IEntity dropped)
|
||||
{
|
||||
User = user;
|
||||
Dropped = dropped;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when an entity item in a hand is selected.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class HandSelectedMessage : EntitySystemMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// If this message has already been "handled" by a previous system.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that owns the selected hand.
|
||||
/// </summary>
|
||||
public IEntity User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The item in question.
|
||||
/// </summary>
|
||||
public IEntity Item { get; }
|
||||
|
||||
public HandSelectedMessage(IEntity user, IEntity item)
|
||||
{
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when an entity item in a hand is deselected.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public class HandDeselectedMessage : EntitySystemMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// If this message has already been "handled" by a previous system.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that owns the deselected hand.
|
||||
/// </summary>
|
||||
public IEntity User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The item in question.
|
||||
/// </summary>
|
||||
public IEntity Item { get; }
|
||||
|
||||
public HandDeselectedMessage(IEntity user, IEntity item)
|
||||
{
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when an entity is activated in the world.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,6 +12,7 @@ using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -27,6 +28,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private const float ThrowForce = 1.5f; // Throwing force of mobs in Newtons
|
||||
@@ -94,7 +96,19 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
if (!TryGetAttachedComponent(session as IPlayerSession, out HandsComponent handsComp))
|
||||
return;
|
||||
|
||||
var interactionSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InteractionSystem>();
|
||||
|
||||
var oldItem = handsComp.GetActiveHand;
|
||||
|
||||
handsComp.SwapHands();
|
||||
|
||||
var newItem = handsComp.GetActiveHand;
|
||||
|
||||
if(oldItem != null)
|
||||
interactionSystem.HandDeselectedInteraction(handsComp.Owner, oldItem.Owner);
|
||||
|
||||
if(newItem != null)
|
||||
interactionSystem.HandSelectedInteraction(handsComp.Owner, newItem.Owner);
|
||||
}
|
||||
|
||||
private bool HandleDrop(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||
@@ -102,14 +116,19 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
var ent = ((IPlayerSession) session).AttachedEntity;
|
||||
|
||||
if (ent == null || !ent.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ent.TryGetComponent(out HandsComponent handsComp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handsComp.GetActiveHand == null)
|
||||
return false;
|
||||
|
||||
if (!_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(ent, handsComp.GetActiveHand.Owner))
|
||||
return false;
|
||||
|
||||
if(handsComp.GetActiveHand != null && !_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(ent, handsComp.GetActiveHand.Owner))
|
||||
return false;
|
||||
|
||||
if (coords.InRange(_mapManager, ent.Transform.GridPosition, InteractionSystem.InteractionRange))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user