mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
14 Commits
serializat
...
22-08-12-l
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63ee32fcd3 | ||
|
|
11deb10e01 | ||
|
|
a94a37d5da | ||
|
|
9a1b8dd14a | ||
|
|
c8b35d28f8 | ||
|
|
c14450e2b3 | ||
|
|
7f6a9e7e8b | ||
|
|
ac6580cb3e | ||
|
|
52f46dc9ea | ||
|
|
7de7ef085c | ||
|
|
55949f41ce | ||
|
|
1bb790cf28 | ||
|
|
2db11d7f29 | ||
|
|
1e271ce47d |
@@ -13,7 +13,7 @@ namespace Robust.Benchmarks.Serialization
|
||||
public SerializationBenchmark()
|
||||
{
|
||||
IoCManager.InitThread();
|
||||
ServerIoC.RegisterIoC();
|
||||
ServerIoC.RegisterIoC(IoCManager.Instance!);
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var assemblies = new[]
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
3
Robust.LanguageServer/AssemblyInfo.cs
Normal file
3
Robust.LanguageServer/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[module: SkipLocalsInit]
|
||||
39
Robust.LanguageServer/CommandLineArgs.cs
Normal file
39
Robust.LanguageServer/CommandLineArgs.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
74
Robust.LanguageServer/DocumentSymbolHandler.cs
Normal file
74
Robust.LanguageServer/DocumentSymbolHandler.cs
Normal 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" })
|
||||
};
|
||||
}
|
||||
}
|
||||
18
Robust.LanguageServer/Helpers.cs
Normal file
18
Robust.LanguageServer/Helpers.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
22
Robust.LanguageServer/LangServerReflectionManager.cs
Normal file
22
Robust.LanguageServer/LangServerReflectionManager.cs
Normal 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.",
|
||||
};
|
||||
}
|
||||
160
Robust.LanguageServer/Program.cs
Normal file
160
Robust.LanguageServer/Program.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
21
Robust.LanguageServer/Robust.LanguageServer.csproj
Normal file
21
Robust.LanguageServer/Robust.LanguageServer.csproj
Normal 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>
|
||||
165
Robust.LanguageServer/SemanticTokensHandler.cs
Normal file
165
Robust.LanguageServer/SemanticTokensHandler.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Robust.LanguageServer/ServiceDependencyCollection.cs
Normal file
136
Robust.LanguageServer/ServiceDependencyCollection.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
73
Robust.LanguageServer/TextDocumentsCache.cs
Normal file
73
Robust.LanguageServer/TextDocumentsCache.cs
Normal 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; }
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Robust.Server
|
||||
{
|
||||
Thread.CurrentThread.Name = "Main Thread";
|
||||
IoCManager.InitThread();
|
||||
ServerIoC.RegisterIoC();
|
||||
ServerIoC.RegisterIoC(IoCManager.Instance!);
|
||||
IoCManager.BuildGraph();
|
||||
SetupLogging();
|
||||
InitReflectionManager();
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
85
Robust.Shared/GameObjects/Systems/PrototypeReloadSystem.cs
Normal file
85
Robust.Shared/GameObjects/Systems/PrototypeReloadSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
20
Robust.Shared/IoC/DependencyCollectionExt.cs
Normal file
20
Robust.Shared/IoC/DependencyCollectionExt.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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" />
|
||||
|
||||
283
Robust.Shared/Serialization/Markdown/DataNodeParser.cs
Normal file
283
Robust.Shared/Serialization/Markdown/DataNodeParser.cs
Normal 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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user