mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 11:40:52 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3538d2797d | ||
|
|
f7cb66f832 | ||
|
|
c9f6fc7182 | ||
|
|
bc8b37de9a | ||
|
|
9d1b15ab4b | ||
|
|
ea1cc5e446 | ||
|
|
bcb5c2d35d | ||
|
|
c011eff80e | ||
|
|
e163c496c3 | ||
|
|
fec81bc2a1 | ||
|
|
7016facb9a | ||
|
|
0c41a041e3 | ||
|
|
55571ef5b1 | ||
|
|
afaef645b0 | ||
|
|
d442d90d60 | ||
|
|
fea592e1d5 | ||
|
|
bb9517fd19 | ||
|
|
a734bc50fa | ||
|
|
9e9ac56c95 | ||
|
|
6979a63b1e | ||
|
|
ae7725aafe | ||
|
|
1a7e490e4b | ||
|
|
51971d0994 | ||
|
|
d2aa8ecb5a | ||
|
|
c4a5752c2a |
@@ -57,7 +57,7 @@
|
||||
<PackageVersion Include="SharpZstd.Interop" Version="1.5.2-beta2" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.6" />
|
||||
<PackageVersion Include="SpaceWizards.HttpListener" Version="0.1.1" />
|
||||
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.1.1" />
|
||||
<PackageVersion Include="SpaceWizards.NFluidsynth" Version="0.2.2" />
|
||||
<PackageVersion Include="SpaceWizards.SharpFont" Version="1.0.2" />
|
||||
<PackageVersion Include="SpaceWizards.Sodium" Version="0.2.1" />
|
||||
<PackageVersion Include="TerraFX.Interop.Windows" Version="10.0.26100.1" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
@@ -54,6 +54,84 @@ END TEMPLATE-->
|
||||
*None yet*
|
||||
|
||||
|
||||
## 246.0.2
|
||||
|
||||
|
||||
## 246.0.1
|
||||
|
||||
|
||||
## 246.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The fixes to renderer state may have inadvertantly broken some rendering code that relied upon the old behavior.
|
||||
* TileRenderFlag has been removed and now it's just a byte flag on the tile for content usage.
|
||||
|
||||
### New features
|
||||
|
||||
* Add BeforeLighting overlay draw space for overlays that need to draw directly to lighting and want to do it immediately beforehand.
|
||||
* Change BlurLights to BlurRenderTarget and make it public for content usage.
|
||||
* Add ContentFlag to tiles for content-flag usage.
|
||||
* Add a basic mix shader for doing canvas blends.
|
||||
* Add GetClearColorEvent for content to override the clear color behavior.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix pushing renderer state not restoring stencil status, blend status, queued shader instance scissor state.
|
||||
|
||||
|
||||
## 245.1.0
|
||||
|
||||
### New features
|
||||
|
||||
* Add more info to the AnchorEntity debug message.
|
||||
* Make ParseObject public where it will parse a supplied Type and string into the specified object.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix EntityPrototypeView not always updating the entity correctly.
|
||||
* Tweak BUI shutdown to potentially avoid skipping closing.
|
||||
|
||||
### Other
|
||||
|
||||
* Increase Audio entity despawn buffer to avoid clipping.
|
||||
|
||||
|
||||
## 245.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* `BoundUserInterface.Open()` now has the `MustCallBase` attribute
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed an error in `MappingDataNode.TryAddCopy()`, which was causing yaml inheritance/deserialization bugs.
|
||||
|
||||
|
||||
## 244.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Increase physics speedcap default from 35m/s to 400m/s in-line with box2d v3.
|
||||
|
||||
### New features
|
||||
|
||||
* Add EntityManager overloads for ComponentRegistration that's faster than the generic methods.
|
||||
* Add CreateWindowCenteredRight for BUIs.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Avoid calling UpdateState before opening a BUI.
|
||||
|
||||
|
||||
## 243.0.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fixed `BaseWindow` sometimes not properly updating the mouse cursor shape.
|
||||
* Revert `BaseWindow` OnClose ordering due to prior reliance upon the ordering.
|
||||
|
||||
|
||||
## 243.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
kind: canvas
|
||||
light_mode: unshaded
|
||||
|
||||
# Simple mix blend
|
||||
- type: shader
|
||||
id: Mix
|
||||
kind: canvas
|
||||
blend_mode: Mix
|
||||
|
||||
- type: shader
|
||||
id: shaded
|
||||
kind: canvas
|
||||
|
||||
96
Robust.Benchmarks/EntityManager/HasComponentBenchmark.cs
Normal file
96
Robust.Benchmarks/EntityManager/HasComponentBenchmark.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public partial class HasComponentBenchmark
|
||||
{
|
||||
private static readonly Consumer Consumer = new();
|
||||
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
|
||||
private ComponentRegistration _compReg = default!;
|
||||
|
||||
private A _dummyA = new();
|
||||
|
||||
[UsedImplicitly]
|
||||
[Params(1, 10, 100, 1000)]
|
||||
public int N;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
_simulation = RobustServerSimulation
|
||||
.NewSimulation()
|
||||
.RegisterComponents(f => f.RegisterClass<A>())
|
||||
.InitializeInstance();
|
||||
|
||||
_entityManager = _simulation.Resolve<IEntityManager>();
|
||||
var map = _simulation.CreateMap().Uid;
|
||||
var coords = new EntityCoordinates(map, default);
|
||||
_compReg = _entityManager.ComponentFactory.GetRegistration(typeof(A));
|
||||
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
var uid = _entityManager.SpawnEntity(null, coords);
|
||||
_entityManager.AddComponent<A>(uid);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HasComponentGeneric()
|
||||
{
|
||||
for (var i = 2; i <= N+1; i++)
|
||||
{
|
||||
var uid = new EntityUid(i);
|
||||
var result = _entityManager.HasComponent<A>(uid);
|
||||
Consumer.Consume(result);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HasComponentCompReg()
|
||||
{
|
||||
for (var i = 2; i <= N+1; i++)
|
||||
{
|
||||
var uid = new EntityUid(i);
|
||||
var result = _entityManager.HasComponent(uid, _compReg);
|
||||
Consumer.Consume(result);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HasComponentType()
|
||||
{
|
||||
for (var i = 2; i <= N+1; i++)
|
||||
{
|
||||
var uid = new EntityUid(i);
|
||||
var result = _entityManager.HasComponent(uid, typeof(A));
|
||||
Consumer.Consume(result);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HasComponentGetType()
|
||||
{
|
||||
for (var i = 2; i <= N+1; i++)
|
||||
{
|
||||
var uid = new EntityUid(i);
|
||||
var type = _dummyA.GetType();
|
||||
var result = _entityManager.HasComponent(uid, type);
|
||||
Consumer.Consume(result);
|
||||
}
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Xilium.CefGlue;
|
||||
|
||||
namespace Robust.Client.WebView.Cef
|
||||
{
|
||||
public static class Program
|
||||
internal static class Program
|
||||
{
|
||||
// This was supposed to be the main entry for the subprocess program... It doesn't work.
|
||||
public static int Main(string[] args)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -24,6 +25,7 @@ namespace Robust.Client.WebView.Cef
|
||||
|
||||
[Dependency] private readonly IDependencyCollection _dependencyCollection = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IGameControllerInternal _gameController = default!;
|
||||
[Dependency] private readonly IResourceManagerInternal _resourceManager = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
@@ -61,7 +63,10 @@ namespace Robust.Client.WebView.Cef
|
||||
|
||||
var cachePath = "";
|
||||
if (_resourceManager.UserData is WritableDirProvider userData)
|
||||
cachePath = userData.GetFullPath(new ResPath("/cef_cache"));
|
||||
{
|
||||
var rootDir = UserDataDir.GetRootUserDataDir(_gameController);
|
||||
cachePath = Path.Combine(rootDir, "cef_cache", "0");
|
||||
}
|
||||
|
||||
var settings = new CefSettings()
|
||||
{
|
||||
|
||||
@@ -382,7 +382,7 @@ namespace Robust.Client
|
||||
|
||||
_prof.Initialize();
|
||||
|
||||
_resManager.Initialize(Options.LoadConfigAndUserData ? userDataDir : null);
|
||||
_resManager.Initialize(Options.LoadConfigAndUserData ? userDataDir : null, hideUserDataDir: true);
|
||||
|
||||
var mountOptions = _commandLineArgs != null
|
||||
? MountOptions.Merge(_commandLineArgs.MountOptions, Options.MountOptions)
|
||||
|
||||
5
Robust.Client/GameStates/PvsOverrideSystem.cs
Normal file
5
Robust.Client/GameStates/PvsOverrideSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Robust.Client.GameStates;
|
||||
|
||||
public sealed partial class PvsOverrideSystem : SharedPvsOverrideSystem;
|
||||
@@ -125,7 +125,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
DebugTools.Assert(space != OverlaySpace.ScreenSpaceBelowWorld && space != OverlaySpace.ScreenSpace);
|
||||
|
||||
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), vp.Eye!.Position.MapId, worldBox, worldBounds);
|
||||
var mapId = vp.Eye!.Position.MapId;
|
||||
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldBox, worldBounds);
|
||||
|
||||
if (!overlay.BeforeDraw(args))
|
||||
return;
|
||||
@@ -175,8 +176,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var worldBounds = CalcWorldBounds(vp);
|
||||
var worldAABB = worldBounds.CalcBoundingBox();
|
||||
var mapId = vp.Eye!.Position.MapId;
|
||||
|
||||
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, vp.Eye!.Position.MapId, worldAABB, worldBounds);
|
||||
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldAABB, worldBounds);
|
||||
|
||||
foreach (var overlay in list)
|
||||
{
|
||||
@@ -421,12 +423,19 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var oldTransform = _currentMatrixModel;
|
||||
var oldScissor = _currentScissorState;
|
||||
var oldMatrixProj = _currentMatrixProj;
|
||||
var oldMatrixView = _currentMatrixView;
|
||||
var oldBoundTarget = _currentBoundRenderTarget;
|
||||
var oldRenderTarget = _currentRenderTarget;
|
||||
var oldShader = _queuedShaderInstance;
|
||||
var oldCaps = _glCaps;
|
||||
|
||||
// Need to get state before flushing render queue in case they modify the original state.
|
||||
var state = PushRenderStateFull();
|
||||
|
||||
// Have to flush the render queue so that all commands finish rendering to the previous framebuffer.
|
||||
FlushRenderQueue();
|
||||
|
||||
var state = PushRenderStateFull();
|
||||
|
||||
{
|
||||
BindRenderTargetFull(RtToLoaded(rt));
|
||||
if (clearColor is not null)
|
||||
@@ -448,8 +457,16 @@ namespace Robust.Client.Graphics.Clyde
|
||||
PopRenderStateFull(state);
|
||||
_updateUniformConstants(_currentRenderTarget.Size);
|
||||
|
||||
SetScissorFull(oldScissor);
|
||||
_currentMatrixModel = oldTransform;
|
||||
|
||||
DebugTools.Assert(oldCaps.Equals(_glCaps));
|
||||
DebugTools.Assert(_currentMatrixModel.Equals(oldTransform));
|
||||
DebugTools.Assert(_currentScissorState.Equals(oldScissor));
|
||||
DebugTools.Assert(_currentMatrixProj.Equals(oldMatrixProj));
|
||||
DebugTools.Assert(oldMatrixView.Equals(_currentMatrixView));
|
||||
DebugTools.Assert(oldRenderTarget.Equals(_currentRenderTarget));
|
||||
DebugTools.Assert(oldBoundTarget.Equals(_currentBoundRenderTarget));
|
||||
DebugTools.Assert(oldShader.Equals(_queuedShaderInstance));
|
||||
}
|
||||
|
||||
private void RenderViewport(Viewport viewport)
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Numerics;
|
||||
using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Maths;
|
||||
using OGLTextureWrapMode = OpenToolkit.Graphics.OpenGL.TextureWrapMode;
|
||||
using TKStencilOp = OpenToolkit.Graphics.OpenGL4.StencilOp;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Client.ComponentTrees;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Graphics;
|
||||
using static Robust.Shared.GameObjects.OccluderComponent;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -279,8 +277,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
const float arbitraryDistanceMax = 1234;
|
||||
|
||||
GL.Disable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = false;
|
||||
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
CheckGlError();
|
||||
@@ -329,8 +326,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
CheckGlError();
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = true;
|
||||
}
|
||||
|
||||
private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 worldAABB, IEye eye)
|
||||
@@ -394,21 +390,43 @@ namespace Robust.Client.Graphics.Clyde
|
||||
FinalizeDepthDraw();
|
||||
}
|
||||
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
_isStencilling = true;
|
||||
IsStencilling = true;
|
||||
|
||||
var (lightW, lightH) = GetLightMapSize(viewport.Size);
|
||||
GL.Viewport(0, 0, lightW, lightH);
|
||||
CheckGlError();
|
||||
|
||||
BindRenderTargetImmediate(RtToLoaded(viewport.LightRenderTarget));
|
||||
DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId));
|
||||
CheckGlError();
|
||||
GLClearColor(_entityManager.GetComponentOrNull<MapLightComponent>(mapUid)?.AmbientLightColor ?? MapLightComponent.DefaultColor);
|
||||
|
||||
var clearEv = new GetClearColorEvent();
|
||||
_entityManager.EventBus.RaiseEvent(EventSource.Local, ref clearEv);
|
||||
|
||||
var clearColor = clearEv.Color ?? GetClearColor(mapUid);
|
||||
GLClearColor(clearColor);
|
||||
GL.ClearStencil(0xFF);
|
||||
GL.StencilMask(0xFF);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
|
||||
CheckGlError();
|
||||
|
||||
var oldTarget = _currentRenderTarget;
|
||||
var oldProj = _currentMatrixProj;
|
||||
var oldShader = _queuedShaderInstance;
|
||||
var oldModel = _currentMatrixModel;
|
||||
var oldScissor = _currentScissorState;
|
||||
var state = PushRenderStateFull();
|
||||
|
||||
RenderOverlays(viewport, OverlaySpace.BeforeLighting, worldAABB, worldBounds);
|
||||
PopRenderStateFull(state);
|
||||
|
||||
DebugTools.Assert(oldScissor.Equals(_currentScissorState));
|
||||
DebugTools.Assert(oldModel.Equals(_currentMatrixModel));
|
||||
DebugTools.Assert(oldShader.Equals(_queuedShaderInstance));
|
||||
DebugTools.Assert(oldProj.Equals(_currentMatrixProj));
|
||||
DebugTools.Assert(oldTarget.Equals(_currentRenderTarget));
|
||||
DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId));
|
||||
|
||||
ApplyLightingFovToBuffer(viewport, eye);
|
||||
|
||||
var lightShader = _loadedShaders[_enableSoftShadows ? _lightSoftShaderHandle : _lightHardShaderHandle]
|
||||
@@ -509,13 +527,12 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
ResetBlendFunc();
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
_isStencilling = false;
|
||||
IsStencilling = false;
|
||||
|
||||
CheckGlError();
|
||||
|
||||
if (_cfg.GetCVar(CVars.LightBlur))
|
||||
BlurLights(viewport, eye);
|
||||
BlurRenderTarget(viewport, viewport.LightRenderTarget, viewport.LightBlurTarget, eye, 14f);
|
||||
|
||||
using (_prof.Group("BlurOntoWalls"))
|
||||
{
|
||||
@@ -531,9 +548,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
GL.Viewport(0, 0, viewport.Size.X, viewport.Size.Y);
|
||||
CheckGlError();
|
||||
|
||||
Array.Clear(_lightsToRenderList, 0, count);
|
||||
|
||||
_lightingReady = true;
|
||||
Array.Clear(_lightsToRenderList, 0, count);
|
||||
}
|
||||
|
||||
private static bool LightQuery(ref (
|
||||
@@ -643,21 +659,33 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return (state.count, expandedBounds);
|
||||
}
|
||||
|
||||
private void BlurLights(Viewport viewport, IEye eye)
|
||||
/// <inheritdoc/>
|
||||
[Pure]
|
||||
public Color GetClearColor(EntityUid mapUid)
|
||||
{
|
||||
using var _ = DebugGroup(nameof(BlurLights));
|
||||
return _entityManager.GetComponentOrNull<MapLightComponent>(mapUid)?.AmbientLightColor ??
|
||||
MapLightComponent.DefaultColor;
|
||||
}
|
||||
|
||||
GL.Disable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
/// <inheritdoc/>
|
||||
public void BlurRenderTarget(IClydeViewport viewport, IRenderTarget target, IRenderTarget blurBuffer, IEye eye, float multiplier)
|
||||
{
|
||||
if (target is not RenderTexture rTexture || blurBuffer is not RenderTexture blurTexture)
|
||||
return;
|
||||
|
||||
using var _ = DebugGroup(nameof(BlurRenderTarget));
|
||||
|
||||
var state = PushRenderStateFull();
|
||||
IsBlending = false;
|
||||
CalcScreenMatrices(viewport.Size, out var proj, out var view);
|
||||
SetProjViewBuffer(proj, view);
|
||||
|
||||
var shader = _loadedShaders[_lightBlurShaderHandle].Program;
|
||||
shader.Use();
|
||||
|
||||
SetupGlobalUniformsImmediate(shader, viewport.LightRenderTarget.Texture);
|
||||
SetupGlobalUniformsImmediate(shader, rTexture.Texture);
|
||||
|
||||
var size = viewport.LightRenderTarget.Size;
|
||||
var size = target.Size;
|
||||
shader.SetUniformMaybe("size", (Vector2)size);
|
||||
shader.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);
|
||||
|
||||
@@ -667,14 +695,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Initially we're pulling from the light render target.
|
||||
// So we set it out of the loop so
|
||||
// _wallBleedIntermediateRenderTarget2 gets bound at the end of the loop body.
|
||||
SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture);
|
||||
SetTexture(TextureUnit.Texture0, rTexture.Texture);
|
||||
|
||||
// Have to scale the blurring radius based on viewport size and camera zoom.
|
||||
const float refCameraHeight = 14;
|
||||
var facBase = _cfg.GetCVar(CVars.LightBlurFactor);
|
||||
var cameraSize = eye.Zoom.Y * viewport.Size.Y * (1 / viewport.RenderScale.Y) / EyeManager.PixelsPerMeter;
|
||||
// 7e-3f is just a magic factor that makes it look ok.
|
||||
var factor = facBase * (refCameraHeight / cameraSize);
|
||||
var factor = facBase * (multiplier / cameraSize);
|
||||
|
||||
// Multi-iteration gaussian blur.
|
||||
for (var i = 3; i > 0; i--)
|
||||
@@ -683,35 +710,31 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Set factor.
|
||||
shader.SetUniformMaybe("radius", scale);
|
||||
|
||||
BindRenderTargetFull(viewport.LightBlurTarget);
|
||||
BindRenderTargetImmediate(RtToLoaded(blurBuffer));
|
||||
|
||||
// Blur horizontally to _wallBleedIntermediateRenderTarget1.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitX);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.LightBlurTarget.Texture);
|
||||
SetTexture(TextureUnit.Texture0, blurTexture.Texture);
|
||||
|
||||
BindRenderTargetFull(viewport.LightRenderTarget);
|
||||
BindRenderTargetImmediate(RtToLoaded(rTexture));
|
||||
|
||||
// Blur vertically to _wallBleedIntermediateRenderTarget2.
|
||||
shader.SetUniformMaybe("direction", Vector2.UnitY);
|
||||
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);
|
||||
|
||||
SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture);
|
||||
SetTexture(TextureUnit.Texture0, rTexture.Texture);
|
||||
}
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
// We didn't trample over the old _currentMatrices so just roll it back.
|
||||
SetProjViewBuffer(_currentMatrixProj, _currentMatrixView);
|
||||
PopRenderStateFull(state);
|
||||
}
|
||||
|
||||
private void BlurOntoWalls(Viewport viewport, IEye eye)
|
||||
{
|
||||
using var _ = DebugGroup(nameof(BlurOntoWalls));
|
||||
|
||||
GL.Disable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = false;
|
||||
CalcScreenMatrices(viewport.Size, out var proj, out var view);
|
||||
SetProjViewBuffer(proj, view);
|
||||
|
||||
@@ -761,8 +784,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
SetTexture(TextureUnit.Texture0, viewport.WallBleedIntermediateRenderTarget2.Texture);
|
||||
}
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = true;
|
||||
// We didn't trample over the old _currentMatrices so just roll it back.
|
||||
SetProjViewBuffer(_currentMatrixProj, _currentMatrixView);
|
||||
}
|
||||
@@ -775,8 +797,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
GL.Viewport(0, 0, viewport.LightRenderTarget.Size.X, viewport.LightRenderTarget.Size.Y);
|
||||
CheckGlError();
|
||||
GL.Disable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = false;
|
||||
|
||||
var shader = _loadedShaders[_mergeWallLayerShaderHandle].Program;
|
||||
shader.Use();
|
||||
@@ -796,8 +817,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
IntPtr.Zero);
|
||||
CheckGlError();
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
CheckGlError();
|
||||
IsBlending = true;
|
||||
}
|
||||
|
||||
private void ApplyFovToBuffer(Viewport viewport, IEye eye)
|
||||
@@ -827,8 +847,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
FovSetTransformAndBlit(viewport, eye.Position.Position, fovShader);
|
||||
|
||||
GL.StencilMask(0x00);
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
_isStencilling = false;
|
||||
IsStencilling = false;
|
||||
}
|
||||
|
||||
private void ApplyLightingFovToBuffer(Viewport viewport, IEye eye)
|
||||
@@ -1135,22 +1154,20 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var lightMapSize = GetLightMapSize(viewport.Size);
|
||||
var lightMapSizeQuart = GetLightMapSize(viewport.Size, true);
|
||||
var lightMapColorFormat = _hasGLFloatFramebuffers
|
||||
? RenderTargetColorFormat.R11FG11FB10F
|
||||
: RenderTargetColorFormat.Rgba8;
|
||||
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };
|
||||
|
||||
viewport.LightRenderTarget?.Dispose();
|
||||
viewport.WallMaskRenderTarget?.Dispose();
|
||||
viewport.WallBleedIntermediateRenderTarget1?.Dispose();
|
||||
viewport.WallBleedIntermediateRenderTarget2?.Dispose();
|
||||
var lightMapColorFormat = _hasGLFloatFramebuffers
|
||||
? RenderTargetColorFormat.R11FG11FB10F
|
||||
: RenderTargetColorFormat.Rgba8;
|
||||
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };
|
||||
|
||||
viewport.WallMaskRenderTarget = CreateRenderTarget(viewport.Size, RenderTargetColorFormat.R8,
|
||||
name: $"{viewport.Name}-{nameof(viewport.WallMaskRenderTarget)}");
|
||||
|
||||
viewport.LightRenderTarget = CreateRenderTarget(lightMapSize,
|
||||
new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: true),
|
||||
lightMapSampleParameters,
|
||||
viewport.LightRenderTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize,
|
||||
$"{viewport.Name}-{nameof(viewport.LightRenderTarget)}");
|
||||
|
||||
viewport.LightBlurTarget = CreateRenderTarget(lightMapSize,
|
||||
@@ -1158,11 +1175,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
lightMapSampleParameters,
|
||||
$"{viewport.Name}-{nameof(viewport.LightBlurTarget)}");
|
||||
|
||||
viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat,
|
||||
viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart,
|
||||
new RenderTargetFormatParameters(lightMapColorFormat),
|
||||
lightMapSampleParameters,
|
||||
$"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget1)}");
|
||||
|
||||
viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat,
|
||||
viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart,
|
||||
new RenderTargetFormatParameters(lightMapColorFormat),
|
||||
lightMapSampleParameters,
|
||||
$"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget2)}");
|
||||
}
|
||||
|
||||
@@ -30,6 +30,20 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// It, like _mainWindowRenderTarget, is initialized in Clyde's constructor
|
||||
private LoadedRenderTarget _currentBoundRenderTarget;
|
||||
|
||||
|
||||
public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true)
|
||||
{
|
||||
var lightMapColorFormat = _hasGLFloatFramebuffers
|
||||
? RTCF.R11FG11FB10F
|
||||
: RTCF.Rgba8;
|
||||
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };
|
||||
|
||||
return CreateRenderTarget(size,
|
||||
new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: depthStencil),
|
||||
lightMapSampleParameters,
|
||||
name: name);
|
||||
}
|
||||
|
||||
IRenderTexture IClyde.CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
|
||||
TextureSampleParameters? sampleParameters, string? name)
|
||||
{
|
||||
@@ -204,7 +218,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
Size = size,
|
||||
TextureHandle = textureObject.TextureId,
|
||||
MemoryPressure = pressure,
|
||||
ColorFormat = format.ColorFormat
|
||||
ColorFormat = format.ColorFormat,
|
||||
SampleParameters = sampleParameters,
|
||||
};
|
||||
|
||||
//GC.AddMemoryPressure(pressure);
|
||||
@@ -251,9 +266,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private LoadedRenderTarget RtToLoaded(RenderTargetBase rt)
|
||||
private LoadedRenderTarget RtToLoaded(IRenderTarget rt)
|
||||
{
|
||||
return _renderTargets[rt.Handle];
|
||||
switch (rt)
|
||||
{
|
||||
case RenderTargetBase based:
|
||||
return _renderTargets[based.Handle];
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -302,6 +323,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Renderbuffer handle
|
||||
public GLHandle DepthStencilHandle;
|
||||
public long MemoryPressure;
|
||||
|
||||
public TextureSampleParameters? SampleParameters;
|
||||
}
|
||||
|
||||
private abstract class RenderTargetBase : IRenderTarget
|
||||
|
||||
@@ -90,9 +90,61 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// (queue) and (misc), current state of the scissor test. Null if disabled.
|
||||
private UIBox2i? _currentScissorState;
|
||||
|
||||
// Some simple flags that basically just tracks the current state of glEnable(GL_STENCIL/GL_SCISSOR_TEST)
|
||||
private bool _isScissoring;
|
||||
private bool _isStencilling;
|
||||
/// <summary>
|
||||
/// Tracks enabled GL capabilities for renderer state.
|
||||
/// </summary>
|
||||
private GLCaps _glCaps = GLCaps.None;
|
||||
|
||||
private bool IsStencilling
|
||||
{
|
||||
get => (_glCaps & GLCaps.Stencilling) == GLCaps.Stencilling;
|
||||
set
|
||||
{
|
||||
if (value == IsStencilling)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
{
|
||||
_glCaps |= GLCaps.Stencilling;
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glCaps &= ~GLCaps.Stencilling;
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
}
|
||||
|
||||
CheckGlError();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsBlending
|
||||
{
|
||||
get => (_glCaps & GLCaps.Blending) == GLCaps.Blending;
|
||||
set
|
||||
{
|
||||
if (value == IsBlending)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
{
|
||||
_glCaps |= GLCaps.Blending;
|
||||
GL.Enable(EnableCap.Blend);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glCaps &= ~GLCaps.Blending;
|
||||
GL.Disable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
CheckGlError();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsScissoring
|
||||
{
|
||||
get => _currentScissorState != null;
|
||||
}
|
||||
|
||||
private readonly RefList<RenderCommand> _queuedRenderCommands = new RefList<RenderCommand>();
|
||||
|
||||
@@ -364,16 +416,17 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private void SetScissorImmediate(bool enable, in UIBox2i box)
|
||||
{
|
||||
var oldIsScissoring = _isScissoring;
|
||||
_isScissoring = enable;
|
||||
if (_isScissoring)
|
||||
if (enable)
|
||||
{
|
||||
if (!oldIsScissoring)
|
||||
{
|
||||
GL.Enable(EnableCap.ScissorTest);
|
||||
CheckGlError();
|
||||
}
|
||||
GL.Enable(EnableCap.ScissorTest);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.Disable(EnableCap.ScissorTest);
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
// Don't forget to flip it, these coordinates have bottom left as origin.
|
||||
// TODO: Broken when rendering to non-screen render targets.
|
||||
|
||||
@@ -387,11 +440,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
CheckGlError();
|
||||
}
|
||||
else if (oldIsScissoring)
|
||||
{
|
||||
GL.Disable(EnableCap.ScissorTest);
|
||||
CheckGlError();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: sRGB IS IN LINEAR IF FRAMEBUFFER_SRGB IS ACTIVE.
|
||||
@@ -420,17 +468,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var program = shader.Program;
|
||||
|
||||
program.Use();
|
||||
IsStencilling = instance.Stencil.Enabled;
|
||||
|
||||
// Handle stencil parameters.
|
||||
if (instance.Stencil.Enabled)
|
||||
{
|
||||
if (!_isStencilling)
|
||||
{
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
CheckGlError();
|
||||
_isStencilling = true;
|
||||
}
|
||||
|
||||
GL.StencilMask(instance.Stencil.WriteMask);
|
||||
CheckGlError();
|
||||
GL.StencilFunc(ToGLStencilFunc(instance.Stencil.Func), instance.Stencil.Ref, instance.Stencil.ReadMask);
|
||||
@@ -438,12 +480,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
GL.StencilOp(TKStencilOp.Keep, TKStencilOp.Keep, ToGLStencilOp(instance.Stencil.Op));
|
||||
CheckGlError();
|
||||
}
|
||||
else if (_isStencilling)
|
||||
{
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
CheckGlError();
|
||||
_isStencilling = false;
|
||||
}
|
||||
|
||||
if (instance.Parameters.Count == 0)
|
||||
return (program, instance);
|
||||
@@ -859,17 +895,34 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private FullStoredRendererState PushRenderStateFull()
|
||||
{
|
||||
return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentRenderTarget);
|
||||
return new FullStoredRendererState(
|
||||
_currentMatrixProj,
|
||||
_currentMatrixView,
|
||||
_currentBoundRenderTarget,
|
||||
_currentRenderTarget,
|
||||
_queuedShaderInstance,
|
||||
_currentScissorState,
|
||||
_glCaps);
|
||||
}
|
||||
|
||||
private void PopRenderStateFull(in FullStoredRendererState state)
|
||||
{
|
||||
SetProjViewFull(state.ProjMatrix, state.ViewMatrix);
|
||||
BindRenderTargetFull(state.RenderTarget);
|
||||
BindRenderTargetImmediate(state.BoundRenderTarget);
|
||||
|
||||
var (width, height) = state.RenderTarget.Size;
|
||||
_queuedShaderInstance = state.QueuedShaderInstance;
|
||||
_currentRenderTarget = state.RenderTarget;
|
||||
var (width, height) = state.BoundRenderTarget.Size;
|
||||
GL.Viewport(0, 0, width, height);
|
||||
CheckGlError();
|
||||
|
||||
IsStencilling = (state.GLCaps & GLCaps.Stencilling) == GLCaps.Stencilling;
|
||||
IsBlending = (state.GLCaps & GLCaps.Blending) == GLCaps.Blending;
|
||||
|
||||
SetScissorFull(state.ScissorState);
|
||||
|
||||
GL.ClearStencil(0xFF);
|
||||
GL.StencilMask(0xFF);
|
||||
GL.Clear(ClearBufferMask.StencilBufferBit);
|
||||
}
|
||||
|
||||
private void SetViewportImmediate(Box2i box)
|
||||
@@ -1061,15 +1114,44 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
public readonly Matrix3x2 ProjMatrix;
|
||||
public readonly Matrix3x2 ViewMatrix;
|
||||
public readonly LoadedRenderTarget BoundRenderTarget;
|
||||
public readonly LoadedRenderTarget RenderTarget;
|
||||
public readonly ClydeShaderInstance QueuedShaderInstance;
|
||||
|
||||
public FullStoredRendererState(in Matrix3x2 projMatrix, in Matrix3x2 viewMatrix,
|
||||
LoadedRenderTarget renderTarget)
|
||||
public readonly UIBox2i? ScissorState;
|
||||
|
||||
public readonly GLCaps GLCaps;
|
||||
|
||||
public FullStoredRendererState(
|
||||
in Matrix3x2 projMatrix,
|
||||
in Matrix3x2 viewMatrix,
|
||||
LoadedRenderTarget boundRenderTarget,
|
||||
LoadedRenderTarget renderTarget,
|
||||
ClydeShaderInstance queuedShaderInstance,
|
||||
UIBox2i? scissorState,
|
||||
GLCaps glcaps
|
||||
)
|
||||
{
|
||||
ProjMatrix = projMatrix;
|
||||
ViewMatrix = viewMatrix;
|
||||
BoundRenderTarget = boundRenderTarget;
|
||||
RenderTarget = renderTarget;
|
||||
QueuedShaderInstance = queuedShaderInstance;
|
||||
|
||||
ScissorState = scissorState;
|
||||
GLCaps = glcaps;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum GLCaps : ushort
|
||||
{
|
||||
// If you add flags here make sure to update PopRenderState!
|
||||
None = 0,
|
||||
|
||||
Blending = 1 << 0,
|
||||
|
||||
Stencilling = 1 << 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode;
|
||||
|
||||
@@ -245,7 +246,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
overrideVersion != null,
|
||||
_windowing!.GetDescription());
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
IsBlending = true;
|
||||
if (_hasGLSrgb && !_isGLES)
|
||||
{
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
|
||||
@@ -9,6 +9,7 @@ using Robust.Client.Input;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -189,6 +190,22 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return new DummyTexture(size);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Color GetClearColor(EntityUid mapUid)
|
||||
{
|
||||
return Color.Transparent;
|
||||
}
|
||||
|
||||
public void BlurRenderTarget(IClydeViewport viewport, IRenderTarget target, IRenderTarget blurBuffer, IEye eye, float multiplier)
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true)
|
||||
{
|
||||
return CreateRenderTarget(size, new RenderTargetFormatParameters(RenderTargetColorFormat.R8, hasDepthStencil: depthStencil), null, name: name);
|
||||
}
|
||||
|
||||
public IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
|
||||
TextureSampleParameters? sampleParameters = null, string? name = null)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Color = Robust.Shared.Maths.Color;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
@@ -71,6 +74,24 @@ namespace Robust.Client.Graphics
|
||||
in TextureLoadParameters? loadParams = null)
|
||||
where T : unmanaged, IPixel<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the clear color for the specified map viewport.
|
||||
/// </summary>
|
||||
[Pure]
|
||||
Color GetClearColor(EntityUid mapUid);
|
||||
|
||||
/// <summary>
|
||||
/// Applies a blur to the specified render target. Requires a separate buffer with similar properties to draw intermediate steps into.
|
||||
/// </summary>
|
||||
/// <param name="viewport">The viewport being used for drawing.</param>
|
||||
/// <param name="target">The blur target.</param>
|
||||
/// <param name="blurBuffer">The separate buffer to draw into.</param>
|
||||
/// <param name="eye">The eye being drawn with.</param>
|
||||
/// <param name="multiplier">Scale of how much blur to blur by.</param>
|
||||
void BlurRenderTarget(IClydeViewport viewport, IRenderTarget target, IRenderTarget blurBuffer, IEye eye, float multiplier);
|
||||
|
||||
IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true);
|
||||
|
||||
IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
|
||||
TextureSampleParameters? sampleParameters = null, string? name = null);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Robust.Client.Graphics
|
||||
/// </summary>
|
||||
IRenderTexture RenderTarget { get; }
|
||||
IRenderTexture LightRenderTarget { get; }
|
||||
|
||||
IEye? Eye { get; set; }
|
||||
Vector2i Size { get; }
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
@@ -15,5 +17,42 @@ namespace Robust.Client.Graphics
|
||||
Vector2i Size { get; }
|
||||
|
||||
void CopyPixelsToMemory<T>(CopyPixelsDelegate<T> callback, UIBox2i? subRegion = null) where T : unmanaged, IPixel<T>;
|
||||
|
||||
public Vector2 LocalToWorld(IEye eye, Vector2 point, Vector2 scale)
|
||||
{
|
||||
var newPoint = point;
|
||||
|
||||
// (inlined version of UiProjMatrix^-1)
|
||||
newPoint -= Size / 2f;
|
||||
newPoint *= new Vector2(1, -1) / EyeManager.PixelsPerMeter;
|
||||
|
||||
// view matrix
|
||||
eye.GetViewMatrixInv(out var viewMatrixInv, scale);
|
||||
newPoint = Vector2.Transform(newPoint, viewMatrixInv);
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
public Vector2 WorldToLocal(Vector2 point, IEye eye, Vector2 scale)
|
||||
{
|
||||
var newPoint = point;
|
||||
|
||||
eye.GetViewMatrix(out var viewMatrix, scale);
|
||||
newPoint = Vector2.Transform(newPoint, viewMatrix);
|
||||
|
||||
// (inlined version of UiProjMatrix)
|
||||
newPoint *= new Vector2(1, -1) * EyeManager.PixelsPerMeter;
|
||||
newPoint += Size / 2f;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
public Matrix3x2 GetWorldToLocalMatrix(IEye eye, Vector2 scale)
|
||||
{
|
||||
eye.GetViewMatrix(out var viewMatrix, scale * new Vector2(EyeManager.PixelsPerMeter, -EyeManager.PixelsPerMeter));
|
||||
viewMatrix.M31 += Size.X / 2f;
|
||||
viewMatrix.M32 += Size.Y / 2f;
|
||||
return viewMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
Robust.Client/Graphics/Lighting/GetClearColorEvent.cs
Normal file
13
Robust.Client/Graphics/Lighting/GetClearColorEvent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Graphics;
|
||||
|
||||
/// <summary>
|
||||
/// Raised by the engine if content wishes to override the default clear color.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct GetClearColorEvent
|
||||
{
|
||||
public Color? Color;
|
||||
}
|
||||
@@ -9,6 +9,5 @@ namespace Robust.Client.Graphics
|
||||
public bool DrawHardFov { get; set; } = true;
|
||||
public bool DrawLighting { get; set; } = true;
|
||||
public bool LockConsoleAccess { get; set; } = false;
|
||||
public Color AmbientLightColor { get; set; } = Color.FromSrgb(Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -39,6 +40,8 @@ namespace Robust.Client.Graphics
|
||||
/// </summary>
|
||||
public readonly UIBox2i ViewportBounds;
|
||||
|
||||
public readonly EntityUid MapUid;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="MapId"/> of the viewport's eye.
|
||||
/// </summary>
|
||||
@@ -65,6 +68,7 @@ namespace Robust.Client.Graphics
|
||||
IClydeViewport viewport,
|
||||
IRenderHandle renderHandle,
|
||||
in UIBox2i viewportBounds,
|
||||
in EntityUid mapUid,
|
||||
in MapId mapId,
|
||||
in Box2 worldAabb,
|
||||
in Box2Rotated worldBounds)
|
||||
@@ -78,6 +82,7 @@ namespace Robust.Client.Graphics
|
||||
Viewport = viewport;
|
||||
RenderHandle = renderHandle;
|
||||
ViewportBounds = viewportBounds;
|
||||
MapUid = mapUid;
|
||||
MapId = mapId;
|
||||
WorldAABB = worldAabb;
|
||||
WorldBounds = worldBounds;
|
||||
|
||||
@@ -51,6 +51,22 @@ public static class BoundUserInterfaceExt
|
||||
return window;
|
||||
}
|
||||
|
||||
public static T CreateWindowCenteredRight<T>(this BoundUserInterface bui) where T : BaseWindow, new()
|
||||
{
|
||||
var window = GetWindow<T>(bui);
|
||||
|
||||
if (bui.EntMan.System<UserInterfaceSystem>().TryGetPosition(bui.Owner, bui.UiKey, out var position))
|
||||
{
|
||||
window.Open(position);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.OpenCenteredRight();
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a control for this BUI that will be disposed when it is disposed.
|
||||
/// </summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ public class EntityPrototypeView : SpriteView
|
||||
{
|
||||
private string? _currentPrototype;
|
||||
private EntityUid? _ourEntity;
|
||||
private bool _isShowing;
|
||||
|
||||
public EntityPrototypeView()
|
||||
{
|
||||
@@ -31,7 +32,7 @@ public class EntityPrototypeView : SpriteView
|
||||
|
||||
_currentPrototype = entProto;
|
||||
|
||||
if (_ourEntity != null)
|
||||
if (_ourEntity != null || _isShowing)
|
||||
{
|
||||
UpdateEntity();
|
||||
}
|
||||
@@ -45,6 +46,8 @@ public class EntityPrototypeView : SpriteView
|
||||
{
|
||||
UpdateEntity();
|
||||
}
|
||||
|
||||
_isShowing = true;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
@@ -52,6 +55,8 @@ public class EntityPrototypeView : SpriteView
|
||||
base.ExitedTree();
|
||||
EntMan.TryQueueDeleteEntity(_ourEntity);
|
||||
_ourEntity = null;
|
||||
|
||||
_isShowing = false;
|
||||
}
|
||||
|
||||
private void UpdateEntity()
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
return;
|
||||
}
|
||||
|
||||
OnClose?.Invoke();
|
||||
Parent.RemoveChild(this);
|
||||
OnClose?.Invoke();
|
||||
}
|
||||
|
||||
protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
@@ -103,6 +103,8 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
var cursor = CursorShape.Arrow;
|
||||
var previewDragMode = GetDragModeFor(args.RelativePosition);
|
||||
previewDragMode &= ~DragMode.Move;
|
||||
|
||||
switch (previewDragMode)
|
||||
{
|
||||
case DragMode.Top:
|
||||
@@ -117,9 +119,6 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
case DragMode.Bottom | DragMode.Left:
|
||||
case DragMode.Top | DragMode.Right:
|
||||
cursor = CursorShape.Crosshair;
|
||||
break;
|
||||
|
||||
case DragMode.Bottom | DragMode.Right:
|
||||
case DragMode.Top | DragMode.Left:
|
||||
cursor = CursorShape.Crosshair;
|
||||
@@ -161,15 +160,6 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
var rect = new UIBox2(left, top, right, bottom);
|
||||
LayoutContainer.SetPosition(this, rect.TopLeft);
|
||||
SetSize = rect.Size;
|
||||
|
||||
/*
|
||||
var timing = IoCManager.Resolve<IGameTiming>();
|
||||
|
||||
var l = GetValue<float>(LayoutContainer.MarginLeftProperty);
|
||||
var t = GetValue<float>(LayoutContainer.MarginTopProperty);
|
||||
|
||||
Logger.Debug($"{timing.CurFrame}: {rect.TopLeft}/({l}, {t}), {rect.Size}/{SetSize}");
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace Robust.Server
|
||||
: null;
|
||||
|
||||
// Set up the VFS
|
||||
_resources.Initialize(dataDir);
|
||||
_resources.Initialize(dataDir, hideUserDataDir: false);
|
||||
|
||||
var mountOptions = _commandLineArgs != null
|
||||
? MountOptions.Merge(_commandLineArgs.MountOptions, Options.MountOptions) : Options.MountOptions;
|
||||
|
||||
@@ -5,13 +5,14 @@ using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Server.GameStates;
|
||||
|
||||
public sealed class PvsOverrideSystem : EntitySystem
|
||||
public sealed class PvsOverrideSystem : SharedPvsOverrideSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IConsoleHost _console = default!;
|
||||
@@ -134,8 +135,10 @@ public sealed class PvsOverrideSystem : EntitySystem
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations,
|
||||
/// causing them to always be sent to all clients.
|
||||
/// </summary>
|
||||
public void AddGlobalOverride(EntityUid uid)
|
||||
public override void AddGlobalOverride(EntityUid uid)
|
||||
{
|
||||
base.AddGlobalOverride(uid);
|
||||
|
||||
if (GlobalOverride.Add(uid))
|
||||
_hasOverride.Add(uid);
|
||||
}
|
||||
@@ -143,8 +146,10 @@ public sealed class PvsOverrideSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Removes an entity from the global overrides.
|
||||
/// </summary>
|
||||
public void RemoveGlobalOverride(EntityUid uid)
|
||||
public override void RemoveGlobalOverride(EntityUid uid)
|
||||
{
|
||||
base.RemoveGlobalOverride(uid);
|
||||
|
||||
GlobalOverride.Remove(uid);
|
||||
// Not bothering to clear _hasOverride, as we'd have to check all the other collections, and at that point we
|
||||
// might as well just do that when the entity gets deleted anyways.
|
||||
@@ -203,8 +208,10 @@ public sealed class PvsOverrideSystem : EntitySystem
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations for a
|
||||
/// specific session.
|
||||
/// </summary>
|
||||
public void AddSessionOverride(EntityUid uid, ICommonSession session)
|
||||
public override void AddSessionOverride(EntityUid uid, ICommonSession session)
|
||||
{
|
||||
base.AddSessionOverride(uid, session);
|
||||
|
||||
if (SessionOverrides.GetOrNew(session).Add(uid))
|
||||
_hasOverride.Add(uid);
|
||||
}
|
||||
@@ -212,8 +219,10 @@ public sealed class PvsOverrideSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Removes an entity from a session's overrides.
|
||||
/// </summary>
|
||||
public void RemoveSessionOverride(EntityUid uid, ICommonSession session)
|
||||
public override void RemoveSessionOverride(EntityUid uid, ICommonSession session)
|
||||
{
|
||||
base.RemoveSessionOverride(uid, session);
|
||||
|
||||
if (!SessionOverrides.TryGetValue(session, out var overrides))
|
||||
return;
|
||||
|
||||
@@ -228,8 +237,10 @@ public sealed class PvsOverrideSystem : EntitySystem
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations,
|
||||
/// causing them to always be sent to all clients.
|
||||
/// </summary>
|
||||
public void AddSessionOverrides(EntityUid uid, Filter filter)
|
||||
public override void AddSessionOverrides(EntityUid uid, Filter filter)
|
||||
{
|
||||
base.AddSessionOverrides(uid, filter);
|
||||
|
||||
foreach (var session in filter.Recipients)
|
||||
{
|
||||
AddSessionOverride(uid, session);
|
||||
|
||||
@@ -73,7 +73,7 @@ internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingData
|
||||
for (ushort x = 0; x < chunk.ChunkSize; x++)
|
||||
{
|
||||
var id = version < 6 ? reader.ReadUInt16() : reader.ReadInt32();
|
||||
var flags = (TileRenderFlag)reader.ReadByte();
|
||||
var flags = reader.ReadByte();
|
||||
var variant = reader.ReadByte();
|
||||
|
||||
var defName = tileMap[id];
|
||||
|
||||
@@ -50,6 +50,9 @@ public sealed class GamePrototypeLoadManager : SharedPrototypeLoadManager
|
||||
|
||||
internal void SendToNewUser(INetChannel channel)
|
||||
{
|
||||
if (LoadedPrototypes.Count == 0)
|
||||
return;
|
||||
|
||||
// Just dump all the prototypes on connect, before them missing could be an issue.
|
||||
var msg = new GamePrototypeLoadMessage
|
||||
{
|
||||
|
||||
@@ -37,6 +37,8 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
[Dependency] protected readonly MetaDataSystem MetadataSys = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem XformSystem = default!;
|
||||
|
||||
private const float AudioDespawnBuffer = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Default max range at which the sound can be heard.
|
||||
/// </summary>
|
||||
@@ -234,7 +236,7 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
{
|
||||
var timed = EnsureComp<TimedDespawnComponent>(entity.Value);
|
||||
var audioLength = GetAudioLength(component.FileName);
|
||||
timed.Lifetime = (float) audioLength.TotalSeconds + 0.01f;
|
||||
timed.Lifetime = (float) audioLength.TotalSeconds + AudioDespawnBuffer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -322,7 +324,7 @@ public abstract partial class SharedAudioSystem : EntitySystem
|
||||
|
||||
var despawn = AddComp<TimedDespawnComponent>(uid);
|
||||
// Don't want to clip audio too short due to imprecision.
|
||||
despawn.Lifetime = (float) length.Value.TotalSeconds + 0.01f;
|
||||
despawn.Lifetime = (float) length.Value.TotalSeconds + AudioDespawnBuffer;
|
||||
}
|
||||
|
||||
if (comp.Params.Variation != null && comp.Params.Variation.Value != 0f)
|
||||
|
||||
@@ -1349,10 +1349,10 @@ namespace Robust.Shared
|
||||
/// MaxLinVelocity is compared to the dot product of linearVelocity * frameTime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default is 35 m/s. Around half a tile per tick at 60 ticks per second.
|
||||
/// Default is 400 m/s in-line with Box2c. Box2d used 120m/s.
|
||||
/// </remarks>
|
||||
public static readonly CVarDef<float> MaxLinVelocity =
|
||||
CVarDef.Create("physics.maxlinvelocity", 35f, CVar.SERVER | CVar.REPLICATED);
|
||||
CVarDef.Create("physics.maxlinvelocity", 400f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Maximum angular velocity in full rotations per second.
|
||||
@@ -1364,7 +1364,6 @@ namespace Robust.Shared
|
||||
public static readonly CVarDef<float> MaxAngVelocity =
|
||||
CVarDef.Create("physics.maxangvelocity", 15f);
|
||||
|
||||
|
||||
/*
|
||||
* User interface
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,58 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Configuration
|
||||
{
|
||||
public static class CVarCommandUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses a string into an object of the given type.
|
||||
/// </summary>
|
||||
/// <exception cref="FormatException">Thrown if the string could not be parsed into the given type.</exception>
|
||||
/// <exception cref="NotSupportedException">Thrown if the type is not supported.</exception>
|
||||
public static object ParseObject(Type type, string input)
|
||||
{
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
if (bool.TryParse(input, out var val))
|
||||
return val;
|
||||
|
||||
if (Parse.TryInt32(input, out var intVal))
|
||||
{
|
||||
if (intVal == 0) return false;
|
||||
if (intVal == 1) return true;
|
||||
}
|
||||
|
||||
throw new FormatException($"Could not parse bool value: {input}");
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
return Parse.Int32(input);
|
||||
}
|
||||
|
||||
if (type == typeof(float))
|
||||
{
|
||||
return Parse.Float(input);
|
||||
}
|
||||
|
||||
if (type == typeof(long))
|
||||
{
|
||||
return long.Parse(input);
|
||||
}
|
||||
|
||||
if (type == typeof(ushort))
|
||||
{
|
||||
return ushort.Parse(input);
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
internal sealed class CVarCommand : LocalizedCommands
|
||||
{
|
||||
@@ -51,7 +103,7 @@ namespace Robust.Shared.Configuration
|
||||
var type = _cfg.GetCVarType(name);
|
||||
try
|
||||
{
|
||||
var parsed = ParseObject(type, value);
|
||||
var parsed = CVarCommandUtil.ParseObject(type, value);
|
||||
_cfg.SetCVar(name, parsed);
|
||||
}
|
||||
catch (FormatException)
|
||||
@@ -95,50 +147,6 @@ namespace Robust.Shared.Configuration
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static object ParseObject(Type type, string input)
|
||||
{
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
if (bool.TryParse(input, out var val))
|
||||
return val;
|
||||
|
||||
if (Parse.TryInt32(input, out var intVal))
|
||||
{
|
||||
if (intVal == 0) return false;
|
||||
if (intVal == 1) return true;
|
||||
}
|
||||
|
||||
throw new FormatException($"Could not parse bool value: {input}");
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
return Parse.Int32(input);
|
||||
}
|
||||
|
||||
if (type == typeof(float))
|
||||
{
|
||||
return Parse.Float(input);
|
||||
}
|
||||
|
||||
if (type == typeof(long))
|
||||
{
|
||||
return long.Parse(input);
|
||||
}
|
||||
|
||||
if (type == typeof(ushort))
|
||||
{
|
||||
return ushort.Parse(input);
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CVarSubsCommand : LocalizedCommands
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Robust.Shared.ContentPack
|
||||
|
||||
internal string GetPath(ResPath relPath)
|
||||
{
|
||||
return Path.GetFullPath(Path.Combine(_directory.FullName, relPath.ToRelativeSystemPath()));
|
||||
return PathHelpers.SafeGetResourcePath(_directory.FullName, relPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -14,7 +14,11 @@ namespace Robust.Shared.ContentPack
|
||||
/// The directory to use for user data.
|
||||
/// If null, a virtual temporary file system is used instead.
|
||||
/// </param>
|
||||
void Initialize(string? userData);
|
||||
/// <param name="hideUserDataDir">
|
||||
/// If true, <see cref="IWritableDirProvider.RootDir"/> will be hidden on
|
||||
/// <see cref="IResourceManager.UserData"/>.
|
||||
/// </param>
|
||||
void Initialize(string? userData, bool hideUserDataDir);
|
||||
|
||||
/// <summary>
|
||||
/// Mounts a single stream as a content file. Useful for unit testing.
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Robust.Shared.ContentPack
|
||||
{
|
||||
/// <summary>
|
||||
/// The root path of this provider.
|
||||
/// Can be null if it's a virtual provider.
|
||||
/// Can be null if it's a virtual provider or the path is protected (e.g. on the client).
|
||||
/// </summary>
|
||||
string? RootDir { get; }
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.ContentPack
|
||||
{
|
||||
@@ -63,5 +64,27 @@ namespace Robust.Shared.ContentPack
|
||||
!OperatingSystem.IsWindows()
|
||||
&& !OperatingSystem.IsMacOS();
|
||||
|
||||
|
||||
internal static string SafeGetResourcePath(string baseDir, ResPath path)
|
||||
{
|
||||
var relSysPath = path.ToRelativeSystemPath();
|
||||
if (relSysPath.Contains("\\..") || relSysPath.Contains("/.."))
|
||||
{
|
||||
// Hard cap on any exploit smuggling a .. in there.
|
||||
// Since that could allow leaving sandbox.
|
||||
throw new InvalidOperationException($"This branch should never be reached. Path: {path}");
|
||||
}
|
||||
|
||||
var retPath = Path.GetFullPath(Path.Join(baseDir, relSysPath));
|
||||
// better safe than sorry check
|
||||
if (!retPath.StartsWith(baseDir))
|
||||
{
|
||||
// Allow path to match if it's just missing the directory separator at the end.
|
||||
if (retPath != baseDir.TrimEnd(Path.DirectorySeparatorChar))
|
||||
throw new InvalidOperationException($"This branch should never be reached. Path: {path}");
|
||||
}
|
||||
|
||||
return retPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +41,13 @@ namespace Robust.Shared.ContentPack
|
||||
public IWritableDirProvider UserData { get; private set; } = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Initialize(string? userData)
|
||||
public virtual void Initialize(string? userData, bool hideRootDir)
|
||||
{
|
||||
Sawmill = _logManager.GetSawmill("res");
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
UserData = new WritableDirProvider(Directory.CreateDirectory(userData));
|
||||
UserData = new WritableDirProvider(Directory.CreateDirectory(userData), hideRootDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -379,7 +379,13 @@ namespace Robust.Shared.ContentPack
|
||||
{
|
||||
if (root is DirLoader loader)
|
||||
{
|
||||
yield return new ResPath(loader.GetPath(new ResPath(@"/")));
|
||||
var rootDir = loader.GetPath(new ResPath(@"/"));
|
||||
|
||||
// TODO: GET RID OF THIS.
|
||||
// This code shouldn't be passing OS disk paths through ResPath.
|
||||
rootDir = rootDir.Replace(Path.DirectorySeparatorChar, '/');
|
||||
|
||||
yield return new ResPath(rootDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,17 +10,22 @@ namespace Robust.Shared.ContentPack
|
||||
/// <inheritdoc />
|
||||
internal sealed class WritableDirProvider : IWritableDirProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
private readonly bool _hideRootDir;
|
||||
|
||||
public string RootDir { get; }
|
||||
|
||||
string? IWritableDirProvider.RootDir => _hideRootDir ? null : RootDir;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance of <see cref="WritableDirProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="rootDir">Root file system directory to allow writing.</param>
|
||||
public WritableDirProvider(DirectoryInfo rootDir)
|
||||
/// <param name="hideRootDir">If true, <see cref="IWritableDirProvider.RootDir"/> is reported as null.</param>
|
||||
public WritableDirProvider(DirectoryInfo rootDir, bool hideRootDir)
|
||||
{
|
||||
// FullName does not have a trailing separator, and we MUST have a separator.
|
||||
RootDir = rootDir.FullName + Path.DirectorySeparatorChar.ToString();
|
||||
_hideRootDir = hideRootDir;
|
||||
}
|
||||
|
||||
#region File Access
|
||||
@@ -119,7 +124,7 @@ namespace Robust.Shared.ContentPack
|
||||
throw new FileNotFoundException();
|
||||
|
||||
var dirInfo = new DirectoryInfo(GetFullPath(path));
|
||||
return new WritableDirProvider(dirInfo);
|
||||
return new WritableDirProvider(dirInfo, _hideRootDir);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -180,20 +185,7 @@ namespace Robust.Shared.ContentPack
|
||||
|
||||
path = path.Clean();
|
||||
|
||||
return GetFullPath(RootDir, path);
|
||||
}
|
||||
|
||||
private static string GetFullPath(string root, ResPath path)
|
||||
{
|
||||
var relPath = path.ToRelativeSystemPath();
|
||||
if (relPath.Contains("\\..") || relPath.Contains("/.."))
|
||||
{
|
||||
// Hard cap on any exploit smuggling a .. in there.
|
||||
// Since that could allow leaving sandbox.
|
||||
throw new InvalidOperationException($"This branch should never be reached. Path: {path}");
|
||||
}
|
||||
|
||||
return Path.GetFullPath(Path.Combine(root, relPath));
|
||||
return PathHelpers.SafeGetResourcePath(RootDir, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace Robust.Shared.Enums
|
||||
/// <summary>
|
||||
/// Overlay will be rendered below grids, entities, and everything else. In world space.
|
||||
/// </summary>
|
||||
WorldSpaceBelowWorld = 1 << 8
|
||||
WorldSpaceBelowWorld = 1 << 8,
|
||||
|
||||
/// <summary>
|
||||
/// Called after GLClear but before FOV applied to the lighting buffer.
|
||||
/// </summary>
|
||||
BeforeLighting = 1 << 9,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Robust.Shared.GameObjects
|
||||
[Dependency] protected readonly ISharedPlayerManager PlayerManager = default!;
|
||||
protected readonly SharedUserInterfaceSystem UiSystem;
|
||||
|
||||
public bool IsOpened { get; protected set; }
|
||||
|
||||
public readonly Enum UiKey;
|
||||
public EntityUid Owner { get; }
|
||||
|
||||
@@ -41,8 +43,13 @@ namespace Robust.Shared.GameObjects
|
||||
/// Invoked when the UI is opened.
|
||||
/// Do all creation and opening of things like windows in here.
|
||||
/// </summary>
|
||||
[MustCallBase]
|
||||
protected internal virtual void Open()
|
||||
{
|
||||
if (IsOpened)
|
||||
return;
|
||||
|
||||
IsOpened = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -93,6 +100,10 @@ namespace Robust.Shared.GameObjects
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (!IsOpened)
|
||||
return;
|
||||
|
||||
IsOpened = false;
|
||||
UiSystem.CloseUi(Owner, UiKey, PlayerManager.LocalEntity, predicted: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -197,17 +197,23 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
var reg = _componentFactory.GetRegistration(name);
|
||||
|
||||
if (HasComponent(target, reg.Type))
|
||||
if (removeExisting)
|
||||
{
|
||||
if (!removeExisting)
|
||||
continue;
|
||||
|
||||
RemoveComponent(target, reg.Type, metadata);
|
||||
var comp = _componentFactory.GetComponent(reg);
|
||||
_serManager.CopyTo(entry.Component, ref comp, notNullableOverride: true);
|
||||
AddComponentInternal(target, comp, reg, overwrite: true, metadata: metadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasComponent(target, reg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var comp = _componentFactory.GetComponent(reg);
|
||||
_serManager.CopyTo(entry.Component, ref comp, notNullableOverride: true);
|
||||
AddComponent(target, comp, metadata: metadata);
|
||||
var comp = _componentFactory.GetComponent(reg);
|
||||
_serManager.CopyTo(entry.Component, ref comp, notNullableOverride: true);
|
||||
AddComponentInternal(target, comp, reg, overwrite: false, metadata: metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +321,22 @@ namespace Robust.Shared.GameObjects
|
||||
AddComponentInternal(uid, component, overwrite, false, metadata);
|
||||
}
|
||||
|
||||
private void AddComponentInternal<T>(
|
||||
EntityUid uid,
|
||||
T component,
|
||||
ComponentRegistration compReg,
|
||||
bool overwrite = false,
|
||||
MetaDataComponent? metadata = null) where T : IComponent
|
||||
{
|
||||
if (!MetaQuery.Resolve(uid, ref metadata, false))
|
||||
throw new ArgumentException($"Entity {uid} is not valid.", nameof(uid));
|
||||
|
||||
DebugTools.Assert(component.Owner == default);
|
||||
component.Owner = uid;
|
||||
|
||||
AddComponentInternal(uid, component, compReg, overwrite, skipInit: false, metadata);
|
||||
}
|
||||
|
||||
private void AddComponentInternal<T>(EntityUid uid, T component, bool overwrite, bool skipInit, MetaDataComponent? metadata) where T : IComponent
|
||||
{
|
||||
if (!MetaQuery.ResolveInternal(uid, ref metadata, false))
|
||||
@@ -731,6 +753,14 @@ namespace Robust.Shared.GameObjects
|
||||
return uid.HasValue && HasComponent<T>(uid.Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[Pure]
|
||||
public bool HasComponent(EntityUid uid, ComponentRegistration reg)
|
||||
{
|
||||
var dict = _entTraitArray[reg.Idx.Value];
|
||||
return dict.TryGetValue(uid, out var comp) && !comp.Deleted;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[Pure]
|
||||
@@ -943,6 +973,23 @@ namespace Robust.Shared.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetComponent(EntityUid uid, ComponentRegistration reg, [NotNullWhen(true)] out IComponent? component)
|
||||
{
|
||||
var dict = _entTraitArray[reg.Idx.Value];
|
||||
if (dict.TryGetValue(uid, out var comp))
|
||||
{
|
||||
if (!comp.Deleted)
|
||||
{
|
||||
component = comp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
component = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetComponent(EntityUid uid, Type type, [NotNullWhen(true)] out IComponent? component)
|
||||
{
|
||||
|
||||
@@ -176,6 +176,14 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>True if the entity has the component type, otherwise false.</returns>
|
||||
bool HasComponent<T>([NotNullWhen(true)] EntityUid? uid) where T : IComponent;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the entity has a component type.
|
||||
/// </summary>
|
||||
/// <param name="uid">Entity UID to check.</param>
|
||||
/// <param name="reg">The component registration to check for.</param>
|
||||
/// <returns>True if the entity has the component type, otherwise false.</returns>
|
||||
bool HasComponent(EntityUid uid, ComponentRegistration reg);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the entity has a component type.
|
||||
/// </summary>
|
||||
@@ -294,6 +302,15 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>If the component existed in the entity.</returns>
|
||||
bool TryGetComponent<T>([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out T? component) where T : IComponent?;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the component of a specific type.
|
||||
/// </summary>
|
||||
/// <param name="uid">Entity UID to check.</param>
|
||||
/// <param name="reg">The component registration to check for.</param>
|
||||
/// <param name="component">Component of the specified type (if exists).</param>
|
||||
/// <returns>If the component existed in the entity.</returns>
|
||||
bool TryGetComponent(EntityUid uid, ComponentRegistration reg, [NotNullWhen(true)] out IComponent? component);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the component of a specific type.
|
||||
/// </summary>
|
||||
|
||||
@@ -119,7 +119,8 @@ public abstract partial class SharedTransformSystem
|
||||
|
||||
public bool AnchorEntity(Entity<TransformComponent> entity, Entity<MapGridComponent>? grid = null)
|
||||
{
|
||||
DebugTools.Assert(grid == null || grid.Value.Owner == entity.Comp.GridUid);
|
||||
DebugTools.Assert(grid == null || grid.Value.Owner == entity.Comp.GridUid,
|
||||
$"Tried to anchor entity {Name(entity)} to a grid ({grid!.Value.Owner}) different from its GridUid ({entity.Comp.GridUid})");
|
||||
|
||||
if (grid == null)
|
||||
{
|
||||
|
||||
@@ -41,13 +41,6 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
/// </summary>
|
||||
private readonly List<(BoundUserInterface Bui, bool value)> _queuedBuis = new();
|
||||
|
||||
/// <summary>
|
||||
/// Temporary storage for BUI keys
|
||||
/// </summary>
|
||||
private ValueList<Enum> _keys = new();
|
||||
|
||||
private ValueList<EntityUid> _entList = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -288,11 +281,12 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
|
||||
protected virtual void OnUserInterfaceShutdown(Entity<UserInterfaceComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
var ents = new ValueList<EntityUid>();
|
||||
foreach (var (key, acts) in ent.Comp.Actors)
|
||||
{
|
||||
_entList.Clear();
|
||||
_entList.AddRange(acts);
|
||||
foreach (var actor in _entList)
|
||||
ents.Clear();
|
||||
ents.AddRange(acts);
|
||||
foreach (var actor in ents)
|
||||
{
|
||||
CloseUiInternal(ent!, key, actor);
|
||||
DebugTools.Assert(!acts.Contains(actor));
|
||||
@@ -487,7 +481,7 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
|
||||
ent.Comp.States[key] = buiState;
|
||||
|
||||
if (!ent.Comp.ClientOpenInterfaces.TryGetValue(key, out var cBui))
|
||||
if (!ent.Comp.ClientOpenInterfaces.TryGetValue(key, out var cBui) || !cBui.IsOpened)
|
||||
continue;
|
||||
|
||||
cBui.State = buiState;
|
||||
@@ -755,8 +749,11 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
// Predict the change on client
|
||||
if (state != null && _netManager.IsClient && entity.Comp.ClientOpenInterfaces.TryGetValue(key, out var bui))
|
||||
{
|
||||
bui.UpdateState(state);
|
||||
bui.Update();
|
||||
if (bui.State?.Equals(state) != true)
|
||||
{
|
||||
bui.UpdateState(state);
|
||||
bui.Update();
|
||||
}
|
||||
}
|
||||
|
||||
DirtyField(entity, nameof(UserInterfaceComponent.States));
|
||||
@@ -894,12 +891,13 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
if (actor.Comp.OpenInterfaces.Count == 0)
|
||||
return;
|
||||
|
||||
var keys = new ValueList<Enum>();
|
||||
foreach (var (uid, enums) in actor.Comp.OpenInterfaces)
|
||||
{
|
||||
_keys.Clear();
|
||||
_keys.AddRange(enums);
|
||||
keys.Clear();
|
||||
keys.AddRange(enums);
|
||||
|
||||
foreach (var weh in _keys)
|
||||
foreach (var weh in keys)
|
||||
{
|
||||
if (weh is not T)
|
||||
continue;
|
||||
@@ -920,12 +918,14 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
if (actor.Comp.OpenInterfaces.Count == 0)
|
||||
return;
|
||||
|
||||
var keys = new ValueList<Enum>();
|
||||
|
||||
foreach (var (uid, enums) in actor.Comp.OpenInterfaces)
|
||||
{
|
||||
_keys.Clear();
|
||||
_keys.AddRange(enums);
|
||||
keys.Clear();
|
||||
keys.AddRange(enums);
|
||||
|
||||
foreach (var key in _keys)
|
||||
foreach (var key in keys)
|
||||
{
|
||||
CloseUiInternal(uid, key, actor.Owner);
|
||||
}
|
||||
|
||||
50
Robust.Shared/GameStates/SharedPvsOverrideSystem.cs
Normal file
50
Robust.Shared/GameStates/SharedPvsOverrideSystem.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Robust.Shared.GameStates;
|
||||
|
||||
public abstract class SharedPvsOverrideSystem : EntitySystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations,
|
||||
/// causing them to always be sent to all clients.
|
||||
/// </summary>
|
||||
public virtual void AddGlobalOverride(EntityUid uid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an entity from the global overrides.
|
||||
/// </summary>
|
||||
public virtual void RemoveGlobalOverride(EntityUid uid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations for a
|
||||
/// specific session.
|
||||
/// </summary>
|
||||
public virtual void AddSessionOverride(EntityUid uid, ICommonSession session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an entity from a session's overrides.
|
||||
/// </summary>
|
||||
public virtual void RemoveSessionOverride(EntityUid uid, ICommonSession session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the entity, all of its parents, and all of its children to ignore normal PVS range limitations,
|
||||
/// causing them to always be sent to all clients.
|
||||
/// </summary>
|
||||
public virtual void AddSessionOverrides(EntityUid uid, Filter filter)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ public sealed partial class MapLightComponent : Component
|
||||
/// <summary>
|
||||
/// Ambient light. This is in linear-light, i.e. when providing a fixed colour, you must use Color.FromSrgb(Color.Black)!
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("ambientLightColor")]
|
||||
public Color AmbientLightColor { get; set; } = Color.FromSrgb(Color.Black);
|
||||
[DataField]
|
||||
public Color AmbientLightColor = Color.FromSrgb(Color.Black);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Map;
|
||||
@@ -16,9 +17,9 @@ public readonly struct Tile : IEquatable<Tile>, ISpanFormattable
|
||||
public readonly int TypeId;
|
||||
|
||||
/// <summary>
|
||||
/// Rendering flags.
|
||||
/// Custom flags for additional tile-data.
|
||||
/// </summary>
|
||||
public readonly TileRenderFlag Flags;
|
||||
public readonly byte Flags;
|
||||
|
||||
/// <summary>
|
||||
/// Variant of this tile to render.
|
||||
@@ -39,9 +40,9 @@ public readonly struct Tile : IEquatable<Tile>, ISpanFormattable
|
||||
/// Creates a new instance of a grid tile.
|
||||
/// </summary>
|
||||
/// <param name="typeId">Internal type ID.</param>
|
||||
/// <param name="flags">Flags used by toolbox's rendering.</param>
|
||||
/// <param name="flags">Custom tile flags for usage.</param>
|
||||
/// <param name="variant">The visual variant this tile is using.</param>
|
||||
public Tile(int typeId, TileRenderFlag flags = 0, byte variant = 0)
|
||||
public Tile(int typeId, byte flags = 0, byte variant = 0)
|
||||
{
|
||||
TypeId = typeId;
|
||||
Flags = flags;
|
||||
@@ -112,9 +113,19 @@ public readonly struct Tile : IEquatable<Tile>, ISpanFormattable
|
||||
return (TypeId.GetHashCode() * 397) ^ Flags.GetHashCode() ^ Variant.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public Tile WithVariant(byte variant)
|
||||
{
|
||||
return new Tile(TypeId, Flags, variant);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public Tile WithFlag(byte flag)
|
||||
{
|
||||
return new Tile(TypeId, flags: flag, variant: Variant);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TileRenderFlag : byte
|
||||
{
|
||||
public sealed class TileFlagLayer {}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,14 +26,23 @@ public partial class SerializationManager
|
||||
|
||||
public DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null)
|
||||
{
|
||||
// TODO SERIALIZATION
|
||||
// Add variant that doesn't require a parent array.
|
||||
|
||||
// TODO SERIALIZATION
|
||||
// Change inheritance pushing so that it modifies the passed in child. This avoids re-creating the child
|
||||
// multiple times when there are multiple children.
|
||||
//
|
||||
// I.e., change the PushCompositionDelegate signature to not have a return value, and also add an override
|
||||
// of this method that modified the given child.
|
||||
|
||||
if (parents.Length == 0)
|
||||
return child.Copy();
|
||||
|
||||
DebugTools.Assert(parents.All(x => x.GetType() == child.GetType()));
|
||||
|
||||
// TODO SERIALIZATION
|
||||
// Change inheritance pushing so that it modifies the passed in child.
|
||||
// I.e., move the child.Clone() statement to the beginning here, then make the delegate modify the clone.
|
||||
|
||||
// the child.Clone() statement to the beginning here, then make the delegate modify the clone.
|
||||
// Currently pusing more than one parent requires multiple unnecessary clones.
|
||||
|
||||
var pusher = GetOrCreatePushCompositionDelegate(type, child);
|
||||
|
||||
@@ -57,13 +57,11 @@ namespace Robust.Shared.Serialization.Manager
|
||||
|
||||
foreach (var flagType in bitflagType.GetCustomAttributes<FlagsForAttribute>(true))
|
||||
{
|
||||
if (_flagsMapping.ContainsKey(flagType.Tag))
|
||||
if (!_flagsMapping.TryAdd(flagType.Tag, bitflagType))
|
||||
{
|
||||
throw new NotSupportedException($"Multiple bitflag enums declared for the tag {flagType.Tag}.");
|
||||
}
|
||||
|
||||
_flagsMapping.Add(flagType.Tag, bitflagType);
|
||||
|
||||
var highestBit = bitflagType
|
||||
.GetEnumValues()
|
||||
.Cast<int>()
|
||||
|
||||
@@ -400,7 +400,11 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
|
||||
public bool TryAdd(DataNode key, DataNode value)
|
||||
{
|
||||
return _children.TryAdd(key, value);
|
||||
if (!_children.TryAdd(key, value))
|
||||
return false;
|
||||
|
||||
_list.Add(new(key, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryAddCopy(DataNode key, DataNode value)
|
||||
@@ -410,6 +414,7 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
return false;
|
||||
|
||||
entry = value.Copy();
|
||||
_list.Add(new(key, entry));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ namespace Robust.UnitTesting.Shared.Map
|
||||
gridOptions.ChunkSize = 8;
|
||||
var grid = mapMan.CreateGridEntity(mapId, gridOptions);
|
||||
|
||||
mapSystem.SetTile(grid, new Vector2i(-9, -1), new Tile(1, (TileRenderFlag)1, 1));
|
||||
mapSystem.SetTile(grid, new Vector2i(-9, -1), new Tile(typeId: 1, flags: 1, variant: 1));
|
||||
var result = mapSystem.GetTileRef(grid.Owner, grid.Comp, new Vector2i(-9, -1));
|
||||
|
||||
Assert.That(grid.Comp.ChunkCount, Is.EqualTo(1));
|
||||
Assert.That(mapSystem.GetMapChunks(grid.Owner, grid.Comp).Keys.ToList()[0], Is.EqualTo(new Vector2i(-2, -1)));
|
||||
Assert.That(result, Is.EqualTo(new TileRef(grid.Owner, new Vector2i(-9,-1), new Tile(1, (TileRenderFlag)1, 1))));
|
||||
Assert.That(result, Is.EqualTo(new TileRef(grid.Owner, new Vector2i(-9,-1), new Tile(typeId: 1, flags: 1, variant: 1))));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -169,14 +169,14 @@ namespace Robust.UnitTesting.Shared.Map
|
||||
gridOptions.ChunkSize = 8;
|
||||
var grid = mapMan.CreateGridEntity(mapId, gridOptions);
|
||||
|
||||
mapSystem.SetTile(grid, new Vector2i(-9, -1), new Tile(1, (TileRenderFlag)1, 1));
|
||||
mapSystem.SetTile(grid, new Vector2i(-9, -1), new Tile(typeId: 1, flags: 1, variant: 1));
|
||||
|
||||
var foundTile = mapSystem.TryGetTileRef(grid.Owner, grid.Comp, new Vector2i(-9, -1), out var tileRef);
|
||||
|
||||
Assert.That(foundTile, Is.True);
|
||||
Assert.That(grid.Comp.ChunkCount, Is.EqualTo(1));
|
||||
Assert.That(mapSystem.GetMapChunks(grid.Owner, grid.Comp).Keys.ToList()[0], Is.EqualTo(new Vector2i(-2, -1)));
|
||||
Assert.That(tileRef, Is.EqualTo(new TileRef(grid.Owner, new Vector2i(-9, -1), new Tile(1, (TileRenderFlag)1, 1))));
|
||||
Assert.That(tileRef, Is.EqualTo(new TileRef(grid.Owner, new Vector2i(-9, -1), new Tile(typeId: 1, flags: 1, variant: 1))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -78,7 +78,7 @@ public sealed class GridDeleteSingleTileRemoveTestTest : RobustIntegrationTest
|
||||
sMap = sys.CreateMap(out var mapId);
|
||||
var comp = mapMan.CreateGridEntity(mapId);
|
||||
grid = (comp.Owner, comp);
|
||||
sys.SetTile(grid, grid, new Vector2i(0, 0), new Tile(1, (TileRenderFlag)1, 1));
|
||||
sys.SetTile(grid, grid, new Vector2i(0, 0), new Tile(typeId: 1, flags: 1, variant: 1));
|
||||
var coords = new EntityCoordinates(grid, 0.5f, 0.5f);
|
||||
|
||||
sPlayer = sEntMan.SpawnEntity(null, coords);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Robust.UnitTesting.Shared.Resources
|
||||
_testDir = Directory.CreateDirectory(_testDirPath);
|
||||
var subDir = Path.Combine(_testDirPath, "writable");
|
||||
|
||||
_dirProvider = new WritableDirProvider(Directory.CreateDirectory(subDir));
|
||||
_dirProvider = new WritableDirProvider(Directory.CreateDirectory(subDir), hideRootDir: false);
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
|
||||
Reference in New Issue
Block a user