mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 11:40:52 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd01ca924b | ||
|
|
38ad8ce132 | ||
|
|
ee440c2df9 | ||
|
|
32f3c863fb | ||
|
|
b00e0bef5a | ||
|
|
0a09b27918 | ||
|
|
c9f6a4e32a | ||
|
|
b205a14f69 | ||
|
|
d5f3292e0a | ||
|
|
561e4b330e | ||
|
|
36a5d102ff | ||
|
|
b9c39e0953 | ||
|
|
ad4c8be132 | ||
|
|
988cbf9a87 | ||
|
|
e26512001a | ||
|
|
8e97982f1e |
@@ -153,7 +153,7 @@ namespace {nameSpace}
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
typeSymbol.Locations[0]));
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
var txt = relevantXamlFile.GetText()?.ToString();
|
||||
@@ -169,7 +169,7 @@ namespace {nameSpace}
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
Location.Create(xamlFileName, new TextSpan(0,0), new LinePositionSpan(new LinePosition(0,0),new LinePosition(0,0)))));
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
@@ -189,7 +189,7 @@ namespace {nameSpace}
|
||||
DiagnosticSeverity.Error,
|
||||
true),
|
||||
typeSymbol.Locations[0]));
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client
|
||||
@@ -50,16 +49,28 @@ namespace Robust.Client
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_net.RegisterNetMessage<MsgSetTickRate>(MsgSetTickRate.NAME, HandleSetTickRate);
|
||||
_net.Connected += OnConnected;
|
||||
_net.ConnectFailed += OnConnectFailed;
|
||||
_net.Disconnect += OnNetDisconnect;
|
||||
|
||||
_configManager.OnValueChanged(CVars.NetTickrate, TickRateChanged);
|
||||
|
||||
_playMan.Initialize();
|
||||
_debugDrawMan.Initialize();
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void TickRateChanged(int tickrate)
|
||||
{
|
||||
if (GameInfo != null)
|
||||
{
|
||||
GameInfo.TickRate = (byte) tickrate;
|
||||
}
|
||||
|
||||
_timing.TickRate = (byte) tickrate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {tickrate} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ConnectToServer(DnsEndPoint endPoint)
|
||||
{
|
||||
@@ -119,11 +130,6 @@ namespace Robust.Client
|
||||
var maxPlayers = _configManager.GetCVar<int>("game.maxplayers");
|
||||
info.ServerMaxPlayers = maxPlayers;
|
||||
|
||||
var tickrate = _configManager.GetCVar<int>("net.tickrate");
|
||||
info.TickRate = (byte) tickrate;
|
||||
_timing.TickRate = (byte) tickrate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {tickrate}");
|
||||
|
||||
var userName = _net.ServerChannel!.UserName;
|
||||
var userId = _net.ServerChannel.UserId;
|
||||
_discord.Update(info.ServerName, userName, info.ServerMaxPlayers.ToString());
|
||||
@@ -168,6 +174,7 @@ namespace Robust.Client
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_configManager.ClearReceivedInitialNwVars();
|
||||
OnRunLevelChanged(ClientRunLevel.Initialize);
|
||||
}
|
||||
|
||||
@@ -194,12 +201,6 @@ namespace Robust.Client
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void HandleSetTickRate(MsgSetTickRate message)
|
||||
{
|
||||
_timing.TickRate = message.NewTickRate;
|
||||
Logger.InfoS("client", $"Tickrate changed to: {message.NewTickRate} on tick {_timing.CurTick}");
|
||||
}
|
||||
|
||||
private void OnLocalStatusChanged(object? obj, StatusEventArgs eventArgs)
|
||||
{
|
||||
// player finished fully connecting to the server.
|
||||
|
||||
@@ -709,7 +709,8 @@ namespace Robust.Client.Console.Commands
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.Enabled = !mgr.Enabled;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.Enabled = !mgr.Enabled;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -722,10 +723,12 @@ namespace Robust.Client.Console.Commands
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<IEyeManager>();
|
||||
if (mgr.CurrentEye != null)
|
||||
mgr.CurrentEye.DrawFov = !mgr.CurrentEye.DrawFov;
|
||||
return false;
|
||||
var lmgr = IoCManager.Resolve<ILightManager>();
|
||||
var mgr = IoCManager.Resolve<IEyeManager>();
|
||||
if (!lmgr.LockConsoleAccess)
|
||||
if (mgr.CurrentEye != null)
|
||||
mgr.CurrentEye.DrawFov = !mgr.CurrentEye.DrawFov;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,7 +741,8 @@ namespace Robust.Client.Console.Commands
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.DrawHardFov = !mgr.DrawHardFov;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawHardFov = !mgr.DrawHardFov;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -752,7 +756,22 @@ namespace Robust.Client.Console.Commands
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
mgr.DrawShadows = !mgr.DrawShadows;
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawShadows = !mgr.DrawShadows;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
internal class ToggleLightBuf : IConsoleCommand
|
||||
{
|
||||
public string Command => "togglelightbuf";
|
||||
public string Description => "Toggles lighting rendering. This includes shadows but not FOV.";
|
||||
public string Help => "togglelightbuf";
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var mgr = IoCManager.Resolve<ILightManager>();
|
||||
if (!mgr.LockConsoleAccess)
|
||||
mgr.DrawLighting = !mgr.DrawLighting;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private const string UniProjViewMatrices = "projectionViewMatrices";
|
||||
private const string UniUniformConstants = "uniformConstants";
|
||||
|
||||
private static readonly Color AmbientLightColor = Color.Black;
|
||||
|
||||
private const int BindingIndexProjView = 0;
|
||||
private const int BindingIndexUniformConstants = 1;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Buffers;
|
||||
using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -30,7 +31,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// Horizontal width, in pixels, of the shadow maps used to render FOV.
|
||||
// I figured this was more accuracy sensitive than lights so resolution is significantly higher.
|
||||
private const int FovMapSize = 2048;
|
||||
private const int MaxLightsPerScene = 128;
|
||||
|
||||
// The maximum possible amount of lights in the light list.
|
||||
// In the average case, the only cost of increasing this value is memory.
|
||||
// If you are ever in a situation where this value needs to be increased, however, it will also implicitly cost some CPU time to sort the additional lights.
|
||||
private const int LightsToRenderListSize = 2048;
|
||||
|
||||
private ClydeShaderInstance _fovDebugShaderInstance = default!;
|
||||
|
||||
@@ -80,16 +85,18 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
// For depth calculation of lighting shadows.
|
||||
private RenderTexture _shadowRenderTarget = default!;
|
||||
// Used because otherwise a MaxLightsPerScene change callback getting hit on startup causes interesting issues (read: bugs)
|
||||
private bool _shadowRenderTargetCanInitializeSafely = false;
|
||||
|
||||
// Proxies to textures of the above render targets.
|
||||
private ClydeTexture FovTexture => _fovRenderTarget.Texture;
|
||||
private ClydeTexture ShadowTexture => _shadowRenderTarget.Texture;
|
||||
|
||||
private readonly (PointLightComponent light, Vector2 pos)[] _lightsToRenderList
|
||||
= new (PointLightComponent light, Vector2 pos)[MaxLightsPerScene];
|
||||
private (PointLightComponent light, Vector2 pos, float distanceSquared)[] _lightsToRenderList = new (PointLightComponent light, Vector2 pos, float distanceSquared)[LightsToRenderListSize];
|
||||
|
||||
private unsafe void InitLighting()
|
||||
{
|
||||
// Other...
|
||||
LoadLightingShaders();
|
||||
|
||||
{
|
||||
@@ -160,10 +167,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
// Shadow FBO.
|
||||
_shadowRenderTarget = CreateRenderTarget((ShadowMapSize, MaxLightsPerScene),
|
||||
new RenderTargetFormatParameters(_hasGLFloatFramebuffers ? RenderTargetColorFormat.RG32F : RenderTargetColorFormat.Rgba8, true),
|
||||
new TextureSampleParameters {WrapMode = TextureWrapMode.Repeat, Filter = true},
|
||||
nameof(_shadowRenderTarget));
|
||||
_shadowRenderTargetCanInitializeSafely = true;
|
||||
MaxLightsPerSceneChanged(_maxLightsPerScene);
|
||||
}
|
||||
|
||||
private void LoadLightingShaders()
|
||||
@@ -334,6 +339,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
DrawFov(viewport, eye);
|
||||
|
||||
if (!_lightManager.DrawLighting)
|
||||
{
|
||||
BindRenderTargetFull(viewport.RenderTarget);
|
||||
GL.Viewport(0, 0, viewport.Size.X, viewport.Size.Y);
|
||||
CheckGlError();
|
||||
return;
|
||||
}
|
||||
|
||||
using (DebugGroup("Draw shadow depth"))
|
||||
{
|
||||
PrepareDepthDraw(RtToLoaded(_shadowRenderTarget));
|
||||
@@ -344,7 +357,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var (light, lightPos) = lights[i];
|
||||
var (light, lightPos, _) = lights[i];
|
||||
|
||||
DrawOcclusionDepth(lightPos, ShadowMapSize, light.Radius, i);
|
||||
}
|
||||
@@ -355,7 +368,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
BindRenderTargetImmediate(RtToLoaded(viewport.LightRenderTarget));
|
||||
CheckGlError();
|
||||
GLClearColor(Color.FromSrgb(AmbientLightColor));
|
||||
GLClearColor(_lightManager.AmbientLightColor);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
CheckGlError();
|
||||
|
||||
@@ -382,7 +395,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var (component, lightPos) = lights[i];
|
||||
var (component, lightPos, _) = lights[i];
|
||||
|
||||
var transform = component.Owner.Transform;
|
||||
|
||||
@@ -473,25 +486,24 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_lightingReady = true;
|
||||
}
|
||||
|
||||
private ((PointLightComponent light, Vector2 pos)[] lights, int count, Box2 expandedBounds)
|
||||
private ((PointLightComponent light, Vector2 pos, float distanceSquared)[] lights, int count, Box2 expandedBounds)
|
||||
GetLightsToRender(MapId map, in Box2 worldBounds)
|
||||
{
|
||||
// When culling occluders later, we can't just remove any occluders outside the worldBounds.
|
||||
// As they could still affect the shadows of (large) light sources.
|
||||
// We expand the world bounds so that it encompasses the center of every light source.
|
||||
// This should make it so no culled occluder can make a difference.
|
||||
// (if the occluder is in the current lights at all, it's still not between the light and the world bounds).
|
||||
var expandedBounds = worldBounds;
|
||||
|
||||
var renderingTreeSystem = _entitySystemManager.GetEntitySystem<RenderingTreeSystem>();
|
||||
var lightTree = renderingTreeSystem.GetLightTreeForMap(map);
|
||||
|
||||
var state = (this, expandedBounds, count: 0);
|
||||
var state = (this, worldBounds, count: 0);
|
||||
|
||||
lightTree.QueryAabb(ref state, (ref (Clyde clyde, Box2 expandedBounds, int count) state, in PointLightComponent light) =>
|
||||
lightTree.QueryAabb(ref state, (ref (Clyde clyde, Box2 worldBounds, int count) state, in PointLightComponent light) =>
|
||||
{
|
||||
var transform = light.Owner.Transform;
|
||||
|
||||
if (state.count >= LightsToRenderListSize)
|
||||
{
|
||||
// There are too many lights to fit in the static memory.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!light.Enabled || light.ContainerOccluded)
|
||||
{
|
||||
return true;
|
||||
@@ -501,26 +513,45 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var circle = new Circle(lightPos, light.Radius);
|
||||
|
||||
if (!circle.Intersects(state.expandedBounds))
|
||||
// If the light doesn't touch anywhere the camera can see, it doesn't matter.
|
||||
if (!circle.Intersects(state.worldBounds))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
state.clyde._lightsToRenderList[state.count] = (light, lightPos);
|
||||
state.count += 1;
|
||||
|
||||
state.expandedBounds = state.expandedBounds.ExtendToContain(lightPos);
|
||||
|
||||
if (state.count == MaxLightsPerScene)
|
||||
{
|
||||
// TODO: Allow more than MaxLightsPerScene lights.
|
||||
return false;
|
||||
}
|
||||
float distanceSquared = (state.worldBounds.Center - lightPos).LengthSquared;
|
||||
state.clyde._lightsToRenderList[state.count++] = (light, lightPos, distanceSquared);
|
||||
|
||||
return true;
|
||||
}, expandedBounds);
|
||||
}, worldBounds);
|
||||
|
||||
return (_lightsToRenderList, state.count, state.expandedBounds);
|
||||
if (state.count > _maxLightsPerScene)
|
||||
{
|
||||
// There are too many lights to fit in the scene.
|
||||
// This check must occur before occluder expansion, or else bad things happen.
|
||||
// Sort lights by distance.
|
||||
Array.Sort(_lightsToRenderList, 0, state.count, Comparer<(PointLightComponent light, Vector2 pos, float distanceSquared)>.Create((x, y) =>
|
||||
{
|
||||
return x.distanceSquared.CompareTo(y.distanceSquared);
|
||||
}));
|
||||
// Then effectively delete the furthest lights.
|
||||
state.count = _maxLightsPerScene;
|
||||
}
|
||||
|
||||
// When culling occluders later, we can't just remove any occluders outside the worldBounds.
|
||||
// As they could still affect the shadows of (large) light sources.
|
||||
// We expand the world bounds so that it encompasses the center of every light source.
|
||||
// This should make it so no culled occluder can make a difference.
|
||||
// (if the occluder is in the current lights at all, it's still not between the light and the world bounds).
|
||||
var expandedBounds = worldBounds;
|
||||
|
||||
for (var i = 0; i < state.count; i++)
|
||||
{
|
||||
var (_, lightPos, _) = _lightsToRenderList[i];
|
||||
expandedBounds = expandedBounds.ExtendToContain(lightPos);
|
||||
}
|
||||
|
||||
return (_lightsToRenderList, state.count, expandedBounds);
|
||||
}
|
||||
|
||||
private void BlurOntoWalls(Viewport viewport, IEye eye)
|
||||
@@ -959,6 +990,25 @@ namespace Robust.Client.Graphics.Clyde
|
||||
RegenAllLightRts();
|
||||
}
|
||||
|
||||
protected override void MaxLightsPerSceneChanged(int newValue)
|
||||
{
|
||||
_maxLightsPerScene = newValue;
|
||||
|
||||
// This guard is in place because otherwise the shadow FBO is initialized before GL is initialized.
|
||||
if (!_shadowRenderTargetCanInitializeSafely)
|
||||
return;
|
||||
|
||||
if (_shadowRenderTarget != null)
|
||||
{
|
||||
DeleteRenderTexture(_shadowRenderTarget.Handle);
|
||||
}
|
||||
// Shadow FBO.
|
||||
_shadowRenderTarget = CreateRenderTarget((ShadowMapSize, _maxLightsPerScene),
|
||||
new RenderTargetFormatParameters(_hasGLFloatFramebuffers ? RenderTargetColorFormat.RG32F : RenderTargetColorFormat.Rgba8, true),
|
||||
new TextureSampleParameters {WrapMode = TextureWrapMode.Repeat, Filter = true},
|
||||
nameof(_shadowRenderTarget));
|
||||
}
|
||||
|
||||
protected override void SoftShadowsChanged(bool newValue)
|
||||
{
|
||||
_enableSoftShadows = newValue;
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private GLShaderProgram? _currentProgram;
|
||||
|
||||
private int _lightmapDivider = 2;
|
||||
private int _maxLightsPerScene = 128;
|
||||
private bool _enableSoftShadows = true;
|
||||
|
||||
private bool _checkGLErrors;
|
||||
@@ -133,6 +134,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
base.ReadConfig();
|
||||
_lightmapDivider = _configurationManager.GetCVar(CVars.DisplayLightMapDivider);
|
||||
_maxLightsPerScene = _configurationManager.GetCVar(CVars.DisplayMaxLightsPerScene);
|
||||
_enableSoftShadows = _configurationManager.GetCVar(CVars.DisplaySoftShadows);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Robust.Client.Graphics
|
||||
_configurationManager.OnValueChanged(CVars.DisplayVSync, _vSyncChanged, true);
|
||||
_configurationManager.OnValueChanged(CVars.DisplayWindowMode, _windowModeChanged, true);
|
||||
_configurationManager.OnValueChanged(CVars.DisplayLightMapDivider, LightmapDividerChanged, true);
|
||||
_configurationManager.OnValueChanged(CVars.DisplayMaxLightsPerScene, MaxLightsPerSceneChanged, true);
|
||||
_configurationManager.OnValueChanged(CVars.DisplaySoftShadows, SoftShadowsChanged, true);
|
||||
|
||||
return true;
|
||||
@@ -76,6 +77,10 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void MaxLightsPerSceneChanged(int newValue)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void SoftShadowsChanged(bool newValue)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Client.Interfaces.Graphics.Lighting;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Graphics.Lighting
|
||||
{
|
||||
@@ -7,5 +8,8 @@ namespace Robust.Client.Graphics.Lighting
|
||||
public bool Enabled { get; set; } = true;
|
||||
public bool DrawShadows { get; set; } = true;
|
||||
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,9 +1,32 @@
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Interfaces.Graphics.Lighting
|
||||
{
|
||||
public interface ILightManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables/disables the entire light manager.
|
||||
/// </summary>
|
||||
bool Enabled { get; set; }
|
||||
/// <summary>
|
||||
/// Enables/disables shadows, but lights are still functional.
|
||||
/// </summary>
|
||||
bool DrawShadows { get; set; }
|
||||
/// <summary>
|
||||
/// Enables/disables hard FOV.
|
||||
/// </summary>
|
||||
bool DrawHardFov { get; set; }
|
||||
/// <summary>
|
||||
/// Enables/disables everything to do with the lighting buffer, without interfering with hard FOV.
|
||||
/// </summary>
|
||||
bool DrawLighting { get; set; }
|
||||
/// <summary>
|
||||
/// This is useful to prevent players messing with lighting setup when they shouldn't.
|
||||
/// </summary>
|
||||
bool LockConsoleAccess { get; set; }
|
||||
/// <summary>
|
||||
/// Ambient light. This is in linear-light, i.e. when providing a fixed colour, you must use Color.FromSrgb(Color.Black)!
|
||||
/// </summary>
|
||||
Color AmbientLightColor { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,8 +446,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var (vSepActual, hSepActual) = (Vector2i) (Separations * UIScale);
|
||||
var hSep = _limitDimension == Dimension.Column ? hSepActual : vSepActual;
|
||||
var vSep = _limitDimension == Dimension.Column ? vSepActual : hSepActual;
|
||||
var width = _limitDimension == Dimension.Column ? Width : Height;
|
||||
var height = _limitDimension == Dimension.Column ? Height : Width;
|
||||
var width = _limitDimension == Dimension.Column ? PixelWidth : PixelHeight;
|
||||
var height = _limitDimension == Dimension.Column ? PixelHeight : PixelWidth;
|
||||
|
||||
var stretchMaxX = width - hSep * (cols - 1);
|
||||
var stretchMaxY = height - vSep * (rows - 1);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -20,7 +19,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override void LayoutUpdateOverride()
|
||||
{
|
||||
var contentBox = _getStyleBox()?.GetContentBox(PixelSizeBox) ?? SizeBox;
|
||||
var contentBox = _getStyleBox()?.GetContentBox(PixelSizeBox) ?? PixelSizeBox;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
base.Draw(handle);
|
||||
|
||||
var bg = _getBackground();
|
||||
bg?.Draw(handle, SizeBox);
|
||||
bg?.Draw(handle, PixelSizeBox);
|
||||
|
||||
var fg = _getForeground();
|
||||
if (fg == null)
|
||||
@@ -69,10 +69,10 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
var minSize = fg.MinimumSize;
|
||||
var size = Width * GetAsRatio() - minSize.X;
|
||||
var size = PixelWidth * GetAsRatio() - minSize.X;
|
||||
if (size > 0)
|
||||
{
|
||||
fg.Draw(handle, UIBox2.FromDimensions(0, 0, minSize.X + size, Height));
|
||||
fg.Draw(handle, UIBox2.FromDimensions(0, 0, minSize.X + size, PixelHeight));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
var oldHeight = _entry.Height;
|
||||
var oldWidth = _entry.Width;
|
||||
_entry.Update(font, MaxWidth ?? Width, UIScale);
|
||||
_entry.Update(font, (MaxWidth ?? Width) * UIScale, UIScale);
|
||||
if (oldHeight != _entry.Height || MaxWidth != null && _entry.Width != oldWidth)
|
||||
{
|
||||
MinimumSizeChanged();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.ViewVariables.Editors
|
||||
{
|
||||
@@ -13,48 +15,32 @@ namespace Robust.Client.ViewVariables.Editors
|
||||
protected override Control MakeUI(object? value)
|
||||
{
|
||||
DebugTools.Assert(value!.GetType().IsEnum);
|
||||
var enumVal = (Enum)value;
|
||||
var enumType = value.GetType();
|
||||
var enumStorageType = enumType.GetEnumUnderlyingType();
|
||||
var enumList = Enum.GetValues(enumType);
|
||||
|
||||
var hBox = new HBoxContainer
|
||||
var optionButton = new OptionButton();
|
||||
foreach (var val in enumList)
|
||||
{
|
||||
CustomMinimumSize = new Vector2(200, 0)
|
||||
};
|
||||
var label = val?.ToString();
|
||||
if (label == null)
|
||||
continue;
|
||||
optionButton.AddItem(label, Convert.ToInt32(val));
|
||||
}
|
||||
|
||||
var lineEdit = new LineEdit
|
||||
{
|
||||
Text = enumVal.ToString(),
|
||||
Editable = !ReadOnly,
|
||||
SizeFlagsHorizontal = Control.SizeFlags.FillExpand
|
||||
};
|
||||
optionButton.SelectId(Convert.ToInt32(value));
|
||||
optionButton.Disabled = ReadOnly;
|
||||
|
||||
if (!ReadOnly)
|
||||
{
|
||||
lineEdit.OnTextEntered += e =>
|
||||
var underlyingType = Enum.GetUnderlyingType(value.GetType());
|
||||
optionButton.OnItemSelected += e =>
|
||||
{
|
||||
var parseSig = new []{typeof(string), typeof(NumberStyles), typeof(CultureInfo), enumStorageType.MakeByRefType()};
|
||||
var parseMethod = enumStorageType.GetMethod("TryParse", parseSig);
|
||||
DebugTools.AssertNotNull(parseMethod);
|
||||
|
||||
var parameters = new object?[] {e.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, null};
|
||||
var parseWorked = (bool)parseMethod!.Invoke(null, parameters)!;
|
||||
|
||||
if (parseWorked) // textbox was the underlying type
|
||||
{
|
||||
DebugTools.AssertNotNull(parameters[3]);
|
||||
ValueChanged(parameters[3]);
|
||||
}
|
||||
else if(Enum.TryParse(enumType, e.Text, true, out var enumValue))
|
||||
{
|
||||
var underlyingVal = Convert.ChangeType(enumValue, enumStorageType);
|
||||
ValueChanged(underlyingVal);
|
||||
}
|
||||
optionButton.SelectId(e.Id);
|
||||
ValueChanged(Convert.ChangeType(e.Id, underlyingType));
|
||||
};
|
||||
}
|
||||
|
||||
hBox.AddChild(lineEdit);
|
||||
return hBox;
|
||||
return optionButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,6 @@ namespace Robust.Server
|
||||
{
|
||||
netMan.Initialize(true);
|
||||
netMan.StartServer();
|
||||
netMan.RegisterNetMessage<MsgSetTickRate>(MsgSetTickRate.NAME);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -468,7 +467,6 @@ namespace Robust.Server
|
||||
_time.TickRate = b;
|
||||
|
||||
Logger.InfoS("game", $"Tickrate changed to: {b} on tick {_time.CurTick}");
|
||||
SendTickRateUpdateToClients(b);
|
||||
});
|
||||
|
||||
_time.TickRate = (byte) _config.GetCVar(CVars.NetTickrate);
|
||||
@@ -478,14 +476,6 @@ namespace Robust.Server
|
||||
Logger.InfoS("srv", $"Max players: {MaxPlayers}");
|
||||
}
|
||||
|
||||
private void SendTickRateUpdateToClients(byte newTickRate)
|
||||
{
|
||||
var msg = _network.CreateNetMessage<MsgSetTickRate>();
|
||||
msg.NewTickRate = newTickRate;
|
||||
|
||||
_network.ServerSendToAll(msg);
|
||||
}
|
||||
|
||||
// called right before main loop returns, do all saving/cleanup in here
|
||||
private void Cleanup()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Maps;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Server.Interfaces.Timing;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -111,7 +112,7 @@ namespace Robust.Server.Console.Commands
|
||||
{
|
||||
public string Command => "loadbp";
|
||||
public string Description => "Loads a blueprint from disk into the game.";
|
||||
public string Help => "loadbp <MapID> <Path>";
|
||||
public string Help => "loadbp <MapID> <Path> [storeUids]";
|
||||
|
||||
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||
{
|
||||
@@ -141,8 +142,14 @@ namespace Robust.Server.Console.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var loadOptions = new MapLoadOptions();
|
||||
if (args.Length > 2)
|
||||
{
|
||||
loadOptions.StoreMapUids = bool.Parse(args[2]);
|
||||
}
|
||||
|
||||
var mapLoader = IoCManager.Resolve<IMapLoader>();
|
||||
mapLoader.LoadBlueprint(mapId, args[1]);
|
||||
mapLoader.LoadBlueprint(mapId, args[1], loadOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Robust.Server.GameObjects.Components.UserInterface
|
||||
_stateDirty = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Switches between closed and open for a specific client.
|
||||
/// </summary>
|
||||
@@ -183,8 +183,8 @@ namespace Robust.Server.GameObjects.Components.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Opens this interface for a specific client.
|
||||
/// </summary>
|
||||
@@ -263,6 +263,7 @@ namespace Robust.Server.GameObjects.Components.UserInterface
|
||||
OnClosed?.Invoke(session);
|
||||
_subscribedSessions.Remove(session);
|
||||
_playerStateOverrides.Remove(session);
|
||||
session.PlayerStatusChanged -= OnSessionOnPlayerStatusChanged;
|
||||
|
||||
if (_subscribedSessions.Count == 0)
|
||||
{
|
||||
|
||||
18
Robust.Server/GameObjects/MapSaveIdComponent.cs
Normal file
18
Robust.Server/GameObjects/MapSaveIdComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Metadata component used to keep consistent UIDs inside map files cross saving.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This component stores the previous map UID of entities from map load.
|
||||
/// This can then be used to re-serialize the entity with the same UID for the merge driver to recognize.
|
||||
/// </remarks>
|
||||
public sealed class MapSaveIdComponent : Component
|
||||
{
|
||||
public override string Name => "MapSaveId";
|
||||
|
||||
public int Uid { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@ namespace Robust.Server.GameObjects
|
||||
Register<DebugExceptionInitializeComponent>();
|
||||
Register<DebugExceptionStartupComponent>();
|
||||
#endif
|
||||
|
||||
Register<MapSaveIdComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Map;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
@@ -7,9 +8,11 @@ namespace Robust.Server.Interfaces.Maps
|
||||
public interface IMapLoader
|
||||
{
|
||||
IMapGrid? LoadBlueprint(MapId mapId, string path);
|
||||
IMapGrid? LoadBlueprint(MapId mapId, string path, MapLoadOptions options);
|
||||
void SaveBlueprint(GridId gridId, string yamlPath);
|
||||
|
||||
void LoadMap(MapId mapId, string path);
|
||||
void LoadMap(MapId mapId, string path, MapLoadOptions options);
|
||||
void SaveMap(MapId mapId, string yamlPath);
|
||||
|
||||
event Action<YamlStream, string> LoadedMapData;
|
||||
|
||||
11
Robust.Server/Maps/MapLoadOptions.cs
Normal file
11
Robust.Server/Maps/MapLoadOptions.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Robust.Server.Maps
|
||||
{
|
||||
public sealed class MapLoadOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, UID components will be created for loaded entities
|
||||
/// to maintain consistency upon subsequent savings.
|
||||
/// </summary>
|
||||
public bool StoreMapUids { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ using Robust.Shared.GameObjects;
|
||||
using System.Globalization;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using System.Linq;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Interfaces.Timing;
|
||||
using Robust.Shared.GameObjects.Components.Map;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
@@ -29,6 +30,8 @@ namespace Robust.Server.Maps
|
||||
/// </summary>
|
||||
public class MapLoader : IMapLoader
|
||||
{
|
||||
private static readonly MapLoadOptions DefaultLoadOptions = new();
|
||||
|
||||
private const int MapFormatVersion = 2;
|
||||
|
||||
[Dependency] private readonly IResourceManager _resMan = default!;
|
||||
@@ -46,7 +49,8 @@ namespace Robust.Server.Maps
|
||||
{
|
||||
var grid = _mapManager.GetGrid(gridId);
|
||||
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager, _componentManager, _prototypeManager);
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager,
|
||||
_componentManager, _prototypeManager);
|
||||
context.RegisterGrid(grid);
|
||||
var root = context.Serialize();
|
||||
var document = new YamlDocument(root);
|
||||
@@ -68,6 +72,11 @@ namespace Robust.Server.Maps
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMapGrid? LoadBlueprint(MapId mapId, string path)
|
||||
{
|
||||
return LoadBlueprint(mapId, path, DefaultLoadOptions);
|
||||
}
|
||||
|
||||
public IMapGrid? LoadBlueprint(MapId mapId, string path, MapLoadOptions options)
|
||||
{
|
||||
TextReader reader;
|
||||
var resPath = new ResourcePath(path).ToRootedPath();
|
||||
@@ -108,7 +117,8 @@ namespace Robust.Server.Maps
|
||||
throw new InvalidDataException("Cannot instance map with multiple grids as blueprint.");
|
||||
}
|
||||
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager, _componentManager, _prototypeManager, (YamlMappingNode)data.RootNode, mapId);
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager,
|
||||
_componentManager, _prototypeManager, (YamlMappingNode) data.RootNode, mapId, options);
|
||||
context.Deserialize();
|
||||
grid = context.Grids[0];
|
||||
|
||||
@@ -128,7 +138,8 @@ namespace Robust.Server.Maps
|
||||
public void SaveMap(MapId mapId, string yamlPath)
|
||||
{
|
||||
Logger.InfoS("map", $"Saving map {mapId} to {yamlPath}");
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager, _componentManager, _prototypeManager);
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager,
|
||||
_componentManager, _prototypeManager);
|
||||
foreach (var grid in _mapManager.GetAllMapGrids(mapId))
|
||||
{
|
||||
context.RegisterGrid(grid);
|
||||
@@ -149,11 +160,16 @@ namespace Robust.Server.Maps
|
||||
stream.Save(new YamlMappingFix(new Emitter(writer)), false);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.InfoS("map", "Save completed!");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void LoadMap(MapId mapId, string path)
|
||||
{
|
||||
LoadMap(mapId, path, DefaultLoadOptions);
|
||||
}
|
||||
|
||||
public void LoadMap(MapId mapId, string path, MapLoadOptions options)
|
||||
{
|
||||
TextReader reader;
|
||||
var resPath = new ResourcePath(path).ToRootedPath();
|
||||
@@ -188,7 +204,8 @@ namespace Robust.Server.Maps
|
||||
|
||||
LoadedMapData?.Invoke(data.Stream, resPath.ToString());
|
||||
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager, _componentManager, _prototypeManager, (YamlMappingNode)data.RootNode, mapId);
|
||||
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _pauseManager,
|
||||
_componentManager, _prototypeManager, (YamlMappingNode) data.RootNode, mapId, options);
|
||||
context.Deserialize();
|
||||
|
||||
if (!context.MapIsPostInit && _pauseManager.IsMapInitialized(mapId))
|
||||
@@ -213,6 +230,7 @@ namespace Robust.Server.Maps
|
||||
private readonly IComponentManager _componentManager;
|
||||
private readonly IPrototypeManager _prototypeManager;
|
||||
|
||||
private readonly MapLoadOptions? _loadOptions;
|
||||
private readonly Dictionary<GridId, int> GridIDMap = new();
|
||||
public readonly List<IMapGrid> Grids = new();
|
||||
|
||||
@@ -225,8 +243,6 @@ namespace Robust.Server.Maps
|
||||
|
||||
private bool IsBlueprintMode => GridIDMap.Count == 1;
|
||||
|
||||
private int uidCounter;
|
||||
|
||||
private readonly YamlMappingNode RootNode;
|
||||
private readonly MapId TargetMap;
|
||||
|
||||
@@ -239,7 +255,9 @@ namespace Robust.Server.Maps
|
||||
|
||||
public bool MapIsPostInit { get; private set; }
|
||||
|
||||
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs, IServerEntityManagerInternal entities, IPauseManager pauseManager, IComponentManager componentManager, IPrototypeManager prototypeManager)
|
||||
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs,
|
||||
IServerEntityManagerInternal entities, IPauseManager pauseManager, IComponentManager componentManager,
|
||||
IPrototypeManager prototypeManager)
|
||||
{
|
||||
_mapManager = maps;
|
||||
_tileDefinitionManager = tileDefs;
|
||||
@@ -251,14 +269,17 @@ namespace Robust.Server.Maps
|
||||
RootNode = new YamlMappingNode();
|
||||
}
|
||||
|
||||
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs, IServerEntityManagerInternal entities,
|
||||
IPauseManager pauseManager, IComponentManager componentManager, IPrototypeManager prototypeManager, YamlMappingNode node, MapId targetMapId)
|
||||
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs,
|
||||
IServerEntityManagerInternal entities,
|
||||
IPauseManager pauseManager, IComponentManager componentManager, IPrototypeManager prototypeManager,
|
||||
YamlMappingNode node, MapId targetMapId, MapLoadOptions options)
|
||||
{
|
||||
_mapManager = maps;
|
||||
_tileDefinitionManager = tileDefs;
|
||||
_serverEntityManager = entities;
|
||||
_pauseManager = pauseManager;
|
||||
_componentManager = componentManager;
|
||||
_loadOptions = options;
|
||||
|
||||
RootNode = node;
|
||||
TargetMap = targetMapId;
|
||||
@@ -438,8 +459,8 @@ namespace Robust.Server.Maps
|
||||
var newId = new GridId?();
|
||||
YamlGridSerializer.DeserializeGrid(
|
||||
_mapManager, TargetMap, ref newId,
|
||||
(YamlMappingNode)grid["settings"],
|
||||
(YamlSequenceNode)grid["chunks"],
|
||||
(YamlMappingNode) grid["settings"],
|
||||
(YamlSequenceNode) grid["chunks"],
|
||||
_tileMap!,
|
||||
_tileDefinitionManager
|
||||
);
|
||||
@@ -489,6 +510,12 @@ namespace Robust.Server.Maps
|
||||
Entities.Add(entity);
|
||||
UidEntityMap.Add(uid, entity.Uid);
|
||||
_entitiesToDeserialize.Add((entity, entityDef));
|
||||
|
||||
if (_loadOptions!.StoreMapUids)
|
||||
{
|
||||
var comp = entity.AddComponent<MapSaveIdComponent>();
|
||||
comp.Uid = uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +528,7 @@ namespace Robust.Server.Maps
|
||||
{
|
||||
foreach (var compData in componentList)
|
||||
{
|
||||
CurrentReadingEntityComponents[compData["type"].AsString()] = (YamlMappingNode)compData;
|
||||
CurrentReadingEntityComponents[compData["type"].AsString()] = (YamlMappingNode) compData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,15 +632,55 @@ namespace Robust.Server.Maps
|
||||
|
||||
private void PopulateEntityList()
|
||||
{
|
||||
var withUid = new List<MapSaveIdComponent>();
|
||||
var withoutUid = new List<IEntity>();
|
||||
var takenIds = new HashSet<int>();
|
||||
|
||||
foreach (var entity in _serverEntityManager.GetEntities())
|
||||
{
|
||||
if (IsMapSavable(entity))
|
||||
{
|
||||
var uid = uidCounter++;
|
||||
EntityUidMap.Add(entity.Uid, uid);
|
||||
Entities.Add(entity);
|
||||
if (entity.TryGetComponent(out MapSaveIdComponent? mapSaveId))
|
||||
{
|
||||
withUid.Add(mapSaveId);
|
||||
}
|
||||
else
|
||||
{
|
||||
withoutUid.Add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go over entities with a MapSaveIdComponent and assign those.
|
||||
|
||||
foreach (var mapIdComp in withUid)
|
||||
{
|
||||
var uid = mapIdComp.Uid;
|
||||
if (takenIds.Contains(uid))
|
||||
{
|
||||
// Duplicate ID. Just pretend it doesn't have an ID and use the without path.
|
||||
withoutUid.Add(mapIdComp.Owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityUidMap.Add(mapIdComp.Owner.Uid, uid);
|
||||
takenIds.Add(uid);
|
||||
}
|
||||
}
|
||||
|
||||
var uidCounter = 0;
|
||||
foreach (var entity in withoutUid)
|
||||
{
|
||||
while (takenIds.Contains(uidCounter))
|
||||
{
|
||||
// Find next available UID.
|
||||
uidCounter += 1;
|
||||
}
|
||||
|
||||
EntityUidMap.Add(entity.Uid, uidCounter);
|
||||
takenIds.Add(uidCounter);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteEntitySection()
|
||||
@@ -621,7 +688,7 @@ namespace Robust.Server.Maps
|
||||
var entities = new YamlSequenceNode();
|
||||
RootNode.Add("entities", entities);
|
||||
|
||||
foreach (var entity in Entities)
|
||||
foreach (var entity in Entities.OrderBy(e => EntityUidMap[e.Uid]))
|
||||
{
|
||||
CurrentWritingEntity = entity;
|
||||
var mapping = new YamlMappingNode
|
||||
@@ -638,6 +705,9 @@ namespace Robust.Server.Maps
|
||||
// See engine#636 for why the Distinct() call.
|
||||
foreach (var component in entity.GetAllComponents())
|
||||
{
|
||||
if (component is MapSaveIdComponent)
|
||||
continue;
|
||||
|
||||
var compMapping = new YamlMappingNode();
|
||||
CurrentWritingComponent = component.Name;
|
||||
var compSerializer = YamlObjectSerializer.NewWriter(compMapping, this);
|
||||
@@ -683,6 +753,7 @@ namespace Robust.Server.Maps
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == typeof(EntityUid))
|
||||
{
|
||||
if (node.AsString() == "null")
|
||||
@@ -694,7 +765,8 @@ namespace Robust.Server.Maps
|
||||
var val = node.AsInt();
|
||||
if (val >= Entities.Count)
|
||||
{
|
||||
Logger.ErrorS("map", "Error in map file: found local entity UID '{0}' which does not exist.", val);
|
||||
Logger.ErrorS("map", "Error in map file: found local entity UID '{0}' which does not exist.",
|
||||
val);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -702,12 +774,14 @@ namespace Robust.Server.Maps
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof(IEntity).IsAssignableFrom(type))
|
||||
{
|
||||
var val = node.AsInt();
|
||||
if (val >= Entities.Count)
|
||||
{
|
||||
Logger.ErrorS("map", "Error in map file: found local entity UID '{0}' which does not exist.", val);
|
||||
Logger.ErrorS("map", "Error in map file: found local entity UID '{0}' which does not exist.",
|
||||
val);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -715,6 +789,7 @@ namespace Robust.Server.Maps
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
obj = null;
|
||||
return false;
|
||||
}
|
||||
@@ -766,6 +841,7 @@ namespace Robust.Server.Maps
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
@@ -878,7 +954,7 @@ namespace Robust.Server.Maps
|
||||
}
|
||||
|
||||
Stream = stream;
|
||||
GridCount = ((YamlSequenceNode)RootNode["grids"]).Children.Count;
|
||||
GridCount = ((YamlSequenceNode) RootNode["grids"]).Children.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +249,9 @@ namespace Robust.Shared
|
||||
public static readonly CVarDef<int> DisplayLightMapDivider =
|
||||
CVarDef.Create("display.lightmapdivider", 2, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
public static readonly CVarDef<int> DisplayMaxLightsPerScene =
|
||||
CVarDef.Create("display.maxlightsperscene", 128, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
public static readonly CVarDef<bool> DisplaySoftShadows =
|
||||
CVarDef.Create("display.softshadows", true, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ namespace Robust.Shared.Configuration
|
||||
/// </summary>
|
||||
void FlushMessages();
|
||||
|
||||
/// <summary>
|
||||
/// Clears internal flag for <see cref="ReceivedInitialNwVars"/>.
|
||||
/// Must be called upon disconnect.
|
||||
/// </summary>
|
||||
void ClearReceivedInitialNwVars();
|
||||
|
||||
public event EventHandler ReceivedInitialNwVars;
|
||||
}
|
||||
|
||||
@@ -77,7 +83,7 @@ namespace Robust.Shared.Configuration
|
||||
_netManager.Connected += PeerConnected;
|
||||
_netManager.Disconnect += PeerDisconnected;
|
||||
}
|
||||
|
||||
|
||||
_netManager.RegisterNetMessage<MsgConVars>(MsgConVars.NAME, HandleNetVarMessage);
|
||||
}
|
||||
|
||||
@@ -94,10 +100,16 @@ namespace Robust.Shared.Configuration
|
||||
private void HandleNetVarMessage(MsgConVars message)
|
||||
{
|
||||
if(!_receivedInitialNwVars)
|
||||
ReceivedInitialNwVars?.Invoke(this, EventArgs.Empty);
|
||||
{
|
||||
_receivedInitialNwVars = true;
|
||||
|
||||
_receivedInitialNwVars = true;
|
||||
_netVarsMessages.Add(message);
|
||||
// apply the initial set immediately, so that they are available to
|
||||
// for the rest of connection building
|
||||
ApplyNetVarChange(message.MsgChannel, message.NetworkedVars);
|
||||
ReceivedInitialNwVars?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
else
|
||||
_netVarsMessages.Add(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -135,7 +147,7 @@ namespace Robust.Shared.Configuration
|
||||
|
||||
_netVarsMessages.Clear();
|
||||
}
|
||||
|
||||
|
||||
private void ApplyNetVarChange(INetChannel msgChannel, List<(string name, object value)> networkedVars)
|
||||
{
|
||||
Logger.DebugS("cfg", "Handling replicated cvars...");
|
||||
@@ -285,6 +297,11 @@ namespace Robust.Shared.Configuration
|
||||
_netManager.ClientSendMessage(msg);
|
||||
}
|
||||
|
||||
public void ClearReceivedInitialNwVars()
|
||||
{
|
||||
_receivedInitialNwVars = false;
|
||||
}
|
||||
|
||||
private List<(string name, object value)> GetReplicatedVars()
|
||||
{
|
||||
var nwVars = new List<(string name, object value)>();
|
||||
@@ -292,7 +309,7 @@ namespace Robust.Shared.Configuration
|
||||
foreach (var cVar in _configVars.Values)
|
||||
{
|
||||
if (!cVar.Registered)
|
||||
return nwVars;
|
||||
continue;
|
||||
|
||||
if ((cVar.Flags & CVar.REPLICATED) == 0)
|
||||
continue;
|
||||
|
||||
@@ -206,8 +206,6 @@ namespace Robust.Shared.GameObjects
|
||||
/// <inheritdoc />
|
||||
public void RemoveComponents(EntityUid uid)
|
||||
{
|
||||
_entCompIndex.Remove(uid);
|
||||
|
||||
foreach (var comp in InSafeOrder(_entCompIndex[uid]))
|
||||
{
|
||||
RemoveComponentDeferred(comp, uid, false);
|
||||
@@ -221,6 +219,10 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
RemoveComponentDeferred(comp, uid, true);
|
||||
}
|
||||
|
||||
// DisposeComponents means the entity is getting deleted.
|
||||
// Safe to wipe the entity out of the index.
|
||||
_entCompIndex.Remove(uid);
|
||||
}
|
||||
|
||||
private void RemoveComponentDeferred(Component component, EntityUid uid, bool removeProtected)
|
||||
@@ -306,6 +308,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
var netId = component.NetID.Value;
|
||||
_entNetIdDict[netId].Remove(entityUid);
|
||||
_entCompIndex.Remove(entityUid, component);
|
||||
|
||||
// mark the owning entity as dirty for networking
|
||||
component.Owner.Dirty();
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Robust.Shared.Network.Messages
|
||||
{
|
||||
public class MsgSetTickRate : NetMessage
|
||||
{
|
||||
#region REQUIRED
|
||||
public static readonly MsgGroups GROUP = MsgGroups.Core;
|
||||
public static readonly string NAME = nameof(MsgSetTickRate);
|
||||
public MsgSetTickRate(INetChannel channel) : base(NAME, GROUP) { }
|
||||
#endregion
|
||||
|
||||
public byte NewTickRate { get; set; }
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||
{
|
||||
NewTickRate = buffer.ReadByte();
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
{
|
||||
buffer.Write(NewTickRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,7 +685,21 @@ namespace Robust.Shared.Network
|
||||
_assignedUsernames.Remove(channel.UserName);
|
||||
_assignedUserIds.Remove(channel.UserId);
|
||||
|
||||
OnDisconnected(channel, reason);
|
||||
#if EXCEPTION_TOLERANCE
|
||||
try
|
||||
{
|
||||
#endif
|
||||
OnDisconnected(channel, reason);
|
||||
#if EXCEPTION_TOLERANCE
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// A throw aborting in the middle of this method would be *really* bad
|
||||
// and cause fun bugs like ghost clients sticking around.
|
||||
// I say "would" as if it hasn't already happened...
|
||||
Logger.ErrorS("net", "Caught exception in OnDisconnected handler:\n{0}", e);
|
||||
}
|
||||
#endif
|
||||
_channels.Remove(connection);
|
||||
peer.RemoveChannel(channel);
|
||||
|
||||
@@ -1004,6 +1018,7 @@ namespace Robust.Shared.Network
|
||||
{
|
||||
await conn(args);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user