Compare commits

...

14 Commits

Author SHA1 Message Date
Pieter-Jan Briers
63ee32fcd3 PrototypeManager cleanup.
Reduce dictionary abuse
Rename "prototype types" and "variants" to consistently "kinds".
2022-08-27 23:23:25 +02:00
Pieter-Jan Briers
11deb10e01 SkipLocalsInit for LanguageServer
Free performance yay
2022-08-27 20:15:42 +02:00
Pieter-Jan Briers
a94a37d5da Support connecting over named pipe.
This is probably sanest to use on Windows.
2022-08-26 22:29:10 +02:00
Pieter-Jan Briers
9a1b8dd14a Fix ServiceDependencyCollection registrations 2022-08-26 22:28:35 +02:00
Pieter-Jan Briers
c8b35d28f8 Some comments 2022-08-26 01:30:57 +02:00
Pieter-Jan Briers
c14450e2b3 Custom YAML -> DataNode parser.
This just avoids a round trip through YDN's RepresentationModel. It still just uses YDN's parser.
2022-08-26 01:27:11 +02:00
Pieter-Jan Briers
7f6a9e7e8b Merge branch 'master' into 22-08-12-lsp 2022-08-24 23:54:57 +02:00
Pieter-Jan Briers
ac6580cb3e Look I gotta commit this at some point. Basic lang server for me experimenting with LSP. 2022-08-15 20:44:36 +02:00
Pieter-Jan Briers
52f46dc9ea Remove hard dependency of IConsoleHost to IMapManager. 2022-08-15 17:51:24 +02:00
Pieter-Jan Briers
7de7ef085c Make RegisterIoC()s take in IDependencyCollection instead.
Need this for LSP, but also just avoids all the TLS loading.
2022-08-14 00:48:09 +02:00
Pieter-Jan Briers
55949f41ce Register<T> extension for IDependencyCollection. 2022-08-14 00:46:18 +02:00
Pieter-Jan Briers
1bb790cf28 Make IoC Register have where TInterface : class
This was basically already implied by the TImplementation constraint.
I needed to add this to bridge constraints for MS IServiceCollection wiring for LSP.
2022-08-14 00:42:43 +02:00
Pieter-Jan Briers
2db11d7f29 Move entity prototype reload logic to entity system.
Removes dependency of IPrototypeManager -> IEntityManager.
2022-08-13 23:01:19 +02:00
Pieter-Jan Briers
1e271ce47d Bump YamlDotNet to 12.0.0 2022-08-12 22:10:10 +02:00
37 changed files with 1674 additions and 503 deletions

View File

@@ -13,7 +13,7 @@ namespace Robust.Benchmarks.Serialization
public SerializationBenchmark()
{
IoCManager.InitThread();
ServerIoC.RegisterIoC();
ServerIoC.RegisterIoC(IoCManager.Instance!);
IoCManager.BuildGraph();
var assemblies = new[]

View File

@@ -37,85 +37,85 @@ namespace Robust.Client
{
internal static class ClientIoC
{
public static void RegisterIoC(GameController.DisplayMode mode)
public static void RegisterIoC(GameController.DisplayMode mode, IDependencyCollection deps)
{
SharedIoC.RegisterIoC();
SharedIoC.RegisterIoC(deps);
IoCManager.Register<IGameTiming, ClientGameTiming>();
IoCManager.Register<IClientGameTiming, ClientGameTiming>();
IoCManager.Register<IPrototypeManager, ClientPrototypeManager>();
IoCManager.Register<IMapManager, NetworkedMapManager>();
IoCManager.Register<IMapManagerInternal, NetworkedMapManager>();
IoCManager.Register<INetworkedMapManager, NetworkedMapManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
IoCManager.Register<IConsoleHost, ClientConsoleHost>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
IoCManager.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
IoCManager.Register<IClydeTileDefinitionManager, ClydeTileDefinitionManager>();
IoCManager.Register<GameController, GameController>();
IoCManager.Register<IGameController, GameController>();
IoCManager.Register<IGameControllerInternal, GameController>();
IoCManager.Register<IResourceManager, ResourceCache>();
IoCManager.Register<IResourceManagerInternal, ResourceCache>();
IoCManager.Register<IResourceCache, ResourceCache>();
IoCManager.Register<IResourceCacheInternal, ResourceCache>();
IoCManager.Register<IClientNetManager, NetManager>();
IoCManager.Register<EntityManager, ClientEntityManager>();
IoCManager.Register<ClientEntityManager>();
IoCManager.Register<IClientEntityManager, ClientEntityManager>();
IoCManager.Register<IClientEntityManagerInternal, ClientEntityManager>();
IoCManager.Register<IEntityNetworkManager, ClientEntityManager>();
IoCManager.Register<IClientGameStateManager, ClientGameStateManager>();
IoCManager.Register<IBaseClient, BaseClient>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<ISharedPlayerManager, PlayerManager>();
IoCManager.Register<IStateManager, StateManager>();
IoCManager.Register<IUserInterfaceManager, UserInterfaceManager>();
IoCManager.Register<IUserInterfaceManagerInternal, UserInterfaceManager>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
IoCManager.Register<IMidiManager, MidiManager>();
IoCManager.Register<IAuthManager, AuthManager>();
IoCManager.Register<ProfViewManager>();
IoCManager.Register<IPhysicsManager, PhysicsManager>();
deps.Register<IGameTiming, ClientGameTiming>();
deps.Register<IClientGameTiming, ClientGameTiming>();
deps.Register<IPrototypeManager, ClientPrototypeManager>();
deps.Register<IMapManager, NetworkedMapManager>();
deps.Register<IMapManagerInternal, NetworkedMapManager>();
deps.Register<INetworkedMapManager, NetworkedMapManager>();
deps.Register<IEntityManager, ClientEntityManager>();
deps.Register<IReflectionManager, ClientReflectionManager>();
deps.Register<IConsoleHost, ClientConsoleHost>();
deps.Register<IClientConsoleHost, ClientConsoleHost>();
deps.Register<IComponentFactory, ClientComponentFactory>();
deps.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
deps.Register<IClydeTileDefinitionManager, ClydeTileDefinitionManager>();
deps.Register<GameController, GameController>();
deps.Register<IGameController, GameController>();
deps.Register<IGameControllerInternal, GameController>();
deps.Register<IResourceManager, ResourceCache>();
deps.Register<IResourceManagerInternal, ResourceCache>();
deps.Register<IResourceCache, ResourceCache>();
deps.Register<IResourceCacheInternal, ResourceCache>();
deps.Register<IClientNetManager, NetManager>();
deps.Register<EntityManager, ClientEntityManager>();
deps.Register<ClientEntityManager>();
deps.Register<IClientEntityManager, ClientEntityManager>();
deps.Register<IClientEntityManagerInternal, ClientEntityManager>();
deps.Register<IEntityNetworkManager, ClientEntityManager>();
deps.Register<IClientGameStateManager, ClientGameStateManager>();
deps.Register<IBaseClient, BaseClient>();
deps.Register<IPlayerManager, PlayerManager>();
deps.Register<ISharedPlayerManager, PlayerManager>();
deps.Register<IStateManager, StateManager>();
deps.Register<IUserInterfaceManager, UserInterfaceManager>();
deps.Register<IUserInterfaceManagerInternal, UserInterfaceManager>();
deps.Register<ILightManager, LightManager>();
deps.Register<IDiscordRichPresence, DiscordRichPresence>();
deps.Register<IMidiManager, MidiManager>();
deps.Register<IAuthManager, AuthManager>();
deps.Register<ProfViewManager>();
deps.Register<IPhysicsManager, PhysicsManager>();
switch (mode)
{
case GameController.DisplayMode.Headless:
IoCManager.Register<IClyde, ClydeHeadless>();
IoCManager.Register<IClipboardManager, ClydeHeadless>();
IoCManager.Register<IClydeInternal, ClydeHeadless>();
IoCManager.Register<IClydeAudio, ClydeAudioHeadless>();
IoCManager.Register<IClydeAudioInternal, ClydeAudioHeadless>();
IoCManager.Register<IInputManager, InputManager>();
IoCManager.Register<IFileDialogManager, DummyFileDialogManager>();
IoCManager.Register<IUriOpener, UriOpenerDummy>();
deps.Register<IClyde, ClydeHeadless>();
deps.Register<IClipboardManager, ClydeHeadless>();
deps.Register<IClydeInternal, ClydeHeadless>();
deps.Register<IClydeAudio, ClydeAudioHeadless>();
deps.Register<IClydeAudioInternal, ClydeAudioHeadless>();
deps.Register<IInputManager, InputManager>();
deps.Register<IFileDialogManager, DummyFileDialogManager>();
deps.Register<IUriOpener, UriOpenerDummy>();
break;
case GameController.DisplayMode.Clyde:
IoCManager.Register<IClyde, Clyde>();
IoCManager.Register<IClipboardManager, Clyde>();
IoCManager.Register<IClydeInternal, Clyde>();
IoCManager.Register<IClydeAudio, FallbackProxyClydeAudio>();
IoCManager.Register<IClydeAudioInternal, FallbackProxyClydeAudio>();
IoCManager.Register<IInputManager, ClydeInputManager>();
IoCManager.Register<IFileDialogManager, FileDialogManager>();
IoCManager.Register<IUriOpener, UriOpener>();
deps.Register<IClyde, Clyde>();
deps.Register<IClipboardManager, Clyde>();
deps.Register<IClydeInternal, Clyde>();
deps.Register<IClydeAudio, FallbackProxyClydeAudio>();
deps.Register<IClydeAudioInternal, FallbackProxyClydeAudio>();
deps.Register<IInputManager, ClydeInputManager>();
deps.Register<IFileDialogManager, FileDialogManager>();
deps.Register<IUriOpener, UriOpener>();
break;
default:
throw new ArgumentOutOfRangeException();
}
IoCManager.Register<IFontManager, FontManager>();
IoCManager.Register<IFontManagerInternal, FontManager>();
IoCManager.Register<IEyeManager, EyeManager>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IOverlayManager, OverlayManager>();
IoCManager.Register<IOverlayManagerInternal, OverlayManager>();
IoCManager.Register<IViewVariablesManager, ViewVariablesManager>();
IoCManager.Register<IViewVariablesManagerInternal, ViewVariablesManager>();
IoCManager.Register<IClientConGroupController, ClientConGroupController>();
IoCManager.Register<IScriptClient, ScriptClient>();
deps.Register<IFontManager, FontManager>();
deps.Register<IFontManagerInternal, FontManager>();
deps.Register<IEyeManager, EyeManager>();
deps.Register<IPlacementManager, PlacementManager>();
deps.Register<IOverlayManager, OverlayManager>();
deps.Register<IOverlayManagerInternal, OverlayManager>();
deps.Register<IViewVariablesManager, ViewVariablesManager>();
deps.Register<IViewVariablesManagerInternal, ViewVariablesManager>();
deps.Register<IClientConGroupController, ClientConGroupController>();
deps.Register<IScriptClient, ScriptClient>();
}
}
}

View File

@@ -10,9 +10,9 @@ namespace Robust.Client
// Partial of GameController to initialize IoC and some other low-level systems like it.
internal sealed partial class GameController
{
private static void InitIoC(DisplayMode mode)
private static void InitIoC(DisplayMode mode, IDependencyCollection deps)
{
ClientIoC.RegisterIoC(mode);
ClientIoC.RegisterIoC(mode, deps);
IoCManager.BuildGraph();
RegisterReflection();
}

View File

@@ -49,7 +49,7 @@ namespace Robust.Client
var mode = args.Headless ? DisplayMode.Headless : DisplayMode.Clyde;
InitIoC(mode);
InitIoC(mode, IoCManager.Instance!);
var gc = IoCManager.Resolve<GameController>();
gc.SetCommandLineArgs(args);

View File

@@ -45,6 +45,7 @@ namespace Robust.Client.Input
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly IUserInterfaceManagerInternal _uiMgr = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
private bool _currentlyFindingViewport;
@@ -486,18 +487,14 @@ namespace Robust.Client.Input
reader = _resourceMan.ContentFileReadText(file);
}
var yamlStream = new YamlStream();
yamlStream.Load(reader);
using var _ = reader;
var mapping = (YamlMappingNode) yamlStream.Documents[0].RootNode;
var documents = DataNodeParser.ParseYamlStream(reader).First();
var mapping = (MappingDataNode) documents.Root;
var serializationManager = IoCManager.Resolve<ISerializationManager>();
var robustMapping = mapping.ToDataNode() as MappingDataNode;
if (robustMapping == null) throw new InvalidOperationException();
if (robustMapping.TryGet("binds", out var BaseKeyRegsNode))
if (mapping.TryGet("binds", out var BaseKeyRegsNode))
{
var baseKeyRegs = serializationManager.Read<KeyBindingRegistration[]>(BaseKeyRegsNode);
var baseKeyRegs = _serialization.Read<KeyBindingRegistration[]>(BaseKeyRegsNode);
foreach (var reg in baseKeyRegs)
{
@@ -524,9 +521,9 @@ namespace Robust.Client.Input
}
}
if (userData && robustMapping.TryGet("leaveEmpty", out var node))
if (userData && mapping.TryGet("leaveEmpty", out var node))
{
var leaveEmpty = serializationManager.Read<BoundKeyFunction[]>(node);
var leaveEmpty = _serialization.Read<BoundKeyFunction[]>(node);
if (leaveEmpty.Length > 0)
{

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[module: SkipLocalsInit]

View File

@@ -0,0 +1,39 @@
using System.Diagnostics.CodeAnalysis;
using C = System.Console;
namespace Robust.LanguageServer;
internal sealed record CommandLineArgs(string? CommunicationPipe)
{
public static bool TryParse(IReadOnlyList<string> args, [NotNullWhen(true)] out CommandLineArgs? parsedArgs)
{
string? commPipe = null;
parsedArgs = null;
// ReSharper disable once GenericEnumeratorNotDisposed
var enumerator = args.GetEnumerator();
while (enumerator.MoveNext())
{
var arg = enumerator.Current;
if (arg == "--pipe")
{
if (!enumerator.MoveNext())
{
C.WriteLine("Expected pipe name");
return false;
}
commPipe = enumerator.Current;
}
else
{
C.WriteLine("Unknown argument");
return false;
}
}
parsedArgs = new CommandLineArgs(commPipe);
return true;
}
}

View File

@@ -0,0 +1,74 @@
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.LanguageServer;
internal sealed class DocumentSymbolHandler : IDocumentSymbolHandler
{
private readonly ILogger<DocumentSymbolHandler> _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly TextDocumentsCache _cache;
public DocumentSymbolHandler(
ILogger<DocumentSymbolHandler> logger,
ILoggerFactory loggerFactory,
TextDocumentsCache cache)
{
_logger = logger;
_loggerFactory = loggerFactory;
_cache = cache;
}
public Task<SymbolInformationOrDocumentSymbolContainer> Handle(
DocumentSymbolParams request,
CancellationToken cancellationToken)
{
var list = new List<SymbolInformationOrDocumentSymbol>();
using var sr = new StringReader(_cache.Get(request.TextDocument.Uri).Text);
var yaml = new YamlStream();
yaml.Load(sr);
foreach (var document in yaml.Documents)
{
var root = document.RootNode;
if (root is not YamlSequenceNode seq)
continue;
foreach (var child in seq.Children)
{
if (child is not YamlMappingNode map)
continue;
if (map.TryGetNode("id", out var idNode) && idNode is YamlScalarNode idScalar && idScalar.Value != null)
{
list.Add(new DocumentSymbol
{
Range = Helpers.ToLsp(idScalar.Start, idScalar.End),
Kind = SymbolKind.Class,
Name = idScalar.Value,
SelectionRange = Helpers.ToLsp(idScalar.Start, idScalar.End)
});
}
}
}
return Task.FromResult<SymbolInformationOrDocumentSymbolContainer>(list);
}
public DocumentSymbolRegistrationOptions GetRegistrationOptions(
DocumentSymbolCapability capability,
ClientCapabilities clientCapabilities)
{
return new DocumentSymbolRegistrationOptions
{
DocumentSelector = new DocumentSelector(new DocumentFilter { Language = "yaml" })
};
}
}

View File

@@ -0,0 +1,18 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using YamlDotNet.Core;
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
namespace Robust.LanguageServer;
public static class Helpers
{
public static Range ToLsp(Mark start, Mark end)
{
return (ToLsp(start), ToLsp(end));
}
public static Position ToLsp(Mark mark)
{
return (mark.Line - 1, mark.Column - 1);
}
}

View File

@@ -0,0 +1,22 @@
using Robust.Shared.Reflection;
namespace Robust.LanguageServer;
public sealed class LangServerReflectionManager : ReflectionManager
{
protected override IEnumerable<string> TypePrefixes => Prefixes;
private static readonly string[] Prefixes =
{
"",
"Robust.Client.",
"Content.Client.",
"Robust.Shared.",
"Content.Shared.",
"Robust.Server.",
"Content.Server.",
};
}

View File

@@ -0,0 +1,160 @@
using System.IO.Pipes;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
using OmniSharp.Extensions.LanguageServer.Server;
using Robust.LanguageServer;
using Robust.Shared;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
using Robust.Shared.Timing;
using Serilog;
if (!CommandLineArgs.TryParse(args, out var cliArgs))
return 1;
Stream outStream;
Stream inStream;
if (cliArgs.CommunicationPipe is { } pipe)
{
// Using pipe means we can log to stdout without ruining everything.
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.MinimumLevel.Verbose()
.CreateLogger();
Log.Debug("Communicating using pipe: {PipeName}", pipe);
var stream = new NamedPipeServerStream(
pipe,
PipeDirection.InOut,
1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
outStream = stream;
inStream = stream;
stream.WaitForConnection();
Log.Debug("Received pipe connection!");
}
else
{
outStream = Console.OpenStandardOutput();
inStream = Console.OpenStandardInput();
}
var server = await LanguageServer.From(options => options
.WithInput(inStream)
.WithOutput(outStream)
.ConfigureLogging(x => x
.AddLanguageProtocolLogging()
.AddSerilog()
.SetMinimumLevel(LogLevel.Debug))
.WithServices(x => x.AddSingleton<TextDocumentsCache>())
.AddHandler<DocumentSymbolHandler>()
.AddHandler<SemanticTokensHandler>()
.AddHandler(x => x.GetRequiredService<TextDocumentsCache>())
.WithServices(x => x.AddLogging(l => l.SetMinimumLevel(LogLevel.Trace)))
.WithServices(InitIoC)
.OnInitialize((languageServer, request, token) =>
{
languageServer.LogInfo("Initialize");
return Task.CompletedTask;
})
.OnInitialized((languageServer, request, response, token) =>
{
languageServer.LogInfo("Initialized!");
return Task.CompletedTask;
})
.OnStarted((languageServer, token) =>
{
var prototypes = languageServer.Services.GetRequiredService<IPrototypeManager>();
const string prototypeDir = @"C:\Users\Pieter-Jan Briers\Projects\ss14\space-station-14\Resources\Prototypes";
languageServer.LogInfo("started");
return Task.CompletedTask;
}));
await server.WaitForExit;
return 0;
void InitIoC(IServiceCollection services)
{
var deps = new ServiceDependencyCollection(services);
SharedIoC.RegisterIoC(deps, false);
deps.Register<IReflectionManager, LangServerReflectionManager>();
deps.Register<IGameTiming, GameTiming>();
deps.Register<IResourceManager, ResourceManager>();
deps.Register<IResourceManagerInternal, ResourceManager>();
deps.Register<IPrototypeManager, PrototypeManager>();
deps.Register<IAuthManager, AuthManager>();
deps.Register<IComponentFactory, ComponentFactory>();
// TODO: Get rid of entity dependencies.
deps.Register<IEntityManager, EntityManager>();
deps.Register<IMapManager, MapManager>();
deps.Register<IEntitySystemManager, EntitySystemManager>();
deps.BuildGraph();
}
sealed class FlushWrapStream : Stream
{
private readonly Stream _baseStream;
public FlushWrapStream(Stream baseStream)
{
_baseStream = baseStream;
}
public override void Flush()
{
_baseStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
_baseStream.Flush();
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="0.19.5" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,165 @@
using System.Collections.Immutable;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Robust.Shared.Collections;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.LanguageServer;
internal sealed class SemanticTokensHandler : ISemanticTokensFullHandler
{
private readonly ILogger<SemanticTokensHandler> _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly TextDocumentsCache _cache;
public SemanticTokensHandler(
ILogger<SemanticTokensHandler> logger,
ILoggerFactory loggerFactory,
TextDocumentsCache cache)
{
_logger = logger;
_loggerFactory = loggerFactory;
_cache = cache;
}
public Task<SemanticTokens?> Handle(SemanticTokensParams request, CancellationToken cancellationToken)
{
var tokens = new ValueList<SemanticTokenData>();
using var sr = new StringReader(_cache.Get(request.TextDocument.Uri).Text);
var yaml = new YamlStream();
yaml.Load(sr);
foreach (var document in yaml.Documents)
{
var root = document.RootNode;
if (root is not YamlSequenceNode seq)
continue;
foreach (var child in seq.Children)
{
if (child is not YamlMappingNode map)
continue;
if (map.TryGetNode("id", out var idNode) && idNode is YamlScalarNode idScalar &&
idScalar.Value != null)
{
var start = Helpers.ToLsp(idScalar.Start);
var end = Helpers.ToLsp(idScalar.End);
ref var token = ref tokens.AddRef();
token.TokenType = 0;
token.Length = end.Character - start.Character;
token.Line = start.Line;
token.StartChar = start.Character;
}
if (map.TryGetNode("type", out var typeNode) && typeNode is YamlScalarNode typeScalar &&
typeScalar.Value != null)
{
var start = Helpers.ToLsp(typeScalar.Start);
var end = Helpers.ToLsp(typeScalar.End);
ref var token = ref tokens.AddRef();
token.TokenType = 1;
token.Length = end.Character - start.Character;
token.Line = start.Line;
token.StartChar = start.Character;
}
}
}
tokens.Sort();
var lastLine = 0;
var lastChar = 0;
var ints = new int[tokens.Count * 5];
for (var i = 0; i < tokens.Count; i++)
{
ref var token = ref tokens[i];
var ii = i * 5;
var dl = token.Line - lastLine;
ints[ii + 0] = dl; // Delta line
ints[ii + 1] = token.StartChar; // Delta start char.
if (dl == 0)
ints[ii + 1] -= lastChar;
ints[ii + 2] = token.Length; // Length
ints[ii + 3] = token.TokenType; // Token type
ints[ii + 4] = token.TokenModifiers; // Token modifier.
lastLine = token.Line;
lastChar = token.StartChar;
}
return Task.FromResult<SemanticTokens?>(new SemanticTokens
{
Data = ImmutableArray.Create(ints)
});
}
public SemanticTokensRegistrationOptions GetRegistrationOptions(
SemanticTokensCapability capability,
ClientCapabilities clientCapabilities)
{
var options = new SemanticTokensRegistrationOptions
{
Full = true,
Legend = new SemanticTokensLegend
{
TokenModifiers = Array.Empty<SemanticTokenModifier>(),
TokenTypes = new[]
{
SemanticTokenType.Class,
SemanticTokenType.Enum,
}
},
Range = false
};
return options;
}
private struct SemanticTokenData : IComparable<SemanticTokenData>
{
public int Line;
public int StartChar;
public int Length;
public int TokenType;
public int TokenModifiers;
public int CompareTo(SemanticTokenData other)
{
var cmp = Line.CompareTo(other.Line);
if (cmp != 0)
return cmp;
return StartChar.CompareTo(other.StartChar);
}
public static bool operator <(SemanticTokenData left, SemanticTokenData right)
{
return left.CompareTo(right) < 0;
}
public static bool operator >(SemanticTokenData left, SemanticTokenData right)
{
return left.CompareTo(right) > 0;
}
public static bool operator <=(SemanticTokenData left, SemanticTokenData right)
{
return left.CompareTo(right) <= 0;
}
public static bool operator >=(SemanticTokenData left, SemanticTokenData right)
{
return left.CompareTo(right) >= 0;
}
}
}

View File

@@ -0,0 +1,136 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using Robust.Shared.IoC;
namespace Robust.LanguageServer;
/// <summary>
/// Implementation of <see cref="IDependencyCollection"/> that copies registrations to a <see cref="IServiceCollection"/>.
/// </summary>
public sealed class ServiceDependencyCollection : IDependencyCollection
{
private readonly IServiceCollection _collection;
private readonly DependencyCollection _deps = new();
public ServiceDependencyCollection(IServiceCollection collection)
{
_collection = collection;
collection.AddSingleton<IDependencyCollection>(this);
}
public void Register<TInterface, TImplementation>(bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
_deps.Register<TInterface, TImplementation>(overwrite);
_collection.AddSingleton<TInterface>(_ => Resolve<TInterface>());
}
public void Register<TInterface, TImplementation>(
DependencyFactoryDelegate<TImplementation> factory,
bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
_deps.Register<TInterface, TImplementation>(factory, overwrite);
_collection.AddSingleton<TInterface>(_ => Resolve<TInterface>());
}
public void Register(
Type implementation,
DependencyFactoryDelegate<object>? factory = null,
bool overwrite = false)
{
_deps.Register(implementation, factory, overwrite);
_collection.AddSingleton(implementation, _ => ResolveType(implementation));
}
public void Register(
Type interfaceType,
Type implementation,
DependencyFactoryDelegate<object>? factory = null,
bool overwrite = false)
{
_deps.Register(interfaceType, implementation, factory, overwrite);
_collection.AddSingleton(interfaceType, _ => ResolveType(interfaceType));
}
public void RegisterInstance<TInterface>(object implementation, bool overwrite = false, bool deferInject = false)
where TInterface : class
{
_deps.RegisterInstance<TInterface>(implementation, overwrite, deferInject);
_collection.AddSingleton((TInterface)implementation);
}
public void RegisterInstance(Type type, object implementation, bool overwrite = false, bool deferInject = false)
{
_deps.RegisterInstance(type, implementation, overwrite, deferInject);
_collection.AddSingleton(type, _ => ResolveType(type));
}
public void Clear()
{
_deps.Clear();
}
public T Resolve<T>()
{
return _deps.Resolve<T>();
}
public void Resolve<T>([NotNull]ref T? instance)
{
_deps.Resolve(ref instance);
}
public void Resolve<T1, T2>([NotNull]ref T1? instance1, [NotNull]ref T2? instance2)
{
_deps.Resolve(ref instance1, ref instance2);
}
public void Resolve<T1, T2, T3>([NotNull]ref T1? instance1, [NotNull]ref T2? instance2, [NotNull]ref T3? instance3)
{
_deps.Resolve(ref instance1, ref instance2, ref instance3);
}
public void Resolve<T1, T2, T3, T4>(
[NotNull]ref T1? instance1,
[NotNull]ref T2? instance2,
[NotNull]ref T3? instance3,
[NotNull]ref T4? instance4)
{
_deps.Resolve(ref instance1, ref instance2, ref instance3, ref instance4);
}
public object ResolveType(Type type)
{
return _deps.ResolveType(type);
}
public bool TryResolveType<T>([NotNullWhen(true)] out T? instance)
{
return _deps.TryResolveType(out instance);
}
public bool TryResolveType(Type objectType, [MaybeNullWhen(false)] out object instance)
{
return _deps.TryResolveType(objectType, out instance);
}
public void BuildGraph()
{
_deps.BuildGraph();
}
public void InjectDependencies(object obj, bool oneOff = false)
{
_deps.InjectDependencies(obj, oneOff);
}
}

View File

@@ -0,0 +1,73 @@
using MediatR;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities;
namespace Robust.LanguageServer;
public sealed class TextDocumentsCache : TextDocumentSyncHandlerBase
{
private readonly Dictionary<DocumentUri, CachedTextDocument> _documents = new();
public CachedTextDocument Get(DocumentUri uri) => _documents[uri];
public override TextDocumentAttributes GetTextDocumentAttributes(DocumentUri uri)
{
return new TextDocumentAttributes(uri, "yaml");
}
public override Task<Unit> Handle(DidOpenTextDocumentParams request, CancellationToken cancellationToken)
{
var doc = new CachedTextDocument
{
Text = request.TextDocument.Text
};
_documents.Add(request.TextDocument.Uri, doc);
return Unit.Task;
}
public override Task<Unit> Handle(DidChangeTextDocumentParams request, CancellationToken cancellationToken)
{
var doc = _documents[request.TextDocument.Uri];
doc.Version = request.TextDocument.Version;
foreach (var change in request.ContentChanges)
{
if (change.Range != null)
throw new NotSupportedException("Incremental updates not currently supported!");
doc.Text = change.Text;
}
return Unit.Task;
}
public override Task<Unit> Handle(DidSaveTextDocumentParams request, CancellationToken cancellationToken)
{
return Unit.Task;
}
public override Task<Unit> Handle(DidCloseTextDocumentParams request, CancellationToken cancellationToken)
{
_documents.Remove(request.TextDocument.Uri);
return Unit.Task;
}
protected override TextDocumentSyncRegistrationOptions CreateRegistrationOptions(
SynchronizationCapability capability,
ClientCapabilities clientCapabilities)
{
return new TextDocumentSyncRegistrationOptions(TextDocumentSyncKind.Full);
}
}
public sealed class CachedTextDocument
{
public string Text { get; set; } = "";
public int? Version { get; set; }
}

View File

@@ -93,17 +93,22 @@ namespace Robust.Server.Maps
{
Logger.InfoS("map", $"Loading Grid: {resPath}");
var data = new MapData(reader);
var (map, gridCount) = LoadBasicMapData(reader);
LoadedMapData?.Invoke(data.Stream, resPath.ToString());
if (data.GridCount != 1)
{
if (gridCount != 1)
throw new InvalidDataException("Cannot instance map with multiple grids as blueprint.");
}
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager,
_prototypeManager, _serializationManager, _componentFactory, data.RootNode.ToDataNodeCast<MappingDataNode>(), mapId, options);
var context = new MapContext(
_mapManager,
_tileDefinitionManager,
_serverEntityManager,
_prototypeManager,
_serializationManager,
_componentFactory,
map,
mapId,
options);
context.Deserialize();
grid = context.Grids.FirstOrDefault();
entities = context.Entities;
@@ -217,12 +222,19 @@ namespace Robust.Server.Maps
{
Logger.InfoS("map", $"Loading Map: {resPath}");
var data = new MapData(reader);
var (map, _) = LoadBasicMapData(reader);
LoadedMapData?.Invoke(data.Stream, resPath.ToString());
var context = new MapContext(
_mapManager,
_tileDefinitionManager,
_serverEntityManager,
_prototypeManager,
_serializationManager,
_componentFactory,
map,
mapId,
options);
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager,
_prototypeManager, _serializationManager, _componentFactory, data.RootNode.ToDataNodeCast<MappingDataNode>(), mapId, options);
context.Deserialize();
grids = context.Grids.Select(x => x.GridEntityId).ToArray(); // TODO: make context use grid IDs.
entities = context.Entities;
@@ -233,6 +245,24 @@ namespace Robust.Server.Maps
return (entities, grids);
}
private static (MappingDataNode, int gridCount) LoadBasicMapData(TextReader reader)
{
var documents = DataNodeParser.ParseYamlStream(reader).ToArray();
if (documents.Length < 1)
throw new InvalidDataException("Stream has no YAML documents.");
// Kinda wanted to just make this print a warning and pick [0] but screw that.
// What is this, a hug box?
if (documents.Length > 1)
throw new InvalidDataException("Stream too many YAML documents. Map files store exactly one.");
var map = (MappingDataNode) documents[0].Root;
var gridCount = ((SequenceDataNode) map["grids"]).Count;
return (map, gridCount);
}
/// <summary>
/// Handles the primary bulk of state during the map serialization process.
/// </summary>
@@ -1193,38 +1223,5 @@ namespace Robust.Server.Maps
return new((int) source);
}
}
/// <summary>
/// Does basic pre-deserialization checks on map file load.
/// For example, let's not try to use maps with multiple grids as blueprints, shall we?
/// </summary>
private sealed class MapData
{
public YamlStream Stream { get; }
public YamlNode RootNode => Stream.Documents[0].RootNode;
public int GridCount { get; }
public MapData(TextReader reader)
{
var stream = new YamlStream();
stream.Load(reader);
if (stream.Documents.Count < 1)
{
throw new InvalidDataException("Stream has no YAML documents.");
}
// Kinda wanted to just make this print a warning and pick [0] but screw that.
// What is this, a hug box?
if (stream.Documents.Count > 1)
{
throw new InvalidDataException("Stream too many YAML documents. Map files store exactly one.");
}
Stream = stream;
GridCount = ((YamlSequenceNode) RootNode["grids"]).Children.Count;
}
}
}
}

View File

@@ -50,7 +50,7 @@ namespace Robust.Server
{
Thread.CurrentThread.Name = "Main Thread";
IoCManager.InitThread();
ServerIoC.RegisterIoC();
ServerIoC.RegisterIoC(IoCManager.Instance!);
IoCManager.BuildGraph();
SetupLogging();
InitReflectionManager();

View File

@@ -31,50 +31,50 @@ namespace Robust.Server
internal static class ServerIoC
{
/// <summary>
/// Registers all the types into the <see cref="IoCManager"/> with <see cref="IoCManager.Register{TInterface, TImplementation}"/>
/// Registers all the types into the <see cref="IDependencyCollection"/>
/// </summary>
internal static void RegisterIoC()
internal static void RegisterIoC(IDependencyCollection deps)
{
SharedIoC.RegisterIoC();
SharedIoC.RegisterIoC(deps);
IoCManager.Register<IBaseServer, BaseServer>();
IoCManager.Register<IBaseServerInternal, BaseServer>();
IoCManager.Register<BaseServer, BaseServer>();
IoCManager.Register<IGameTiming, GameTiming>();
IoCManager.Register<IReflectionManager, ServerReflectionManager>();
IoCManager.Register<IConsoleHost, ServerConsoleHost>();
IoCManager.Register<IServerConsoleHost, ServerConsoleHost>();
IoCManager.Register<IComponentFactory, ServerComponentFactory>();
IoCManager.Register<IConGroupController, ConGroupController>();
IoCManager.Register<IMapManager, NetworkedMapManager>();
IoCManager.Register<IMapManagerInternal, NetworkedMapManager>();
IoCManager.Register<INetworkedMapManager, NetworkedMapManager>();
IoCManager.Register<IEntityManager, ServerEntityManager>();
IoCManager.Register<IEntityNetworkManager, ServerEntityManager>();
IoCManager.Register<IServerEntityNetworkManager, ServerEntityManager>();
IoCManager.Register<IMapLoader, MapLoader>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<ISharedPlayerManager, PlayerManager>();
IoCManager.Register<IPrototypeManager, ServerPrototypeManager>();
IoCManager.Register<IResourceManager, ResourceManager>();
IoCManager.Register<IResourceManagerInternal, ResourceManager>();
IoCManager.Register<EntityManager, ServerEntityManager>();
IoCManager.Register<IServerEntityManager, ServerEntityManager>();
IoCManager.Register<IServerEntityManagerInternal, ServerEntityManager>();
IoCManager.Register<IServerGameStateManager, ServerGameStateManager>();
IoCManager.Register<IServerNetManager, NetManager>();
IoCManager.Register<IStatusHost, StatusHost>();
IoCManager.Register<ISystemConsoleManager, SystemConsoleManager>();
IoCManager.Register<ITileDefinitionManager, TileDefinitionManager>();
IoCManager.Register<IViewVariablesHost, ViewVariablesHost>();
IoCManager.Register<IWatchdogApi, WatchdogApi>();
IoCManager.Register<IScriptHost, ScriptHost>();
IoCManager.Register<IMetricsManager, MetricsManager>();
IoCManager.Register<IAuthManager, AuthManager>();
IoCManager.Register<IPhysicsManager, PhysicsManager>();
IoCManager.Register<IBqlQueryManager, BqlQueryManager>();
IoCManager.Register<HubManager, HubManager>();
deps.Register<IBaseServer, BaseServer>();
deps.Register<IBaseServerInternal, BaseServer>();
deps.Register<BaseServer, BaseServer>();
deps.Register<IGameTiming, GameTiming>();
deps.Register<IReflectionManager, ServerReflectionManager>();
deps.Register<IConsoleHost, ServerConsoleHost>();
deps.Register<IServerConsoleHost, ServerConsoleHost>();
deps.Register<IComponentFactory, ServerComponentFactory>();
deps.Register<IConGroupController, ConGroupController>();
deps.Register<IMapManager, NetworkedMapManager>();
deps.Register<IMapManagerInternal, NetworkedMapManager>();
deps.Register<INetworkedMapManager, NetworkedMapManager>();
deps.Register<IEntityManager, ServerEntityManager>();
deps.Register<IEntityNetworkManager, ServerEntityManager>();
deps.Register<IServerEntityNetworkManager, ServerEntityManager>();
deps.Register<IMapLoader, MapLoader>();
deps.Register<IPlacementManager, PlacementManager>();
deps.Register<IPlayerManager, PlayerManager>();
deps.Register<ISharedPlayerManager, PlayerManager>();
deps.Register<IPrototypeManager, ServerPrototypeManager>();
deps.Register<IResourceManager, ResourceManager>();
deps.Register<IResourceManagerInternal, ResourceManager>();
deps.Register<EntityManager, ServerEntityManager>();
deps.Register<IServerEntityManager, ServerEntityManager>();
deps.Register<IServerEntityManagerInternal, ServerEntityManager>();
deps.Register<IServerGameStateManager, ServerGameStateManager>();
deps.Register<IServerNetManager, NetManager>();
deps.Register<IStatusHost, StatusHost>();
deps.Register<ISystemConsoleManager, SystemConsoleManager>();
deps.Register<ITileDefinitionManager, TileDefinitionManager>();
deps.Register<IViewVariablesHost, ViewVariablesHost>();
deps.Register<IWatchdogApi, WatchdogApi>();
deps.Register<IScriptHost, ScriptHost>();
deps.Register<IMetricsManager, MetricsManager>();
deps.Register<IAuthManager, AuthManager>();
deps.Register<IPhysicsManager, PhysicsManager>();
deps.Register<IBqlQueryManager, BqlQueryManager>();
deps.Register<HubManager, HubManager>();
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
namespace Robust.Shared.GameObjects;
internal sealed class PrototypeReloadSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
public override void Initialize()
{
_prototypes.PrototypesReloaded += OnPrototypesReloaded;
}
public override void Shutdown()
{
base.Shutdown();
_prototypes.PrototypesReloaded -= OnPrototypesReloaded;
}
private void OnPrototypesReloaded(PrototypesReloadedEventArgs eventArgs)
{
if (!eventArgs.ByType.TryGetValue(typeof(EntityPrototype), out var set))
return;
foreach (var metadata in EntityQuery<MetaDataComponent>())
{
var id = metadata.EntityPrototype?.ID;
if (id == null || !set.Modified.ContainsKey(id))
continue;
var proto = _prototypes.Index<EntityPrototype>(id);
UpdateEntity(metadata.Owner, metadata, proto);
}
}
private void UpdateEntity(EntityUid entity, MetaDataComponent metaData, EntityPrototype newPrototype)
{
var oldPrototype = metaData.EntityPrototype;
var oldPrototypeComponents = oldPrototype?.Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, _componentFactory.GetRegistration(name).Type))
.ToList() ?? new List<(string name, Type Type)>();
var newPrototypeComponents = newPrototype.Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, _componentFactory.GetRegistration(name).Type))
.ToList();
var ignoredComponents = new List<string>();
// Find components to be removed, and remove them
foreach (var (name, type) in oldPrototypeComponents.Except(newPrototypeComponents))
{
if (newPrototype.Components.ContainsKey(name))
{
ignoredComponents.Add(name);
continue;
}
RemComp(entity, type);
}
EntityManager.CullRemovedComponents();
// Add new components
foreach (var (name, _) in newPrototypeComponents.Where(t => !ignoredComponents.Contains(t.name))
.Except(oldPrototypeComponents))
{
var data = newPrototype.Components[name];
var component = (Component)_componentFactory.GetComponent(name);
component.Owner = entity;
EntityManager.AddComponent(entity, component);
}
// Update entity metadata
metaData.EntityPrototype = newPrototype;
}
}

View File

@@ -79,6 +79,7 @@ namespace Robust.Shared.IoC
/// <inheritdoc />
public void Register<TInterface, TImplementation>(bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
Register<TInterface, TImplementation>(() =>
{
@@ -118,6 +119,8 @@ namespace Robust.Shared.IoC
/// <inheritdoc />
public void Register<TInterface, TImplementation>(DependencyFactoryDelegate<TImplementation> factory, bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
var interfaceType = typeof(TInterface);
CheckRegisterInterface(interfaceType, typeof(TImplementation), overwrite);
@@ -198,6 +201,7 @@ namespace Robust.Shared.IoC
/// <inheritdoc />
public void RegisterInstance<TInterface>(object implementation, bool overwrite = false, bool deferInject = false)
where TInterface : class
{
RegisterInstance(typeof(TInterface), implementation, overwrite, deferInject);
}

View File

@@ -0,0 +1,20 @@
using JetBrains.Annotations;
namespace Robust.Shared.IoC;
/// <summary>
/// Extension methods for <see cref="IDependencyCollection"/>.
/// </summary>
public static class DependencyCollectionExt
{
/// <summary>
/// Register a type as both implementation and interface.
/// This is equivalent to calling <see cref="IDependencyCollection.Register{TInterface, TImplementation}(bool)"/> with both type args set to <typeparamref name="T"/>.
/// </summary>
/// <param name="deps">The dependency collection to register into.</param>
public static void Register<[MeansImplicitUse] T>(this IDependencyCollection deps)
where T : class
{
deps.Register<T, T>();
}
}

View File

@@ -44,7 +44,8 @@ namespace Robust.Shared.IoC
/// or if an already instantiated interface (by <see cref="DependencyCollection.BuildGraph"/>) is attempting to be overwritten.
/// </exception>
void Register<TInterface, [MeansImplicitUse] TImplementation>(bool overwrite = false)
where TImplementation : class, TInterface;
where TImplementation : class, TInterface
where TInterface : class;
/// <summary>
/// Registers an interface to an implementation, to make it accessible to <see cref="DependencyCollection.Resolve{T}"/>
@@ -62,7 +63,8 @@ namespace Robust.Shared.IoC
/// or if an already instantiated interface (by <see cref="DependencyCollection.BuildGraph"/>) is attempting to be overwritten.
/// </exception>
void Register<TInterface, TImplementation>(DependencyFactoryDelegate<TImplementation> factory, bool overwrite = false)
where TImplementation : class, TInterface;
where TImplementation : class, TInterface
where TInterface : class;
/// <summary>
@@ -107,7 +109,8 @@ namespace Robust.Shared.IoC
/// If this is false, dependencies will be immediately injected. If the registered type requires dependencies
/// that don't exist yet because you have not called BuildGraph, set this to true.
/// </param>
void RegisterInstance<TInterface>(object implementation, bool overwrite = false, bool deferInject = false);
void RegisterInstance<TInterface>(object implementation, bool overwrite = false, bool deferInject = false)
where TInterface : class;
/// <summary>
/// Registers an interface to an existing instance of an implementation,

View File

@@ -101,6 +101,7 @@ namespace Robust.Shared.IoC
/// </exception>
public static void Register<TInterface, [MeansImplicitUse] TImplementation>(bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
DebugTools.Assert(_container.IsValueCreated, NoContextAssert);
@@ -141,6 +142,7 @@ namespace Robust.Shared.IoC
/// </exception>
public static void Register<TInterface, TImplementation>(DependencyFactoryDelegate<TImplementation> factory, bool overwrite = false)
where TImplementation : class, TInterface
where TInterface : class
{
DebugTools.Assert(_container.IsValueCreated, NoContextAssert);
@@ -166,6 +168,7 @@ namespace Robust.Shared.IoC
/// that don't exist yet because you have not called BuildGraph, set this to true.
/// </param>
public static void RegisterInstance<TInterface>(object implementation, bool overwrite = false, bool deferInject = false)
where TInterface : class
{
DebugTools.Assert(_container.IsValueCreated, NoContextAssert);

View File

@@ -1,8 +1,11 @@
using System;
using System.Globalization;
using System.Linq;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
namespace Robust.Shared.Map
{
@@ -11,10 +14,10 @@ namespace Robust.Shared.Map
/// <inheritdoc />
public void SetMapPaused(MapId mapId, bool paused)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return;
if(!MapExists(mapId))
if (!MapExists(mapId))
throw new ArgumentException("That map does not exist.");
if (paused)
@@ -51,7 +54,7 @@ namespace Robust.Shared.Map
/// <inheritdoc />
public void DoMapInitialize(MapId mapId)
{
if(!MapExists(mapId))
if (!MapExists(mapId))
throw new ArgumentException("That map does not exist.");
if (IsMapInitialized(mapId))
@@ -76,7 +79,7 @@ namespace Robust.Shared.Map
{
// RunMapInit can modify the TransformTree
// ToArray caches deleted euids, we check here if they still exist.
if(!metaQuery.TryGetComponent(entity, out var meta))
if (!metaQuery.TryGetComponent(entity, out var meta))
return;
EntityManager.RunMapInit(entity, meta);
@@ -96,7 +99,7 @@ namespace Robust.Shared.Map
private void SetMapPause(MapId mapId)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return;
var mapEuid = GetMapEntityId(mapId);
@@ -106,7 +109,7 @@ namespace Robust.Shared.Map
private bool CheckMapPause(MapId mapId)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return false;
var mapEuid = GetMapEntityId(mapId);
@@ -120,7 +123,7 @@ namespace Robust.Shared.Map
private void ClearMapPause(MapId mapId)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return;
var mapEuid = GetMapEntityId(mapId);
@@ -130,7 +133,7 @@ namespace Robust.Shared.Map
private void SetMapPreInit(MapId mapId)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return;
var mapEuid = GetMapEntityId(mapId);
@@ -140,7 +143,7 @@ namespace Robust.Shared.Map
private bool CheckMapPreInit(MapId mapId)
{
if(mapId == MapId.Nullspace)
if (mapId == MapId.Nullspace)
return false;
var mapEuid = GetMapEntityId(mapId);
@@ -193,71 +196,83 @@ namespace Robust.Shared.Map
{
return !CheckMapPreInit(mapId);
}
/// <summary>
/// Initializes the map pausing system.
/// </summary>
private void InitializeMapPausing()
{
_conhost.RegisterCommand("pausemap",
"Pauses a map, pausing all simulation processing on it.",
"pausemap <map ID>",
(shell, _, args) =>
{
if (args.Length != 1)
{
shell.WriteError("Need to supply a valid MapId");
return;
}
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!MapExists(mapId))
{
shell.WriteError("That map does not exist.");
return;
}
SetMapPaused(mapId, true);
});
_conhost.RegisterCommand("querymappaused",
"Check whether a map is paused or not.",
"querymappaused <map ID>",
(shell, _, args) =>
{
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!MapExists(mapId))
{
shell.WriteError("That map does not exist.");
return;
}
shell.WriteLine(IsMapPaused(mapId).ToString());
});
_conhost.RegisterCommand("unpausemap",
"unpauses a map, resuming all simulation processing on it.",
"Usage: unpausemap <map ID>",
(shell, _, args) =>
{
if (args.Length != 1)
{
shell.WriteLine("Need to supply a valid MapId");
return;
}
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!MapExists(mapId))
{
shell.WriteLine("That map does not exist.");
return;
}
SetMapPaused(mapId, false);
});
}
}
}
internal sealed class PauseMapCommand : IConsoleCommand
{
[Dependency] private readonly IMapManager _map = default!;
public string Command => "pausemap";
public string Description => "Pauses a map, pausing all simulation processing on it.";
public string Help => "pausemap <map ID>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
shell.WriteError("Need to supply a valid MapId");
return;
}
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!_map.MapExists(mapId))
{
shell.WriteError("That map does not exist.");
return;
}
_map.SetMapPaused(mapId, true);
}
}
internal sealed class QueryMapPausedCommand : IConsoleCommand
{
[Dependency] private readonly IMapManager _map = default!;
public string Command => "querymappaused";
public string Description => "Check whether a map is paused or not.";
public string Help => "querymappaused <map ID>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!_map.MapExists(mapId))
{
shell.WriteError("That map does not exist.");
return;
}
shell.WriteLine(_map.IsMapPaused(mapId).ToString());
}
}
internal sealed class UnPauseMapCommand : IConsoleCommand
{
[Dependency] private readonly IMapManager _map = default!;
public string Command => "unpausemap";
public string Description => "unpauses a map, resuming all simulation processing on it.";
public string Help => "Usage: unpausemap <map ID>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
shell.WriteLine("Need to supply a valid MapId");
return;
}
var mapId = new MapId(int.Parse(args[0], CultureInfo.InvariantCulture));
if (!_map.MapExists(mapId))
{
shell.WriteLine("That map does not exist.");
return;
}
_map.SetMapPaused(mapId, false);
}
}

View File

@@ -14,8 +14,6 @@ internal partial class MapManager : IMapManagerInternal, IEntityEventSubscriber
[field: Dependency] public IGameTiming GameTiming { get; } = default!;
[field: Dependency] public IEntityManager EntityManager { get; } = default!;
[Dependency] private readonly IConsoleHost _conhost = default!;
/// <inheritdoc />
public void Initialize()
{
@@ -24,7 +22,6 @@ internal partial class MapManager : IMapManagerInternal, IEntityEventSubscriber
DebugTools.Assert(!_dbgGuardRunning);
_dbgGuardInit = true;
#endif
InitializeMapPausing();
}
/// <inheritdoc />

View File

@@ -12,6 +12,7 @@
[assembly: InternalsVisibleTo("Content.Benchmarks")]
[assembly: InternalsVisibleTo("Robust.Benchmarks")]
[assembly: InternalsVisibleTo("Robust.Client.WebView")]
[assembly: InternalsVisibleTo("Robust.LanguageServer")]
#if NET5_0_OR_GREATER
[module: SkipLocalsInit]

View File

@@ -190,60 +190,6 @@ namespace Robust.Shared.Prototypes
return true;
}
public void UpdateEntity(EntityUid entity)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
var metaData = entityManager.GetComponent<MetaDataComponent>(entity);
if (ID != metaData.EntityPrototype?.ID)
{
Logger.Error(
$"Reloaded prototype used to update entity did not match entity's existing prototype: Expected '{ID}', got '{entityManager.GetComponent<MetaDataComponent>(entity).EntityPrototype?.ID}'");
return;
}
var factory = IoCManager.Resolve<IComponentFactory>();
var oldPrototype = metaData.EntityPrototype;
var oldPrototypeComponents = oldPrototype?.Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, factory.GetRegistration(name).Type))
.ToList() ?? new List<(string name, Type Type)>();
var newPrototypeComponents = Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, factory.GetRegistration(name).Type))
.ToList();
var ignoredComponents = new List<string>();
// Find components to be removed, and remove them
foreach (var (name, type) in oldPrototypeComponents.Except(newPrototypeComponents))
{
if (Components.Keys.Contains(name))
{
ignoredComponents.Add(name);
continue;
}
entityManager.RemoveComponent(entity, type);
}
entityManager.CullRemovedComponents();
// Add new components
foreach (var (name, type) in newPrototypeComponents.Where(t => !ignoredComponents.Contains(t.name))
.Except(oldPrototypeComponents))
{
var data = Components[name];
var component = (Component) factory.GetComponent(name);
component.Owner = entity;
entityManager.AddComponent(entity, component);
}
// Update entity metadata
metaData.EntityPrototype = this;
}
internal static void LoadEntity(
EntityPrototype? prototype,
EntityUid entity,

View File

@@ -6,10 +6,8 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using JetBrains.Annotations;
using Prometheus;
using Robust.Shared.Asynchronous;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.IoC.Exceptions;
using Robust.Shared.Log;
@@ -18,10 +16,10 @@ using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Prototypes
@@ -29,43 +27,48 @@ namespace Robust.Shared.Prototypes
/// <summary>
/// Handle storage and loading of YAML prototypes.
/// </summary>
/// <remarks>
/// Terminology:
/// "Kinds" are the types of prototypes there are, like <see cref="EntityPrototype"/>.
/// "Prototypes" are simply filled-in prototypes from YAML.
/// </remarks>
public interface IPrototypeManager
{
void Initialize();
/// <summary>
/// Return an IEnumerable to iterate all prototypes of a certain type.
/// Return an <see cref="IEnumerable{T}"/> to iterate all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the type of prototype is not registered.
/// Thrown if the kind of prototype is not registered.
/// </exception>
IEnumerable<T> EnumeratePrototypes<T>() where T : class, IPrototype;
/// <summary>
/// Return an IEnumerable to iterate all prototypes of a certain type.
/// Return an IEnumerable to iterate all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the type of prototype is not registered.
/// Thrown if the kind of prototype is not registered.
/// </exception>
IEnumerable<IPrototype> EnumeratePrototypes(Type type);
IEnumerable<IPrototype> EnumeratePrototypes(Type kind);
/// <summary>
/// Return an IEnumerable to iterate all prototypes of a certain variant.
/// Return an <see cref="IEnumerable{T}"/> to iterate all prototypes of a certain kind.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the variant of prototype is not registered.
/// Thrown if the kind of prototype is not registered.
/// </exception>
IEnumerable<IPrototype> EnumeratePrototypes(string variant);
IEnumerable<IPrototype> EnumeratePrototypes(string kind);
/// <summary>
/// Returns an IEnumerable to iterate all parents of a prototype of a certain type.
/// Returns an IEnumerable to iterate all parents of a prototype of a certain kind.
/// </summary>
IEnumerable<T> EnumerateParents<T>(string id, bool includeSelf = false) where T : class, IPrototype, IInheritingPrototype;
/// <summary>
/// Returns an IEnumerable to iterate all parents of a prototype of a certain type.
/// Returns an IEnumerable to iterate all parents of a prototype of a certain kind.
/// </summary>
IEnumerable<IPrototype> EnumerateParents(Type type, string id, bool includeSelf = false);
IEnumerable<IPrototype> EnumerateParents(Type kind, string id, bool includeSelf = false);
/// <summary>
/// Index for a <see cref="IPrototype"/> by ID.
@@ -79,25 +82,26 @@ namespace Robust.Shared.Prototypes
/// Index for a <see cref="IPrototype"/> by ID.
/// </summary>
/// <exception cref="KeyNotFoundException">
/// Thrown if the ID does not exist or the type of prototype is not registered.
/// Thrown if the ID does not exist or the kind of prototype is not registered.
/// </exception>
IPrototype Index(Type type, string id);
IPrototype Index(Type kind, string id);
/// <summary>
/// Returns whether a prototype of type <typeparamref name="T"/> with the specified <param name="id"/> exists.
/// </summary>
bool HasIndex<T>(string id) where T : class, IPrototype;
bool TryIndex<T>(string id, [NotNullWhen(true)] out T? prototype) where T : class, IPrototype;
bool TryIndex(Type type, string id, [NotNullWhen(true)] out IPrototype? prototype);
bool TryIndex(Type kind, string id, [NotNullWhen(true)] out IPrototype? prototype);
bool HasMapping<T>(string id);
bool TryGetMapping(Type type, string id, [NotNullWhen(true)] out MappingDataNode? mappings);
bool TryGetMapping(Type kind, string id, [NotNullWhen(true)] out MappingDataNode? mappings);
/// <summary>
/// Returns whether a prototype variant <param name="variant"/> exists.
/// </summary>
/// <param name="variant">Identifier for the prototype variant.</param>
/// <returns>Whether the prototype variant exists.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool HasVariant(string variant);
/// <summary>
@@ -108,6 +112,7 @@ namespace Robust.Shared.Prototypes
/// <exception cref="KeyNotFoundException">
/// Thrown when the specified prototype variant isn't registered or doesn't exist.
/// </exception>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
Type GetVariantType(string variant);
/// <summary>
@@ -116,6 +121,7 @@ namespace Robust.Shared.Prototypes
/// <param name="variant">Identifier for the prototype variant.</param>
/// <param name="prototype">The specified prototype Type, or null.</param>
/// <returns>Whether the prototype type was found and <see cref="prototype"/> isn't null.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantType(string variant, [NotNullWhen(true)] out Type? prototype);
/// <summary>
@@ -124,6 +130,7 @@ namespace Robust.Shared.Prototypes
/// <param name="type"></param>
/// <param name="variant"></param>
/// <returns></returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom(Type type, [NotNullWhen(true)] out string? variant);
/// <summary>
@@ -132,6 +139,7 @@ namespace Robust.Shared.Prototypes
/// <param name="prototype">The prototype in question.</param>
/// <param name="variant">Identifier for the prototype variant, or null.</param>
/// <returns>Whether the prototype variant was successfully retrieved.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom(IPrototype prototype, [NotNullWhen(true)] out string? variant);
/// <summary>
@@ -140,8 +148,59 @@ namespace Robust.Shared.Prototypes
/// <param name="variant">Identifier for the prototype variant, or null.</param>
/// <typeparam name="T">The prototype in question.</typeparam>
/// <returns>Whether the prototype variant was successfully retrieved.</returns>
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
bool TryGetVariantFrom<T>([NotNullWhen(true)] out string? variant) where T : class, IPrototype;
/// <summary>
/// Returns whether a prototype kind <param name="kind"/> exists.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <returns>Whether the prototype kind exists.</returns>
bool HasKind(string kind);
/// <summary>
/// Returns the Type for a prototype kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <returns>The specified prototype Type.</returns>
/// <exception cref="KeyNotFoundException">
/// Thrown when the specified prototype kind isn't registered or doesn't exist.
/// </exception>
Type GetKindType(string kind);
/// <summary>
/// Attempts to get the Type for a prototype kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind.</param>
/// <param name="prototype">The specified prototype Type, or null.</param>
/// <returns>Whether the prototype type was found and <see cref="prototype"/> isn't null.</returns>
bool TryGetKindType(string kind, [NotNullWhen(true)] out Type? prototype);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="type"></param>
/// <param name="kind"></param>
/// <returns></returns>
bool TryGetKindFrom(Type type, [NotNullWhen(true)] out string? kind);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="prototype">The prototype in question.</param>
/// <param name="kind">Identifier for the prototype kind, or null.</param>
/// <returns>Whether the prototype kind was successfully retrieved.</returns>
bool TryGetKindFrom(IPrototype prototype, [NotNullWhen(true)] out string? kind);
/// <summary>
/// Attempts to get a prototype's kind.
/// </summary>
/// <param name="kind">Identifier for the prototype kind, or null.</param>
/// <typeparam name="T">The prototype in question.</typeparam>
/// <returns>Whether the prototype kind was successfully retrieved.</returns>
bool TryGetKindFrom<T>([NotNullWhen(true)] out string? kind) where T : class, IPrototype;
/// <summary>
/// Load prototypes from files in a directory, recursively.
/// </summary>
@@ -220,11 +279,10 @@ namespace Robust.Shared.Prototypes
{
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] protected readonly IResourceManager Resources = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] protected readonly ITaskManager TaskManager = default!;
[Dependency] private readonly ISerializationManager _serializationManager = default!;
private readonly Dictionary<string, Type> _prototypeTypes = new();
private readonly Dictionary<string, Type> _kindNames = new();
private readonly Dictionary<Type, int> _prototypePriorities = new();
private bool _initialized;
@@ -232,9 +290,7 @@ namespace Robust.Shared.Prototypes
#region IPrototypeManager members
private readonly Dictionary<Type, Dictionary<string, IPrototype>> _prototypes = new();
private readonly Dictionary<Type, Dictionary<string, MappingDataNode>> _prototypeResults = new();
private readonly Dictionary<Type, MultiRootInheritanceGraph<string>> _inheritanceTrees = new();
private readonly Dictionary<Type, KindData> _kinds = new();
private readonly HashSet<string> _ignoredPrototypeTypes = new();
@@ -246,7 +302,7 @@ namespace Robust.Shared.Prototypes
}
_initialized = true;
ReloadPrototypeTypes();
ReloadPrototypeKinds();
}
public IEnumerable<T> EnumeratePrototypes<T>() where T : class, IPrototype
@@ -256,27 +312,27 @@ namespace Robust.Shared.Prototypes
throw new InvalidOperationException("No prototypes have been loaded yet.");
}
var protos = _prototypes[typeof(T)];
var data = _kinds[typeof(T)];
foreach (var (_, proto) in protos)
foreach (var proto in data.Instances.Values)
{
yield return (T) proto;
}
}
public IEnumerable<IPrototype> EnumeratePrototypes(Type type)
public IEnumerable<IPrototype> EnumeratePrototypes(Type kind)
{
if (!_hasEverBeenReloaded)
{
throw new InvalidOperationException("No prototypes have been loaded yet.");
}
return _prototypes[type].Values;
return _kinds[kind].Instances.Values;
}
public IEnumerable<IPrototype> EnumeratePrototypes(string variant)
public IEnumerable<IPrototype> EnumeratePrototypes(string kind)
{
return EnumeratePrototypes(GetVariantType(variant));
return EnumeratePrototypes(GetKindType(kind));
}
public IEnumerable<T> EnumerateParents<T>(string id, bool includeSelf = false) where T : class, IPrototype, IInheritingPrototype
@@ -306,19 +362,19 @@ namespace Robust.Shared.Prototypes
}
}
public IEnumerable<IPrototype> EnumerateParents(Type type, string id, bool includeSelf = false)
public IEnumerable<IPrototype> EnumerateParents(Type kind, string id, bool includeSelf = false)
{
if (!_hasEverBeenReloaded)
{
throw new InvalidOperationException("No prototypes have been loaded yet.");
}
if (!type.IsAssignableTo(typeof(IInheritingPrototype)))
if (!kind.IsAssignableTo(typeof(IInheritingPrototype)))
{
throw new InvalidOperationException("The provided prototype type is not an inheriting prototype");
throw new InvalidOperationException("The provided prototype kind is not an inheriting prototype");
}
if(!TryIndex(type, id, out var prototype))
if(!TryIndex(kind, id, out var prototype))
yield break;
if (includeSelf) yield return prototype;
var iPrototype = (IInheritingPrototype)prototype;
@@ -327,7 +383,7 @@ namespace Robust.Shared.Prototypes
var queue = new Queue<string>(iPrototype.Parents);
while (queue.TryDequeue(out var prototypeId))
{
if (!TryIndex(type, id, out var parent))
if (!TryIndex(kind, id, out var parent))
continue;
yield return parent;
iPrototype = (IInheritingPrototype)parent;
@@ -349,7 +405,7 @@ namespace Robust.Shared.Prototypes
try
{
return (T) _prototypes[typeof(T)][id];
return (T) _kinds[typeof(T)].Instances[id];
}
catch (KeyNotFoundException)
{
@@ -357,22 +413,20 @@ namespace Robust.Shared.Prototypes
}
}
public IPrototype Index(Type type, string id)
public IPrototype Index(Type kind, string id)
{
if (!_hasEverBeenReloaded)
{
throw new InvalidOperationException("No prototypes have been loaded yet.");
}
return _prototypes[type][id];
return _kinds[kind].Instances[id];
}
public void Clear()
{
_prototypeTypes.Clear();
_prototypes.Clear();
_prototypeResults.Clear();
_inheritanceTrees.Clear();
_kindNames.Clear();
_kinds.Clear();
}
private int SortPrototypesByPriority(Type a, Type b)
@@ -402,16 +456,18 @@ namespace Robust.Shared.Prototypes
foreach (var type in prototypeTypeOrder)
{
var typeData = _kinds[type];
if (!type.IsAssignableTo(typeof(IInheritingPrototype)))
{
foreach (var id in prototypes[type])
{
_prototypes[type][id] = (IPrototype) _serializationManager.Read(type, _prototypeResults[type][id])!;
var prototype = (IPrototype)_serializationManager.Read(type, typeData.Results[id])!;
typeData.Instances[id] = prototype;
}
continue;
}
var tree = _inheritanceTrees[type];
var tree = typeData.Inheritance!;
var processQueue = new Queue<string>();
foreach (var id in prototypes[type])
{
@@ -444,7 +500,7 @@ namespace Robust.Shared.Prototypes
}
}
TryReadPrototype(type, id, _prototypeResults[type][id]);
TryReadPrototype(type, id, typeData.Results[id]);
pushedSet.Add(id);
}
@@ -457,24 +513,7 @@ namespace Robust.Shared.Prototypes
.ToDictionary(
g => g.Key,
g => new PrototypesReloadedEventArgs.PrototypeChangeSet(
g.Value.Where(x => _prototypes[g.Key].ContainsKey(x)).ToDictionary(a => a, a => _prototypes[g.Key][a])))));
// TODO filter by entity prototypes changed
if (!pushed.ContainsKey(typeof(EntityPrototype))) return;
var entityPrototypes = _prototypes[typeof(EntityPrototype)];
foreach (var prototype in pushed[typeof(EntityPrototype)])
{
foreach (var entity in _entityManager.GetEntities())
{
var metaData = _entityManager.GetComponent<MetaDataComponent>(entity);
if (metaData.EntityPrototype != null && metaData.EntityPrototype.ID == prototype)
{
((EntityPrototype) entityPrototypes[prototype]).UpdateEntity(entity);
}
}
}
g.Value.Where(x => _kinds[g.Key].Instances.ContainsKey(x)).ToDictionary(a => a, a => _kinds[g.Key].Instances[a])))));
#endif
}
@@ -483,11 +522,12 @@ namespace Robust.Shared.Prototypes
/// </summary>
public void ResolveResults()
{
var types = _prototypeResults.Keys.ToList();
var types = _kinds.Keys.ToList();
types.Sort(SortPrototypesByPriority);
foreach (var type in types)
{
if(_inheritanceTrees.TryGetValue(type, out var tree))
var typeData = _kinds[type];
if (typeData.Inheritance is { } tree)
{
var processed = new HashSet<string>();
var workList = new Queue<string>(tree.RootNodes);
@@ -515,7 +555,7 @@ namespace Robust.Shared.Prototypes
}
}
foreach (var (id, mapping) in _prototypeResults[type])
foreach (var (id, mapping) in typeData.Results)
{
TryReadPrototype(type, id, mapping);
}
@@ -528,7 +568,7 @@ namespace Robust.Shared.Prototypes
return;
try
{
_prototypes[type][id] = (IPrototype) _serializationManager.Read(type, mapping)!;
_kinds[type].Instances[id] = (IPrototype) _serializationManager.Read(type, mapping)!;
}
catch (Exception e)
{
@@ -538,16 +578,21 @@ namespace Robust.Shared.Prototypes
private void PushInheritance(Type type, string id, string parent)
{
_prototypeResults[type][id] = _serializationManager.PushCompositionWithGenericNode(type,
new[] { _prototypeResults[type][parent] }, _prototypeResults[type][id]);
var kindData = _kinds[type];
kindData.Results[id] = _serializationManager.PushCompositionWithGenericNode(
type,
new[] { kindData.Results[parent] },
kindData.Results[id]);
}
/// <inheritdoc />
public void LoadDirectory(ResourcePath path, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
_hasEverBeenReloaded = true;
var streams = Resources.ContentFindFiles(path).ToList().AsParallel()
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."));
var streams = Resources.ContentFindFiles(path)
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."))
.ToArray();
foreach (var resourcePath in streams)
{
@@ -579,7 +624,7 @@ namespace Robust.Shared.Prototypes
foreach (YamlMappingNode node in rootNode.Cast<YamlMappingNode>())
{
var type = node.GetNode("type").AsString();
if (!_prototypeTypes.ContainsKey(type))
if (!_kindNames.ContainsKey(type))
{
if (_ignoredPrototypeTypes.Contains(type))
{
@@ -591,7 +636,7 @@ namespace Robust.Shared.Prototypes
var mapping = node.ToDataNodeCast<MappingDataNode>();
mapping.Remove("type");
var errorNodes = _serializationManager.ValidateNode(_prototypeTypes[type], mapping).GetErrors()
var errorNodes = _serializationManager.ValidateNode(_kindNames[type], mapping).GetErrors()
.ToHashSet();
if (errorNodes.Count == 0) continue;
if (!dict.TryGetValue(resourcePath.ToString(), out var hashSet))
@@ -642,34 +687,81 @@ namespace Robust.Shared.Prototypes
using var reader = ReadFile(file, !overwrite);
if (reader == null)
{
return;
}
var yamlStream = new YamlStream();
yamlStream.Load(reader);
// LoadedData?.Invoke(yamlStream, file.ToString());
LoadedData?.Invoke(yamlStream, file.ToString());
for (var i = 0; i < yamlStream.Documents.Count; i++)
var i = 0;
foreach (var document in DataNodeParser.ParseYamlStream(reader))
{
try
{
LoadFromDocument(yamlStream.Documents[i], overwrite, changed);
var seq = (SequenceDataNode)document.Root;
foreach (var mapping in seq.Sequence)
{
LoadFromMapping((MappingDataNode) mapping, overwrite, changed);
}
}
catch (Exception e)
{
Logger.ErrorS("eng", $"Exception whilst loading prototypes from {file}#{i}:\n{e}");
}
i += 1;
}
}
catch (YamlException e)
catch (Exception e)
{
var sawmill = Logger.GetSawmill("eng");
sawmill.Error("YamlException whilst loading prototypes from {0}: {1}", file, e.Message);
}
}
private void LoadFromMapping(
MappingDataNode datanode,
bool overwrite = false,
Dictionary<Type, HashSet<string>>? changed = null)
{
var type = datanode.Get<ValueDataNode>("type").Value;
if (!_kindNames.TryGetValue(type, out var kind))
{
if (_ignoredPrototypeTypes.Contains(type))
return;
throw new PrototypeLoadException($"Unknown prototype type: '{type}'");
}
if (!datanode.TryGet<ValueDataNode>(IdDataFieldAttribute.Name, out var idNode))
throw new PrototypeLoadException($"Prototype type {type} is missing an 'id' datafield.");
var kindData = _kinds[kind];
if (!overwrite && kindData.Instances.ContainsKey(idNode.Value))
throw new PrototypeLoadException($"Duplicate ID: '{idNode.Value}'");
kindData.Results[idNode.Value] = datanode;
if (kindData.Inheritance is { } inheritance)
{
if (datanode.TryGet(ParentDataFieldAttribute.Name, out var parentNode))
{
var parents = _serializationManager.Read<string[]>(parentNode);
inheritance.Add(idNode.Value, parents);
}
else
{
inheritance.Add(idNode.Value);
}
}
if (changed == null)
return;
if (!changed.TryGetValue(kind, out var set))
changed[kind] = set = new HashSet<string>();
set.Add(idNode.Value);
}
public void LoadFromStream(TextReader stream, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
_hasEverBeenReloaded = true;
@@ -709,30 +801,25 @@ namespace Robust.Shared.Prototypes
foreach (var node in root.Cast<YamlMappingNode>())
{
var typeString = node.GetNode("type").AsString();
if (!_prototypeTypes.TryGetValue(typeString, out var type))
{
if (!_kindNames.TryGetValue(typeString, out var kind))
continue;
}
var kindData = _kinds[kind];
var id = node.GetNode("id").AsString();
if (_inheritanceTrees.TryGetValue(type, out var tree))
{
if (kindData.Inheritance is { } tree)
tree.Remove(id, true);
}
if (_prototypes.TryGetValue(type, out var prototypeIds))
{
prototypeIds.Remove(id);
_prototypeResults[type].Remove(id);
}
kindData.Instances.Remove(id);
kindData.Results.Remove(id);
}
}
}
#endregion IPrototypeManager members
private void ReloadPrototypeTypes()
private void ReloadPrototypeKinds()
{
Clear();
foreach (var type in _reflectionManager.GetAllChildren<IPrototype>())
@@ -748,57 +835,18 @@ namespace Robust.Shared.Prototypes
foreach (var node in rootNode.Cast<YamlMappingNode>())
{
var datanode = node.ToDataNodeCast<MappingDataNode>();
var type = datanode.Get<ValueDataNode>("type").Value;
if (!_prototypeTypes.ContainsKey(type))
{
if (_ignoredPrototypeTypes.Contains(type))
{
continue;
}
throw new PrototypeLoadException($"Unknown prototype type: '{type}'");
}
var prototypeType = _prototypeTypes[type];
if (!datanode.TryGet<ValueDataNode>(IdDataFieldAttribute.Name, out var idNode))
throw new PrototypeLoadException($"Prototype type {type} is missing an 'id' datafield.");
if (!overwrite && _prototypes[prototypeType].ContainsKey(idNode.Value))
{
throw new PrototypeLoadException($"Duplicate ID: '{idNode.Value}'");
}
_prototypeResults[prototypeType][idNode.Value] = datanode;
if (prototypeType.IsAssignableTo(typeof(IInheritingPrototype)))
{
if (datanode.TryGet(ParentDataFieldAttribute.Name, out var parentNode))
{
var parents = _serializationManager.Read<string[]>(parentNode);
_inheritanceTrees[prototypeType].Add(idNode.Value, parents);
}
else
{
_inheritanceTrees[prototypeType].Add(idNode.Value);
}
}
if (changed == null) continue;
if (!changed.TryGetValue(prototypeType, out var set))
changed[prototypeType] = set = new HashSet<string>();
set.Add(idNode.Value);
LoadFromMapping(datanode, overwrite, changed);
}
}
public bool HasIndex<T>(string id) where T : class, IPrototype
{
if (!_prototypes.TryGetValue(typeof(T), out var index))
if (!_kinds.TryGetValue(typeof(T), out var index))
{
throw new UnknownPrototypeException(id);
}
return index.ContainsKey(id);
return index.Instances.ContainsKey(id);
}
public bool TryIndex<T>(string id, [NotNullWhen(true)] out T? prototype) where T : class, IPrototype
@@ -808,50 +856,54 @@ namespace Robust.Shared.Prototypes
return returned;
}
public bool TryIndex(Type type, string id, [NotNullWhen(true)] out IPrototype? prototype)
public bool TryIndex(Type kind, string id, [NotNullWhen(true)] out IPrototype? prototype)
{
if (!_prototypes.TryGetValue(type, out var index))
if (!_kinds.TryGetValue(kind, out var index))
{
throw new UnknownPrototypeException(id);
}
return index.TryGetValue(id, out prototype);
return index.Instances.TryGetValue(id, out prototype);
}
public bool HasMapping<T>(string id)
{
if (!_prototypeResults.TryGetValue(typeof(T), out var index))
if (!_kinds.TryGetValue(typeof(T), out var index))
{
throw new UnknownPrototypeException(id);
}
return index.ContainsKey(id);
return index.Results.ContainsKey(id);
}
public bool TryGetMapping(Type type, string id, [NotNullWhen(true)] out MappingDataNode? mappings)
public bool TryGetMapping(Type kind, string id, [NotNullWhen(true)] out MappingDataNode? mappings)
{
return _prototypeResults[type].TryGetValue(id, out mappings);
return _kinds[kind].Results.TryGetValue(id, out mappings);
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public bool HasVariant(string variant)
{
return _prototypeTypes.ContainsKey(variant);
return _kindNames.ContainsKey(variant);
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public Type GetVariantType(string variant)
{
return _prototypeTypes[variant];
return _kindNames[variant];
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public bool TryGetVariantType(string variant, [NotNullWhen(true)] out Type? prototype)
{
return _prototypeTypes.TryGetValue(variant, out prototype);
return _kindNames.TryGetValue(variant, out prototype);
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public bool TryGetVariantFrom(Type type, [NotNullWhen(true)] out string? variant)
{
variant = null;
@@ -875,15 +927,64 @@ namespace Robust.Shared.Prototypes
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public bool TryGetVariantFrom(IPrototype prototype, [NotNullWhen(true)] out string? variant)
{
return TryGetVariantFrom(prototype.GetType(), out variant);
}
/// <inheritdoc />
[Obsolete("Variant is outdated naming, use *kind* functions instead")]
public bool TryGetVariantFrom<T>([NotNullWhen(true)] out string? variant) where T : class, IPrototype
{
return TryGetVariantFrom(typeof(T), out variant);
}
/// <inheritdoc />
public bool TryGetVariantFrom(IPrototype prototype, [NotNullWhen(true)] out string? variant)
public bool HasKind(string kind)
{
return TryGetVariantFrom(prototype.GetType(), out variant);
return _kindNames.ContainsKey(kind);
}
public Type GetKindType(string kind)
{
return _kindNames[kind];
}
public bool TryGetKindType(string kind, [NotNullWhen(true)] out Type? prototype)
{
return _kindNames.TryGetValue(kind, out prototype);
}
public bool TryGetKindFrom(Type type, [NotNullWhen(true)] out string? kind)
{
kind = null;
// If the type doesn't implement IPrototype, this fails.
if (!type.IsAssignableTo(typeof(IPrototype)))
return false;
var attribute = (PrototypeAttribute?) Attribute.GetCustomAttribute(type, typeof(PrototypeAttribute));
// If the prototype type doesn't have the attribute, this fails.
if (attribute == null)
return false;
// If the variant isn't registered, this fails.
if (!HasKind(attribute.Type))
return false;
kind = attribute.Type;
return true;
}
public bool TryGetKindFrom(IPrototype prototype, [NotNullWhen(true)] out string? kind)
{
return TryGetKindFrom(prototype.GetType(), out kind);
}
public bool TryGetKindFrom<T>([NotNullWhen(true)] out string? kind) where T : class, IPrototype
{
return TryGetKindFrom(typeof(T), out kind);
}
public void RegisterIgnore(string name)
@@ -906,11 +1007,11 @@ namespace Robust.Shared.Prototypes
"No " + nameof(PrototypeAttribute) + " to give it a type string.");
}
if (_prototypeTypes.ContainsKey(attribute.Type))
if (_kindNames.ContainsKey(attribute.Type))
{
throw new InvalidImplementationException(type,
typeof(IPrototype),
$"Duplicate prototype type ID: {attribute.Type}. Current: {_prototypeTypes[attribute.Type]}");
$"Duplicate prototype type ID: {attribute.Type}. Current: {_kindNames[attribute.Type]}");
}
var foundIdAttribute = false;
@@ -966,20 +1067,26 @@ namespace Robust.Shared.Prototypes
typeof(IInheritingPrototype),
$"Did not find any member annotated with the {nameof(ParentDataFieldAttribute)} and/or {nameof(AbstractDataFieldAttribute)}");
_prototypeTypes[attribute.Type] = type;
_kindNames[attribute.Type] = type;
_prototypePriorities[type] = attribute.LoadPriority;
if (typeof(IPrototype).IsAssignableFrom(type))
{
_prototypes[type] = new Dictionary<string, IPrototype>();
_prototypeResults[type] = new Dictionary<string, MappingDataNode>();
if (typeof(IInheritingPrototype).IsAssignableFrom(type))
_inheritanceTrees[type] = new MultiRootInheritanceGraph<string>();
}
var kindData = new KindData();
_kinds[type] = kindData;
if (type.IsAssignableTo(typeof(IInheritingPrototype)))
kindData.Inheritance = new MultiRootInheritanceGraph<string>();
}
public event Action<YamlStream, string>? LoadedData;
public event Action<PrototypesReloadedEventArgs>? PrototypesReloaded;
private sealed class KindData
{
public readonly Dictionary<string, IPrototype> Instances = new();
public readonly Dictionary<string, MappingDataNode> Results = new();
// Only initialized if prototype is inheriting.
public MultiRootInheritanceGraph<string>? Inheritance;
}
}
[Serializable]

View File

@@ -16,7 +16,7 @@
<PackageReference Include="prometheus-net" Version="4.1.1" />
<PackageReference Include="Robust.Shared.AuthLib" Version="0.1.2" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="YamlDotNet" Version="9.1.4" />
<PackageReference Include="YamlDotNet" Version="12.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Linguini.Bundle" Version="0.1.3" />
<PackageReference Include="SharpZstd.Interop" Version="1.5.2-beta2" />

View File

@@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
using System.IO;
using Robust.Shared.Collections;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
namespace Robust.Shared.Serialization.Markdown;
// YDN has broken nullable annotations. Yeppers.
#nullable disable
/// <summary>
/// Utilities for parsing <see cref="DataNode"/> and related types.
/// </summary>
public static class DataNodeParser
{
// Parsing logic here is pretty straightforward.
// We take the "events" from YDN's parser and make our own nodes with them.
// This improves performance (no round tripping through YDN's RepresentationModel)
// And also fixes End marks for maps/sequences.
// If we encounter an anchor we don't have yet, we track the node containing it and fix it up later.
/// <summary>
/// Parse a <see cref="TextReader"/> of YAML straight into a <see cref="DataNode"/>.
/// </summary>
public static IEnumerable<DataNodeDocument> ParseYamlStream(TextReader reader)
{
return ParseYamlStream(new Parser(reader));
}
internal static IEnumerable<DataNodeDocument> ParseYamlStream(Parser parser)
{
parser.Consume<StreamStart>();
while (!parser.TryConsume<StreamEnd>(out _))
{
yield return ParseDocument(parser);
}
}
private static DataNodeDocument ParseDocument(Parser parser)
{
var state = new DocumentState();
parser.Consume<DocumentStart>();
var root = Parse(parser, state);
parser.Consume<DocumentEnd>();
ResolveAliases(state);
return new DataNodeDocument(root);
}
private static DataNode Parse(Parser parser, DocumentState state)
{
if (parser.Current is Scalar)
return ParseValue(parser, state);
if (parser.Current is SequenceStart)
return ParseSequence(parser, state);
if (parser.Current is MappingStart)
return ParseMapping(parser, state);
if (parser.Current is AnchorAlias)
return ParseAlias(parser, state);
throw new NotSupportedException();
}
private static DataNode ParseAlias(Parser parser, DocumentState state)
{
var alias = parser.Consume<AnchorAlias>();
if (!state.Anchors.TryGetValue(alias.Value, out var node))
{
// Don't have this anchor yet. It may be defined later in the document.
return new DataNodeAlias(alias.Value);
}
return node;
}
private static ValueDataNode ParseValue(Parser parser, DocumentState state)
{
var ev = parser.Consume<Scalar>();
var node = new ValueDataNode(ev.Value);
node.Tag = ConvertTag(ev.Tag);
node.Start = ev.Start;
node.End = ev.End;
NodeParsed(node, ev, false, state);
return node;
}
private static SequenceDataNode ParseSequence(Parser parser, DocumentState state)
{
var ev = parser.Consume<SequenceStart>();
var node = new SequenceDataNode();
node.Tag = ConvertTag(ev.Tag);
node.Start = ev.Start;
var unresolvedAlias = false;
SequenceEnd seqEnd;
while (!parser.TryConsume(out seqEnd))
{
var value = Parse(parser, state);
node.Add(value);
unresolvedAlias |= value is DataNodeAlias;
}
node.End = seqEnd.End;
NodeParsed(node, ev, unresolvedAlias, state);
return node;
}
private static MappingDataNode ParseMapping(Parser parser, DocumentState state)
{
var ev = parser.Consume<MappingStart>();
var node = new MappingDataNode();
node.Tag = ConvertTag(ev.Tag);
var unresolvedAlias = false;
MappingEnd mapEnd;
while (!parser.TryConsume(out mapEnd))
{
var key = Parse(parser, state);
var value = Parse(parser, state);
node.Add(key, value);
unresolvedAlias |= key is DataNodeAlias;
unresolvedAlias |= value is DataNodeAlias;
}
node.End = mapEnd.End;
NodeParsed(node, ev, unresolvedAlias, state);
return node;
}
private static void NodeParsed(DataNode node, NodeEvent ev, bool unresolvedAlias, DocumentState state)
{
if (unresolvedAlias)
state.UnresolvedAliasOwners.Add(node);
if (ev.Anchor.IsEmpty)
return;
if (state.Anchors.ContainsKey(ev.Anchor))
throw new DataParseException($"Duplicate anchor defined in document: {ev.Anchor}");
state.Anchors[ev.Anchor] = node;
}
private static void ResolveAliases(DocumentState state)
{
foreach (var node in state.UnresolvedAliasOwners)
{
switch (node)
{
case MappingDataNode mapping:
ResolveMappingAliases(mapping, state);
break;
case SequenceDataNode sequence:
ResolveSequenceAliases(sequence, state);
break;
}
}
}
private static void ResolveMappingAliases(MappingDataNode mapping, DocumentState state)
{
var swaps = new ValueList<(DataNode key, DataNode value)>();
foreach (var (key, value) in mapping)
{
if (key is not DataNodeAlias && value is not DataNodeAlias)
return;
var newKey = key is DataNodeAlias keyAlias ? ResolveAlias(keyAlias, state) : key;
var newValue = value is DataNodeAlias valueAlias ? ResolveAlias(valueAlias, state) : value;
swaps.Add((newKey, newValue));
mapping.Remove(key);
}
foreach (var (key, value) in swaps)
{
mapping[key] = value;
}
}
private static void ResolveSequenceAliases(SequenceDataNode sequence, DocumentState state)
{
for (var i = 0; i < sequence.Count; i++)
{
if (sequence[i] is DataNodeAlias alias)
sequence[i] = ResolveAlias(alias, state);
}
}
private static DataNode ResolveAlias(DataNodeAlias alias, DocumentState state)
{
if (!state.Anchors.TryGetValue(alias.Anchor, out var node))
throw new DataParseException($"Unable to resolve alias '{alias.Anchor}'");
return node;
}
private static string ConvertTag(TagName tag)
{
return (tag.IsNonSpecific || tag.IsEmpty) ? null : tag.Value;
}
private sealed class DocumentState
{
public readonly Dictionary<AnchorName, DataNode> Anchors = new();
public ValueList<DataNode> UnresolvedAliasOwners;
}
private sealed class DataNodeAlias : DataNode
{
public readonly AnchorName Anchor;
public DataNodeAlias(AnchorName anchor) : base(default, default)
{
Anchor = anchor;
}
public override bool IsEmpty => true;
public override DataNode Copy()
{
throw new NotSupportedException();
}
public override DataNode Except(DataNode node)
{
throw new NotSupportedException();
}
public override DataNode PushInheritance(DataNode parent)
{
throw new NotSupportedException();
}
}
}
public sealed class DataParseException : Exception
{
public DataParseException()
{
}
public DataParseException(string message) : base(message)
{
}
public DataParseException(string message, Exception inner) : base(message, inner)
{
}
}
public sealed record DataNodeDocument(DataNode Root);

View File

@@ -40,7 +40,7 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
_children.Add(key.ToDataNode(), val.ToDataNode());
}
Tag = mapping.Tag;
Tag = (mapping.Tag.IsNonSpecific || mapping.Tag.IsEmpty) ? null : mapping.Tag.Value;
}
public MappingDataNode(Dictionary<DataNode, DataNode> nodes) : base(NodeMark.Invalid, NodeMark.Invalid)

View File

@@ -42,7 +42,7 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
_nodes.Add(node.ToDataNode());
}
Tag = sequence.Tag;
Tag = (sequence.Tag.IsNonSpecific || sequence.Tag.IsEmpty) ? null : sequence.Tag.Value;
}
public SequenceDataNode(params DataNode[] nodes) : base(NodeMark.Invalid, NodeMark.Invalid)

View File

@@ -17,7 +17,7 @@ namespace Robust.Shared.Serialization.Markdown.Value
public ValueDataNode(YamlScalarNode node) : base(node.Start, node.End)
{
Value = node.Value ?? string.Empty;
Tag = node.Tag;
Tag = (node.Tag.IsNonSpecific || node.Tag.IsEmpty) ? null : node.Tag.Value;
}
public string Value { get; set; }

View File

@@ -321,15 +321,15 @@ namespace Robust.Shared.Serialization
foreach (var node in doc.AllNodes)
{
var a = node.Anchor;
if (!string.IsNullOrEmpty(a))
if (!a.IsEmpty)
{
AddString(a);
AddString(a.Value);
}
var t = node.Tag;
if (!string.IsNullOrEmpty(t))
if (!t.IsEmpty)
{
AddString(t);
AddString(t.Value);
}
if (!(node is YamlScalarNode scalar))

View File

@@ -22,35 +22,37 @@ namespace Robust.Shared
{
internal static class SharedIoC
{
public static void RegisterIoC()
public static void RegisterIoC(IDependencyCollection deps, bool entities=true)
{
IoCManager.Register<ISerializationManager, SerializationManager>();
IoCManager.Register<IConfigurationManager, NetConfigurationManager>();
IoCManager.Register<INetConfigurationManager, NetConfigurationManager>();
IoCManager.Register<IConfigurationManagerInternal, NetConfigurationManager>();
IoCManager.Register<IDynamicTypeFactory, DynamicTypeFactory>();
IoCManager.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
IoCManager.Register<IEntitySystemManager, EntitySystemManager>();
IoCManager.Register<ILocalizationManager, LocalizationManager>();
IoCManager.Register<ILocalizationManagerInternal, LocalizationManager>();
IoCManager.Register<ILogManager, LogManager>();
IoCManager.Register<IModLoader, ModLoader>();
IoCManager.Register<IModLoaderInternal, ModLoader>();
IoCManager.Register<INetManager, NetManager>();
IoCManager.Register<IRobustSerializer, RobustSerializer>();
IoCManager.Register<IRuntimeLog, RuntimeLog>();
IoCManager.Register<ITaskManager, TaskManager>();
IoCManager.Register<TaskManager, TaskManager>();
IoCManager.Register<ITimerManager, TimerManager>();
IoCManager.Register<ProfManager, ProfManager>();
IoCManager.Register<IRobustRandom, RobustRandom>();
IoCManager.Register<IRobustMappedStringSerializer, RobustMappedStringSerializer>();
IoCManager.Register<ISandboxHelper, SandboxHelper>();
IoCManager.Register<IManifoldManager, CollisionManager>();
IoCManager.Register<IIslandManager, IslandManager>();
IoCManager.Register<IVerticesSimplifier, RamerDouglasPeuckerSimplifier>();
IoCManager.Register<IParallelManager, ParallelManager>();
IoCManager.Register<IParallelManagerInternal, ParallelManager>();
deps.Register<ISerializationManager, SerializationManager>();
deps.Register<IConfigurationManager, NetConfigurationManager>();
deps.Register<INetConfigurationManager, NetConfigurationManager>();
deps.Register<IConfigurationManagerInternal, NetConfigurationManager>();
deps.Register<IDynamicTypeFactory, DynamicTypeFactory>();
deps.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
deps.Register<ILocalizationManager, LocalizationManager>();
deps.Register<ILocalizationManagerInternal, LocalizationManager>();
deps.Register<ILogManager, LogManager>();
deps.Register<IModLoader, ModLoader>();
deps.Register<IModLoaderInternal, ModLoader>();
deps.Register<INetManager, NetManager>();
deps.Register<IRobustSerializer, RobustSerializer>();
deps.Register<IRuntimeLog, RuntimeLog>();
deps.Register<ITaskManager, TaskManager>();
deps.Register<TaskManager, TaskManager>();
deps.Register<ITimerManager, TimerManager>();
deps.Register<ProfManager, ProfManager>();
deps.Register<IRobustRandom, RobustRandom>();
deps.Register<IRobustMappedStringSerializer, RobustMappedStringSerializer>();
deps.Register<ISandboxHelper, SandboxHelper>();
deps.Register<IManifoldManager, CollisionManager>();
deps.Register<IIslandManager, IslandManager>();
deps.Register<IVerticesSimplifier, RamerDouglasPeuckerSimplifier>();
deps.Register<IParallelManager, ParallelManager>();
deps.Register<IParallelManagerInternal, ParallelManager>();
if (entities)
deps.Register<IEntitySystemManager, EntitySystemManager>();
}
}
}

View File

@@ -586,7 +586,7 @@ namespace Robust.UnitTesting
private BaseServer Init()
{
IoCManager.InitThread(DependencyCollection, replaceExisting: true);
ServerIoC.RegisterIoC();
ServerIoC.RegisterIoC(DependencyCollection);
IoCManager.Register<INetManager, IntegrationNetManager>(true);
IoCManager.Register<IServerNetManager, IntegrationNetManager>(true);
IoCManager.Register<IntegrationNetManager, IntegrationNetManager>(true);
@@ -732,7 +732,7 @@ namespace Robust.UnitTesting
private GameController Init()
{
IoCManager.InitThread(DependencyCollection, replaceExisting: true);
ClientIoC.RegisterIoC(GameController.DisplayMode.Headless);
ClientIoC.RegisterIoC(GameController.DisplayMode.Headless, DependencyCollection);
IoCManager.Register<INetManager, IntegrationNetManager>(true);
IoCManager.Register<IClientNetManager, IntegrationNetManager>(true);
IoCManager.Register<IntegrationNetManager, IntegrationNetManager>(true);

View File

@@ -16,11 +16,11 @@ namespace Robust.UnitTesting
switch (Project)
{
case UnitTestProject.Client:
ClientIoC.RegisterIoC(GameController.DisplayMode.Headless);
ClientIoC.RegisterIoC(GameController.DisplayMode.Headless, IoCManager.Instance!);
break;
case UnitTestProject.Server:
ServerIoC.RegisterIoC();
ServerIoC.RegisterIoC(IoCManager.Instance!);
break;
default: