Fix Flares, Give Skia Spacewalk (#4417)

* Fix various light sources counting as Light, Give Skia spacewalk

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Replace the Ignore Gravity with Jetpack

* Clean up event code + Avoid touching upstream code where possible

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Double cone, strategic untouches

* Additional strategic untouch

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
William Lemon 2025-09-26 20:03:43 +10:00 committed by GitHub
parent 061b844c99
commit 01fe85f77e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 157 additions and 6 deletions

View File

@ -0,0 +1,22 @@
using Content.Client.Light.Components;
using Content.Shared._DV.Light;
using Robust.Client.GameObjects;
namespace Content.Client._DV.Light.EntitySystems;
public sealed partial class ExpendableLightEnergySystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ExpendableLightComponent, OnGetLightEnergyEvent>(GetLightEnergy);
}
private void GetLightEnergy(Entity<ExpendableLightComponent> ent, ref OnGetLightEnergyEvent args)
{
if (!TryComp<PointLightComponent>(ent, out var pointLight))
return;
args.LightEnergy = pointLight.Energy;
args.LightRadius = pointLight.Radius;
}
}

View File

@ -16,7 +16,7 @@ public sealed partial class LightReactiveSystem : SharedLightReactiveSystem
_validLightsInRange.Clear();
foreach (var light in _lightsInRange)
{
if(light.Comp.Enabled && !light.Comp.Deleted && light.Comp.NetSyncEnabled)
if (light.Comp.Enabled && !light.Comp.Deleted)
_validLightsInRange.Add(new(light.Owner, light.Comp));
}
return _validLightsInRange;

View File

@ -0,0 +1,37 @@
using Content.Server.Light.Components;
using Content.Shared._DV.Light;
using Content.Shared.Light.Components;
namespace Content.Server._DV.Light.EntitySystems;
public sealed partial class ExpendableLightEnergySystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ExpendableLightComponent, OnGetLightEnergyEvent>(GetLightEnergy);
}
private void GetLightEnergy(Entity<ExpendableLightComponent> ent, ref OnGetLightEnergyEvent args)
{
// This isn't a perfect clone of the Clientside code, as it relies on animation behaviours
// and thus is by nature different per-client (Especially those with random flickers)
// This same code is not used clientside, because the client doesn't actually have access to the start time(??)
float lightFactor;
switch (ent.Comp.CurrentState)
{
case ExpendableLightState.Lit:
float timeElapsed = ent.Comp.GlowDuration.Seconds - ent.Comp.StateExpiryTime;
lightFactor = MathF.Min(1.0f, 1.0f - timeElapsed / ent.Comp.FadeInDuration);
break;
case ExpendableLightState.Fading:
lightFactor = MathF.Min(1.0f, ent.Comp.StateExpiryTime / ent.Comp.FadeOutDuration.Seconds);
break;
default: // Other states aren't lit.
return;
}
args.LightEnergy = ent.Comp.LitEnergy * lightFactor;
args.LightRadius = ent.Comp.LitRadius * lightFactor;
}
}

View File

@ -16,7 +16,10 @@ public sealed partial class LightReactiveSystem : SharedLightReactiveSystem
_validLightsInRange.Clear();
foreach (var light in _lightsInRange)
{
if(light.Comp.Enabled && !light.Comp.Deleted && light.Comp.NetSyncEnabled)
// On the server, we check if it's Enabled OR if netSyncEnabled is false
// Because sometimes the server doesn't actually know if it should be enabled or not.
// The Client however, can be assumed to always be right.
if ((light.Comp.Enabled || !light.Comp.NetSyncEnabled) && !light.Comp.Deleted)
_validLightsInRange.Add(new(light.Owner, light.Comp));
}
return _validLightsInRange;

View File

@ -42,6 +42,17 @@ public abstract partial class SharedExpendableLightComponent : Component
[DataField]
public SoundSpecifier? DieSound;
// Begin DeltaV additions
[DataField(required: true)]
public float LitRadius = 0.0f;
[DataField(required: true)]
public float LitEnergy = 0.0f;
[DataField]
public float FadeInDuration = 0.0f;
// End DeltaV additions
}
[Serializable, NetSerializable]

View File

@ -0,0 +1,27 @@
using Content.Shared._DV.Light;
using Content.Shared.Light.Components;
namespace Content.Shared._DV.Light.EntitySystems;
public sealed partial class ItemTogglePointLightEnergySystem : EntitySystem
{
[Dependency] private readonly SharedPointLightSystem _light = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ItemTogglePointLightComponent, OnGetLightEnergyEvent>(GetLightEnergy);
}
private void GetLightEnergy(Entity<ItemTogglePointLightComponent> ent, ref OnGetLightEnergyEvent args)
{
if (!_light.TryGetLight(ent.Owner, out var light))
return;
if (!light.Enabled)
return;
args.LightEnergy = light.Energy;
args.LightRadius = light.Radius;
}
}

View File

@ -77,6 +77,21 @@ public abstract class SharedLightReactiveSystem : EntitySystem
foreach (var (lightUid, lightComp) in GetLights(uid))
{
var energy = lightComp.Energy;
var radius = lightComp.Radius;
if (!lightComp.NetSyncEnabled)
{
// Try to use the GetLightEnergyEvent if we can't rely on it being network synced.
var lightEnergyEvnt = new OnGetLightEnergyEvent();
RaiseLocalEvent(lightUid, ref lightEnergyEvnt);
energy = lightEnergyEvnt.LightEnergy;
radius = lightEnergyEvnt.LightRadius;
if (MathHelper.CloseTo(energy, 0f))
continue; // No light, no problem.
}
energy = MathF.Min(energy, 2f); // Clamp energy, to normalize strange values.
// Ensure we're on the same grid as the light source
if (_transform.GetMap(lightUid) != map)
continue;
@ -84,26 +99,50 @@ public abstract class SharedLightReactiveSystem : EntitySystem
// Ensure we're within the light's radius.
var lightPos = _transform.GetWorldPosition(lightUid);
var sqrDistance = Vector2.DistanceSquared(pos, lightPos);
if (sqrDistance > lightComp.Radius * lightComp.Radius)
if (sqrDistance > radius * radius)
continue;
if (sqrDistance < 0.01f)
{
// If we're right on top of the light, just add its full energy value.
val += lightComp.Energy;
val += energy;
continue;
}
// Collision ray check from the entity to the light source
var ray = new CollisionRay(pos, (lightPos - pos).Normalized(), (int)CollisionGroup.Opaque);
var hit = _physics.IntersectRay(_transform.GetMapId(uid), ray, MathF.Sqrt(sqrDistance) - 0.5f, returnOnFirstHit: true);
var hit = _physics.IntersectRay(_transform.GetMapId(uid), ray, MathF.Sqrt(sqrDistance) - 0.5f, ignoredEnt: lightUid, returnOnFirstHit: true);
if (hit.Any() && hit.First().Distance != 0)
continue;
// Manual hack for cones.
if (lightComp.MaskPath == "/Textures/Effects/LightMasks/cone.png")
{
var forward = _transform.GetWorldRotation(lightUid).RotateVec(new Vector2(0.0f, -1.0f));
energy *= MathF.Max(0f, Vector2.Dot((pos - lightPos).Normalized(), forward));
}
else if (lightComp.MaskPath == "/Textures/Effects/LightMasks/double_cone.png")
{
var forward = _transform.GetWorldRotation(lightUid).RotateVec(new Vector2(0.0f, -1.0f));
energy *= MathF.Abs(Vector2.Dot((pos - lightPos).Normalized(), forward));
}
// If we reach here, the light is unobstructed and within range, calculate a light value to add.
val += lightComp.Energy * (1.0f - sqrDistance / (lightComp.Radius * lightComp.Radius));
val += energy * (1.0f - sqrDistance / (radius * radius));
}
return val;
}
}
/// <summary>
/// Passed to unsync'd light sources to get the expected light energy.
/// ONLY called when NetSync is not enabled. Otherwise, uses the light directly.
/// </summary>
[ByRefEvent]
public record struct OnGetLightEnergyEvent()
{
public float LightEnergy = 0f;
public float LightRadius = 0f;
}

View File

@ -12,6 +12,9 @@
iconStateSpent: torch_spent
turnOnBehaviourID: turn_on
fadeOutBehaviourID: fade_out
litRadius: 6.0 # DeltaV
litEnergy: 5.0 # DeltaV
fadeInDuration: 8.0 # DeltaV
# Sounds legit nuff
litSound:
path: /Audio/Items/Flare/flare_on.ogg

View File

@ -16,6 +16,9 @@
iconStateSpent: flare_spent
turnOnBehaviourID: turn_on
fadeOutBehaviourID: fade_out
litRadius: 10.0 # DeltaV
litEnergy: 9.0 # DeltaV
fadeInDuration: 45.0 # DeltaV
litSound:
path: /Audio/Items/Flare/flare_on.ogg
loopedSound:

View File

@ -13,6 +13,8 @@
fadeOutBehaviourID: fade_out
iconStateLit: glowstick_lit
iconStateSpent: glowstick_unlit
litRadius: 5.0 # DeltaV
litEnergy: 3.0 # DeltaV
litSound:
path: /Audio/Items/Handcuffs/rope_breakout.ogg
- type: Sprite

View File

@ -44,6 +44,10 @@
- type: MovementSpeedModifier
baseWalkSpeed: 2.25
baseSprintSpeed: 3.75
- type: NoSlip
- type: MovedByPressure
enabled: false
- type: JetpackUser
- type: CombatMode
- type: MeleeWeapon
soundHit: