mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3538d2797d | ||
|
|
f7cb66f832 | ||
|
|
c9f6fc7182 | ||
|
|
bc8b37de9a | ||
|
|
9d1b15ab4b | ||
|
|
ea1cc5e446 | ||
|
|
bcb5c2d35d | ||
|
|
c011eff80e | ||
|
|
e163c496c3 | ||
|
|
fec81bc2a1 | ||
|
|
7016facb9a | ||
|
|
0c41a041e3 | ||
|
|
55571ef5b1 | ||
|
|
afaef645b0 | ||
|
|
d442d90d60 |
@@ -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,60 @@ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ 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)
|
||||
|
||||
@@ -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));
|
||||
@@ -897,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;
|
||||
@@ -923,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);
|
||||
}
|
||||
|
||||
@@ -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