Muzzle flash enhancements (#9527)

This commit is contained in:
metalgearsloth
2022-07-14 23:03:48 +10:00
committed by GitHub
parent 2341d97ece
commit cd4b7bd85c
6 changed files with 134 additions and 45 deletions

View File

@@ -1,6 +1,7 @@
using Content.Client.Items; using Content.Client.Items;
using Content.Client.Weapons.Ranged.Components; using Content.Client.Weapons.Ranged.Components;
using Content.Shared.Camera; using Content.Shared.Camera;
using Content.Shared.Spawners.Components;
using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Events;
@@ -10,11 +11,11 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Input; using Robust.Client.Input;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Animations;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Input; using Robust.Shared.Input;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using SharedGunSystem = Content.Shared.Weapons.Ranged.Systems.SharedGunSystem; 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 IInputManager _inputManager = default!;
[Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!; [Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
[Dependency] private readonly EffectSystem _effects = default!;
[Dependency] private readonly InputSystem _inputSystem = default!; [Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!; [Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
@@ -43,10 +43,10 @@ public sealed partial class GunSystem : SharedGunSystem
{ {
overlayManager.AddOverlay(new GunSpreadOverlay( overlayManager.AddOverlay(new GunSpreadOverlay(
EntityManager, EntityManager,
IoCManager.Resolve<IEyeManager>(), _eyeManager,
IoCManager.Resolve<IGameTiming>(), Timing,
IoCManager.Resolve<IInputManager>(), _inputManager,
IoCManager.Resolve<IPlayerManager>(), _player,
this)); this));
} }
else else
@@ -63,6 +63,7 @@ public sealed partial class GunSystem : SharedGunSystem
base.Initialize(); base.Initialize();
UpdatesOutsidePrediction = true; UpdatesOutsidePrediction = true;
SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect); SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect);
SubscribeLocalEvent<GunComponent, MuzzleFlashEvent>(OnMuzzleFlash);
// Plays animated effects on the client. // Plays animated effects on the client.
SubscribeNetworkEvent<HitscanEvent>(OnHitscan); SubscribeNetworkEvent<HitscanEvent>(OnHitscan);
@@ -71,6 +72,11 @@ public sealed partial class GunSystem : SharedGunSystem
InitializeSpentAmmo(); InitializeSpentAmmo();
} }
private void OnMuzzleFlash(EntityUid uid, GunComponent component, MuzzleFlashEvent args)
{
CreateEffect(uid, args);
}
private void OnHitscan(HitscanEvent ev) private void OnHitscan(HitscanEvent ev)
{ {
// ALL I WANT IS AN ANIMATED EFFECT // 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)); 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<TransformComponent>(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<TimedDespawnComponent>(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<PointLightComponent>(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<AnimationPlayerComponent>(uid);
_animPlayer.Stop(uid, uidPlayer, "muzzle-flash-light");
_animPlayer.Play(uid, uidPlayer, animTwo,"muzzle-flash-light");
} }
} }

View File

@@ -22,7 +22,6 @@ namespace Content.Server.Weapon.Ranged.Systems;
public sealed partial class GunSystem : SharedGunSystem public sealed partial class GunSystem : SharedGunSystem
{ {
[Dependency] private readonly EffectSystem _effects = default!;
[Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly StaminaSystem _stamina = default!;
public const float DamagePitchVariation = MeleeWeaponSystem.DamagePitchVariation; 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 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<ActorComponent>(user, out var actor)) if (TryComp<ActorComponent>(user, out var actor))
{ filter.RemovePlayer(actor.PlayerSession);
_effects.CreateParticle(message, actor.PlayerSession);
} RaiseNetworkEvent(message, filter);
else
{
_effects.CreateParticle(message);
}
} }
public void PlayImpactSound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound) public void PlayImpactSound(EntityUid otherEntity, DamageSpecifier? modifiedDamage, SoundSpecifier? weaponSound, bool forceWeaponSound)

View File

@@ -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. // Muzzle flash stored on ammo because if we swap a gun to whatever we may want to override it.
[ViewVariables, DataField("muzzleFlash")] [ViewVariables(VVAccess.ReadWrite), DataField("muzzleFlash", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public ResourcePath? MuzzleFlash = new ResourcePath("Objects/Weapons/Guns/Projectiles/projectiles.rsi/muzzle_bullet.png"); public string? MuzzleFlash = "MuzzleFlashEffect";
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,17 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Weapons.Ranged.Events;
/// <summary>
/// Raised whenever a muzzle flash client-side entity needs to be spawned.
/// </summary>
[Serializable, NetSerializable]
public sealed class MuzzleFlashEvent : EntityEventArgs
{
public string Prototype;
public MuzzleFlashEvent(string prototype)
{
Prototype = prototype;
}
}

View File

@@ -49,13 +49,11 @@ public abstract partial class SharedGunSystem : EntitySystem
protected ISawmill Sawmill = default!; protected ISawmill Sawmill = default!;
private const float MuzzleFlashLifetime = 1f;
private const float InteractNextFire = 0.3f; private const float InteractNextFire = 0.3f;
private const double SafetyNextFire = 0.5; private const double SafetyNextFire = 0.5;
private const float EjectOffset = 0.4f; private const float EjectOffset = 0.4f;
protected const string AmmoExamineColor = "yellow"; protected const string AmmoExamineColor = "yellow";
protected const string FireRateExamineColor = "yellow"; protected const string FireRateExamineColor = "yellow";
protected const string SafetyExamineColor = "lightgreen";
protected const string ModeExamineColor = "cyan"; protected const string ModeExamineColor = "cyan";
public override void Initialize() public override void Initialize()
@@ -345,36 +343,17 @@ public abstract partial class SharedGunSystem : EntitySystem
protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? user = null) 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) if (sprite == null)
return; return;
var time = Timing.CurTime; var ev = new MuzzleFlashEvent(sprite);
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 message = new EffectSystemMessage CreateEffect(gun, ev, user);
{
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);
} }
protected abstract void CreateEffect(EffectSystemMessage message, EntityUid? user = null); protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null);
[Serializable, NetSerializable] [Serializable, NetSerializable]
protected sealed class GunComponentState : ComponentState protected sealed class GunComponentState : ComponentState

View File

@@ -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 # One bullet to bring them all into the darkness and bind them
- type: entity - type: entity
id: BaseBullet id: BaseBullet