]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix effects (#27533)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Thu, 2 May 2024 02:40:07 +0000 (12:40 +1000)
committerGitHub <noreply@github.com>
Thu, 2 May 2024 02:40:07 +0000 (12:40 +1000)
* Fix effects

- Fix muzzle flash rotations.
- Fix effects so they update every frame.
- Fix effects tanking client performance.

* Fix merge artifact

Content.Client/Animations/TrackUserComponent.cs [new file with mode: 0644]
Content.Client/MouseRotator/MouseRotatorSystem.cs
Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
Content.Client/Weapons/Ranged/Systems/GunSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs
Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs

diff --git a/Content.Client/Animations/TrackUserComponent.cs b/Content.Client/Animations/TrackUserComponent.cs
new file mode 100644 (file)
index 0000000..374c187
--- /dev/null
@@ -0,0 +1,17 @@
+using System.Numerics;
+
+namespace Content.Client.Animations;
+
+/// <summary>
+/// Entities with this component tracks the user's world position every frame.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TrackUserComponent : Component
+{
+    public EntityUid? User;
+
+    /// <summary>
+    /// Offset in the direction of the entity's rotation.
+    /// </summary>
+    public Vector2 Offset = Vector2.Zero;
+}
index 44e82053554184e4aba78967b24ca91f564bc0b8..4894c17c4c01224f5b3513a35d63c8c63c575887 100644 (file)
@@ -49,7 +49,7 @@ public sealed class MouseRotatorSystem : SharedMouseRotatorSystem
             if (angleDir == curRot.GetCardinalDir())
                 return;
 
-            RaisePredictiveEvent(new  RequestMouseRotatorRotationSimpleEvent()
+            RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent()
             {
                 Direction = angleDir,
             });
index c33bc913d3e3ff639edeab363141f8f3fb74565d..baac42d1937cc619f8731e5a0b3775c062e50fc2 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Client.Animations;
 using Content.Client.Weapons.Melee.Components;
 using Content.Shared.Weapons.Melee;
 using Robust.Client.Animations;
@@ -59,17 +60,20 @@ public sealed partial class MeleeWeaponSystem
         var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
 
         var xform = _xformQuery.GetComponent(animationUid);
+        TrackUserComponent track;
 
         switch (arcComponent.Animation)
         {
             case WeaponArcAnimation.Slash:
-                arcComponent.User = user;
+                track = EnsureComp<TrackUserComponent>(animationUid);
+                track.User = user;
                 _animation.Play(animationUid, GetSlashAnimation(sprite, angle, spriteRotation), SlashAnimationKey);
                 if (arcComponent.Fadeout)
                     _animation.Play(animationUid, GetFadeAnimation(sprite, 0.065f, 0.065f + 0.05f), FadeAnimationKey);
                 break;
             case WeaponArcAnimation.Thrust:
-                arcComponent.User = user;
+                track = EnsureComp<TrackUserComponent>(animationUid);
+                track.User = user;
                 _animation.Play(animationUid, GetThrustAnimation(sprite, distance, spriteRotation), ThrustAnimationKey);
                 if (arcComponent.Fadeout)
                     _animation.Play(animationUid, GetFadeAnimation(sprite, 0.05f, 0.15f), FadeAnimationKey);
@@ -206,15 +210,23 @@ public sealed partial class MeleeWeaponSystem
     /// <summary>
     /// Updates the effect positions to follow the user
     /// </summary>
-    void UpdateEffects(float frameTime)
+    private void UpdateEffects()
     {
-        var arcQuery = EntityQueryEnumerator<TransformComponent, WeaponArcVisualsComponent>();
-        while(arcQuery.MoveNext(out var uid, out var xform, out var arcComponent))
+        var query = EntityQueryEnumerator<TrackUserComponent, TransformComponent>();
+        while (query.MoveNext(out var arcComponent, out var xform))
         {
             if (arcComponent.User == null)
                 continue;
-            var userPos = TransformSystem.GetWorldPosition(arcComponent.User.Value);
-            TransformSystem.SetWorldPosition(xform, userPos);
+
+            Vector2 targetPos = TransformSystem.GetWorldPosition(arcComponent.User.Value);
+
+            if (arcComponent.Offset != Vector2.Zero)
+            {
+                var entRotation = TransformSystem.GetWorldRotation(xform);
+                targetPos += entRotation.RotateVec(arcComponent.Offset);
+            }
+
+            TransformSystem.SetWorldPosition(xform, targetPos);
         }
     }
 }
index 95de207471eeed94fa102bc0769f5a4aee8d7b20..039af55bd0100f23f4ccd7057e93a304524fe822 100644 (file)
@@ -43,10 +43,15 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
         UpdatesOutsidePrediction = true;
     }
 
+    public override void FrameUpdate(float frameTime)
+    {
+        base.FrameUpdate(frameTime);
+        UpdateEffects();
+    }
+
     public override void Update(float frameTime)
     {
         base.Update(frameTime);
-        UpdateEffects(frameTime);
 
         if (!Timing.IsFirstTimePredicted)
             return;
index 9e50cab3e10f0e0a6068a95bc2124d60af181486..5aba04bdf8a826d35e647a49fa6cdcb0d42ad02b 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Client.Animations;
 using Content.Client.Items;
 using Content.Client.Weapons.Ranged.Components;
 using Content.Shared.Camera;
@@ -15,6 +16,7 @@ using Robust.Client.Player;
 using Robust.Shared.Animations;
 using Robust.Shared.Input;
 using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 using SharedGunSystem = Content.Shared.Weapons.Ranged.Systems.SharedGunSystem;
@@ -24,13 +26,14 @@ namespace Content.Client.Weapons.Ranged.Systems;
 
 public sealed partial class GunSystem : SharedGunSystem
 {
+    [Dependency] private readonly IComponentFactory _factory = default!;
     [Dependency] private readonly IEyeManager _eyeManager = default!;
     [Dependency] private readonly IInputManager _inputManager = default!;
     [Dependency] private readonly IPlayerManager _player = default!;
     [Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
     [Dependency] private readonly InputSystem _inputSystem = default!;
     [Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
-    [Dependency] private readonly IComponentFactory _factory = default!;
+    [Dependency] private readonly SharedMapSystem _maps = default!;
 
     [ValidatePrototypeId<EntityPrototype>]
     public const string HitscanProto = "HitscanEffect";
@@ -123,7 +126,7 @@ public sealed partial class GunSystem : SharedGunSystem
                 }
             };
 
-            _animPlayer.Play(ent, null, anim, "hitscan-effect");
+            _animPlayer.Play(ent, anim, "hitscan-effect");
         }
     }
 
@@ -189,6 +192,7 @@ public sealed partial class GunSystem : SharedGunSystem
         // to just delete the spawned entities. This is for programmer sanity despite the wasted perf.
         // This also means any ammo specific stuff can be grabbed as necessary.
         var direction = fromCoordinates.ToMapPos(EntityManager, TransformSystem) - toCoordinates.ToMapPos(EntityManager, TransformSystem);
+        var worldAngle = direction.ToAngle().Opposite();
 
         foreach (var (ent, shootable) in ammo)
         {
@@ -208,7 +212,7 @@ public sealed partial class GunSystem : SharedGunSystem
                     if (!cartridge.Spent)
                     {
                         SetCartridgeSpent(ent!.Value, cartridge, true);
-                        MuzzleFlash(gunUid, cartridge, user);
+                        MuzzleFlash(gunUid, cartridge, worldAngle, user);
                         Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
                         Recoil(user, direction, gun.CameraRecoilScalarModified);
                         // TODO: Can't predict entity deletions.
@@ -226,7 +230,7 @@ public sealed partial class GunSystem : SharedGunSystem
 
                     break;
                 case AmmoComponent newAmmo:
-                    MuzzleFlash(gunUid, newAmmo, user);
+                    MuzzleFlash(gunUid, newAmmo, worldAngle, user);
                     Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
                     Recoil(user, direction, gun.CameraRecoilScalarModified);
                     if (IsClientSide(ent!.Value))
@@ -258,33 +262,41 @@ public sealed partial class GunSystem : SharedGunSystem
         PopupSystem.PopupEntity(message, uid.Value, user.Value);
     }
 
-    protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null)
+    protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null)
     {
         if (!Timing.IsFirstTimePredicted)
             return;
 
+        var gunXform = Transform(gunUid);
+        var gridUid = gunXform.GridUid;
         EntityCoordinates coordinates;
 
-        if (message.MatchRotation)
-            coordinates = new EntityCoordinates(uid, Vector2.Zero);
-        else if (TryComp<TransformComponent>(uid, out var xform))
-            coordinates = xform.Coordinates;
+        if (TryComp(gridUid, out MapGridComponent? mapGrid))
+        {
+            coordinates = new EntityCoordinates(gridUid.Value, _maps.LocalToGrid(gridUid.Value, mapGrid, gunXform.Coordinates));
+        }
+        else if (gunXform.MapUid != null)
+        {
+            coordinates = new EntityCoordinates(gunXform.MapUid.Value, TransformSystem.GetWorldPosition(gunXform));
+        }
         else
+        {
             return;
-
-        if (!coordinates.IsValid(EntityManager))
-            return;
+        }
 
         var ent = Spawn(message.Prototype, coordinates);
+        TransformSystem.SetWorldRotationNoLerp(ent, message.Angle);
 
-        var effectXform = Transform(ent);
-        TransformSystem.SetLocalPositionRotation(effectXform,
-            effectXform.LocalPosition + new Vector2(0f, -0.5f),
-            effectXform.LocalRotation - MathF.PI / 2);
+        if (user != null)
+        {
+            var track = EnsureComp<TrackUserComponent>(ent);
+            track.User = user;
+            track.Offset = Vector2.UnitX / 2f;
+        }
 
         var lifetime = 0.4f;
 
-        if (TryComp<TimedDespawnComponent>(uid, out var despawn))
+        if (TryComp<TimedDespawnComponent>(gunUid, out var despawn))
         {
             lifetime = despawn.Lifetime;
         }
@@ -309,18 +321,17 @@ public sealed partial class GunSystem : SharedGunSystem
         };
 
         _animPlayer.Play(ent, anim, "muzzle-flash");
-        if (!TryComp(uid, out PointLightComponent? light))
+        if (!TryComp(gunUid, out PointLightComponent? light))
         {
             light = (PointLightComponent) _factory.GetComponent(typeof(PointLightComponent));
-            light.Owner = uid;
             light.NetSyncEnabled = false;
-            AddComp(uid, light);
+            AddComp(gunUid, light);
         }
 
-        Lights.SetEnabled(uid, true, light);
-        Lights.SetRadius(uid, 2f, light);
-        Lights.SetColor(uid, Color.FromHex("#cc8e2b"), light);
-        Lights.SetEnergy(uid, 5f, light);
+        Lights.SetEnabled(gunUid, true, light);
+        Lights.SetRadius(gunUid, 2f, light);
+        Lights.SetColor(gunUid, Color.FromHex("#cc8e2b"), light);
+        Lights.SetEnergy(gunUid, 5f, light);
 
         var animTwo = new Animation()
         {
@@ -352,9 +363,9 @@ public sealed partial class GunSystem : SharedGunSystem
             }
         };
 
-        var uidPlayer = EnsureComp<AnimationPlayerComponent>(uid);
+        var uidPlayer = EnsureComp<AnimationPlayerComponent>(gunUid);
 
-        _animPlayer.Stop(uid, uidPlayer, "muzzle-flash-light");
-        _animPlayer.Play(uid, uidPlayer, animTwo,"muzzle-flash-light");
+        _animPlayer.Stop(gunUid, uidPlayer, "muzzle-flash-light");
+        _animPlayer.Play((gunUid, uidPlayer), animTwo,"muzzle-flash-light");
     }
 }
index 7449b0c59e99a4032d6471814c9e8cb4e4614e81..f495f29e4aebf970acc527060f95a2a840b9d474 100644 (file)
@@ -154,7 +154,7 @@ public sealed partial class GunSystem : SharedGunSystem
                         });
 
                         SetCartridgeSpent(ent.Value, cartridge, true);
-                        MuzzleFlash(gunUid, cartridge, user);
+                        MuzzleFlash(gunUid, cartridge, mapDirection.ToAngle(), user);
                         Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
 
                         if (cartridge.DeleteOnSpawn)
@@ -175,7 +175,7 @@ public sealed partial class GunSystem : SharedGunSystem
                 // Ammo shoots itself
                 case AmmoComponent newAmmo:
                     shotProjectiles.Add(ent!.Value);
-                    MuzzleFlash(gunUid, newAmmo, user);
+                    MuzzleFlash(gunUid, newAmmo, mapDirection.ToAngle(), user);
                     Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
                     ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, gunUid, user);
                     break;
@@ -326,9 +326,9 @@ public sealed partial class GunSystem : SharedGunSystem
 
     protected override void Popup(string message, EntityUid? uid, EntityUid? user) { }
 
-    protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null)
+    protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null)
     {
-        var filter = Filter.Pvs(uid, entityManager: EntityManager);
+        var filter = Filter.Pvs(gunUid, entityManager: EntityManager);
 
         if (TryComp<ActorComponent>(user, out var actor))
             filter.RemovePlayer(actor.PlayerSession);
index 91f5e6cd8682887b94d6751b7fdbf703d13f6a41..10d4c2fe3c8bb27ace08b66f1ad7d1ba903669ed 100644 (file)
@@ -11,15 +11,12 @@ public sealed class MuzzleFlashEvent : EntityEventArgs
     public NetEntity Uid;
     public string Prototype;
 
-    /// <summary>
-    /// Should the effect match the rotation of the entity.
-    /// </summary>
-    public bool MatchRotation;
+    public Angle Angle;
 
-    public MuzzleFlashEvent(NetEntity uid, string prototype, bool matchRotation = false)
+    public MuzzleFlashEvent(NetEntity uid, string prototype, Angle angle)
     {
         Uid = uid;
         Prototype = prototype;
-        MatchRotation = matchRotation;
+        Angle = angle;
     }
 }
index 129d536a70cbff1a753b3d74def67039d226e30f..51e2e1358fdb6b3b411a7ee5bfa46cd074760458 100644 (file)
@@ -136,7 +136,6 @@ public abstract partial class SharedGunSystem : EntitySystem
             return;
 
         gun.ShootCoordinates = GetCoordinates(msg.Coordinates);
-        Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}");
         AttemptShoot(user.Value, ent, gun);
     }
 
@@ -195,7 +194,6 @@ public abstract partial class SharedGunSystem : EntitySystem
         if (gun.ShotCounter == 0)
             return;
 
-        Log.Debug($"Stopped shooting {ToPrettyString(uid)}");
         gun.ShotCounter = 0;
         gun.ShootCoordinates = null;
         Dirty(uid, gun);
@@ -461,7 +459,7 @@ public abstract partial class SharedGunSystem : EntitySystem
         RemCompDeferred<AmmoComponent>(uid);
     }
 
-    protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? user = null)
+    protected void MuzzleFlash(EntityUid gun, AmmoComponent component, Angle worldAngle, EntityUid? user = null)
     {
         var attemptEv = new GunMuzzleFlashAttemptEvent();
         RaiseLocalEvent(gun, ref attemptEv);
@@ -473,7 +471,7 @@ public abstract partial class SharedGunSystem : EntitySystem
         if (sprite == null)
             return;
 
-        var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, user == gun);
+        var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, worldAngle);
         CreateEffect(gun, ev, user);
     }
 
@@ -522,7 +520,7 @@ public abstract partial class SharedGunSystem : EntitySystem
         Dirty(gun);
     }
 
-    protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null);
+    protected abstract void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null);
 
     /// <summary>
     /// Used for animated effects on the client.