Skip to content

Commit

Permalink
Shadowkin fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Rxup committed Mar 24, 2024
1 parent eea65ea commit 6a7f70b
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 110 deletions.
47 changes: 47 additions & 0 deletions Content.Server/Backmen/Species/Shadowkin/Jobs/ShadowkinLightJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Backmen.Species.Shadowkin.Components;
using Content.Server.Backmen.Species.Shadowkin.Systems;
using Content.Shared.Backmen.Species.Shadowkin.Components;
using Robust.Server.GameObjects;
using Robust.Shared.CPUJob.JobQueues;
using Robust.Shared.Timing;

namespace Content.Server.Backmen.Species.Shadowkin.Jobs;

public sealed class ShadowkinLightJob : Job<object>
{
private readonly ShadowkinDarkenSystem _system;
private readonly TransformSystem _transform;
private readonly EntityLookupSystem _lookup;
private readonly Entity<ShadowkinDarkSwappedComponent, TransformComponent> _ent;

public ShadowkinLightJob(ShadowkinDarkenSystem system, TransformSystem transform, EntityLookupSystem lookup, Entity<ShadowkinDarkSwappedComponent, TransformComponent> ent, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_system = system;
_transform = transform;
_lookup = lookup;
_ent = ent;
}

public ShadowkinLightJob(ShadowkinDarkenSystem system, TransformSystem transform, EntityLookupSystem lookup, Entity<ShadowkinDarkSwappedComponent, TransformComponent> ent, double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation)
{
_system = system;
_transform = transform;
_lookup = lookup;
_ent = ent;
}

private readonly HashSet<Entity<ShadowkinLightComponent>> _lightQuery = new();

protected override async Task<object?> Process()
{
var transform = _transform.GetMapCoordinates(_ent, _ent);
// Get all lights in range
_lightQuery.Clear();
_lookup.GetEntitiesInRange(transform, _ent.Comp1.DarkenRange, _lightQuery, flags: LookupFlags.StaticSundries);
_system.ProcessLight(_ent, transform, _lightQuery, _ent);

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Content.Shared.Ghost;
using Content.Shared.NPC.Components;
using Content.Shared.NPC.Systems;
using Content.Shared.StatusEffect;
using Content.Shared.Stealth;
using Content.Shared.Stealth.Components;
using Robust.Server.GameObjects;
Expand All @@ -44,6 +45,8 @@ public sealed class ShadowkinDarkSwapSystem : EntitySystem
[Dependency] private readonly EyeSystem _eye = default!;
[Dependency] private readonly StunSystem _stunSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private EntityQuery<PsionicsDisabledComponent> _activePsionicsDisabled;
private EntityQuery<StaminaComponent> _activeStamina;

public override void Initialize()
{
Expand All @@ -59,6 +62,9 @@ public override void Initialize()
SubscribeLocalEvent<ShadowkinDarkSwappedComponent, MoveEvent>(OnMoveInInvis);
SubscribeLocalEvent<ShadowkinDarkSwappedComponent, DamageChangedEvent>(OnDamageInInvis);
SubscribeLocalEvent<ShadowkinDarkSwappedComponent, DispelledEvent>(OnDispelled);

_activePsionicsDisabled = GetEntityQuery<PsionicsDisabledComponent>();
_activeStamina = GetEntityQuery<StaminaComponent>();
}

private void OnDispelled(Entity<ShadowkinDarkSwappedComponent> ent, ref DispelledEvent args)
Expand Down Expand Up @@ -89,12 +95,13 @@ private void OnMoveInInvis(Entity<ShadowkinDarkSwappedComponent> ent, ref MoveEv
if (distance == 0)
return;

if (!TryComp<StaminaComponent>(ent, out var staminaComponent))
if (!_activeStamina.TryGetComponent(ent, out var staminaComponent))
{
RemCompDeferred<ShadowkinDarkSwappedComponent>(ent);
return;
}

_stamina.TakeStaminaDamage(ent, Math.Abs(distance), visual: false, source: ent, chaosDamage: true);
_stamina.TakeStaminaDamage(ent, Math.Abs(distance), staminaComponent, visual: false, source: ent, chaosDamage: true);
staminaComponent.NextUpdate = _timing.CurTime + TimeSpan.FromSeconds(staminaComponent.Cooldown);
}

Expand All @@ -116,13 +123,13 @@ public override void Update(float frameTime)

var currentTime = _timing.CurTime;

var q = EntityQueryEnumerator<StaminaComponent, ShadowkinDarkSwappedComponent>();
while (q.MoveNext(out var uid, out var stamina, out var comp))
var q = EntityQueryEnumerator<StaminaComponent, ShadowkinDarkSwappedComponent, StatusEffectsComponent>();
while (q.MoveNext(out var uid, out var stamina, out var comp, out var statusEffectsComponent))
{
if (stamina.Critical || HasComp<PsionicsDisabledComponent>(uid))
if (stamina.Critical || _activePsionicsDisabled.HasComponent(uid))
{
RemCompDeferred<ShadowkinDarkSwappedComponent>(uid);
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(5), true);
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(5), true, statusEffectsComponent);
continue;
}

Expand Down Expand Up @@ -269,15 +276,17 @@ public void SetVisibility(EntityUid uid, bool set)
// We require the visibility component for this to work
var visibility = EnsureComp<VisibilityComponent>(uid);

Entity<VisibilityComponent?> ent = (uid, visibility);

if (set) // Invisible
{
// Allow the entity to see DarkSwapped entities
if (TryComp(uid, out EyeComponent? eye))
_eye.SetVisibilityMask(uid, eye.VisibilityMask | (int) VisibilityFlags.DarkSwapInvisibility, eye);

// Make other entities unable to see the entity unless also DarkSwapped
_visibility.AddLayer(uid, visibility, (int) VisibilityFlags.DarkSwapInvisibility, false);
_visibility.RemoveLayer(uid, visibility, (int) VisibilityFlags.Normal, false);
_visibility.AddLayer(ent, (int) VisibilityFlags.DarkSwapInvisibility, false);
_visibility.RemoveLayer(ent, (int) VisibilityFlags.Normal, false);
_visibility.RefreshVisibility(uid);

// If not a ghost, add a stealth shader to the entity
Expand All @@ -290,8 +299,8 @@ public void SetVisibility(EntityUid uid, bool set)
if (TryComp(uid, out EyeComponent? eye))
_eye.SetVisibilityMask(uid, eye.VisibilityMask & ~(int) VisibilityFlags.DarkSwapInvisibility, eye);
// Make other entities able to see the entity again
_visibility.RemoveLayer(uid, visibility, (int) VisibilityFlags.DarkSwapInvisibility, false);
_visibility.AddLayer(uid, visibility, (int) VisibilityFlags.Normal, false);
_visibility.RemoveLayer(ent, (int) VisibilityFlags.DarkSwapInvisibility, false);
_visibility.AddLayer(ent, (int) VisibilityFlags.Normal, false);
_visibility.RefreshVisibility(uid);

// Remove the stealth shader from the entity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Linq;
using Content.Server.Light.Components;
using Content.Server.Backmen.Species.Shadowkin.Components;
using Content.Server.Backmen.Species.Shadowkin.Jobs;
using Content.Shared.Backmen.Species.Shadowkin.Components;
using Robust.Server.GameObjects;
using Robust.Shared.CPUJob.JobQueues.Queues;
using Robust.Shared.Map;
using Robust.Shared.Random;

namespace Content.Server.Backmen.Species.Shadowkin.Systems;
Expand All @@ -14,6 +17,15 @@ public sealed class ShadowkinDarkenSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;

private const double MoverJobTime = 0.005;
private readonly JobQueue _moveJobQueue = new(MoverJobTime);

public override void Initialize()
{
base.Initialize();

_activePointLight = GetEntityQuery<PointLightComponent>();
}

public void ResetLight(EntityUid uid, PointLightComponent light, ShadowkinLightComponent sLight)
{
Expand All @@ -29,114 +41,119 @@ public void ResetLight(EntityUid uid, PointLightComponent light, ShadowkinLightC
}


public override void Update(float frameTime)
private EntityQuery<PointLightComponent> _activePointLight;

public void ProcessLight(EntityUid uid, MapCoordinates transform, HashSet<Entity<ShadowkinLightComponent>> lightQuery, ShadowkinDarkSwappedComponent shadowkin)
{
base.Update(frameTime);
var darkened = new List<EntityUid>();
// Add all lights in range to the list if not already there
foreach (var entity in lightQuery)
{
if (!darkened.Contains(entity) && _activePointLight.HasComponent(entity))
darkened.Add(entity);
}

var shadowkins = EntityQueryEnumerator<ShadowkinDarkSwappedComponent>();
// Randomize the list to avoid bias
_random.Shuffle(darkened);
shadowkin.DarkenedLights = darkened;

while (shadowkins.MoveNext(out var uid, out var shadowkin))
{
// Don't do anything if this Shadowkin isn't darkening
if (!shadowkin.Darken)
continue;
var playerPos = transform.Position;

var transform = _transform.GetMapCoordinates(uid);
foreach (var light in shadowkin.DarkenedLights.ToArray())
{
var lightPos = _transform.GetWorldPosition(light);
var pointLight = _activePointLight.GetComponent(light);

// Cooldown
shadowkin.DarkenAccumulator -= frameTime;
if (shadowkin.DarkenAccumulator > 0f)
// Not a light we should affect
if (!TryComp(light, out ShadowkinLightComponent? shadowkinLight))
continue;
shadowkin.DarkenAccumulator += shadowkin.DarkenRate;
// Not powered, undo changes
if (TryComp(light, out PoweredLightComponent? powered) && !powered.On)
{
ResetLight(light, pointLight, shadowkinLight);
continue;
}


var darkened = new List<EntityUid>();
var lightQuery = new HashSet<Entity<ShadowkinLightComponent>>();
// Get all lights in range
_lookup.GetEntitiesInRange(transform, shadowkin.DarkenRange, lightQuery, flags: LookupFlags.StaticSundries);
// If the light isn't attached to an entity, attach it to this Shadowkin
if (shadowkinLight.AttachedEntity == EntityUid.Invalid ||
TerminatingOrDeleted(shadowkinLight.AttachedEntity))
{
shadowkinLight.AttachedEntity = uid;
}

// Add all lights in range to the list if not already there
foreach (var entity in lightQuery)
// Check if the light is being updated by the correct Shadowkin
// Prevents horrible flickering when the light is in range of multiple Shadowkin
if (shadowkinLight.AttachedEntity != EntityUid.Invalid &&
shadowkinLight.AttachedEntity != uid)
{
if (!darkened.Contains(entity) && HasComp<PointLightComponent>(entity))
darkened.Add(entity);
shadowkin.DarkenedLights.Remove(light);
continue;
}

// 3% chance to remove the attached entity so it can become another Shadowkin's light
if (shadowkinLight.AttachedEntity == uid)
{
if (_random.Prob(0.03f))
shadowkinLight.AttachedEntity = EntityUid.Invalid;
}

// Randomize the list to avoid bias
_random.Shuffle(darkened);
shadowkin.DarkenedLights = darkened;

var playerPos = _transform.GetWorldPosition(uid);
// If we haven't edited the radius yet, save the old radius
if (!shadowkinLight.OldRadiusEdited)
{
shadowkinLight.OldRadius = pointLight.Radius;
shadowkinLight.OldRadiusEdited = true;
}

foreach (var light in shadowkin.DarkenedLights.ToArray())
if (!shadowkinLight.OldEnergyEdited)
{
var lightPos = _transform.GetWorldPosition(light);
var pointLight = Comp<PointLightComponent>(light);

// Not a light we should affect
if (!TryComp(light, out ShadowkinLightComponent? shadowkinLight))
continue;
// Not powered, undo changes
if (TryComp(light, out PoweredLightComponent? powered) && !powered.On)
{
ResetLight(light, pointLight, shadowkinLight);
continue;
}


// If the light isn't attached to an entity, attach it to this Shadowkin
if (shadowkinLight.AttachedEntity == EntityUid.Invalid || TerminatingOrDeleted(shadowkinLight.AttachedEntity))
{
shadowkinLight.AttachedEntity = uid;
}
// Check if the light is being updated by the correct Shadowkin
// Prevents horrible flickering when the light is in range of multiple Shadowkin
if (shadowkinLight.AttachedEntity != EntityUid.Invalid &&
shadowkinLight.AttachedEntity != uid)
{
shadowkin.DarkenedLights.Remove(light);
continue;
}
// 3% chance to remove the attached entity so it can become another Shadowkin's light
if (shadowkinLight.AttachedEntity == uid)
{
if (_random.Prob(0.03f))
shadowkinLight.AttachedEntity = EntityUid.Invalid;
}


// If we haven't edited the radius yet, save the old radius
if (!shadowkinLight.OldRadiusEdited)
{
shadowkinLight.OldRadius = pointLight.Radius;
shadowkinLight.OldRadiusEdited = true;
}
if (!shadowkinLight.OldEnergyEdited)
{
shadowkinLight.OldEnergy = pointLight.Energy;
shadowkinLight.OldEnergyEdited = true;
}

var distance = (lightPos - playerPos).Length();
var radius = distance * 2f;
var energy = distance * 0.8f;

// Set new radius based on distance
if (shadowkinLight.OldRadiusEdited && radius > shadowkinLight.OldRadius)
radius = shadowkinLight.OldRadius;
if (shadowkinLight.OldRadiusEdited && radius < shadowkinLight.OldRadius * 0.20f)
radius = shadowkinLight.OldRadius * 0.20f;

// Set new energy based on distance
if (shadowkinLight.OldEnergyEdited && energy > shadowkinLight.OldEnergy)
energy = shadowkinLight.OldEnergy;
if (shadowkinLight.OldEnergyEdited && energy < shadowkinLight.OldEnergy * 0.20f)
energy = shadowkinLight.OldEnergy * 0.20f;

// Put changes into effect
_light.SetRadius(light, radius);
_light.SetEnergy(light, energy, pointLight);
shadowkinLight.OldEnergy = pointLight.Energy;
shadowkinLight.OldEnergyEdited = true;
}

var distance = (lightPos - playerPos).Length();
var radius = distance * 2f;
var energy = distance * 0.8f;

// Set new radius based on distance
if (shadowkinLight.OldRadiusEdited && radius > shadowkinLight.OldRadius)
radius = shadowkinLight.OldRadius;
if (shadowkinLight.OldRadiusEdited && radius < shadowkinLight.OldRadius * 0.20f)
radius = shadowkinLight.OldRadius * 0.20f;

// Set new energy based on distance
if (shadowkinLight.OldEnergyEdited && energy > shadowkinLight.OldEnergy)
energy = shadowkinLight.OldEnergy;
if (shadowkinLight.OldEnergyEdited && energy < shadowkinLight.OldEnergy * 0.20f)
energy = shadowkinLight.OldEnergy * 0.20f;

// Put changes into effect
_light.SetRadius(light, radius);
_light.SetEnergy(light, energy, pointLight);
}
}

public override void Update(float frameTime)
{
base.Update(frameTime);

_moveJobQueue.Process();

var q = EntityQueryEnumerator<ShadowkinDarkSwappedComponent, TransformComponent>();
while (q.MoveNext(out var uid, out var shadowkin, out var xform))
{
// Don't do anything if this Shadowkin isn't darkening
if (!shadowkin.Darken)
continue;

// Cooldown
shadowkin.DarkenAccumulator -= frameTime;
if (shadowkin.DarkenAccumulator > 0f)
continue;
shadowkin.DarkenAccumulator += shadowkin.DarkenRate;

_moveJobQueue.EnqueueJob(new ShadowkinLightJob(this, _transform, _lookup, (uid, shadowkin, xform), MoverJobTime));
}
}
}
Loading

0 comments on commit 6a7f70b

Please sign in to comment.