Files
RobustToolbox/Robust.Server/GameObjects/EntitySystems/PointLightSystem.cs
deltanedasGitHubdeltanedas <@deltanedas:goida.zip>metalgearsloth
9cd8401cfb Serializer improvement and cleanup (#6674)
Co-authored-by: deltanedas <@deltanedas:goida.zip>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
2026-07-24 00:57:13 +10:00

135 lines
4.9 KiB
C#

using System.Diagnostics.CodeAnalysis;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
namespace Robust.Server.GameObjects;
public sealed partial class PointLightSystem : SharedPointLightSystem
{
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private MetaDataSystem _metadata = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PointLightComponent, ComponentGetState>(OnLightGetState);
//SubscribeLocalEvent<PointLightComponent, EntInsertedIntoContainerMessage>(OnInserted);
SubscribeLocalEvent<PointLightComponent, EntGotInsertedIntoContainerMessage>(OnInserted);
SubscribeLocalEvent<PointLightComponent, EntGotRemovedFromContainerMessage>(OnRemoved);
SubscribeLocalEvent<PointLightComponent, ComponentStartup>(OnLightStartup);
SubscribeLocalEvent<PointLightComponent, ComponentShutdown>(OnLightShutdown);
SubscribeLocalEvent<PointLightComponent, MetaFlagRemoveAttemptEvent>(OnFlagRemoveAttempt);
}
private void OnLightStartup(Entity<PointLightComponent> ent, ref ComponentStartup args)
{
UpdatePriority(ent.Owner, ent.Comp, MetaData(ent.Owner));
SetContainerOccluded(ent.Owner, IsCurrentContainerOrParentOccluder(ent.Owner), ent.Comp);
_lightTree.QueueTreeUpdate(ent.Owner, ent.Comp);
}
private void OnLightShutdown(Entity<PointLightComponent> ent, ref ComponentShutdown args)
{
UpdatePriority(ent.Owner, ent.Comp, MetaData(ent.Owner));
_lightTree.QueueTreeUpdate(ent.Owner, ent.Comp);
}
private void OnFlagRemoveAttempt(Entity<PointLightComponent> ent, ref MetaFlagRemoveAttemptEvent args)
{
if (IsHighPriority(ent.Comp))
args.ToRemove &= ~MetaDataFlags.PvsPriority;
}
private bool IsHighPriority(SharedPointLightComponent comp)
{
return comp is { Enabled: true, CastShadows: true, Radius: > 7, LifeStage: <= ComponentLifeStage.Running };
}
private void OnInserted(EntityUid uid, PointLightComponent component, EntGotInsertedIntoContainerMessage args)
{
SetContainerOccluded(uid, IsContainerOrParentOccluder(args.Container), component);
}
private void OnRemoved(EntityUid uid, PointLightComponent component, EntGotRemovedFromContainerMessage args)
{
SetContainerOccluded(uid, IsCurrentContainerOrParentOccluder(uid), component);
}
private void OnLightGetState(EntityUid uid, PointLightComponent component, ref ComponentGetState args)
{
args.State = new PointLightComponentState()
{
Color = component.Color,
Enabled = component.Enabled,
Energy = component.Energy,
Offset = component.Offset,
Radius = component.Radius,
Softness = component.Softness,
Falloff = component.Falloff,
CurveFactor = component.CurveFactor,
CastShadows = component.CastShadows,
ContainerOccluded = component.ContainerOccluded,
};
}
protected override void UpdatePriority(EntityUid uid, SharedPointLightComponent comp, MetaDataComponent meta)
{
_metadata.SetFlag((uid, meta), MetaDataFlags.PvsPriority, IsHighPriority(comp));
}
public override SharedPointLightComponent EnsureLight(EntityUid uid)
{
return EnsureComp<PointLightComponent>(uid);
}
public override bool ResolveLight(EntityUid uid, [NotNullWhen(true)] ref SharedPointLightComponent? component)
{
if (component is not null)
return true;
TryComp<PointLightComponent>(uid, out var comp);
component = comp;
return component != null;
}
public override bool TryGetLight(EntityUid uid, [NotNullWhen(true)] out SharedPointLightComponent? component)
{
if (TryComp<PointLightComponent>(uid, out var comp))
{
component = comp;
return true;
}
component = null;
return false;
}
public override bool RemoveLightDeferred(EntityUid uid)
{
return RemCompDeferred<PointLightComponent>(uid);
}
/// <summary>
/// Recursively check if a container or any parent container occludes light.
/// This is probably a terribly unoptimized way to get the occlusion right
/// </summary>
/// <returns>True if any container should block light.</returns>
private bool IsContainerOrParentOccluder(BaseContainer container)
{
if (container.OccludesLight)
return true;
if (!_container.TryGetContainingContainer(container.Owner, out var nextContainer))
return false;
return IsContainerOrParentOccluder(nextContainer);
}
private bool IsCurrentContainerOrParentOccluder(EntityUid uid)
{
return _container.TryGetContainingContainer(uid, out var container) && IsContainerOrParentOccluder(container);
}
}