Skip to content

Commit

Permalink
Fix effects (#27533)
Browse files Browse the repository at this point in the history
* Fix effects

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

* Fix merge artifact
  • Loading branch information
metalgearsloth authored May 2, 2024
1 parent 6596584 commit 5053c8a
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 51 deletions.
17 changes: 17 additions & 0 deletions Content.Client/Animations/TrackUserComponent.cs
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion Content.Client/MouseRotator/MouseRotatorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public override void Update(float frameTime)
if (angleDir == curRot.GetCardinalDir())
return;

RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent()
RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent()
{
Direction = angleDir,
});
Expand Down
26 changes: 19 additions & 7 deletions Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -59,17 +60,20 @@ public override void DoLunge(EntityUid user, EntityUid weapon, Angle angle, Vect
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);
Expand Down Expand Up @@ -206,15 +210,23 @@ private Animation GetLungeAnimation(Vector2 direction)
/// <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);
}
}
}
7 changes: 6 additions & 1 deletion Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,15 @@ public override void Initialize()
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;
Expand Down
65 changes: 38 additions & 27 deletions Content.Client/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -15,6 +16,7 @@
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;
Expand All @@ -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";
Expand Down Expand Up @@ -123,7 +126,7 @@ private void OnHitscan(HitscanEvent ev)
}
};

_animPlayer.Play(ent, null, anim, "hitscan-effect");
_animPlayer.Play(ent, anim, "hitscan-effect");
}
}

Expand Down Expand Up @@ -189,6 +192,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?
// 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)
{
Expand All @@ -208,7 +212,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?
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.
Expand All @@ -226,7 +230,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?

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))
Expand Down Expand Up @@ -258,33 +262,41 @@ protected override void Popup(string message, EntityUid? uid, EntityUid? user)
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;
}
Expand All @@ -309,18 +321,17 @@ protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, En
};

_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()
{
Expand Down Expand Up @@ -352,9 +363,9 @@ protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, En
}
};

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");
}
}
8 changes: 4 additions & 4 deletions Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?
});

SetCartridgeSpent(ent.Value, cartridge, true);
MuzzleFlash(gunUid, cartridge, user);
MuzzleFlash(gunUid, cartridge, mapDirection.ToAngle(), user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);

if (cartridge.DeleteOnSpawn)
Expand All @@ -175,7 +175,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?
// 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;
Expand Down Expand Up @@ -326,9 +326,9 @@ private Angle GetRecoilAngle(TimeSpan curTime, GunComponent component, Angle dir

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);
Expand Down
9 changes: 3 additions & 6 deletions Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
8 changes: 3 additions & 5 deletions Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ private void OnShootRequest(RequestShootEvent msg, EntitySessionEventArgs args)
return;

gun.ShootCoordinates = GetCoordinates(msg.Coordinates);
Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}");
AttemptShoot(user.Value, ent, gun);
}

Expand Down Expand Up @@ -195,7 +194,6 @@ private void StopShooting(EntityUid uid, GunComponent gun)
if (gun.ShotCounter == 0)
return;

Log.Debug($"Stopped shooting {ToPrettyString(uid)}");
gun.ShotCounter = 0;
gun.ShootCoordinates = null;
Dirty(uid, gun);
Expand Down Expand Up @@ -461,7 +459,7 @@ protected void RemoveShootable(EntityUid uid)
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);
Expand All @@ -473,7 +471,7 @@ protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? us
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);
}

Expand Down Expand Up @@ -522,7 +520,7 @@ public void RefreshModifiers(Entity<GunComponent?> gun)
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.
Expand Down

0 comments on commit 5053c8a

Please sign in to comment.