Compare commits

..

13 Commits

Author SHA1 Message Date
DrSmugleaf
e78ab8f922 Add YamlObjectSerializer.NodeToType with generic argument (#1456) 2020-12-20 20:46:56 +01:00
20kdc
6972000293 Make the "softness" of soft shadows adjustible per-light. (#1454)
Note: Thanks to the nature of YAML properties in RobustToolbox, this commit is only an API blocker if the Softness property is directly manipulated from code, which is unlikely.
2020-12-19 21:44:47 +01:00
DrSmugleaf
58560f589f Defer MoveEvent out of TransformComponent.HandleComponentState (#1453)
* Defer MoveEvent out of TransformComponent.HandleComponentState

* Imports

* Make the update loop more readable and call ToArray

* Fix tests

* Fix tests HALLELUJAH
2020-12-19 13:09:16 +01:00
Pieter-Jan Briers
6e931ac175 Fix some CVars not saving. 2020-12-19 02:31:46 +01:00
Pieter-Jan Briers
a7eb5e8115 Use nvidia GPU on optimus laptops.
With an undocumented crappy hack, of course.
2020-12-19 02:25:10 +01:00
metalgearsloth
712e4acc66 Cache TryLooseGetType (#1448)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-12-19 01:42:51 +01:00
Pieter-Jan Briers
fdcfdffc0b Provide fallback for /status API if content does not override it. 2020-12-19 00:43:46 +01:00
Pieter-Jan Briers
74eb8e3e8d Allow build.json contents to be overriden by --cvar. 2020-12-17 17:13:07 +01:00
Pieter-Jan Briers
ae4c764e4f Whitelist System.Guid for sandbox. 2020-12-17 16:37:20 +01:00
Pieter-Jan Briers
7ef2cec121 Fix names parsed from build.json 2020-12-17 15:28:01 +01:00
Pieter-Jan Briers
40bff81017 Fix nullable warning. 2020-12-17 00:58:26 +01:00
Pieter-Jan Briers
f7c28992f8 Disable string map caching to hopefully fix connect. 2020-12-17 00:48:15 +01:00
Pieter-Jan Briers
920ae58019 Fix LoaderApiLoader.FindFiles() 2020-12-17 00:33:39 +01:00
19 changed files with 161 additions and 29 deletions

View File

@@ -13,7 +13,7 @@ highp float createOcclusion(highp vec2 diff)
// Change soft shadow size based on distance from primary occluder.
highp float distRatio = (ourDist - occlDist.x) / occlDist.x / 2.0;
perpendicular *= distRatio;
perpendicular *= distRatio * lightSoftness;
// Totally not hacky PCF on top of VSM.
highp float occlusion = smoothstep(0.1, 1.0, ChebyshevUpperBound(occlDist, ourDist));

View File

@@ -13,6 +13,7 @@ uniform highp vec4 lightColor;
uniform highp vec2 lightCenter;
uniform highp float lightRange;
uniform highp float lightPower;
uniform highp float lightSoftness;
uniform highp float lightIndex;
uniform sampler2D shadowMap;

View File

@@ -32,6 +32,7 @@ using Robust.Shared.Interfaces.Timers;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -65,6 +66,7 @@ namespace Robust.Client
[Dependency] private readonly IScriptClient _scriptClient = default!;
[Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustMappedStringSerializer _stringSerializer = default!;
private CommandLineArgs? _commandLineArgs;
private bool _disableAssemblyLoadContext;
@@ -125,6 +127,7 @@ namespace Robust.Client
ProgramShared.DoMounts(_resourceCache, _commandLineArgs?.MountOptions, "Content.Client", _loaderArgs != null);
if (_loaderArgs != null)
{
_stringSerializer.EnableCaching = false;
_resourceCache.MountLoaderApi(_loaderArgs.FileApi, "Resources/");
_modLoader.VerifierExtraLoadHandler = VerifierExtraLoadHandler;
}

View File

@@ -83,6 +83,18 @@ namespace Robust.Client.GameObjects
set => _energy = value;
}
/// <summary>
/// Soft shadow strength multiplier.
/// Has no effect if soft shadows are not enabled.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public float Softness
{
get => _softness;
set => _softness = value;
}
[ViewVariables(VVAccess.ReadWrite)]
public bool VisibleNested
{
@@ -115,6 +127,7 @@ namespace Robust.Client.GameObjects
private bool _maskAutoRotate;
private Angle _rotation;
private float _energy;
private float _softness;
/// <summary>
/// Radius, in meters.
@@ -167,6 +180,7 @@ namespace Robust.Client.GameObjects
serializer.DataFieldCached(ref _color, "color", Color.White);
serializer.DataFieldCached(ref _enabled, "enabled", true);
serializer.DataFieldCached(ref _energy, "energy", 1f);
serializer.DataFieldCached(ref _softness, "softness", 1f);
serializer.DataFieldCached(ref _maskAutoRotate, "autoRot", false);
serializer.DataFieldCached(ref _visibleNested, "nestedvisible", true);

View File

@@ -16,7 +16,7 @@ namespace Robust.Client.GameObjects.EntitySystems
/// Handles interpolation of transform positions.
/// </summary>
[UsedImplicitly]
internal sealed class TransformSystem : EntitySystem
internal sealed class TransformSystem : SharedTransformSystem
{
// Max distance per tick how far an entity can move before it is considered teleporting.
// TODO: Make these values somehow dependent on server TPS.

View File

@@ -11,6 +11,22 @@ namespace Robust.Client.Graphics.Clyde
{
static Clyde()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
RuntimeInformation.ProcessArchitecture == Architecture.X64)
{
try
{
// We force load nvapi64.dll so nvidia gives us the dedicated GPU on optimus laptops.
// This is 100x easier than nvidia's documented approach of NvOptimusEnablement,
// and works while developing.
NativeLibrary.Load("nvapi64.dll");
}
catch (Exception)
{
// If this fails whatever.
}
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;

View File

@@ -377,6 +377,7 @@ namespace Robust.Client.Graphics.Clyde
var lastRange = float.NaN;
var lastPower = float.NaN;
var lastColor = new Color(float.NaN, float.NaN, float.NaN, float.NaN);
var lastSoftness = float.NaN;
Texture? lastMask = null;
for (var i = 0; i < count; i++)
@@ -424,6 +425,12 @@ namespace Robust.Client.Graphics.Clyde
lightShader.SetUniformMaybe("lightColor", lastColor);
}
if (_enableSoftShadows && !MathHelper.CloseTo(lastSoftness, component.Softness))
{
lastSoftness = component.Softness;
lightShader.SetUniformMaybe("lightSoftness", lastSoftness);
}
lightShader.SetUniformMaybe("lightCenter", lightPos);
lightShader.SetUniformMaybe("lightIndex", (i + 0.5f) / ShadowTexture.Height);

View File

@@ -38,7 +38,10 @@ namespace Robust.Client.ResourceManagement
{
foreach (var relPath in _api.AllFiles)
{
var resP = new ResourcePath(relPath);
if (!relPath.StartsWith(_prefix))
continue;
var resP = new ResourcePath(relPath[_prefix.Length..]);
if (resP.TryRelativeTo(path, out _))
{
yield return resP;

View File

@@ -38,13 +38,6 @@ namespace Robust.Server.ServerStatus
return false;
}
if (OnStatusRequest == null)
{
_httpSawmill.Warning("OnStatusRequest is not set, responding with a 501.");
response.Respond(method, "Not Implemented", HttpStatusCode.NotImplemented);
return true;
}
response.StatusCode = (int) HttpStatusCode.OK;
response.ContentType = "application/json";
@@ -53,7 +46,13 @@ namespace Robust.Server.ServerStatus
return true;
}
var jObject = new JObject();
var jObject = new JObject
{
// We need to send at LEAST name and player count to have the launcher work with us.
// Content can override these if it wants (e.g. stealthmins).
["name"] = _serverNameCache,
["players"] = _playerManager.PlayerCount
};
OnStatusRequest?.Invoke(jObject);

View File

@@ -7,8 +7,11 @@ using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Robust.Server.Interfaces;
using Robust.Server.Interfaces.Player;
using Robust.Server.Interfaces.ServerStatus;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Log;
@@ -28,6 +31,8 @@ namespace Robust.Server.ServerStatus
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly IServerNetManager _netManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IBaseServer _baseServer = default!;
private static readonly JsonSerializer JsonSerializer = new();
private readonly List<StatusHostHandler> _handlers = new();
@@ -35,6 +40,8 @@ namespace Robust.Server.ServerStatus
private TaskCompletionSource? _stopSource;
private ISawmill _httpSawmill = default!;
private string? _serverNameCache;
public Task ProcessRequestAsync(HttpListenerContext context)
{
var response = context.Response;
@@ -85,6 +92,10 @@ namespace Robust.Server.ServerStatus
_httpSawmill = Logger.GetSawmill($"{Sawmill}.http");
RegisterCVars();
// Cache this in a field to avoid thread safety shenanigans.
// Writes/reads of references are atomic in C# so no further synchronization necessary.
_configurationManager.OnValueChanged(CVars.GameHostName, n => _serverNameCache = n);
if (!_configurationManager.GetCVar(CVars.StatusEnabled))
{
return;
@@ -146,15 +157,22 @@ namespace Robust.Server.ServerStatus
var buildInfo = File.ReadAllText(PathHelpers.ExecutableRelativeFile("build.json"));
var info = JsonConvert.DeserializeObject<BuildInfo>(buildInfo);
_configurationManager.SetCVar(CVars.BuildEngineVersion, info.EngineVersion);
_configurationManager.SetCVar(CVars.BuildForkId, info.ForkId);
_configurationManager.SetCVar(CVars.BuildVersion, info.Version);
_configurationManager.SetCVar(CVars.BuildDownloadUrl, info.Download);
_configurationManager.SetCVar(CVars.BuildHash, info.Hash ?? "");
// Don't replace cvars with contents of build.json if overriden by --cvar or such.
SetCVarIfUnmodified(CVars.BuildEngineVersion, info.EngineVersion);
SetCVarIfUnmodified(CVars.BuildForkId, info.ForkId);
SetCVarIfUnmodified(CVars.BuildVersion, info.Version);
SetCVarIfUnmodified(CVars.BuildDownloadUrl, info.Download ?? "");
SetCVarIfUnmodified(CVars.BuildHash, info.Hash ?? "");
}
catch (FileNotFoundException)
{
}
void SetCVarIfUnmodified(CVarDef<string> cvar, string val)
{
if (_configurationManager.GetCVar(cvar) == "")
_configurationManager.SetCVar(cvar, val);
}
}
public void Dispose()
@@ -172,8 +190,8 @@ namespace Robust.Server.ServerStatus
private sealed class BuildInfo
{
[JsonProperty("engine_version")] public string EngineVersion = default!;
[JsonProperty("hashes")] public string? Hash;
[JsonProperty("downloads")] public string Download = default!;
[JsonProperty("hash")] public string? Hash;
[JsonProperty("download")] public string? Download;
[JsonProperty("fork_id")] public string ForkId = default!;
[JsonProperty("version")] public string Version = default!;
}

View File

@@ -233,10 +233,10 @@ namespace Robust.Shared
CVarDef.Create("display.height", 720, CVar.CLIENTONLY);
public static readonly CVarDef<int> DisplayLightMapDivider =
CVarDef.Create("display.lightmapdivider", 2, CVar.CLIENTONLY);
CVarDef.Create("display.lightmapdivider", 2, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<bool> DisplaySoftShadows =
CVarDef.Create("display.softshadows", true, CVar.CLIENTONLY);
CVarDef.Create("display.softshadows", true, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<float> DisplayUIScale =
CVarDef.Create("display.uiScale", 0f, CVar.ARCHIVE | CVar.CLIENTONLY);
@@ -261,7 +261,7 @@ namespace Robust.Shared
CVarDef.Create("audio.device", string.Empty, CVar.CLIENTONLY);
public static readonly CVarDef<float> AudioMasterVolume =
CVarDef.Create("audio.mastervolume", 1.0f, CVar.CLIENTONLY);
CVarDef.Create("audio.mastervolume", 1.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
/*
* PLAYER

View File

@@ -845,6 +845,7 @@ Types:
Func`15: { All: True }
Func`16: { All: True }
Func`17: { All: True }
Guid: { All: True }
HashCode: { All: True }
IAsyncDisposable: { All: True }
IAsyncResult: { }

View File

@@ -5,6 +5,7 @@ using Robust.Shared.Animations;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects.Components.Map;
using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Map;
@@ -722,8 +723,9 @@ namespace Robust.Shared.GameObjects.Components.Transform
var oldPos = Coordinates;
SetPosition(newState.LocalPosition);
Owner.EntityManager.EventBus.RaiseEvent(
EventSource.Local, new MoveEvent(Owner, oldPos, Coordinates));
var ev = new MoveEvent(Owner, oldPos, Coordinates);
EntitySystem.Get<SharedTransformSystem>().DeferMoveEvent(ev);
rebuildMatrices = true;
}
@@ -873,6 +875,7 @@ namespace Robust.Shared.GameObjects.Components.Transform
public IEntity Sender { get; }
public EntityCoordinates OldPosition { get; }
public EntityCoordinates NewPosition { get; }
public bool Handled { get; set; }
}
public class RotateEvent : EntitySystemMessage

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects.Components.Map;
using Robust.Shared.GameObjects.Components.Transform;
namespace Robust.Shared.GameObjects.Systems
{
internal class SharedTransformSystem : EntitySystem
{
private readonly List<MoveEvent> _deferredMoveEvents = new();
public void DeferMoveEvent(MoveEvent moveEvent)
{
_deferredMoveEvents.Add(moveEvent);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var events = _deferredMoveEvents
.OrderBy(e => e.Sender.HasComponent<IMapGridComponent>())
.ToArray();
foreach (var ev in events)
{
ev.Sender.EntityManager.EventBus.RaiseEvent(EventSource.Local, ev);
ev.Handled = true;
}
_deferredMoveEvents.RemoveAll(e => e.Handled);
}
}
}

View File

@@ -40,6 +40,8 @@ namespace Robust.Shared.Serialization
/// </exception>
ReadOnlySpan<byte> MappedStringsHash { get; }
bool EnableCaching { get; set; }
/// <summary>
/// Add a string to the constant mapping.
/// </summary>

View File

@@ -29,6 +29,8 @@ namespace Robust.Shared.Reflection
private readonly Dictionary<(Type baseType, string typeName), Type?> _yamlTypeTagCache = new();
private readonly Dictionary<string, Type> _looseTypeCache = new();
/// <inheritdoc />
public IEnumerable<Type> GetAllChildren<T>(bool inclusive = false)
{
@@ -134,6 +136,9 @@ namespace Robust.Shared.Reflection
public bool TryLooseGetType(string name, [NotNullWhen(true)] out Type? type)
{
if (_looseTypeCache.TryGetValue(name, out type))
return true;
foreach (var assembly in assemblies)
{
foreach (var tryType in assembly.DefinedTypes)
@@ -141,6 +146,7 @@ namespace Robust.Shared.Reflection
if (tryType.FullName!.EndsWith(name))
{
type = tryType;
_looseTypeCache[name] = type;
return true;
}
}

View File

@@ -121,6 +121,8 @@ namespace Robust.Shared.Serialization
/// </exception>
public ReadOnlySpan<byte> MappedStringsHash => _stringMapHash;
public bool EnableCaching { get; set; } = true;
private static readonly Regex RxSymbolSplitter
= new(
@"(?<=[^\s\W])(?=[A-Z]) # Match for split at start of new capital letter
@@ -283,7 +285,10 @@ namespace Robust.Shared.Serialization
LogSzr.Debug($"Locked in at {_dict.StringCount} mapped strings.");
packageStream.Position = 0;
WriteStringCache(packageStream);
if (EnableCaching)
{
WriteStringCache(packageStream);
}
// ok we're good now
var channel = msg.MsgChannel;
@@ -405,7 +410,7 @@ namespace Robust.Shared.Serialization
LogSzr.Debug($"Received server handshake with hash {hashStr}.");
var fileName = CacheForHash(hashStr);
if (!File.Exists(fileName))
if (fileName == null || !File.Exists(fileName))
{
LogSzr.Debug($"No string cache for {hashStr}.");
var handshake = _net.CreateNetMessage<MsgMapStrClientHandshake>();
@@ -458,8 +463,12 @@ namespace Robust.Shared.Serialization
/// file itself may or may not exist. If it does not exist, no cache
/// was made for the given hash.
/// </returns>
private static string CacheForHash(string hashStr)
private string? CacheForHash(string hashStr)
{
if (!EnableCaching)
{
return null;
}
return PathHelpers.ExecutableRelativeFile($"strings-{hashStr}");
}
@@ -471,7 +480,7 @@ namespace Robust.Shared.Serialization
var hashStr = Convert.ToBase64String(MappedStringsHash);
hashStr = ConvertToBase64Url(hashStr);
var fileName = CacheForHash(hashStr);
var fileName = CacheForHash(hashStr)!;
using var file = File.OpenWrite(fileName);
stream.CopyTo(file);

View File

@@ -614,6 +614,11 @@ namespace Robust.Shared.Serialization
throw new ArgumentException($"Type {type.FullName} is not supported.", nameof(type));
}
public T NodeToType<T>(YamlNode node)
{
return (T) NodeToType(typeof(T), node);
}
private static Type ResolveConcreteType(Type baseType, string typeName)
{
var reflection = IoCManager.Resolve<IReflectionManager>();

View File

@@ -1,10 +1,10 @@
using System.IO;
using Moq;
using NUnit.Framework;
using Robust.Client.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
@@ -35,6 +35,17 @@ namespace Robust.UnitTesting.Client.GameObjects.Components
private MapId MapB;
private IMapGrid GridB = default!;
protected override void OverrideIoC()
{
base.OverrideIoC();
var mock = new Mock<IEntitySystemManager>();
var system = new SharedTransformSystem();
mock.Setup(m => m.GetEntitySystem<SharedTransformSystem>()).Returns(system);
IoCManager.RegisterInstance<IEntitySystemManager>(mock.Object, true);
}
[OneTimeSetUp]
public void Setup()
{