mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-01 09:37:03 +02:00
219 lines
8.5 KiB
C#
219 lines
8.5 KiB
C#
using System.Numerics;
|
|
using NUnit.Framework;
|
|
using Robust.Server.ComponentTrees;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared;
|
|
using Robust.Shared.ComponentTrees;
|
|
using Robust.Shared.Configuration;
|
|
//using Robust.Shared.Containers;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Light;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.UnitTesting.Server;
|
|
|
|
namespace Robust.Server.IntegrationTests.Light;
|
|
|
|
[TestFixture]
|
|
public sealed class LightLevelSystemTests
|
|
{
|
|
private const string InvalidMaskPrototype = @"
|
|
- type: lightMask
|
|
id: InvalidCone
|
|
maskPath: /Textures/invalid.png
|
|
lightCones:
|
|
- direction: 0
|
|
innerWidth: 90
|
|
outerWidth: 45
|
|
";
|
|
|
|
private static ISimulation NewSimulation(bool lightTree)
|
|
{
|
|
return RobustServerSimulation
|
|
.NewSimulation()
|
|
.RegisterComponents(f =>
|
|
{
|
|
f.RegisterClass<PointLightComponent>();
|
|
f.RegisterClass<LightTreeComponent>();
|
|
})
|
|
.RegisterEntitySystems(f =>
|
|
{
|
|
IoCManager.Resolve<IConfigurationManager>().SetCVar(CVars.LookupEnableServerLightTree, lightTree);
|
|
var recursiveMove = typeof(SharedLightTreeSystem).Assembly.GetType("Robust.Shared.ComponentTrees.RecursiveMoveSystem")!;
|
|
typeof(IEntitySystemManager).GetMethod(nameof(IEntitySystemManager.LoadExtraSystemType))!
|
|
.MakeGenericMethod(recursiveMove)
|
|
.Invoke(f, null);
|
|
f.LoadExtraSystemType<ServerOccluderSystem>();
|
|
f.LoadExtraSystemType<LightTreeSystem>();
|
|
f.LoadExtraSystemType<PointLightSystem>();
|
|
f.LoadExtraSystemType<LightLevelSystem>();
|
|
})
|
|
.InitializeInstance();
|
|
}
|
|
|
|
private static T Sys<T>(ISimulation sim) where T : IEntitySystem
|
|
{
|
|
return sim.Resolve<IEntitySystemManager>().GetEntitySystem<T>();
|
|
}
|
|
|
|
[Test]
|
|
public void AmbientOnlyLighting()
|
|
{
|
|
var sim = NewSimulation(true);
|
|
var map = sim.CreateMap();
|
|
var mapSys = Sys<SharedMapSystem>(sim);
|
|
var light = Sys<LightLevelSystem>(sim);
|
|
|
|
mapSys.SetAmbientLight(map.MapId, Color.Red);
|
|
|
|
Assert.That(light.TryCalculateLightColor(new MapCoordinates(Vector2.Zero, map.MapId), out var color), Is.True);
|
|
Assert.That(color.R, Is.EqualTo(Color.Red.R).Within(0.001f));
|
|
Assert.That(color.G, Is.EqualTo(Color.Red.G).Within(0.001f));
|
|
Assert.That(color.B, Is.EqualTo(Color.Red.B).Within(0.001f));
|
|
}
|
|
|
|
[Test]
|
|
public void MapLightingDisabledReturnsFullyLitEvenWithServerTreeDisabled()
|
|
{
|
|
var sim = NewSimulation(false);
|
|
var map = sim.CreateMap();
|
|
var light = Sys<LightLevelSystem>(sim);
|
|
|
|
sim.Resolve<IEntityManager>().GetComponent<MapComponent>(map.Uid).LightingEnabled = false;
|
|
|
|
Assert.That(light.TryCalculateLightColor(new MapCoordinates(Vector2.Zero, map.MapId), out var color), Is.True);
|
|
Assert.That(color, Is.EqualTo(Color.White));
|
|
Assert.That(light.TryCalculateLightLevel(new MapCoordinates(Vector2.Zero, map.MapId), out var level), Is.True);
|
|
Assert.That(level, Is.EqualTo(1f));
|
|
}
|
|
|
|
[Test]
|
|
public void EnabledMapReturnsUnavailableWhenServerTreeDisabled()
|
|
{
|
|
var sim = NewSimulation(false);
|
|
var map = sim.CreateMap();
|
|
var light = Sys<LightLevelSystem>(sim);
|
|
|
|
Assert.That(light.TryCalculateLightColor(new MapCoordinates(Vector2.Zero, map.MapId), out _), Is.False);
|
|
Assert.That(light.CalculateLightColor(new MapCoordinates(Vector2.Zero, map.MapId)), Is.EqualTo(Color.Black));
|
|
}
|
|
|
|
[Test]
|
|
public void NonShadowLightPassesThroughOccluder()
|
|
{
|
|
var sim = NewSimulation(true);
|
|
var map = sim.CreateMap();
|
|
AddLight(sim, map.MapId, Vector2.Zero, castShadows: false);
|
|
AddOccluder(sim, map.MapId, new Vector2(2, 0));
|
|
|
|
Assert.That(Sys<LightLevelSystem>(sim).TryCalculateLightLevel(new MapCoordinates(new Vector2(4, 0), map.MapId), out var level), Is.True);
|
|
Assert.That(level, Is.GreaterThan(0f));
|
|
}
|
|
|
|
[Test]
|
|
public void ShadowCastingLightBlockedByOccluder()
|
|
{
|
|
var sim = NewSimulation(true);
|
|
var map = sim.CreateMap();
|
|
AddLight(sim, map.MapId, Vector2.Zero, castShadows: true);
|
|
AddOccluder(sim, map.MapId, new Vector2(2, 0));
|
|
|
|
Assert.That(Sys<LightLevelSystem>(sim).TryCalculateLightLevel(new MapCoordinates(new Vector2(4, 0), map.MapId), out var level), Is.True);
|
|
Assert.That(level, Is.EqualTo(0f).Within(0.001f));
|
|
}
|
|
|
|
[Test]
|
|
public void RuntimeOffsetChangeUpdatesTreeBounds()
|
|
{
|
|
var sim = NewSimulation(true);
|
|
var map = sim.CreateMap();
|
|
var uid = AddLight(sim, map.MapId, new Vector2(10, 0), castShadows: false, radius: 2f);
|
|
var light = Sys<LightLevelSystem>(sim);
|
|
var pointLight = sim.Resolve<IEntityManager>().GetComponent<PointLightComponent>(uid);
|
|
|
|
Assert.That(light.TryCalculateLightLevel(new MapCoordinates(Vector2.Zero, map.MapId), out var before), Is.True);
|
|
Assert.That(before, Is.EqualTo(0f).Within(0.001f));
|
|
|
|
Sys<PointLightSystem>(sim).SetOffset(uid, new Vector2(-10, 0), pointLight);
|
|
|
|
Assert.That(light.TryCalculateLightLevel(new MapCoordinates(Vector2.Zero, map.MapId), out var after), Is.True);
|
|
Assert.That(after, Is.GreaterThan(0f));
|
|
}
|
|
|
|
[Test]
|
|
public void InvalidMaskConePrototypeValuesFail()
|
|
{
|
|
var sim = NewSimulation(false);
|
|
var proto = sim.Resolve<IPrototypeManager>();
|
|
|
|
Assert.Throws<PrototypeLoadException>(() => proto.LoadString(InvalidMaskPrototype, true));
|
|
}
|
|
|
|
/*
|
|
[Test]
|
|
public void NestedContainerTransferAndRemovalUpdatesOcclusion()
|
|
{
|
|
var sim = NewSimulation(false);
|
|
var map = sim.CreateMap();
|
|
var entMan = sim.Resolve<IEntityManager>();
|
|
var containers = entMan.System<SharedContainerSystem>();
|
|
var lightUid = AddLight(sim, map.MapId, Vector2.Zero, castShadows: false);
|
|
var light = entMan.GetComponent<PointLightComponent>(lightUid);
|
|
var outerA = entMan.Spawn(null, new MapCoordinates(Vector2.Zero, map.MapId));
|
|
var outerB = entMan.Spawn(null, new MapCoordinates(Vector2.Zero, map.MapId));
|
|
var inner = entMan.Spawn(null, new MapCoordinates(Vector2.Zero, map.MapId));
|
|
|
|
entMan.AddComponent<ContainerManagerComponent>(outerA);
|
|
entMan.AddComponent<ContainerManagerComponent>(outerB);
|
|
entMan.AddComponent<ContainerManagerComponent>(inner);
|
|
var outerAContainer = containers.MakeContainer<Container>(outerA, "outerA");
|
|
var outerBContainer = containers.MakeContainer<Container>(outerB, "outerB");
|
|
var innerContainer = containers.MakeContainer<Container>(inner, "inner");
|
|
outerAContainer.OccludesLight = true;
|
|
outerBContainer.OccludesLight = true;
|
|
innerContainer.OccludesLight = false;
|
|
|
|
containers.Insert(lightUid, innerContainer);
|
|
containers.Insert(inner, outerAContainer);
|
|
Assert.That(light.ContainerOccluded, Is.True);
|
|
|
|
containers.Remove(inner, outerAContainer);
|
|
containers.Insert(inner, outerBContainer);
|
|
Assert.That(light.ContainerOccluded, Is.True);
|
|
|
|
containers.Remove(inner, outerBContainer);
|
|
Assert.That(light.ContainerOccluded, Is.False);
|
|
}
|
|
*/
|
|
|
|
private static EntityUid AddLight(ISimulation sim, MapId mapId, Vector2 position, bool castShadows, float radius = 6f)
|
|
{
|
|
var entMan = sim.Resolve<IEntityManager>();
|
|
var uid = entMan.Spawn(null, new MapCoordinates(position, mapId));
|
|
var pointLightSys = entMan.System<PointLightSystem>();
|
|
var light = entMan.AddComponent<PointLightComponent>(uid);
|
|
pointLightSys.SetRadius(uid, radius, light);
|
|
pointLightSys.SetCastShadows(uid, castShadows, light);
|
|
pointLightSys.SetColor(uid, Color.White, light);
|
|
pointLightSys.SetEnergy(uid, 1f, light);
|
|
return uid;
|
|
}
|
|
|
|
private static void AddOccluder(ISimulation sim, MapId mapId, Vector2 position)
|
|
{
|
|
var entMan = sim.Resolve<IEntityManager>();
|
|
var uid = entMan.Spawn(null, new MapCoordinates(position, mapId));
|
|
var occluder = entMan.AddComponent<OccluderComponent>(uid);
|
|
entMan.System<ServerOccluderSystem>().SetPolygon(uid,
|
|
[
|
|
new(-0.25f, -2f),
|
|
new(0.25f, -2f),
|
|
new(0.25f, 2f),
|
|
new(-0.25f, 2f),
|
|
], occluder);
|
|
}
|
|
}
|