Portable flasher tweaks (#6517)
This commit is contained in:
@@ -78,7 +78,6 @@ namespace Content.Client.Entry
|
|||||||
"BodyScanner",
|
"BodyScanner",
|
||||||
"Stunbaton",
|
"Stunbaton",
|
||||||
"Tool",
|
"Tool",
|
||||||
"TriggerOnProximity",
|
|
||||||
"TilePrying",
|
"TilePrying",
|
||||||
"RandomSpriteColor",
|
"RandomSpriteColor",
|
||||||
"ConditionalSpawner",
|
"ConditionalSpawner",
|
||||||
|
|||||||
6
Content.Client/Explosion/TriggerOnProximityComponent.cs
Normal file
6
Content.Client/Explosion/TriggerOnProximityComponent.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using Content.Shared.Explosion;
|
||||||
|
|
||||||
|
namespace Content.Client.Explosion;
|
||||||
|
|
||||||
|
[RegisterComponent, Friend(typeof(TriggerSystem))]
|
||||||
|
public sealed class TriggerOnProximityComponent : SharedTriggerOnProximityComponent {}
|
||||||
101
Content.Client/Explosion/TriggerSystem.Proximity.cs
Normal file
101
Content.Client/Explosion/TriggerSystem.Proximity.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using Content.Client.Trigger;
|
||||||
|
using Content.Shared.Trigger;
|
||||||
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Animations;
|
||||||
|
|
||||||
|
namespace Content.Client.Explosion;
|
||||||
|
|
||||||
|
public sealed partial class TriggerSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently all of the appearance stuff is hardcoded for portable flashers
|
||||||
|
* If you ever add mines it shouldn't be hard to tweak it slightly
|
||||||
|
*/
|
||||||
|
|
||||||
|
private const string AnimKey = "proximity";
|
||||||
|
|
||||||
|
private static readonly Animation _flasherAnimation = new Animation
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(0.3f),
|
||||||
|
AnimationTracks = {
|
||||||
|
new AnimationTrackSpriteFlick
|
||||||
|
{
|
||||||
|
LayerKey = ProximityTriggerVisualLayers.Base,
|
||||||
|
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame("flashing", 0f)}
|
||||||
|
},
|
||||||
|
new AnimationTrackComponentProperty()
|
||||||
|
{
|
||||||
|
ComponentType = typeof(PointLightComponent),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Nearest,
|
||||||
|
Property = nameof(PointLightComponent.Radius),
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(0.1f, 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(3f, 0.1f),
|
||||||
|
new AnimationTrackProperty.KeyFrame(0.1f, 0.5f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void InitializeProximity()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
|
||||||
|
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
|
||||||
|
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProxAnimation(EntityUid uid, TriggerOnProximityComponent component, AnimationCompletedEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<AppearanceComponent>(uid, out var appearance)) return;
|
||||||
|
|
||||||
|
// So animation doesn't get spammed if no server state comes in.
|
||||||
|
appearance.SetData(ProximityTriggerVisualState.State, ProximityTriggerVisuals.Inactive);
|
||||||
|
OnChangeData(uid, component, appearance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProximityInit(EntityUid uid, TriggerOnProximityComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
EntityManager.EnsureComponent<AnimationPlayerComponent>(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProxAppChange(EntityUid uid, TriggerOnProximityComponent component, AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
OnChangeData(uid, component, args.Component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChangeData(EntityUid uid, TriggerOnProximityComponent component, AppearanceComponent appearance)
|
||||||
|
{
|
||||||
|
if (!TryComp<SpriteComponent>(component.Owner, out var spriteComponent)) return;
|
||||||
|
|
||||||
|
TryComp<AnimationPlayerComponent>(component.Owner, out var player);
|
||||||
|
appearance.TryGetData(ProximityTriggerVisualState.State, out ProximityTriggerVisuals state);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case ProximityTriggerVisuals.Inactive:
|
||||||
|
// Don't interrupt the flash animation
|
||||||
|
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
||||||
|
_player.Stop(uid, player, AnimKey);
|
||||||
|
spriteComponent.LayerSetState(ProximityTriggerVisualLayers.Base, "on");
|
||||||
|
break;
|
||||||
|
case ProximityTriggerVisuals.Active:
|
||||||
|
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
|
||||||
|
_player.Play(uid, player, _flasherAnimation, AnimKey);
|
||||||
|
break;
|
||||||
|
case ProximityTriggerVisuals.Off:
|
||||||
|
default:
|
||||||
|
_player.Stop(uid, player, AnimKey);
|
||||||
|
spriteComponent.LayerSetState(ProximityTriggerVisualLayers.Base, "off");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ProximityTriggerVisualLayers : byte
|
||||||
|
{
|
||||||
|
Base,
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Content.Client/Explosion/TriggerSystem.cs
Normal file
10
Content.Client/Explosion/TriggerSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Content.Client.Explosion;
|
||||||
|
|
||||||
|
public sealed partial class TriggerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
InitializeProximity();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Shared.Trigger;
|
|
||||||
using Robust.Client.Animations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.Animations;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
|
|
||||||
namespace Content.Client.Trigger
|
|
||||||
{
|
|
||||||
public sealed class ProximityTriggerVisualizer : AppearanceVisualizer
|
|
||||||
{
|
|
||||||
[DataField("animationState")]
|
|
||||||
private string? _animationState;
|
|
||||||
|
|
||||||
[DataField("duration")]
|
|
||||||
private float _animationDuration = 0.3f;
|
|
||||||
|
|
||||||
private const string AnimKey = "proximity";
|
|
||||||
|
|
||||||
private static Animation _animation = default!;
|
|
||||||
|
|
||||||
public override void InitializeEntity(EntityUid entityUid)
|
|
||||||
{
|
|
||||||
|
|
||||||
base.InitializeEntity(entityUid);
|
|
||||||
|
|
||||||
if (_animationState == null) return;
|
|
||||||
|
|
||||||
IoCManager.Resolve<IEntityManager>().EnsureComponent<AnimationPlayerComponent>(entityUid);
|
|
||||||
|
|
||||||
_animation = new Animation
|
|
||||||
{
|
|
||||||
Length = TimeSpan.FromSeconds(_animationDuration),
|
|
||||||
AnimationTracks = {new AnimationTrackSpriteFlick
|
|
||||||
{
|
|
||||||
LayerKey = ProximityTriggerVisualLayers.Base,
|
|
||||||
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(_animationState, 0f)}
|
|
||||||
|
|
||||||
},
|
|
||||||
new AnimationTrackComponentProperty()
|
|
||||||
{
|
|
||||||
ComponentType = typeof(PointLightComponent),
|
|
||||||
InterpolationMode = AnimationInterpolationMode.Nearest,
|
|
||||||
Property = nameof(PointLightComponent.Radius),
|
|
||||||
KeyFrames =
|
|
||||||
{
|
|
||||||
new AnimationTrackProperty.KeyFrame(0.1f, 0),
|
|
||||||
new AnimationTrackProperty.KeyFrame(3f, 0.1f),
|
|
||||||
new AnimationTrackProperty.KeyFrame(0.1f, 0.5f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnChangeData(AppearanceComponent component)
|
|
||||||
{
|
|
||||||
base.OnChangeData(component);
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
if (!entityManager.TryGetComponent(component.Owner, out SpriteComponent spriteComponent)) return;
|
|
||||||
|
|
||||||
var animSystem = EntitySystem.Get<AnimationPlayerSystem>();
|
|
||||||
entityManager.TryGetComponent(component.Owner, out AnimationPlayerComponent? player);
|
|
||||||
component.TryGetData(ProximityTriggerVisualState.State, out ProximityTriggerVisuals state);
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case ProximityTriggerVisuals.Inactive:
|
|
||||||
if (player != null)
|
|
||||||
animSystem.Stop(player, AnimKey);
|
|
||||||
|
|
||||||
spriteComponent.LayerSetState(ProximityTriggerVisualLayers.Base, "on");
|
|
||||||
break;
|
|
||||||
case ProximityTriggerVisuals.Active:
|
|
||||||
/* TODO: Waiting on ECS OnChangeData so we can actually subscribe to the animation finishing properly.
|
|
||||||
if (_animationState == null || player == null ||
|
|
||||||
animSystem.HasRunningAnimation(player, AnimKey)) return;
|
|
||||||
|
|
||||||
animSystem.Play(player, _animation, AnimKey);
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
case ProximityTriggerVisuals.Off:
|
|
||||||
default:
|
|
||||||
spriteComponent.LayerSetState(ProximityTriggerVisualLayers.Base, "off");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ProximityTriggerVisualLayers : byte
|
|
||||||
{
|
|
||||||
Base,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,7 @@ using Robust.Shared.Physics.Collision.Shapes;
|
|||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Explosion;
|
||||||
|
|
||||||
namespace Content.Server.Explosion.Components
|
namespace Content.Server.Explosion.Components
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,7 @@ namespace Content.Server.Explosion.Components
|
|||||||
/// Raises a <see cref="TriggerEvent"/> whenever an entity collides with a fixture attached to the owner of this component.
|
/// Raises a <see cref="TriggerEvent"/> whenever an entity collides with a fixture attached to the owner of this component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class TriggerOnProximityComponent : Component
|
public sealed class TriggerOnProximityComponent : SharedTriggerOnProximityComponent
|
||||||
{
|
{
|
||||||
public const string FixtureID = "trigger-on-proximity-fixture";
|
public const string FixtureID = "trigger-on-proximity-fixture";
|
||||||
|
|
||||||
|
|||||||
@@ -73,14 +73,11 @@ public sealed partial class TriggerSystem
|
|||||||
component.Colliding.Add(args.OtherFixture.Body);
|
component.Colliding.Add(args.OtherFixture.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnProximityEndCollide(EntityUid uid, TriggerOnProximityComponent component, EndCollideEvent args)
|
private static void OnProximityEndCollide(EntityUid uid, TriggerOnProximityComponent component, EndCollideEvent args)
|
||||||
{
|
{
|
||||||
if (args.OurFixture.ID != TriggerOnProximityComponent.FixtureID) return;
|
if (args.OurFixture.ID != TriggerOnProximityComponent.FixtureID) return;
|
||||||
|
|
||||||
component.Colliding.Remove(args.OtherFixture.Body);
|
component.Colliding.Remove(args.OtherFixture.Body);
|
||||||
|
|
||||||
if (component.Colliding.Count == 0)
|
|
||||||
_activeProximities.Remove(component);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetProximityAppearance(EntityUid uid, TriggerOnProximityComponent component)
|
private void SetProximityAppearance(EntityUid uid, TriggerOnProximityComponent component)
|
||||||
@@ -103,10 +100,14 @@ public sealed partial class TriggerSystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
component.Accumulator = component.Cooldown;
|
component.Accumulator += component.Cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComponent))
|
||||||
|
{
|
||||||
|
appearanceComponent.SetData(ProximityTriggerVisualState.State, ProximityTriggerVisuals.Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetProximityAppearance(component.Owner, component);
|
|
||||||
Trigger(component.Owner);
|
Trigger(component.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,12 +117,6 @@ public sealed partial class TriggerSystem
|
|||||||
|
|
||||||
foreach (var comp in _activeProximities)
|
foreach (var comp in _activeProximities)
|
||||||
{
|
{
|
||||||
if (!comp.Enabled)
|
|
||||||
{
|
|
||||||
toRemove.Add(comp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaDataComponent? metadata = null;
|
MetaDataComponent? metadata = null;
|
||||||
|
|
||||||
if (Deleted(comp.Owner, metadata))
|
if (Deleted(comp.Owner, metadata))
|
||||||
@@ -130,12 +125,22 @@ public sealed partial class TriggerSystem
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetProximityAppearance(comp.Owner, comp);
|
||||||
|
|
||||||
if (Paused(comp.Owner, metadata)) continue;
|
if (Paused(comp.Owner, metadata)) continue;
|
||||||
|
|
||||||
comp.Accumulator -= frameTime;
|
comp.Accumulator -= frameTime;
|
||||||
|
|
||||||
if (comp.Accumulator > 0f) continue;
|
if (comp.Accumulator > 0f) continue;
|
||||||
|
|
||||||
|
// Only remove it from accumulation when nothing colliding anymore.
|
||||||
|
if (!comp.Enabled || comp.Colliding.Count == 0)
|
||||||
|
{
|
||||||
|
comp.Accumulator = 0f;
|
||||||
|
toRemove.Add(comp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Alright now that we have no cd check everything in range.
|
// Alright now that we have no cd check everything in range.
|
||||||
|
|
||||||
foreach (var colliding in comp.Colliding)
|
foreach (var colliding in comp.Colliding)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Content.Shared.Explosion;
|
||||||
|
|
||||||
|
public abstract class SharedTriggerOnProximityComponent : Component
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
name: portable flasher
|
name: portable flasher
|
||||||
parent: BaseStructure
|
parent: BaseStructure
|
||||||
id: Portableflasher
|
id: PortableFlasher
|
||||||
description: An ultrabright flashbulb with a proximity trigger, useful for making an area security-only.
|
description: An ultrabright flashbulb with a proximity trigger, useful for making an area security-only.
|
||||||
components:
|
components:
|
||||||
- type: SoundOnTrigger
|
- type: SoundOnTrigger
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
map: ["enum.ProximityTriggerVisualLayers.Base"]
|
map: ["enum.ProximityTriggerVisualLayers.Base"]
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Physics
|
- type: Physics
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
- shape:
|
- shape:
|
||||||
!type:PhysShapeAabb
|
!type:PhysShapeAabb
|
||||||
@@ -90,9 +90,7 @@
|
|||||||
- MobImpassable
|
- MobImpassable
|
||||||
mass: 70
|
mass: 70
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
- type: AnimationPlayer
|
||||||
- type: ProximityTriggerVisualizer
|
|
||||||
animationState: flashing
|
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
energy: 2.0
|
energy: 2.0
|
||||||
radius: 0
|
radius: 0
|
||||||
|
|||||||
Reference in New Issue
Block a user