diff --git a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs index 29511ceb4d..80fc60360c 100644 --- a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Shared.GameObjects.Components.Instruments; +using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Client.Audio.Midi; using Robust.Shared.Audio.Midi; @@ -28,6 +29,7 @@ namespace Content.Client.GameObjects.Components.Instruments [Dependency] private readonly IGameTiming _timing; #pragma warning restore 649 + [CanBeNull] private IMidiRenderer _renderer; private int _instrumentProgram = 1; @@ -42,8 +44,14 @@ namespace Content.Client.GameObjects.Components.Instruments [ViewVariables(VVAccess.ReadWrite)] public bool LoopMidi { - get => _renderer.LoopMidi; - set => _renderer.LoopMidi = value; + get => _renderer?.LoopMidi ?? false; + set + { + if (_renderer != null) + { + _renderer.LoopMidi = value; + } + } } /// @@ -53,9 +61,13 @@ namespace Content.Client.GameObjects.Components.Instruments public int InstrumentProgram { get => _instrumentProgram; - set { + set + { _instrumentProgram = value; - _renderer.MidiProgram = _instrumentProgram; + if (_renderer != null) + { + _renderer.MidiProgram = _instrumentProgram; + } } } @@ -63,22 +75,26 @@ namespace Content.Client.GameObjects.Components.Instruments /// Whether there's a midi song being played or not. /// [ViewVariables] - public bool IsMidiOpen => _renderer.Status == MidiRendererStatus.File; + public bool IsMidiOpen => _renderer?.Status == MidiRendererStatus.File; /// /// Whether the midi renderer is listening for midi input or not. /// [ViewVariables] - public bool IsInputOpen => _renderer.Status == MidiRendererStatus.Input; + public bool IsInputOpen => _renderer?.Status == MidiRendererStatus.Input; public override void Initialize() { base.Initialize(); IoCManager.InjectDependencies(this); _renderer = _midiManager.GetNewRenderer(); - _renderer.MidiProgram = _instrumentProgram; - _renderer.TrackingEntity = Owner; - _renderer.OnMidiPlayerFinished += () => { OnMidiPlaybackEnded?.Invoke(); }; + + if (_renderer != null) + { + _renderer.MidiProgram = _instrumentProgram; + _renderer.TrackingEntity = Owner; + _renderer.OnMidiPlayerFinished += () => { OnMidiPlaybackEnded?.Invoke(); }; + } } protected override void Shutdown() @@ -93,9 +109,16 @@ namespace Content.Client.GameObjects.Components.Instruments serializer.DataField(ref _instrumentProgram, "program", 1); } - public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) + public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, + IComponent component = null) { base.HandleMessage(message, netChannel, component); + + if (_renderer == null) + { + return; + } + switch (message) { case InstrumentMidiEventMessage midiEventMessage: @@ -107,8 +130,8 @@ namespace Content.Client.GameObjects.Components.Instruments case InstrumentStopMidiMessage _: _renderer.StopAllNotes(); - if(IsInputOpen) CloseInput(); - if(IsMidiOpen) CloseMidi(); + if (IsInputOpen) CloseInput(); + if (IsMidiOpen) CloseMidi(); break; } } @@ -116,7 +139,7 @@ namespace Content.Client.GameObjects.Components.Instruments /// public bool OpenInput() { - if (_renderer.OpenInput()) + if (_renderer != null && _renderer.OpenInput()) { _renderer.OnMidiEvent += RendererOnMidiEvent; return true; @@ -128,28 +151,37 @@ namespace Content.Client.GameObjects.Components.Instruments /// public bool CloseInput() { - if (!_renderer.CloseInput()) return false; + if (_renderer == null || !_renderer.CloseInput()) + { + return false; + } + _renderer.OnMidiEvent -= RendererOnMidiEvent; return true; - } /// public bool OpenMidi(string filename) { - if (!_renderer.OpenMidi(filename)) return false; + if (_renderer == null || !_renderer.OpenMidi(filename)) + { + return false; + } + _renderer.OnMidiEvent += RendererOnMidiEvent; return true; - } /// public bool CloseMidi() { - if (!_renderer.CloseMidi()) return false; + if (_renderer == null || !_renderer.CloseMidi()) + { + return false; + } + _renderer.OnMidiEvent -= RendererOnMidiEvent; return true; - } /// diff --git a/Content.Client/Instruments/InstrumentMenu.cs b/Content.Client/Instruments/InstrumentMenu.cs index b0880fbb48..0fb39bde2e 100644 --- a/Content.Client/Instruments/InstrumentMenu.cs +++ b/Content.Client/Instruments/InstrumentMenu.cs @@ -1,10 +1,13 @@ using Content.Client.GameObjects.Components.Instruments; +using Content.Client.UserInterface; using Robust.Client.Audio.Midi; +using Robust.Client.Graphics.Drawing; using Robust.Client.Interfaces.UserInterface; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.IoC; +using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Maths; @@ -27,7 +30,7 @@ namespace Content.Client.Instruments public InstrumentMenu(InstrumentBoundUserInterface owner) { IoCManager.InjectDependencies(this); - Title = "Instrument"; + Title = Loc.GetString("Instrument"); _owner = owner; @@ -55,7 +58,7 @@ namespace Content.Client.Instruments midiInputButton = new Button() { - Text = "MIDI Input", + Text = Loc.GetString("MIDI Input"), TextAlign = Label.AlignMode.Center, SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1, @@ -73,7 +76,7 @@ namespace Content.Client.Instruments var midiFileButton = new Button() { - Text = "Open File", + Text = Loc.GetString("Play MIDI File"), TextAlign = Label.AlignMode.Center, SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1, @@ -91,7 +94,7 @@ namespace Content.Client.Instruments midiLoopButton = new Button() { - Text = "Loop", + Text = Loc.GetString("Loop"), TextAlign = Label.AlignMode.Center, SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1, @@ -110,7 +113,7 @@ namespace Content.Client.Instruments midiStopButton = new Button() { - Text = "Stop", + Text = Loc.GetString("Stop"), TextAlign = Label.AlignMode.Center, SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1, @@ -132,6 +135,26 @@ namespace Content.Client.Instruments margin.AddChild(vBox); + if (!_midiManager.IsAvailable) + { + margin.AddChild(new PanelContainer + { + MouseFilter = MouseFilterMode.Stop, + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.90f)}, + Children = + { + new Label + { + Align = Label.AlignMode.Center, + SizeFlagsVertical = SizeFlags.ShrinkCenter, + SizeFlagsHorizontal = SizeFlags.ShrinkCenter, + StyleClasses = {NanoStyle.StyleClassLabelBig}, + Text = Loc.GetString("MIDI support is currently\nnot available on your platform.") + } + } + }); + } + Contents.AddChild(margin); } @@ -148,7 +171,8 @@ namespace Content.Client.Instruments private async void MidiFileButtonOnOnPressed(BaseButton.ButtonEventArgs obj) { - var filename = await _fileDialogManager.OpenFile(); + var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi")); + var filename = await _fileDialogManager.OpenFile(filters); if (filename == null) return; @@ -160,7 +184,7 @@ namespace Content.Client.Instruments if (!_owner.Instrument.OpenMidi(filename)) return; MidiPlaybackSetButtonsDisabled(false); - if(midiInputButton.Pressed) + if (midiInputButton.Pressed) midiInputButton.Pressed = false; } diff --git a/Resources/Prototypes/Entities/buildings/instruments.yml b/Resources/Prototypes/Entities/buildings/instruments.yml index ce8cc881b9..2c6edf0355 100644 --- a/Resources/Prototypes/Entities/buildings/instruments.yml +++ b/Resources/Prototypes/Entities/buildings/instruments.yml @@ -1,70 +1,70 @@ -# - type: entity -# name: BaseInstrument -# id: BaseInstrument -# abstract: true -# components: -# - type: Instrument -# handheld: false -# -# - type: Clickable -# - type: InteractionOutline -# -# - type: Collidable -# shapes: -# - !type:PhysShapeAabb -# layer: 31 -# -# - type: SnapGrid -# offset: Center -# -# - type: Damageable -# - type: Destructible -# thresholdvalue: 50 -# -# - type: UserInterface -# interfaces: -# - key: enum.InstrumentUiKey.Key -# type: InstrumentBoundUserInterface -# -# - type: entity -# name: Piano -# parent: BaseInstrument -# id: PianoInstrument -# description: Play Needles Piano Now. -# components: -# - type: Instrument -# program: 1 -# - type: Sprite -# sprite: Objects/Instruments/musician.rsi -# state: piano -# - type: Icon -# sprite: Objects/Instruments/musician.rsi -# state: piano -# -# - type: entity -# name: Minimoog -# parent: BaseInstrument -# id: MinimoogInstrument -# components: -# - type: Instrument -# program: 7 -# - type: Sprite -# sprite: Objects/Instruments/musician.rsi -# state: minimoog -# - type: Icon -# sprite: Objects/Instruments/musician.rsi -# state: minimoog -# -# - type: entity -# name: Xylophone -# parent: BaseInstrument -# id: XylophoneInstrument -# components: -# - type: Instrument -# program: 13 -# - type: Sprite -# sprite: Objects/Instruments/musician.rsi -# state: xylophone -# - type: Icon -# sprite: Objects/Instruments/musician.rsi -# state: xylophone + - type: entity + name: BaseInstrument + id: BaseInstrument + abstract: true + components: + - type: Instrument + handheld: false + + - type: Clickable + - type: InteractionOutline + + - type: Collidable + shapes: + - !type:PhysShapeAabb + layer: 31 + + - type: SnapGrid + offset: Center + + - type: Damageable + - type: Destructible + thresholdvalue: 50 + + - type: UserInterface + interfaces: + - key: enum.InstrumentUiKey.Key + type: InstrumentBoundUserInterface + + - type: entity + name: Piano + parent: BaseInstrument + id: PianoInstrument + description: Play Needles Piano Now. + components: + - type: Instrument + program: 1 + - type: Sprite + sprite: Objects/Instruments/musician.rsi + state: piano + - type: Icon + sprite: Objects/Instruments/musician.rsi + state: piano + + - type: entity + name: Minimoog + parent: BaseInstrument + id: MinimoogInstrument + components: + - type: Instrument + program: 7 + - type: Sprite + sprite: Objects/Instruments/musician.rsi + state: minimoog + - type: Icon + sprite: Objects/Instruments/musician.rsi + state: minimoog + + - type: entity + name: Xylophone + parent: BaseInstrument + id: XylophoneInstrument + components: + - type: Instrument + program: 13 + - type: Sprite + sprite: Objects/Instruments/musician.rsi + state: xylophone + - type: Icon + sprite: Objects/Instruments/musician.rsi + state: xylophone