From cd4b7bd85c9797d3c6a580583280469f8c5c2e9a Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 14 Jul 2022 23:03:48 +1000 Subject: [PATCH] Muzzle flash enhancements (#9527) --- .../Weapons/Ranged/Systems/GunSystem.cs | 96 +++++++++++++++++-- .../Weapon/Ranged/Systems/GunSystem.cs | 16 ++-- .../Ranged/Components/AmmoComponent.cs | 4 +- .../Weapons/Ranged/Events/MuzzleFlashEvent.cs | 17 ++++ .../Weapons/Ranged/Systems/SharedGunSystem.cs | 29 +----- .../Weapons/Guns/Projectiles/projectiles.yml | 17 ++++ 6 files changed, 134 insertions(+), 45 deletions(-) create mode 100644 Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs index 88967b3eb7..ab6868f157 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs @@ -1,6 +1,7 @@ using Content.Client.Items; using Content.Client.Weapons.Ranged.Components; using Content.Shared.Camera; +using Content.Shared.Spawners.Components; using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; @@ -10,11 +11,11 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Player; +using Robust.Shared.Animations; using Robust.Shared.Audio; using Robust.Shared.Input; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Timing; using Robust.Shared.Utility; using SharedGunSystem = Content.Shared.Weapons.Ranged.Systems.SharedGunSystem; @@ -26,7 +27,6 @@ public sealed partial class GunSystem : SharedGunSystem [Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly AnimationPlayerSystem _animPlayer = default!; - [Dependency] private readonly EffectSystem _effects = default!; [Dependency] private readonly InputSystem _inputSystem = default!; [Dependency] private readonly SharedCameraRecoilSystem _recoil = default!; @@ -43,10 +43,10 @@ public sealed partial class GunSystem : SharedGunSystem { overlayManager.AddOverlay(new GunSpreadOverlay( EntityManager, - IoCManager.Resolve(), - IoCManager.Resolve(), - IoCManager.Resolve(), - IoCManager.Resolve(), + _eyeManager, + Timing, + _inputManager, + _player, this)); } else @@ -63,6 +63,7 @@ public sealed partial class GunSystem : SharedGunSystem base.Initialize(); UpdatesOutsidePrediction = true; SubscribeLocalEvent(OnAmmoCounterCollect); + SubscribeLocalEvent(OnMuzzleFlash); // Plays animated effects on the client. SubscribeNetworkEvent(OnHitscan); @@ -71,6 +72,11 @@ public sealed partial class GunSystem : SharedGunSystem InitializeSpentAmmo(); } + private void OnMuzzleFlash(EntityUid uid, GunComponent component, MuzzleFlashEvent args) + { + CreateEffect(uid, args); + } + private void OnHitscan(HitscanEvent ev) { // ALL I WANT IS AN ANIMATED EFFECT @@ -227,8 +233,82 @@ public sealed partial class GunSystem : SharedGunSystem PopupSystem.PopupEntity(message, uid.Value, Filter.Entities(user.Value)); } - protected override void CreateEffect(EffectSystemMessage message, EntityUid? user = null) + protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null) { - _effects.CreateEffect(message); + if (!Timing.IsFirstTimePredicted || !TryComp(uid, out var xform)) return; + var ent = Spawn(message.Prototype, xform.Coordinates); + + var effectXform = Transform(ent); + effectXform.LocalRotation -= MathF.PI / 2; + effectXform.LocalPosition += new Vector2(0f, -0.5f); + + var lifetime = 0.4f; + + if (TryComp(uid, out var despawn)) + { + lifetime = despawn.Lifetime; + } + + var anim = new Animation() + { + Length = TimeSpan.FromSeconds(lifetime), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(SpriteComponent), + Property = nameof(SpriteComponent.Color), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Color.White.WithAlpha(1f), 0), + new AnimationTrackProperty.KeyFrame(Color.White.WithAlpha(0f), lifetime) + } + } + } + }; + + _animPlayer.Play(ent, anim, "muzzle-flash"); + var light = EnsureComp(uid); + + light.Enabled = true; + light.Color = Color.FromHex("#cc8e2b"); + light.Radius = 2f; + light.Energy = 5f; + + var animTwo = new Animation() + { + Length = TimeSpan.FromSeconds(lifetime), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(PointLightComponent), + Property = nameof(PointLightComponent.Energy), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(5f, 0), + new AnimationTrackProperty.KeyFrame(0f, lifetime) + } + }, + new AnimationTrackComponentProperty + { + ComponentType = typeof(PointLightComponent), + Property = nameof(PointLightComponent.Enabled), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(true, 0), + new AnimationTrackProperty.KeyFrame(false, lifetime) + } + } + } + }; + + var uidPlayer = EnsureComp(uid); + + _animPlayer.Stop(uid, uidPlayer, "muzzle-flash-light"); + _animPlayer.Play(uid, uidPlayer, animTwo,"muzzle-flash-light"); } } diff --git a/Content.Server/Weapon/Ranged/Systems/GunSystem.cs b/Content.Server/Weapon/Ranged/Systems/GunSystem.cs index b8e4915580..6aff79b2e6 100644 --- a/Content.Server/Weapon/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapon/Ranged/Systems/GunSystem.cs @@ -22,7 +22,6 @@ namespace Content.Server.Weapon.Ranged.Systems; public sealed partial class GunSystem : SharedGunSystem { - [Dependency] private readonly EffectSystem _effects = default!; [Dependency] private readonly StaminaSystem _stamina = default!; public const float DamagePitchVariation = MeleeWeaponSystem.DamagePitchVariation; @@ -215,17 +214,14 @@ public sealed partial class GunSystem : SharedGunSystem protected override void Popup(string message, EntityUid? uid, EntityUid? user) {} - protected override void CreateEffect(EffectSystemMessage message, EntityUid? user = null) + protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null) { - // TODO: Fucking bad + var filter = Filter.Pvs(uid, entityManager: EntityManager); + if (TryComp(user, out var actor)) - { - _effects.CreateParticle(message, actor.PlayerSession); - } - else - { - _effects.CreateParticle(message); - } + filter.RemovePlayer(actor.PlayerSession); + + RaiseNetworkEvent(message, filter); } public void PlayImpactSound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound) diff --git a/Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs b/Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs index b070051988..8ba1b5b5a4 100644 --- a/Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/AmmoComponent.cs @@ -15,8 +15,8 @@ public class AmmoComponent : Component, IShootable { // Muzzle flash stored on ammo because if we swap a gun to whatever we may want to override it. - [ViewVariables, DataField("muzzleFlash")] - public ResourcePath? MuzzleFlash = new ResourcePath("Objects/Weapons/Guns/Projectiles/projectiles.rsi/muzzle_bullet.png"); + [ViewVariables(VVAccess.ReadWrite), DataField("muzzleFlash", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string? MuzzleFlash = "MuzzleFlashEffect"; } /// diff --git a/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs new file mode 100644 index 0000000000..69409c6575 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Weapons.Ranged.Events; + +/// +/// Raised whenever a muzzle flash client-side entity needs to be spawned. +/// +[Serializable, NetSerializable] +public sealed class MuzzleFlashEvent : EntityEventArgs +{ + public string Prototype; + + public MuzzleFlashEvent(string prototype) + { + Prototype = prototype; + } +} diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index af2e31d311..86aef929fa 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -49,13 +49,11 @@ public abstract partial class SharedGunSystem : EntitySystem protected ISawmill Sawmill = default!; - private const float MuzzleFlashLifetime = 1f; private const float InteractNextFire = 0.3f; private const double SafetyNextFire = 0.5; private const float EjectOffset = 0.4f; protected const string AmmoExamineColor = "yellow"; protected const string FireRateExamineColor = "yellow"; - protected const string SafetyExamineColor = "lightgreen"; protected const string ModeExamineColor = "cyan"; public override void Initialize() @@ -345,36 +343,17 @@ public abstract partial class SharedGunSystem : EntitySystem protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? user = null) { - var sprite = component.MuzzleFlash?.ToString(); + var sprite = component.MuzzleFlash; - // TODO: AAAAA THIS MUZZLE FLASH CODE IS BAD - // NEEDS EFFECTS TO NOT BE BAD! if (sprite == null) return; - var time = Timing.CurTime; - var deathTime = time + TimeSpan.FromSeconds(MuzzleFlashLifetime); - // Offset the sprite so it actually looks like it's coming from the gun - var offset = new Vector2(0.0f, -0.5f); + var ev = new MuzzleFlashEvent(sprite); - var message = new EffectSystemMessage - { - EffectSprite = sprite, - Born = time, - DeathTime = deathTime, - AttachedEntityUid = gun, - AttachedOffset = offset, - //Rotated from east facing - Rotation = -MathF.PI / 2f, - Color = Vector4.Multiply(new Vector4(255, 255, 255, 255), 1.0f), - ColorDelta = new Vector4(0, 0, 0, -1500f), - Shaded = false - }; - - CreateEffect(message, user); + CreateEffect(gun, ev, user); } - protected abstract void CreateEffect(EffectSystemMessage message, EntityUid? user = null); + protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null); [Serializable, NetSerializable] protected sealed class GunComponentState : ComponentState diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index a1ddefb570..1cbe993cd9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -1,3 +1,20 @@ +- type: entity + id: MuzzleFlashEffect + noSpawn: true + components: + - type: TimedDespawn + lifetime: 0.4 + - type: Sprite + netsync: false + drawdepth: Effects + layers: + - shader: unshaded + map: ["enum.EffectLayers.Unshaded"] + sprite: Objects/Weapons/Guns/Projectiles/projectiles.rsi + state: muzzle_bullet + - type: EffectVisuals + - type: AnimationPlayer + # One bullet to bring them all into the darkness and bind them - type: entity id: BaseBullet