Compare commits

...

21 Commits

Author SHA1 Message Date
Paul
fd1e25c584 Version: 0.9.3.2 2022-04-05 18:51:03 +02:00
Paul Ritter
6bb66ae70e fixes loc (#2685) 2022-04-05 18:50:27 +02:00
Paul
cc82d6b1d9 Version: 0.9.3.1 2022-04-05 18:36:19 +02:00
Paul
956be749b6 fix prototype reload 2022-04-05 18:36:09 +02:00
Paul Ritter
6585a00608 readds expandpvsevent (#2684) 2022-04-05 19:47:14 +10:00
metalgearsloth
c0525f710f Sprite subscription shutdown (#2688) 2022-04-05 19:45:23 +10:00
Vera Aguilera Puerto
d3672807d2 Improves SpriteSystem.GetPrototypeIcon method significantly. (#2680) 2022-04-05 16:36:16 +10:00
ElectroJr
60f18d5f36 Version: 0.9.3.0 2022-04-05 18:06:43 +12:00
mirrorcult
e72d3de256 Local event for BUI opening (#2687) 2022-04-05 15:52:02 +10:00
Moony
ba9846b9c4 Fix vector2 CVars (#2686) 2022-04-05 15:03:10 +10:00
Paul
09586284dc Version: 0.9.2.0 2022-04-04 20:28:53 +02:00
Paul
a1ee4374b2 add a check for major version == 0 2022-04-04 20:28:26 +02:00
Paul Ritter
4de6f25f11 updates version-script to use the new version format (#2683) 2022-04-04 20:25:12 +02:00
Paul Ritter
582d8a5587 pvsrange vec2 + eyezoom (#2676)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2022-04-04 20:20:13 +02:00
Leon Friedrich
ec53b04f99 Add NotNullWhen attribute to TryComp (#2681) 2022-04-04 11:29:02 +02:00
metalgearsloth
950fc94408 Physicsmap tweaks (#2663) 2022-04-04 17:10:15 +10:00
Leon Friedrich
58d12e6e09 Remove Component.OnAdd() (#2660) 2022-04-04 16:11:47 +10:00
ElectroJr
94323005c4 Version: 0.9.1 2022-04-04 17:43:01 +12:00
metalgearsloth
4989842057 Remove IgnorePause (#2649) 2022-04-04 15:41:38 +10:00
Paul
80172636a8 version 0.9 - serv3 refactor 2022-04-03 02:00:41 +02:00
Paul Ritter
8491f7be24 New Serv3 api just dropped (#2605)
Co-authored-by: Paul Ritter <ritter.paul1@gmail.com>
2022-04-03 01:59:48 +02:00
146 changed files with 1824 additions and 2075 deletions

View File

@@ -1,4 +1,4 @@
<Project>
<!-- This file automatically reset by Tools/version.py -->
<PropertyGroup><Version>0.8.86</Version></PropertyGroup>
<PropertyGroup><Version>0.9.3.2</Version></PropertyGroup>
</Project>

View File

@@ -1,7 +1,6 @@
using System.Globalization;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -19,10 +18,10 @@ namespace Robust.Benchmarks.Serialization
: new ErrorNode(node, $"Failed parsing int value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, int _ = default)
{
return new DeserializedValue<int>(int.Parse(node.Value, CultureInfo.InvariantCulture));
return int.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, int value, bool alwaysWrite = false,

View File

@@ -28,7 +28,7 @@ namespace Robust.Benchmarks.Serialization.Copy
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping);
}
private const string String = "ABC";

View File

@@ -36,7 +36,7 @@ namespace Robust.Benchmarks.Serialization.Definitions
Max: 10
PotencyDivisor: 10";
[DataField("id", required: true)] public string ID { get; set; } = default!;
[IdDataFieldAttribute] public string ID { get; set; } = default!;
#region Tracking
[DataField("name")] public string Name { get; set; } = string.Empty;

View File

@@ -2,7 +2,6 @@
using BenchmarkDotNet.Attributes;
using Robust.Benchmarks.Serialization.Definitions;
using Robust.Shared.Analyzers;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
@@ -42,32 +41,32 @@ namespace Robust.Benchmarks.Serialization.Read
private ValueDataNode FlagThirtyOne { get; } = new("ThirtyOne");
[Benchmark]
public string? ReadString()
public string ReadString()
{
return SerializationManager.ReadValue<string>(StringNode);
return SerializationManager.Read<string>(StringNode);
}
[Benchmark]
public int? ReadInteger()
public int ReadInteger()
{
return SerializationManager.ReadValue<int>(IntNode);
return SerializationManager.Read<int>(IntNode);
}
[Benchmark]
public DataDefinitionWithString? ReadDataDefinitionWithString()
public DataDefinitionWithString ReadDataDefinitionWithString()
{
return SerializationManager.ReadValue<DataDefinitionWithString>(StringDataDefNode);
return SerializationManager.Read<DataDefinitionWithString>(StringDataDefNode);
}
[Benchmark]
public SeedDataDefinition? ReadSeedDataDefinition()
public SeedDataDefinition ReadSeedDataDefinition()
{
return SerializationManager.ReadValue<SeedDataDefinition>(SeedNode);
return SerializationManager.Read<SeedDataDefinition>(SeedNode);
}
[Benchmark]
[BenchmarkCategory("flag")]
public DeserializationResult ReadFlagZero()
public object? ReadFlagZero()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),
@@ -77,7 +76,7 @@ namespace Robust.Benchmarks.Serialization.Read
[Benchmark]
[BenchmarkCategory("flag")]
public DeserializationResult ReadThirtyOne()
public object? ReadThirtyOne()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),
@@ -87,7 +86,7 @@ namespace Robust.Benchmarks.Serialization.Read
[Benchmark]
[BenchmarkCategory("customTypeSerializer")]
public DeserializationResult ReadIntegerCustomSerializer()
public object? ReadIntegerCustomSerializer()
{
return SerializationManager.ReadWithTypeSerializer(
typeof(int),

View File

@@ -46,84 +46,84 @@ namespace Robust.Benchmarks.Serialization
[BenchmarkCategory("read")]
public string[]? ReadEmptyString()
{
return SerializationManager.ReadValue<string[]>(EmptyNode);
return SerializationManager.Read<string[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadOneString()
{
return SerializationManager.ReadValue<string[]>(OneIntNode);
return SerializationManager.Read<string[]>(OneIntNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public string[]? ReadTenStrings()
{
return SerializationManager.ReadValue<string[]>(TenIntsNode);
return SerializationManager.Read<string[]>(TenIntsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadEmptyInt()
{
return SerializationManager.ReadValue<int[]>(EmptyNode);
return SerializationManager.Read<int[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadOneInt()
{
return SerializationManager.ReadValue<int[]>(OneIntNode);
return SerializationManager.Read<int[]>(OneIntNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public int[]? ReadTenInts()
{
return SerializationManager.ReadValue<int[]>(TenIntsNode);
return SerializationManager.Read<int[]>(TenIntsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadEmptyStringDataDef()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(EmptyNode);
return SerializationManager.Read<DataDefinitionWithString[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadOneStringDataDef()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(OneStringDefNode);
return SerializationManager.Read<DataDefinitionWithString[]>(OneStringDefNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public DataDefinitionWithString[]? ReadTenStringDataDefs()
{
return SerializationManager.ReadValue<DataDefinitionWithString[]>(TenStringDefsNode);
return SerializationManager.Read<DataDefinitionWithString[]>(TenStringDefsNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadEmptySealedStringDataDef()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(EmptyNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(EmptyNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadOneSealedStringDataDef()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(OneStringDefNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(OneStringDefNode);
}
[Benchmark]
[BenchmarkCategory("read")]
public SealedDataDefinitionWithString[]? ReadTenSealedStringDataDefs()
{
return SerializationManager.ReadValue<SealedDataDefinitionWithString[]>(TenStringDefsNode);
return SerializationManager.Read<SealedDataDefinitionWithString[]>(TenStringDefsNode);
}
}
}

View File

@@ -28,7 +28,7 @@ namespace Robust.Benchmarks.Serialization.Write
var seedMapping = yamlStream.Documents[0].RootNode.ToDataNodeCast<SequenceDataNode>().Cast<MappingDataNode>(0);
Seed = SerializationManager.ReadValueOrThrow<SeedDataDefinition>(seedMapping);
Seed = SerializationManager.Read<SeedDataDefinition>(seedMapping);
}
private const string String = "ABC";

View File

@@ -132,7 +132,7 @@ namespace Robust.Client
_console.Initialize();
_prototypeManager.Initialize();
_prototypeManager.LoadDirectory(Options.PrototypeDirectory);
_prototypeManager.Resync();
_prototypeManager.ResolveResults();
_entityManager.Initialize();
_mapManager.Initialize();
_gameStateManager.Initialize();

View File

@@ -1,3 +1,4 @@
using System;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
@@ -32,11 +33,13 @@ namespace Robust.Client.GameObjects
public const string LogCategory = "go.comp.icon";
const string SerializationCache = "icon";
[Obsolete("Use SpriteSystem instead.")]
private static IRsiStateLike TextureForConfig(IconComponent compData, IResourceCache resourceCache)
{
return compData.Icon?.Default ?? resourceCache.GetFallback<TextureResource>().Texture;
}
[Obsolete("Use SpriteSystem instead.")]
public static IRsiStateLike? GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
{
if (!prototype.Components.TryGetValue("Icon", out var compData))

View File

@@ -1520,6 +1520,7 @@ namespace Robust.Client.GameObjects
}
}
[Obsolete("Use SpriteSystem instead.")]
internal static RSI.State GetFallbackState(IResourceCache cache)
{
var rsi = cache.GetResource<RSIResource>("/Textures/error.rsi").RSI;

View File

@@ -75,6 +75,10 @@ namespace Robust.Client.GameObjects
(BoundUserInterface) _dynamicTypeFactory.CreateInstance(type, new[] {this, wrapped.UiKey});
boundInterface.Open();
_openInterfaces[wrapped.UiKey] = boundInterface;
var playerSession = _playerManager.LocalPlayer?.Session;
if(playerSession != null)
_entityManager.EventBus.RaiseLocalEvent(Owner, new BoundUIOpenedEvent(wrapped.UiKey, Owner, playerSession));
}
internal void Close(object uiKey, bool remoteCall)

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
@@ -17,13 +18,13 @@ public sealed partial class SpriteSystem
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Pure]
private readonly Dictionary<string, IRsiStateLike> _cachedPrototypeIcons = new();
public Texture Frame0(SpriteSpecifier specifier)
{
return RsiStateLike(specifier).Default;
}
[Pure]
public IRsiStateLike RsiStateLike(SpriteSpecifier specifier)
{
switch (specifier)
@@ -35,38 +36,71 @@ public sealed partial class SpriteSystem
return GetState(rsi);
case SpriteSpecifier.EntityPrototype prototypeIcon:
if (!_proto.TryIndex<EntityPrototype>(prototypeIcon.EntityPrototypeId, out var prototype))
{
Logger.Error("Failed to load PrototypeIcon {0}", prototypeIcon.EntityPrototypeId);
return SpriteComponent.GetFallbackState(_resourceCache);
}
return SpriteComponent.GetPrototypeIcon(prototype, _resourceCache);
return GetPrototypeIcon(prototypeIcon.EntityPrototypeId);
default:
throw new NotSupportedException();
}
}
[Pure]
public IRsiStateLike GetPrototypeIcon(EntityPrototype prototype, IResourceCache resourceCache)
/// <summary>
/// Returns an icon for a given <see cref="EntityPrototype"/> ID, or a fallback in case of an error.
/// This method caches the result based on the prototype identifier.
/// </summary>
public IRsiStateLike GetPrototypeIcon(string prototype)
{
var icon = IconComponent.GetPrototypeIcon(prototype, _resourceCache);
if (icon != null) return icon;
// Check if this prototype has been cached before, and if so return the result.
if (_cachedPrototypeIcons.TryGetValue(prototype, out var cachedResult))
return cachedResult;
if (!prototype.Components.ContainsKey("Sprite"))
if (!_proto.TryIndex<EntityPrototype>(prototype, out var entityPrototype))
{
return SpriteComponent.GetFallbackState(resourceCache);
// The specified prototype doesn't exist, return the fallback "error" sprite.
Logger.Error("Failed to load PrototypeIcon {0}", prototype);
return GetFallbackState();
}
// Generate the icon and cache it in case it's ever needed again.
var result = GetPrototypeIcon(entityPrototype);
_cachedPrototypeIcons[prototype] = result;
return result;
}
/// <summary>
/// Returns an icon for a given <see cref="EntityPrototype"/> ID, or a fallback in case of an error.
/// This method does NOT cache the result.
/// </summary>
public IRsiStateLike GetPrototypeIcon(EntityPrototype prototype)
{
// IconComponent takes precedence. If it has a valid icon, return that. Otherwise, continue as normal.
if (prototype.Components.TryGetValue("Icon", out var compData)
&& compData is IconComponent {Icon: {} icon})
{
return icon.Default;
}
// If the prototype doesn't have a SpriteComponent, then there's nothing we can do but return the fallback.
if (!prototype.Components.ContainsKey("Sprite"))
{
return GetFallbackState();
}
// Finally, we use spawn a dummy entity to get its icon.
var dummy = Spawn(prototype.ID, MapCoordinates.Nullspace);
var spriteComponent = EnsureComp<SpriteComponent>(dummy);
var result = spriteComponent.Icon ?? SpriteComponent.GetFallbackState(resourceCache);
var result = spriteComponent.Icon ?? GetFallbackState();
Del(dummy);
return result;
}
[Pure]
public RSI.State GetFallbackState()
{
return _resourceCache.GetFallback<RSIResource>().RSI["error"];
}
[Pure]
public RSI.State GetState(SpriteSpecifier.Rsi rsiSpecifier)
{
@@ -79,6 +113,20 @@ public sealed partial class SpriteSystem
}
Logger.Error("Failed to load RSI {0}", rsiSpecifier.RsiPath);
return SpriteComponent.GetFallbackState(_resourceCache);
return GetFallbackState();
}
private void OnPrototypesReloaded(PrototypesReloadedEventArgs protoReloaded)
{
// Check if any EntityPrototype has been changed.
if (!protoReloaded.ByType.TryGetValue(typeof(EntityPrototype), out var changedSet))
return;
// Remove all changed prototypes from the cache, if they're there.
foreach (var (prototype, _) in changedSet.Modified)
{
// Let's be lazy and not regenerate them until something needs them again.
_cachedPrototypeIcons.Remove(prototype);
}
}
}

View File

@@ -23,9 +23,16 @@ namespace Robust.Client.GameObjects
{
base.Initialize();
_proto.PrototypesReloaded += OnPrototypesReloaded;
SubscribeLocalEvent<SpriteUpdateInertEvent>(QueueUpdateInert);
}
public override void Shutdown()
{
base.Shutdown();
_proto.PrototypesReloaded -= OnPrototypesReloaded;
}
private void QueueUpdateInert(SpriteUpdateInertEvent ev)
{
_inertUpdateQueue.Enqueue(ev.Sprite);

View File

@@ -19,7 +19,7 @@ namespace Robust.Client.Graphics
[Dependency] private readonly IResourceCache _resourceCache = default!;
[ViewVariables]
[DataField("id", required: true)]
[IdDataFieldAttribute]
public string ID { get; } = default!;
private ShaderKind Kind;

View File

@@ -497,7 +497,7 @@ namespace Robust.Client.Input
if (robustMapping.TryGet("binds", out var BaseKeyRegsNode))
{
var baseKeyRegs = serializationManager.ReadValueOrThrow<KeyBindingRegistration[]>(BaseKeyRegsNode);
var baseKeyRegs = serializationManager.Read<KeyBindingRegistration[]>(BaseKeyRegsNode);
foreach (var reg in baseKeyRegs)
{
@@ -526,7 +526,7 @@ namespace Robust.Client.Input
if (userData && robustMapping.TryGet("leaveEmpty", out var node))
{
var leaveEmpty = serializationManager.ReadValueOrThrow<BoundKeyFunction[]>(node);
var leaveEmpty = serializationManager.Read<BoundKeyFunction[]>(node);
if (leaveEmpty.Length > 0)
{

View File

@@ -22,6 +22,8 @@ namespace Robust.Client.ResourceManagement
{
private static readonly float[] OneArray = {1};
public override ResourcePath? Fallback => new("/Textures/error.rsi");
private static readonly JsonSerializerOptions SerializerOptions =
new JsonSerializerOptions(JsonSerializerDefaults.Web)
{

View File

@@ -1,10 +1,10 @@
using System;
using Robust.Client.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -16,26 +16,40 @@ namespace Robust.Client.Serialization
[TypeSerializer]
public sealed class AppearanceVisualizerSerializer : ITypeSerializer<AppearanceVisualizer, MappingDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, MappingDataNode node,
public AppearanceVisualizer Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, AppearanceVisualizer? value = null)
{
Type? type = null;
if (!node.TryGet("type", out var typeNode))
throw new InvalidMappingException("No type specified for AppearanceVisualizer!");
{
if (value == null)
throw new InvalidMappingException("No type specified for AppearanceVisualizer!");
if (typeNode is not ValueDataNode typeValueDataNode)
throw new InvalidMappingException("Type node not a value node for AppearanceVisualizer!");
type = value.GetType();
}
else
{
if (typeNode is not ValueDataNode typeValueDataNode)
throw new InvalidMappingException("Type node not a value node for AppearanceVisualizer!");
var type = IoCManager.Resolve<IReflectionManager>()
.YamlTypeTagLookup(typeof(AppearanceVisualizer), typeValueDataNode.Value);
if (type == null)
throw new InvalidMappingException(
$"Invalid type {typeValueDataNode.Value} specified for AppearanceVisualizer!");
type = IoCManager.Resolve<IReflectionManager>()
.YamlTypeTagLookup(typeof(AppearanceVisualizer), typeValueDataNode.Value);
if (type == null)
throw new InvalidMappingException(
$"Invalid type {typeValueDataNode.Value} specified for AppearanceVisualizer!");
if(value != null && !type.IsInstanceOfType(value))
{
throw new InvalidMappingException(
$"Specified Type does not match type of provided Value for AppearanceVisualizer! (TypeOfValue: {value.GetType()}, ProvidedValue: {type})");
}
}
var newNode = node.Copy();
newNode.Remove("type");
return serializationManager.Read(type, newNode, context, skipHook);
return (AppearanceVisualizer) serializationManager.Read(type, newNode, context, skipHook, value)!;
}
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,

View File

@@ -228,7 +228,7 @@ namespace Robust.Client.UserInterface.CustomControls
foreach (var prototype in prototypeManager.EnumeratePrototypes<EntityPrototype>())
{
if (prototype.Abstract)
if (prototype.NoSpawn || prototype.Abstract)
{
continue;
}

View File

@@ -338,7 +338,7 @@ namespace Robust.Server
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.Initialize();
prototypeManager.LoadDirectory(Options.PrototypeDirectory);
prototypeManager.Resync();
prototypeManager.ResolveResults();
_consoleHost.Initialize();
_entityManager.Startup();

View File

@@ -184,6 +184,7 @@ namespace Robust.Server.GameObjects
}
_subscribedSessions.Add(session);
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(Owner.Owner, new BoundUIOpenedEvent(UiKey, Owner.Owner, session));
SendMessage(new OpenBoundInterfaceMessage(), session);
if (_lastState != null)
{
@@ -236,11 +237,11 @@ namespace Robust.Server.GameObjects
public void CloseShared(IPlayerSession session)
{
var owner = Owner.Owner;
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(owner, new BoundUIClosedEvent(UiKey, owner, session));
OnClosed?.Invoke(session);
_subscribedSessions.Remove(session);
_playerStateOverrides.Remove(session);
session.PlayerStatusChanged -= OnSessionOnPlayerStatusChanged;
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(owner, new BoundUIClosedEvent(UiKey, owner, session));
if (_subscribedSessions.Count == 0)
{

View File

@@ -11,7 +11,7 @@ public struct ChunkIndicesEnumerator
private int _x;
private int _y;
public ChunkIndicesEnumerator(Vector2 viewPos, float range, float chunkSize)
public ChunkIndicesEnumerator(Vector2 viewPos, Vector2 range, float chunkSize)
{
_bottomLeft = ((viewPos - range) / chunkSize).Floored();
// Also floor this as we get the whole chunk anyway.

View File

@@ -43,7 +43,7 @@ internal sealed partial class PVSSystem : EntitySystem
/// <summary>
/// Size of the side of the view bounds square.
/// </summary>
private float _viewSize;
private Vector2 _viewSize;
/// <summary>
/// If PVS disabled then we'll track if we've dumped all entities on the player.
@@ -118,7 +118,7 @@ internal sealed partial class PVSSystem : EntitySystem
EntityManager.EntityDeleted += OnEntityDeleted;
_configManager.OnValueChanged(CVars.NetPVS, SetPvs, true);
_configManager.OnValueChanged(CVars.NetMaxUpdateRange, OnViewsizeChanged, true);
_configManager.OnValueChanged(CVars.NetDefaultUpdateRange, OnViewsizeChanged, true);
InitializeDirty();
}
@@ -144,14 +144,14 @@ internal sealed partial class PVSSystem : EntitySystem
EntityManager.EntityDeleted -= OnEntityDeleted;
_configManager.UnsubValueChanged(CVars.NetPVS, SetPvs);
_configManager.UnsubValueChanged(CVars.NetMaxUpdateRange, OnViewsizeChanged);
_configManager.UnsubValueChanged(CVars.NetDefaultUpdateRange, OnViewsizeChanged);
ShutdownDirty();
}
private void OnViewsizeChanged(float obj)
private void OnViewsizeChanged(Vector2 obj)
{
_viewSize = obj * 2;
_viewSize = obj;
}
private void SetPvs(bool value)
@@ -323,7 +323,6 @@ internal sealed partial class PVSSystem : EntitySystem
{
var playerChunks = new HashSet<int>[sessions.Length];
var eyeQuery = EntityManager.GetEntityQuery<EyeComponent>();
var transformQuery = EntityManager.GetEntityQuery<TransformComponent>();
var viewerEntities = new EntityUid[sessions.Length][];
_chunkList.Clear();
@@ -350,11 +349,17 @@ internal sealed partial class PVSSystem : EntitySystem
foreach (var eyeEuid in viewers)
{
var (viewPos, range, mapId) = CalcViewBounds(in eyeEuid, transformQuery);
var xform = xformQuery.GetComponent(eyeEuid);
var viewPos = xform.WorldPosition;
var range = _viewSize;
var mapId = xform.MapID;
uint visMask = EyeComponent.DefaultVisibilityMask;
if (eyeQuery.TryGetComponent(eyeEuid, out var eyeComp))
{
visMask = eyeComp.VisibilityMask;
range *= eyeComp.Zoom;
}
// Get the nyoom dictionary for index lookups.
if (!_mapIndices.TryGetValue(visMask, out var mapDict))
@@ -399,7 +404,7 @@ internal sealed partial class PVSSystem : EntitySystem
physicsQuery,
true))
{
var localPos = transformQuery.GetComponent(mapGrid.GridEntityId).InvWorldMatrix.Transform(viewPos);
var localPos = xformQuery.GetComponent(mapGrid.GridEntityId).InvWorldMatrix.Transform(viewPos);
var gridChunkEnumerator =
new ChunkIndicesEnumerator(localPos, range, ChunkSize);
@@ -601,6 +606,14 @@ internal sealed partial class PVSSystem : EntitySystem
ref entitiesSent, mQuery, tQuery, in enteredEntityBudget, in newEntityBudget);
}
var expandEvent = new ExpandPvsEvent(session, new List<EntityUid>());
RaiseLocalEvent(ref expandEvent);
foreach (var entityUid in expandEvent.Entities)
{
RecursivelyAddOverride(in entityUid, seenSet, playerVisibleSet, visibleEnts, fromTick, ref newEntitiesSent,
ref entitiesSent, mQuery, tQuery, in enteredEntityBudget, in newEntityBudget);
}
var entityStates = new List<EntityState>();
foreach (var (entityUid, visiblity) in visibleEnts)
@@ -963,13 +976,6 @@ internal sealed partial class PVSSystem : EntitySystem
return viewerArray;
}
// Read Safe
private (Vector2 worldPos, float range, MapId mapId) CalcViewBounds(in EntityUid euid, EntityQuery<TransformComponent> transformQuery)
{
var xform = transformQuery.GetComponent(euid);
return (xform.WorldPosition, _viewSize / 2f, xform.MapID);
}
public sealed class SetPolicy<T> : PooledObjectPolicy<HashSet<T>>
{
public override HashSet<T> Create()

View File

@@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
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.Serialization.TypeSerializers.Interfaces;
namespace Robust.Server.Maps
{
[TypeSerializer]
internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingDataNode>
{
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, ISerializationContext? context = null)
{
throw new NotImplementedException();
}
public MapChunk Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, MapChunk? chunk = null)
{
var tileNode = (ValueDataNode)node["tiles"];
var tileBytes = Convert.FromBase64String(tileNode.Value);
using var stream = new MemoryStream(tileBytes);
using var reader = new BinaryReader(stream);
var mapManager = dependencies.Resolve<IMapManager>();
mapManager.SuppressOnTileChanged = true;
if (chunk == null)
{
throw new InvalidOperationException(
$"Someone tried deserializing a gridchunk without passing a value.");
}
if (context is not MapLoader.MapContext mapContext)
{
throw new InvalidOperationException(
$"Someone tried serializing a gridchunk without passing {nameof(MapLoader.MapContext)} as context.");
}
var tileMap = mapContext.TileMap;
if (tileMap == null)
{
throw new InvalidOperationException(
$"Someone tried deserializing a gridchunk before deserializing the tileMap.");
}
chunk.SuppressCollisionRegeneration = true;
var tileDefinitionManager = dependencies.Resolve<ITileDefinitionManager>();
for (ushort y = 0; y < chunk.ChunkSize; y++)
{
for (ushort x = 0; x < chunk.ChunkSize; x++)
{
var id = reader.ReadUInt16();
var flags = (TileRenderFlag)reader.ReadByte();
var variant = reader.ReadByte();
var defName = tileMap[id];
id = tileDefinitionManager[defName].TileId;
var tile = new Tile(id, flags, variant);
chunk.SetTile(x, y, tile);
}
}
chunk.SuppressCollisionRegeneration = false;
mapManager.SuppressOnTileChanged = false;
return chunk;
}
public DataNode Write(ISerializationManager serializationManager, MapChunk value, bool alwaysWrite = false,
ISerializationContext? context = null)
{
var root = new MappingDataNode();
var ind = new ValueDataNode($"{value.X},{value.Y}");
root.Add("ind", ind);
var gridNode = new ValueDataNode();
root.Add("tiles", gridNode);
gridNode.Value = SerializeTiles(value);
return root;
}
private static string SerializeTiles(MapChunk chunk)
{
// number of bytes written per tile, because sizeof(Tile) is useless.
const int structSize = 4;
var nTiles = chunk.ChunkSize * chunk.ChunkSize * structSize;
var barr = new byte[nTiles];
using (var stream = new MemoryStream(barr))
using (var writer = new BinaryWriter(stream))
{
for (ushort y = 0; y < chunk.ChunkSize; y++)
{
for (ushort x = 0; x < chunk.ChunkSize; x++)
{
var tile = chunk.GetTile(x, y);
writer.Write(tile.TypeId);
writer.Write((byte)tile.Flags);
writer.Write(tile.Variant);
}
}
}
return Convert.ToBase64String(barr);
}
public MapChunk Copy(ISerializationManager serializationManager, MapChunk source, MapChunk target, bool skipHook,
ISerializationContext? context = null)
{
throw new NotImplementedException();
}
}
//todo paul make this be used
[TypeSerializer]
internal sealed class GridSerializer : ITypeSerializer<MapGrid, MappingDataNode>
{
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, ISerializationContext? context = null)
{
throw new NotImplementedException();
}
public MapGrid Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, MapGrid? grid = null)
{
var info = node.Get<MappingDataNode>("settings");
var chunks = node.Get<SequenceDataNode>("chunks");
ushort csz = 0;
ushort tsz = 0;
float sgsz = 0.0f;
foreach (var kvInfo in info.Cast<KeyValuePair<ValueDataNode, ValueDataNode>>())
{
var key = kvInfo.Key.Value;
var val = kvInfo.Value.Value;
if (key == "chunksize")
csz = ushort.Parse(val);
else if (key == "tilesize")
tsz = ushort.Parse(val);
else if (key == "snapsize")
sgsz = float.Parse(val, CultureInfo.InvariantCulture);
}
//TODO: Pass in options
if (context is not MapLoader.MapContext mapContext)
{
throw new InvalidOperationException(
$"Someone tried serializing a mapgrid without passing {nameof(MapLoader.MapContext)} as context.");
}
if (grid == null) throw new NotImplementedException();
//todo paul grid ??= dependencies.Resolve<MapManager>().CreateUnboundGrid(mapContext.TargetMap);
foreach (var chunkNode in chunks.Cast<MappingDataNode>())
{
var (chunkOffsetX, chunkOffsetY) =
serializationManager.Read<Vector2i>(chunkNode["ind"], context, skipHook);
var chunk = grid.GetChunk(chunkOffsetX, chunkOffsetY);
serializationManager.Read(typeof(MapChunkSerializer), chunkNode, context, skipHook, chunk);
}
return grid;
}
public DataNode Write(ISerializationManager serializationManager, MapGrid value, bool alwaysWrite = false,
ISerializationContext? context = null)
{
var gridn = new MappingDataNode();
var info = new MappingDataNode();
var chunkSeq = new SequenceDataNode();
gridn.Add("settings", info);
gridn.Add("chunks", chunkSeq);
info.Add("chunksize", value.ChunkSize.ToString(CultureInfo.InvariantCulture));
info.Add("tilesize", value.TileSize.ToString(CultureInfo.InvariantCulture));
var chunks = value.GetMapChunks();
foreach (var chunk in chunks)
{
var chunkNode = serializationManager.WriteValue(chunk.Value);
chunkSeq.Add(chunkNode);
}
return gridn;
}
public MapGrid Copy(ISerializationManager serializationManager, MapGrid source, MapGrid target, bool skipHook,
ISerializationContext? context = null)
{
throw new NotImplementedException();
}
}
}

View File

@@ -13,14 +13,15 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
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.Serialization.TypeSerializers.Interfaces;
@@ -44,6 +45,7 @@ namespace Robust.Server.Maps
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly IServerEntityManagerInternal _serverEntityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ISerializationManager _serializationManager = default!;
public event Action<YamlStream, string>? LoadedMapData;
@@ -52,7 +54,7 @@ namespace Robust.Server.Maps
{
var grid = _mapManager.GetGrid(gridId);
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _prototypeManager);
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _prototypeManager, _serializationManager);
context.RegisterGrid(grid);
var root = context.Serialize();
var document = new YamlDocument(root);
@@ -99,7 +101,7 @@ namespace Robust.Server.Maps
}
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager,
_prototypeManager, (YamlMappingNode) data.RootNode, mapId, options);
_prototypeManager, _serializationManager, data.RootNode.ToDataNodeCast<MappingDataNode>(), mapId, options);
context.Deserialize();
grid = context.Grids[0];
@@ -139,7 +141,7 @@ namespace Robust.Server.Maps
public void SaveMap(MapId mapId, string yamlPath)
{
Logger.InfoS("map", $"Saving map {mapId} to {yamlPath}");
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _prototypeManager);
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager, _prototypeManager, _serializationManager);
foreach (var grid in _mapManager.GetAllMapGrids(mapId))
{
context.RegisterGrid(grid);
@@ -206,7 +208,7 @@ namespace Robust.Server.Maps
LoadedMapData?.Invoke(data.Stream, resPath.ToString());
var context = new MapContext(_mapManager, _tileDefinitionManager, _serverEntityManager,
_prototypeManager, (YamlMappingNode) data.RootNode, mapId, options);
_prototypeManager, _serializationManager, data.RootNode.ToDataNodeCast<MappingDataNode>(), mapId, options);
context.Deserialize();
PostDeserialize(mapId, context);
@@ -216,7 +218,7 @@ namespace Robust.Server.Maps
/// <summary>
/// Handles the primary bulk of state during the map serialization process.
/// </summary>
private sealed class MapContext : ISerializationContext, IEntityLoadContext,
internal sealed class MapContext : ISerializationContext, IEntityLoadContext,
ITypeSerializer<GridId, ValueDataNode>,
ITypeSerializer<EntityUid, ValueDataNode>,
ITypeReaderWriter<EntityUid, ValueDataNode>
@@ -225,6 +227,7 @@ namespace Robust.Server.Maps
private readonly ITileDefinitionManager _tileDefinitionManager;
private readonly IServerEntityManagerInternal _serverEntityManager;
private readonly IPrototypeManager _prototypeManager;
private readonly ISerializationManager _serializationManager;
private readonly MapLoadOptions? _loadOptions;
private readonly Dictionary<GridId, int> GridIDMap = new();
@@ -235,19 +238,20 @@ namespace Robust.Server.Maps
private readonly Dictionary<int, EntityUid> UidEntityMap = new();
public readonly List<EntityUid> Entities = new();
private readonly List<(EntityUid, YamlMappingNode)> _entitiesToDeserialize
private readonly List<(EntityUid, MappingDataNode)> _entitiesToDeserialize
= new();
private bool IsBlueprintMode => GridIDMap.Count == 1;
private readonly YamlMappingNode RootNode;
private readonly MapId TargetMap;
private readonly MappingDataNode RootNode;
public readonly MapId TargetMap;
private Dictionary<string, YamlMappingNode>? CurrentReadingEntityComponents;
private Dictionary<string, MappingDataNode>? CurrentReadingEntityComponents;
private string? CurrentWritingComponent;
private EntityUid? CurrentWritingEntity;
public IReadOnlyDictionary<ushort, string>? TileMap => _tileMap;
private Dictionary<ushort, string>? _tileMap;
public Dictionary<(Type, Type), object> TypeReaders { get; }
@@ -258,14 +262,16 @@ namespace Robust.Server.Maps
public bool MapIsPostInit { get; private set; }
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs,
IServerEntityManagerInternal entities, IPrototypeManager prototypeManager)
IServerEntityManagerInternal entities, IPrototypeManager prototypeManager,
ISerializationManager serializationManager)
{
_mapManager = maps;
_tileDefinitionManager = tileDefs;
_serverEntityManager = entities;
_prototypeManager = prototypeManager;
_serializationManager = serializationManager;
RootNode = new YamlMappingNode();
RootNode = new MappingDataNode();
TypeWriters = new Dictionary<Type, object>()
{
{typeof(GridId), this},
@@ -281,12 +287,14 @@ namespace Robust.Server.Maps
public MapContext(IMapManagerInternal maps, ITileDefinitionManager tileDefs,
IServerEntityManagerInternal entities,
IPrototypeManager prototypeManager,
YamlMappingNode node, MapId targetMapId, MapLoadOptions options)
ISerializationManager serializationManager,
MappingDataNode node, MapId targetMapId, MapLoadOptions options)
{
_mapManager = maps;
_tileDefinitionManager = tileDefs;
_serverEntityManager = entities;
_loadOptions = options;
_serializationManager = serializationManager;
RootNode = node;
TargetMap = targetMapId;
@@ -355,13 +363,13 @@ namespace Robust.Server.Maps
private void VerifyEntitiesExist()
{
var fail = false;
var entities = RootNode.GetNode<YamlSequenceNode>("entities");
var entities = RootNode.Get<SequenceDataNode>("entities");
var reportedError = new HashSet<string>();
foreach (var entityDef in entities.Cast<YamlMappingNode>())
foreach (var entityDef in entities.Cast<MappingDataNode>())
{
if (entityDef.TryGetNode("type", out var typeNode))
if (entityDef.TryGet<ValueDataNode>("type", out var typeNode))
{
var type = typeNode.AsString();
var type = typeNode.Value;
if (!_prototypeManager.HasIndex<EntityPrototype>(type) && !reportedError.Contains(type))
{
Logger.Error("Missing prototype for map: {0}", type);
@@ -384,7 +392,7 @@ namespace Robust.Server.Maps
foreach (var (entity, data) in _entitiesToDeserialize)
{
if (!data.TryGetNode("components", out YamlSequenceNode? componentList))
if (!data.TryGet("components", out SequenceDataNode? componentList))
{
continue;
}
@@ -399,7 +407,7 @@ namespace Robust.Server.Maps
var castComp = (Component) component;
var compName = compFactory.GetComponentName(castComp.GetType());
if (componentList.Any(p => p["type"].AsString() == compName))
if (componentList.Cast<MappingDataNode>().Any(p => ((ValueDataNode)p["type"]).Value == compName))
{
if (prototype.Components.ContainsKey(compName))
{
@@ -487,7 +495,7 @@ namespace Robust.Server.Maps
// Now we need to actually bind the MapGrids to their components so that you can resolve GridId -> EntityUid
// After doing this, it should be 100% safe to use the MapManager API like normal.
var yamlGrids = RootNode.GetNode<YamlSequenceNode>("grids");
var yamlGrids = RootNode.Get<SequenceDataNode>("grids");
// get ents that the grids will bind to
var gridComps = new Dictionary<GridId, MapGridComponent>(_readGridIndices.Count);
@@ -511,28 +519,30 @@ namespace Robust.Server.Maps
{
// Here is where the implicit index pairing magic happens from the yaml.
var gridIndex = _readGridIndices[index];
var yamlGrid = (YamlMappingNode)yamlGrids.Children[index];
var yamlGrid = (MappingDataNode)yamlGrids[index];
// designed to throw if something is broken, every grid must map to an ent
var gridComp = gridComps[gridIndex];
DebugTools.Assert(gridComp.GridIndex == gridIndex);
YamlMappingNode yamlGridInfo = (YamlMappingNode)yamlGrid["settings"];
YamlSequenceNode yamlGridChunks = (YamlSequenceNode)yamlGrid["chunks"];
MappingDataNode yamlGridInfo = (MappingDataNode)yamlGrid["settings"];
SequenceDataNode yamlGridChunks = (SequenceDataNode)yamlGrid["chunks"];
var grid = AllocateMapGrid(gridComp, yamlGridInfo);
foreach (var chunkNode in yamlGridChunks.Cast<YamlMappingNode>())
foreach (var chunkNode in yamlGridChunks.Cast<MappingDataNode>())
{
YamlGridSerializer.DeserializeChunk(_mapManager, grid, chunkNode, _tileMap!, _tileDefinitionManager);
var (chunkOffsetX, chunkOffsetY) = _serializationManager.Read<Vector2i>(chunkNode["ind"]);
var chunk = grid.GetChunk(chunkOffsetX, chunkOffsetY);
_serializationManager.Read(chunkNode, this, value: chunk);
}
Grids.Add(grid); // Grids are kept in index order
}
}
private static MapGrid AllocateMapGrid(MapGridComponent gridComp, YamlMappingNode yamlGridInfo)
private static MapGrid AllocateMapGrid(MapGridComponent gridComp, MappingDataNode yamlGridInfo)
{
// sane defaults
ushort csz = 16;
@@ -540,8 +550,8 @@ namespace Robust.Server.Maps
foreach (var kvInfo in yamlGridInfo)
{
var key = kvInfo.Key.ToString();
var val = kvInfo.Value.ToString();
var key = ((ValueDataNode)kvInfo.Key).Value;
var val = ((ValueDataNode)kvInfo.Value).Value;
if (key == "chunksize")
csz = ushort.Parse(val);
else if (key == "tilesize")
@@ -590,14 +600,14 @@ namespace Robust.Server.Maps
private void ReadMetaSection()
{
var meta = RootNode.GetNode<YamlMappingNode>("meta");
var ver = meta.GetNode("format").AsInt();
var meta = RootNode.Get<MappingDataNode>("meta");
var ver = meta.Get<ValueDataNode>("format").AsInt();
if (ver != MapFormatVersion)
{
throw new InvalidDataException("Cannot handle this map file version.");
}
if (meta.TryGetNode("postmapinit", out var mapInitNode))
if (meta.TryGet<ValueDataNode>("postmapinit", out var mapInitNode))
{
MapIsPostInit = mapInitNode.AsBool();
}
@@ -612,11 +622,11 @@ namespace Robust.Server.Maps
// Load tile mapping so that we can map the stored tile IDs into the ones actually used at runtime.
_tileMap = new Dictionary<ushort, string>();
var tileMap = RootNode.GetNode<YamlMappingNode>("tilemap");
foreach (var (key, value) in tileMap)
var tileMap = RootNode.Get<MappingDataNode>("tilemap");
foreach (var (key, value) in tileMap.Children)
{
var tileId = (ushort) key.AsInt();
var tileDefName = value.AsString();
var tileId = (ushort) ((ValueDataNode)key).AsInt();
var tileDefName = ((ValueDataNode)value).Value;
_tileMap.Add(tileId, tileDefName);
}
}
@@ -625,9 +635,9 @@ namespace Robust.Server.Maps
{
// sets up the mapping so the serializer can properly deserialize GridIds.
var yamlGrids = RootNode.GetNode<YamlSequenceNode>("grids");
var yamlGrids = RootNode.Get<SequenceDataNode>("grids");
for (var i = 0; i < yamlGrids.Children.Count; i++)
for (var i = 0; i < yamlGrids.Count; i++)
{
_readGridIndices.Add(_mapManager.GenerateGridId(null));
}
@@ -652,17 +662,17 @@ namespace Robust.Server.Maps
private void AllocEntities()
{
var entities = RootNode.GetNode<YamlSequenceNode>("entities");
foreach (var entityDef in entities.Cast<YamlMappingNode>())
var entities = RootNode.Get<SequenceDataNode>("entities");
foreach (var entityDef in entities.Cast<MappingDataNode>())
{
string? type = null;
if (entityDef.TryGetNode("type", out var typeNode))
if (entityDef.TryGet<ValueDataNode>("type", out var typeNode))
{
type = typeNode.AsString();
type = typeNode.Value;
}
var uid = Entities.Count;
if (entityDef.TryGetNode("uid", out var uidNode))
if (entityDef.TryGet<ValueDataNode>("uid", out var uidNode))
{
uid = uidNode.AsInt();
}
@@ -684,15 +694,14 @@ namespace Robust.Server.Maps
{
foreach (var (entity, data) in _entitiesToDeserialize)
{
CurrentReadingEntityComponents = new Dictionary<string, YamlMappingNode>();
if (data.TryGetNode("components", out YamlSequenceNode? componentList))
CurrentReadingEntityComponents = new Dictionary<string, MappingDataNode>();
if (data.TryGet("components", out SequenceDataNode? componentList))
{
foreach (var compData in componentList)
foreach (var compData in componentList.Cast<MappingDataNode>())
{
var copy = new YamlMappingNode(((YamlMappingNode)compData).AsEnumerable());
copy.Children.Remove(new YamlScalarNode("type"));
//TODO Paul: maybe replace mapping with datanode
CurrentReadingEntityComponents[compData["type"].AsString()] = copy;
var datanode = compData.Copy();
datanode.Remove("type");
CurrentReadingEntityComponents[((ValueDataNode)compData["type"]).Value] = datanode;
}
}
@@ -737,12 +746,12 @@ namespace Robust.Server.Maps
PopulateEntityList();
WriteEntitySection();
return RootNode;
return RootNode.ToYaml();
}
private void WriteMetaSection()
{
var meta = new YamlMappingNode();
var meta = new MappingDataNode();
RootNode.Add("meta", meta);
meta.Add("format", MapFormatVersion.ToString(CultureInfo.InvariantCulture));
// TODO: Make these values configurable.
@@ -764,7 +773,7 @@ namespace Robust.Server.Maps
private void WriteTileMapSection()
{
var tileMap = new YamlMappingNode();
var tileMap = new MappingDataNode();
RootNode.Add("tilemap", tileMap);
foreach (var tileDefinition in _tileDefinitionManager)
{
@@ -774,12 +783,12 @@ namespace Robust.Server.Maps
private void WriteGridSection()
{
var grids = new YamlSequenceNode();
var grids = new SequenceDataNode();
RootNode.Add("grids", grids);
foreach (var grid in Grids)
{
var entry = YamlGridSerializer.SerializeGrid(grid);
var entry = _serializationManager.WriteValue(grid, context: this);
grids.Add(entry);
}
}
@@ -843,14 +852,14 @@ namespace Robust.Server.Maps
var serializationManager = IoCManager.Resolve<ISerializationManager>();
var compFactory = IoCManager.Resolve<IComponentFactory>();
var metaQuery = _serverEntityManager.GetEntityQuery<MetaDataComponent>();
var entities = new YamlSequenceNode();
var entities = new SequenceDataNode();
RootNode.Add("entities", entities);
var prototypeCompCache = new Dictionary<string, Dictionary<string, MappingDataNode>>();
foreach (var (saveId, entityUid) in UidEntityMap.OrderBy(e=>e.Key))
{
CurrentWritingEntity = entityUid;
var mapping = new YamlMappingNode
var mapping = new MappingDataNode
{
{"uid", saveId.ToString(CultureInfo.InvariantCulture)}
};
@@ -870,7 +879,7 @@ namespace Robust.Server.Maps
}
}
var components = new YamlSequenceNode();
var components = new SequenceDataNode();
// See engine#636 for why the Distinct() call.
foreach (var component in _serverEntityManager.GetComponents(entityUid))
@@ -894,11 +903,11 @@ namespace Robust.Server.Maps
{
compMapping.Add("type", new ValueDataNode(compName));
// Something actually got written!
components.Add(compMapping.ToYamlNode());
components.Add(compMapping);
}
}
if (components.Children.Count != 0)
if (components.Count != 0)
{
mapping.Add("components", components);
}
@@ -908,8 +917,8 @@ namespace Robust.Server.Maps
}
// Create custom object serializers that will correctly allow data to be overriden by the map file.
IComponent IEntityLoadContext.GetComponentData(string componentName,
IComponent? protoData)
MappingDataNode IEntityLoadContext.GetComponentData(string componentName,
MappingDataNode? protoData)
{
if (CurrentReadingEntityComponents == null)
{
@@ -919,20 +928,15 @@ namespace Robust.Server.Maps
var serializationManager = IoCManager.Resolve<ISerializationManager>();
var factory = IoCManager.Resolve<IComponentFactory>();
IComponent data = protoData != null
? serializationManager.CreateCopy(protoData, this)!
: (IComponent) Activator.CreateInstance(factory.GetRegistration(componentName).Type)!;
if (CurrentReadingEntityComponents.TryGetValue(componentName, out var mapping))
{
var mapData = (IDeserializedDefinition) serializationManager.Read(
factory.GetRegistration(componentName).Type,
mapping.ToDataNode(), this);
var newData = serializationManager.PopulateDataDefinition(data, mapData);
data = (IComponent) newData.RawValue!;
if (protoData == null) return mapping.Copy();
return serializationManager.PushCompositionWithGenericNode(
factory.GetRegistration(componentName).Type, new[] { protoData }, mapping, this);
}
return data;
return protoData ?? new MappingDataNode();
}
public IEnumerable<string> GetExtraComponentTypes()
@@ -947,10 +951,10 @@ namespace Robust.Server.Maps
: base(message) { }
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
public GridId Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, GridId _ = default)
{
// This is the code that deserializes the Grids index into the GridId. This has to happen between Grid allocation
// and when grids are bound to their entities.
@@ -966,7 +970,7 @@ namespace Robust.Server.Maps
throw new MapLoadException($"Error in map file: found local grid ID '{val}' which does not exist.");
}
return new DeserializedValue<GridId>(_readGridIndices[val]);
return _readGridIndices[val];
}
ValidationNode ITypeValidator<EntityUid, ValueDataNode>.Validate(ISerializationManager serializationManager,
@@ -1032,15 +1036,15 @@ namespace Robust.Server.Maps
}
}
DeserializationResult ITypeReader<EntityUid, ValueDataNode>.Read(ISerializationManager serializationManager,
EntityUid ITypeReader<EntityUid, ValueDataNode>.Read(ISerializationManager serializationManager,
ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, EntityUid _)
{
if (node.Value == "null")
{
return new DeserializedValue<EntityUid>(EntityUid.Invalid);
return EntityUid.Invalid;
}
var val = int.Parse(node.Value);
@@ -1048,11 +1052,11 @@ namespace Robust.Server.Maps
if (val >= Entities.Count || !UidEntityMap.ContainsKey(val) || !Entities.TryFirstOrNull(e => e == UidEntityMap[val], out var entity))
{
Logger.ErrorS("map", "Error in map file: found local entity UID '{0}' which does not exist.", val);
return null!;
return EntityUid.Invalid;
}
else
{
return new DeserializedValue<EntityUid>(entity!.Value);
return entity!.Value;
}
}

View File

@@ -1,120 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
namespace Robust.Server.Maps
{
internal static class YamlGridSerializer
{
public static YamlMappingNode SerializeGrid(IMapGrid mapGrid)
{
var grid = (IMapGridInternal) mapGrid;
var gridn = new YamlMappingNode();
var info = new YamlMappingNode();
var chunkSeq = new YamlSequenceNode();
gridn.Add("settings", info);
gridn.Add("chunks", chunkSeq);
info.Add("chunksize", grid.ChunkSize.ToString(CultureInfo.InvariantCulture));
info.Add("tilesize", grid.TileSize.ToString(CultureInfo.InvariantCulture));
var chunks = grid.GetMapChunks();
foreach (var chunk in chunks)
{
var chunkNode = SerializeChunk(chunk.Value);
chunkSeq.Add(chunkNode);
}
return gridn;
}
private static YamlNode SerializeChunk(MapChunk chunk)
{
var root = new YamlMappingNode();
var value = new YamlScalarNode($"{chunk.X},{chunk.Y}");
value.Style = ScalarStyle.DoubleQuoted;
root.Add("ind", value);
var gridNode = new YamlScalarNode();
root.Add("tiles", gridNode);
gridNode.Value = SerializeTiles(chunk);
return root;
}
private static string SerializeTiles(MapChunk chunk)
{
// number of bytes written per tile, because sizeof(Tile) is useless.
const int structSize = 4;
var nTiles = chunk.ChunkSize * chunk.ChunkSize * structSize;
var barr = new byte[nTiles];
using (var stream = new MemoryStream(barr))
using (var writer = new BinaryWriter(stream))
{
for (ushort y = 0; y < chunk.ChunkSize; y++)
{
for (ushort x = 0; x < chunk.ChunkSize; x++)
{
var tile = chunk.GetTile(x, y);
writer.Write(tile.TypeId);
writer.Write((byte)tile.Flags);
writer.Write(tile.Variant);
}
}
}
return Convert.ToBase64String(barr);
}
public static void DeserializeChunk(IMapManager mapMan, IMapGridInternal grid,
YamlMappingNode chunkData,
IReadOnlyDictionary<ushort, string> tileDefMapping,
ITileDefinitionManager tileDefinitionManager)
{
var indNode = chunkData["ind"];
var tileNode = chunkData["tiles"];
var (chunkOffsetX, chunkOffsetY) = indNode.AsVector2i();
var tileBytes = Convert.FromBase64String(tileNode.ToString());
using var stream = new MemoryStream(tileBytes);
using var reader = new BinaryReader(stream);
mapMan.SuppressOnTileChanged = true;
var chunk = grid.GetChunk(chunkOffsetX, chunkOffsetY);
chunk.SuppressCollisionRegeneration = true;
for (ushort y = 0; y < grid.ChunkSize; y++)
{
for (ushort x = 0; x < grid.ChunkSize; x++)
{
var id = reader.ReadUInt16();
var flags = (TileRenderFlag)reader.ReadByte();
var variant = reader.ReadByte();
var defName = tileDefMapping[id];
id = tileDefinitionManager[defName].TileId;
var tile = new Tile(id, flags, variant);
chunk.SetTile(x, y, tile);
}
}
chunk.SuppressCollisionRegeneration = false;
mapMan.SuppressOnTileChanged = false;
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Threading;
using Robust.Shared.Audio;
using Robust.Shared.Configuration;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Physics;
@@ -121,8 +122,8 @@ namespace Robust.Shared
/// View size to take for PVS calculations,
/// as the size of the sides of a square centered on the view points of clients.
/// </summary>
public static readonly CVarDef<float> NetMaxUpdateRange =
CVarDef.Create("net.maxupdaterange", 12.5f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<Vector2> NetDefaultUpdateRange =
CVarDef.Create("net.defaultupdaterange", new Vector2(12.5f, 12.5f), CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// The amount of new entities that can be sent to a client in a single game state, under PVS.

View File

@@ -35,7 +35,7 @@ namespace Robust.Shared.GameObjects
/// <summary>
/// Increases the life stage from <see cref="ComponentLifeStage.PreAdd" /> to <see cref="ComponentLifeStage.Added" />,
/// calling <see cref="OnAdd" />.
/// after raising a <see cref="ComponentAdd"/> event.
/// </summary>
internal void LifeAddToEntity(IEntityManager entManager)
{
@@ -44,14 +44,7 @@ namespace Robust.Shared.GameObjects
LifeStage = ComponentLifeStage.Adding;
CreationTick = entManager.CurrentTick;
entManager.EventBus.RaiseComponentEvent(this, CompAddInstance);
OnAdd();
#if DEBUG
if (LifeStage != ComponentLifeStage.Added)
{
DebugTools.Assert($"Component {this.GetType().Name} did not call base {nameof(OnAdd)} in derived method.");
}
#endif
LifeStage = ComponentLifeStage.Added;
}
/// <summary>
@@ -166,14 +159,6 @@ namespace Robust.Shared.GameObjects
private static readonly ComponentShutdown CompShutdownInstance = new();
private static readonly ComponentRemove CompRemoveInstance = new();
/// <summary>
/// Called when the component gets added to an entity.
/// </summary>
protected virtual void OnAdd()
{
LifeStage = ComponentLifeStage.Added;
}
/// <summary>
/// Called when all of the entity's other components have been added and are available,
/// But are not necessarily initialized yet. DO NOT depend on the values of other components to be correct.

View File

@@ -87,6 +87,7 @@ namespace Robust.Shared.GameObjects
/// </summary>
internal LinkedList<Contact> Contacts = new();
[DataField("ignorePaused"), ViewVariables(VVAccess.ReadWrite)]
public bool IgnorePaused { get; set; }
internal SharedPhysicsMapComponent? PhysicsMap { get; set; }
@@ -113,7 +114,8 @@ namespace Robust.Shared.GameObjects
_angularVelocity = 0.0f;
// SynchronizeFixtures(); TODO: When CCD
}
else
// Even if it's dynamic if it can't collide then don't force it awake.
else if (_canCollide)
{
SetAwake(true);
}

View File

@@ -1,5 +1,3 @@
using System;
namespace Robust.Shared.GameObjects
{
// If you wanna use these, add it to some random prototype.
@@ -11,24 +9,15 @@ namespace Robust.Shared.GameObjects
/// <summary>
/// Throws an exception in <see cref="OnAdd" />.
/// </summary>
public sealed class DebugExceptionOnAddComponent : Component
{
protected override void OnAdd() => throw new NotSupportedException();
}
public sealed class DebugExceptionOnAddComponent : Component { }
/// <summary>
/// Throws an exception in <see cref="Initialize" />.
/// </summary>
public sealed class DebugExceptionInitializeComponent : Component
{
protected override void Initialize() => throw new NotSupportedException();
}
public sealed class DebugExceptionInitializeComponent : Component { }
/// <summary>
/// Throws an exception in <see cref="Startup" />.
/// </summary>
public sealed class DebugExceptionStartupComponent : Component
{
protected override void Startup() => throw new NotSupportedException();
}
public sealed class DebugExceptionStartupComponent : Component { }
}

View File

@@ -1,25 +0,0 @@
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Robust.Shared.GameObjects
{
[RegisterComponent]
public sealed class IgnorePauseComponent : Component
{
protected override void OnAdd()
{
base.OnAdd();
IoCManager.Resolve<IEntityManager>().GetComponent<MetaDataComponent>(Owner).EntityPaused = false;
}
protected override void OnRemove()
{
base.OnRemove();
var entMan = IoCManager.Resolve<IEntityManager>();
if (IoCManager.Resolve<IMapManager>().IsMapPaused(entMan.GetComponent<TransformComponent>(Owner).MapID))
{
entMan.GetComponent<MetaDataComponent>(Owner).EntityPaused = true;
}
}
}
}

View File

@@ -151,12 +151,8 @@ namespace Robust.Shared.GameObjects
if (_entityPaused == value)
return;
var entMan = IoCManager.Resolve<IEntityManager>();
if (value && entMan.HasComponent<IgnorePauseComponent>(Owner))
return;
_entityPaused = value;
entMan.EventBus.RaiseLocalEvent(Owner, new EntityPausedEvent(Owner, value));
IoCManager.Resolve<IEntityManager>().EventBus.RaiseLocalEvent(Owner, new EntityPausedEvent(Owner, value));
}
}

View File

@@ -135,6 +135,16 @@ namespace Robust.Shared.GameObjects
}
}
public sealed class BoundUIOpenedEvent : BoundUserInterfaceMessage
{
public BoundUIOpenedEvent(object uiKey, EntityUid uid, ICommonSession session)
{
UiKey = uiKey;
Entity = uid;
Session = session;
}
}
public sealed class BoundUIClosedEvent : BoundUserInterfaceMessage
{
public BoundUIClosedEvent(object uiKey, EntityUid uid, ICommonSession session)

View File

@@ -417,7 +417,7 @@ namespace Robust.Shared.GameObjects
var entity = AllocEntity(prototypeName, uid);
try
{
EntityPrototype.LoadEntity(GetComponent<MetaDataComponent>(entity).EntityPrototype, entity, ComponentFactory, this, _serManager, null);
EntityPrototype.LoadEntity(GetComponent<MetaDataComponent>(entity).EntityPrototype, entity, ComponentFactory, PrototypeManager, this, _serManager, null);
return entity;
}
catch (Exception e)
@@ -431,7 +431,7 @@ namespace Robust.Shared.GameObjects
private protected void LoadEntity(EntityUid entity, IEntityLoadContext? context)
{
EntityPrototype.LoadEntity(GetComponent<MetaDataComponent>(entity).EntityPrototype, entity, ComponentFactory, this, _serManager, context);
EntityPrototype.LoadEntity(GetComponent<MetaDataComponent>(entity).EntityPrototype, entity, ComponentFactory, PrototypeManager, this, _serManager, context);
}
private void InitializeAndStartEntity(EntityUid entity, MapId mapId)

View File

@@ -410,7 +410,7 @@ public partial class EntitySystem
/// <inheritdoc cref="IEntityManager.TryGetComponent&lt;T&gt;(EntityUid?, out T)"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected bool TryComp<T>(EntityUid? uid, [NotNullWhen(true)] out T? comp)
protected bool TryComp<T>([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out T? comp)
{
if (!uid.HasValue)
{

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown.Mapping;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.GameObjects
@@ -14,7 +15,7 @@ namespace Robust.Shared.GameObjects
/// <summary>
/// Gets the serializer used to ExposeData a specific component.
/// </summary>
IComponent GetComponentData(string componentName, IComponent? protoData);
MappingDataNode GetComponentData(string componentName, MappingDataNode? protoData);
/// <summary>
/// Gets extra component names that must also be instantiated on top of the ones defined in the prototype,

View File

@@ -0,0 +1,15 @@
using System;
namespace Robust.Shared.GameObjects;
public sealed class DebugExceptionSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DebugExceptionOnAddComponent, ComponentAdd>((_, _, _) => throw new NotSupportedException());
SubscribeLocalEvent<DebugExceptionInitializeComponent, ComponentInit>((_, _, _) => throw new NotSupportedException());
SubscribeLocalEvent<DebugExceptionStartupComponent, ComponentStartup>((_, _, _) => throw new NotSupportedException());
}
}

View File

@@ -30,16 +30,15 @@ public abstract partial class SharedPhysicsSystem
if (component.CanCollide)
{
if (component.Awake)
{
EntityManager.EventBus.RaiseEvent(EventSource.Local, new PhysicsWakeMessage(component));
}
if (!_containerSystem.IsEntityInContainer(uid))
{
// TODO: Probably a bad idea but ehh future sloth's problem; namely that we have to duplicate code between here and CanCollide.
EntityManager.EventBus.RaiseLocalEvent(uid, new CollisionChangeMessage(component, uid, component._canCollide));
}
else
{
component._canCollide = false;
}
}
else
{

View File

@@ -56,79 +56,71 @@ namespace Robust.Shared.Localization
string? suffix = null;
Dictionary<string, string>? attributes = null;
while (true)
_prototype.TryIndex<EntityPrototype>(prototypeId, out var prototype);
var locId = prototype?.CustomLocalizationID ?? $"ent-{prototypeId}";
if (TryGetMessage(locId, out var bundle, out var msg))
{
var prototype = _prototype.Index<EntityPrototype>(prototypeId);
var locId = prototype.CustomLocalizationID ?? $"ent-{prototypeId}";
// Localization override exists.
var msgAttrs = msg.Attributes;
if (TryGetMessage(locId, out var bundle, out var msg))
if (name == null && msg.Value != null)
{
// Localization override exists.
var msgAttrs = msg.Attributes;
if (name == null && msg.Value != null)
{
// Only set name if the value isn't empty.
// So that you can override *only* a desc/suffix.
name = bundle.FormatPattern(msg.Value, null, out var fmtErr);
WriteWarningForErrs(fmtErr, locId);
}
if (msgAttrs.Count != 0)
{
foreach (var (attrId, pattern) in msg.Attributes)
{
var attrib = attrId.ToString();
if (attrib.Equals("desc")
|| attrib.Equals("suffix"))
continue;
attributes ??= new Dictionary<string, string>();
if (!attributes.ContainsKey(attrib))
{
var value = bundle.FormatPattern(pattern, null, out var errors);
WriteWarningForErrs(errors, locId);
attributes[attrib] = value;
}
}
var allErrors = new List<FluentError>();
if (desc == null
&& bundle.TryGetMsg(locId, "desc", null, out var err1, out desc))
{
allErrors.AddRange(err1);
}
if (suffix == null
&& bundle.TryGetMsg(locId, "suffix", null, out var err, out suffix))
{
allErrors.AddRange(err);
}
WriteWarningForErrs(allErrors, locId);
}
// Only set name if the value isn't empty.
// So that you can override *only* a desc/suffix.
name = bundle.FormatPattern(msg.Value, null, out var fmtErr);
WriteWarningForErrs(fmtErr, locId);
}
name ??= prototype.SetName;
desc ??= prototype.SetDesc;
suffix ??= prototype.SetSuffix;
if (prototype.LocProperties.Count != 0)
if (msgAttrs.Count != 0)
{
foreach (var (attrib, value) in prototype.LocProperties)
foreach (var (attrId, pattern) in msg.Attributes)
{
var attrib = attrId.ToString();
if (attrib.Equals("desc")
|| attrib.Equals("suffix"))
continue;
attributes ??= new Dictionary<string, string>();
if (!attributes.ContainsKey(attrib))
{
var value = bundle.FormatPattern(pattern, null, out var errors);
WriteWarningForErrs(errors, locId);
attributes[attrib] = value;
}
}
var allErrors = new List<FluentError>();
if (desc == null
&& bundle.TryGetMsg(locId, "desc", null, out var err1, out desc))
{
allErrors.AddRange(err1);
}
if (suffix == null
&& bundle.TryGetMsg(locId, "suffix", null, out var err, out suffix))
{
allErrors.AddRange(err);
}
WriteWarningForErrs(allErrors, locId);
}
}
if (prototype.Parent == null)
break;
name ??= prototype?.SetName;
desc ??= prototype?.SetDesc;
suffix ??= prototype?.SetSuffix;
prototypeId = prototype.Parent;
if (prototype?.LocProperties != null && prototype.LocProperties.Count != 0)
{
foreach (var (attrib, value) in prototype.LocProperties)
{
attributes ??= new Dictionary<string, string>();
if (!attributes.ContainsKey(attrib))
{
attributes[attrib] = value;
}
}
}
return new EntityLocData(

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using Lidgren.Network;
using Robust.Shared.Configuration;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Robust.Shared.Network.Messages
@@ -66,8 +68,13 @@ namespace Robust.Shared.Network.Messages
case CvarType.Double:
value = buffer.ReadDouble();
break;
case CvarType.Vector2:
var valX = buffer.ReadFloat();
var valY = buffer.ReadFloat();
value = new Vector2(valX, valY);
break;
default:
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(value), valType, $"CVar {name} is not of a valid CVar type!");
}
NetworkedVars.Add((name, value));
@@ -116,8 +123,13 @@ namespace Robust.Shared.Network.Messages
buffer.Write((byte)CvarType.Double);
buffer.Write(val);
break;
case Vector2 val:
buffer.Write((byte)CvarType.Vector2);
buffer.Write(val.X);
buffer.Write(val.Y);
break;
default:
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(value), value.GetType(), $"CVar {name} is not of a valid CVar type!");
}
}
}
@@ -126,13 +138,13 @@ namespace Robust.Shared.Network.Messages
{
// ReSharper disable once UnusedMember.Local
None,
Int,
Long,
Bool,
String,
Float,
Double
Double,
Vector2,
}
}
}

View File

@@ -22,6 +22,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -98,11 +99,6 @@ namespace Robust.Shared.Physics.Dynamics
/// </summary>
private HashSet<PhysicsComponent> _islandSet = new();
private HashSet<PhysicsComponent> _queuedWake = new();
private HashSet<PhysicsComponent> _queuedSleep = new();
private Queue<CollisionChangeMessage> _queuedCollisionMessages = new();
private List<PhysicsComponent> _islandBodies = new(64);
private List<Contact> _islandContacts = new(32);
private List<Joint> _islandJoints = new(8);
@@ -127,10 +123,8 @@ namespace Robust.Shared.Physics.Dynamics
if (Bodies.Contains(body)) return;
// TODO: Kinda dodgy with this and wake shit.
// Look at my note under ProcessWakeQueue
if (body.Awake && body.BodyType != BodyType.Static)
{
_queuedWake.Remove(body);
AwakeBodies.Add(body);
}
@@ -140,7 +134,20 @@ namespace Robust.Shared.Physics.Dynamics
public void AddAwakeBody(PhysicsComponent body)
{
_queuedWake.Add(body);
if (body.BodyType == BodyType.Static)
{
Logger.ErrorS("physics", $"Tried to add static body {_entityManager.ToPrettyString(body.Owner)} as an awake body to map!");
return;
}
DebugTools.Assert(Bodies.Contains(body));
if (!Bodies.Contains(body))
{
Logger.ErrorS("physics", $"Tried to add {_entityManager.ToPrettyString(body.Owner)} as an awake body to map when it's not contained on the map!");
return;
}
AwakeBodies.Add(body);
}
public void RemoveBody(PhysicsComponent body)
@@ -153,63 +160,11 @@ namespace Robust.Shared.Physics.Dynamics
public void RemoveSleepBody(PhysicsComponent body)
{
_queuedSleep.Add(body);
AwakeBodies.Remove(body);
}
#endregion
#region Queue
private void ProcessChanges()
{
ProcessBodyChanges();
ProcessWakeQueue();
ProcessSleepQueue();
}
private void ProcessBodyChanges()
{
while (_queuedCollisionMessages.Count > 0)
{
var message = _queuedCollisionMessages.Dequeue();
if (!message.Body.Deleted && message.Body.CanCollide)
{
AddBody(message.Body);
}
else
{
RemoveBody(message.Body);
}
}
}
private void ProcessWakeQueue()
{
foreach (var body in _queuedWake)
{
// Sloth note: So FPE doesn't seem to handle static bodies being woken gracefully as they never sleep
// (No static body's an island so can't increase their min sleep time).
// AFAIK not adding it to woken bodies shouldn't matter for anything tm...
if (!body.Awake || body.BodyType == BodyType.Static || !Bodies.Contains(body)) continue;
AwakeBodies.Add(body);
}
_queuedWake.Clear();
}
private void ProcessSleepQueue()
{
foreach (var body in _queuedSleep)
{
if (body.Awake) continue;
AwakeBodies.Remove(body);
}
_queuedSleep.Clear();
}
#endregion
/// <summary>
/// Where the magic happens.
/// </summary>
@@ -217,10 +172,6 @@ namespace Robust.Shared.Physics.Dynamics
/// <param name="prediction"></param>
public void Step(float frameTime, bool prediction)
{
// The original doesn't call ProcessChanges quite so much but stuff like collision behaviors
// can edit things during the solver so we'll just handle it as it comes up.
ProcessChanges();
// Box2D does this at the end of a step and also here when there's a fixture update.
// Given external stuff can move bodies we'll just do this here.
// Unfortunately this NEEDS to be predicted to make pushing remotely fucking good.
@@ -237,9 +188,6 @@ namespace Robust.Shared.Physics.Dynamics
if (!prediction)
ContactManager.PreSolve(frameTime);
// Remove all deleted entities etc.
ProcessChanges();
// Integrate velocities, solve velocity constraints, and do integration.
Solve(frameTime, dtRatio, invDt, prediction);

View File

@@ -5,6 +5,7 @@ using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Players;
@@ -78,7 +79,7 @@ namespace Robust.Shared.Player
if (!cfgMan.GetCVar(CVars.NetPVS))
return AddAllPlayers();
var pvsRange = cfgMan.GetCVar(CVars.NetMaxUpdateRange) * rangeMultiplier;
var pvsRange = cfgMan.GetCVar(CVars.NetDefaultUpdateRange) * rangeMultiplier;
return AddInRange(origin, pvsRange, playerMan);
}
@@ -175,6 +176,13 @@ namespace Robust.Shared.Player
(xform.WorldPosition - position.Position).Length < range, playerMan);
}
/// <summary>
/// Adds all players in range of a position.
/// </summary>
public Filter AddInRange(MapCoordinates position, Vector2 range, ISharedPlayerManager? playerMan = null,
IEntityManager? entMan = null)
=> AddInRange(position, range.Length, playerMan, entMan);
/// <summary>
/// Removes all players without the specified visibility flag.
/// </summary>

View File

@@ -10,6 +10,9 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.ViewVariables;
@@ -31,7 +34,6 @@ namespace Robust.Shared.Prototypes
private const int DEFAULT_RANGE = 200;
[NeverPushInheritance]
[DataField("loc")]
private Dictionary<string, string>? _locPropertiesSet;
@@ -39,7 +41,7 @@ namespace Robust.Shared.Prototypes
/// The "in code name" of the object. Must be unique.
/// </summary>
[ViewVariables]
[DataField("id")]
[IdDataFieldAttribute]
public string ID { get; private set; } = default!;
/// <summary>
@@ -48,17 +50,14 @@ namespace Robust.Shared.Prototypes
/// </summary>
/// <seealso cref="Name"/>
[ViewVariables]
[NeverPushInheritance]
[DataField("name")]
public string? SetName { get; private set; }
[ViewVariables]
[NeverPushInheritance]
[DataField("description")]
public string? SetDesc { get; private set; }
[ViewVariables]
[NeverPushInheritance]
[DataField("suffix")]
public string? SetSuffix { get; private set; }
@@ -89,7 +88,6 @@ namespace Robust.Shared.Prototypes
/// </summary>
[ViewVariables]
[DataField("localizationId")]
[NeverPushInheritance]
public string? CustomLocalizationID { get; private set; }
@@ -98,8 +96,8 @@ namespace Robust.Shared.Prototypes
/// </summary>
[ViewVariables]
[NeverPushInheritance]
[DataField("abstract")]
public bool Abstract { get; private set; }
[DataField("noSpawn")]
public bool NoSpawn { get; private set; }
[DataField("placement")] private EntityPlacementProperties PlacementProperties = new();
@@ -138,9 +136,14 @@ namespace Robust.Shared.Prototypes
/// The prototype we inherit from.
/// </summary>
[ViewVariables]
[DataField("parent", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
[ParentDataFieldAttribute(typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? Parent { get; private set; }
[ViewVariables]
[NeverPushInheritance]
[AbstractDataField]
public bool Abstract { get; }
/// <summary>
/// A dictionary mapping the component type list to the YAML mapping containing their settings.
/// </summary>
@@ -233,6 +236,7 @@ namespace Robust.Shared.Prototypes
EntityPrototype? prototype,
EntityUid entity,
IComponentFactory factory,
IPrototypeManager prototypeManager,
IEntityManager entityManager,
ISerializationManager serManager,
IEntityLoadContext? context) //yeah officer this method right here
@@ -245,12 +249,22 @@ namespace Robust.Shared.Prototypes
if (prototype != null)
{
foreach (var (name, data) in prototype.Components)
prototypeManager.TryGetMapping(typeof(EntityPrototype), prototype.ID, out var prototypeData);
foreach (var (name, _) in prototype.Components)
{
var fullData = data;
MappingDataNode? fullData = null;
if (prototypeData != null && prototypeData.TryGet<SequenceDataNode>("components", out var compList))
{
fullData = compList.Cast<MappingDataNode>().FirstOrDefault(x =>
x.TryGet<ValueDataNode>("type", out var typeNode) && typeNode.Value == name);
}
fullData ??= new MappingDataNode();
if (context != null)
{
fullData = context.GetComponentData(name, data);
fullData = context.GetComponentData(name, fullData);
}
EnsureCompExistsAndDeserialize(entity, factory, entityManager, serManager, name, fullData, context as ISerializationContext);
@@ -281,7 +295,7 @@ namespace Robust.Shared.Prototypes
IEntityManager entityManager,
ISerializationManager serManager,
string compName,
IComponent data, ISerializationContext? context)
MappingDataNode data, ISerializationContext? context)
{
var compType = factory.GetRegistration(compName).Type;
@@ -294,7 +308,7 @@ namespace Robust.Shared.Prototypes
}
// TODO use this value to support struct components
_ = serManager.Copy(data, component, context);
serManager.Read(compType, data, context, value: component);
}
public override string ToString()

View File

@@ -1,4 +1,10 @@
using Robust.Shared.ViewVariables;
using System;
using JetBrains.Annotations;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.ViewVariables;
using YamlDotNet.Core.Tokens;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Prototypes
@@ -25,4 +31,31 @@ namespace Robust.Shared.Prototypes
bool Abstract { get; }
}
public sealed class IdDataFieldAttribute : DataFieldAttribute
{
public const string Name = "id";
public IdDataFieldAttribute(int priority = 1, Type? customTypeSerializer = null) :
base(Name, false, priority, true, false, customTypeSerializer)
{
}
}
public sealed class ParentDataFieldAttribute : DataFieldAttribute
{
public const string Name = "parent";
public ParentDataFieldAttribute(Type prototypeIdSerializer, int priority = 1) :
base(Name, false, priority, false, false, prototypeIdSerializer)
{
}
}
public sealed class AbstractDataFieldAttribute : DataFieldAttribute
{
public const string Name = "abstract";
public AbstractDataFieldAttribute(int priority = 1) :
base(Name, false, priority, false, false, null)
{
}
}
}

View File

@@ -6,6 +6,7 @@ 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;
@@ -15,10 +16,10 @@ using Robust.Shared.Log;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
@@ -79,6 +80,9 @@ namespace Robust.Shared.Prototypes
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 HasMapping<T>(string id);
bool TryGetMapping(Type type, string id, [NotNullWhen(true)] out MappingDataNode? mappings);
/// <summary>
/// Returns whether a prototype variant <param name="variant"/> exists.
/// </summary>
@@ -131,13 +135,13 @@ namespace Robust.Shared.Prototypes
/// <summary>
/// Load prototypes from files in a directory, recursively.
/// </summary>
List<IPrototype> LoadDirectory(ResourcePath path, bool overwrite = false);
void LoadDirectory(ResourcePath path, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
Dictionary<string, HashSet<ErrorNode>> ValidateDirectory(ResourcePath path);
List<IPrototype> LoadFromStream(TextReader stream, bool overwrite = false);
void LoadFromStream(TextReader stream, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
List<IPrototype> LoadString(string str, bool overwrite = false);
void LoadString(string str, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null);
void RemoveString(string prototypes);
@@ -149,7 +153,7 @@ namespace Robust.Shared.Prototypes
/// <summary>
/// Syncs all inter-prototype data. Call this when operations adding new prototypes are done.
/// </summary>
void Resync();
void ResolveResults();
/// <summary>
/// Registers a specific prototype name to be ignored.
@@ -213,7 +217,7 @@ namespace Robust.Shared.Prototypes
#region IPrototypeManager members
private readonly Dictionary<Type, Dictionary<string, IPrototype>> _prototypes = new();
private readonly Dictionary<Type, Dictionary<string, DeserializationResult>> _prototypeResults = new();
private readonly Dictionary<Type, Dictionary<string, MappingDataNode>> _prototypeResults = new();
private readonly Dictionary<Type, PrototypeInheritanceTree> _inheritanceTrees = new();
private readonly HashSet<string> _ignoredPrototypeTypes = new();
@@ -302,63 +306,62 @@ namespace Robust.Shared.Prototypes
protected void ReloadPrototypes(IEnumerable<ResourcePath> filePaths)
{
#if !FULL_RELEASE
var changed = filePaths.SelectMany(f => LoadFile(f.ToRootedPath(), true)).ToList();
var changed = new Dictionary<Type, HashSet<string>>();
foreach (var filePath in filePaths)
{
LoadFile(filePath.ToRootedPath(), true, changed);
}
ReloadPrototypes(changed);
#endif
}
internal void ReloadPrototypes(List<IPrototype> prototypes)
internal void ReloadPrototypes(Dictionary<Type, HashSet<string>> prototypes)
{
#if !FULL_RELEASE
prototypes.Sort((a, b) => SortPrototypesByPriority(a.GetType(), b.GetType()));
var prototypeTypeOrder = prototypes.Keys.ToList();
prototypeTypeOrder.Sort(SortPrototypesByPriority);
var pushed = new Dictionary<Type, HashSet<string>>();
foreach (var prototype in prototypes)
foreach (var type in prototypeTypeOrder)
{
if (prototype is not IInheritingPrototype inheritingPrototype) continue;
var type = prototype.GetType();
if (!pushed.ContainsKey(type)) pushed[type] = new HashSet<string>();
var baseNode = prototype.ID;
if (pushed[type].Contains(baseNode))
if (!type.IsAssignableTo(typeof(IInheritingPrototype)))
{
continue;
}
var tree = _inheritanceTrees[type];
var currentNode = inheritingPrototype.Parent;
if (currentNode == null)
{
PushInheritance(type, baseNode, null, pushed[type]);
continue;
}
while (true)
{
var parent = tree.GetParent(currentNode);
if (parent == null)
foreach (var id in prototypes[type])
{
break;
_prototypes[type][id] = (IPrototype) _serializationManager.Read(type, _prototypeResults[type][id])!;
}
continue;
}
foreach (var id in prototypes[type])
{
if (!pushed.ContainsKey(type))
pushed[type] = new HashSet<string>();
if (pushed[type].Contains(id))
{
continue;
}
baseNode = currentNode;
currentNode = parent;
var set = new HashSet<string>();
set.Add(id);
PushInheritance(type, id, _inheritanceTrees[type].GetParent(id), set);
foreach (var changedId in set)
{
TryReadPrototype(type, changedId, _prototypeResults[type][changedId]);
}
pushed[type].UnionWith(set);
}
PushInheritance(type, currentNode, baseNode, null, pushed[type]);
}
//todo paul i hate it but i am not opening that can of worms in this refactor
PrototypesReloaded?.Invoke(
new PrototypesReloadedEventArgs(
prototypes
.GroupBy(p => p.GetType())
.ToDictionary(
g => g.Key,
g => new PrototypesReloadedEventArgs.PrototypeChangeSet(
g.ToDictionary(a => a.ID, a => a)))));
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;
@@ -379,90 +382,77 @@ namespace Robust.Shared.Prototypes
#endif
}
public void Resync()
/// <summary>
/// Resolves the mappings stored in memory to actual prototypeinstances.
/// </summary>
public void ResolveResults()
{
var trees = _inheritanceTrees.Keys.ToList();
trees.Sort(SortPrototypesByPriority);
foreach (var type in trees)
var types = _prototypeResults.Keys.ToList();
types.Sort(SortPrototypesByPriority);
foreach (var type in types)
{
var tree = _inheritanceTrees[type];
foreach (var baseNode in tree.BaseNodes)
{
PushInheritance(type, baseNode, null, new HashSet<string>());
}
// Go over all prototypes and double check that their parent actually exists.
var typePrototypes = _prototypes[type];
foreach (var (id, proto) in typePrototypes)
{
var iProto = (IInheritingPrototype) proto;
var parent = iProto.Parent;
if (parent != null && !typePrototypes.ContainsKey(parent!))
if(_inheritanceTrees.TryGetValue(type, out var tree)){
foreach (var baseNode in tree.BaseNodes)
{
Logger.ErrorS("Serv3", $"{iProto.GetType().Name} '{id}' has invalid parent: {parent}");
PushInheritance(type, baseNode);
}
}
foreach (var (id, mapping) in _prototypeResults[type])
{
TryReadPrototype(type, id, mapping);
}
}
}
public void PushInheritance(Type type, string id, string child, DeserializationResult? baseResult,
HashSet<string> changed)
private void TryReadPrototype(Type type, string id, MappingDataNode mapping)
{
changed.Add(id);
var myRes = _prototypeResults[type][id];
var newResult = baseResult != null ? myRes.PushInheritanceFrom(baseResult) : myRes;
PushInheritance(type, child, newResult, changed);
newResult.CallAfterDeserializationHook();
var populatedRes =
_serializationManager.PopulateDataDefinition(_prototypes[type][id], (IDeserializedDefinition) newResult);
_prototypes[type][id] = (IPrototype) populatedRes.RawValue!;
}
public void PushInheritance(Type type, string id, DeserializationResult? baseResult, HashSet<string> changed)
{
changed.Add(id);
var myRes = _prototypeResults[type][id];
var newResult = baseResult != null ? myRes.PushInheritanceFrom(baseResult) : myRes;
foreach (var childID in _inheritanceTrees[type].Children(id))
{
PushInheritance(type, childID, newResult, changed);
}
if (newResult.RawValue is not IInheritingPrototype inheritingPrototype)
{
Logger.ErrorS("Serv3", $"PushInheritance was called on non-inheriting prototype! ({type}, {id})");
if(mapping.TryGet<ValueDataNode>(AbstractDataFieldAttribute.Name, out var abstractNode) && abstractNode.AsBool())
return;
try
{
_prototypes[type][id] = (IPrototype) _serializationManager.Read(type, mapping)!;
}
catch (Exception e)
{
Logger.ErrorS("PROTO", $"Reading {type}({id}) threw the following exception: {e}");
}
}
private void PushInheritance(Type type, string id, string? parent = null, HashSet<string>? changed = null)
{
if (parent != null)
{
PushInheritanceWithoutRecursion(type, id, parent, changed);
}
if (!inheritingPrototype.Abstract)
newResult.CallAfterDeserializationHook();
var populatedRes =
_serializationManager.PopulateDataDefinition(_prototypes[type][id], (IDeserializedDefinition) newResult);
_prototypes[type][id] = (IPrototype) populatedRes.RawValue!;
if(!_inheritanceTrees[type].HasId(id)) return;
foreach (var child in _inheritanceTrees[type].Children(id))
{
PushInheritance(type, child, id, changed);
}
}
private void PushInheritanceWithoutRecursion(Type type, string id, string parent,
HashSet<string>? changed = null)
{
_prototypeResults[type][id] = _serializationManager.PushCompositionWithGenericNode(type,
new[] { _prototypeResults[type][parent] }, _prototypeResults[type][id]);
changed?.Add(id);
}
/// <inheritdoc />
public List<IPrototype> LoadDirectory(ResourcePath path, bool overwrite = false)
public void LoadDirectory(ResourcePath path, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
var changedPrototypes = new List<IPrototype>();
_hasEverBeenReloaded = true;
var streams = Resources.ContentFindFiles(path).ToList().AsParallel()
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."));
foreach (var resourcePath in streams)
{
var filePrototypes = LoadFile(resourcePath, overwrite);
changedPrototypes.AddRange(filePrototypes);
LoadFile(resourcePath, overwrite, changed);
}
return changedPrototypes;
}
public Dictionary<string, HashSet<ErrorNode>> ValidateDirectory(ResourcePath path)
@@ -545,17 +535,15 @@ namespace Robust.Shared.Prototypes
}
}
public HashSet<IPrototype> LoadFile(ResourcePath file, bool overwrite = false)
public void LoadFile(ResourcePath file, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
var changedPrototypes = new HashSet<IPrototype>();
try
{
using var reader = ReadFile(file, !overwrite);
if (reader == null)
{
return changedPrototypes;
return;
}
var yamlStream = new YamlStream();
@@ -567,8 +555,7 @@ namespace Robust.Shared.Prototypes
{
try
{
var documentPrototypes = LoadFromDocument(yamlStream.Documents[i], overwrite);
changedPrototypes.UnionWith(documentPrototypes);
LoadFromDocument(yamlStream.Documents[i], overwrite, changed);
}
catch (Exception e)
{
@@ -581,13 +568,10 @@ namespace Robust.Shared.Prototypes
var sawmill = Logger.GetSawmill("eng");
sawmill.Error("YamlException whilst loading prototypes from {0}: {1}", file, e.Message);
}
return changedPrototypes;
}
public List<IPrototype> LoadFromStream(TextReader stream, bool overwrite = false)
public void LoadFromStream(TextReader stream, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
var changedPrototypes = new List<IPrototype>();
_hasEverBeenReloaded = true;
var yaml = new YamlStream();
yaml.Load(stream);
@@ -596,8 +580,7 @@ namespace Robust.Shared.Prototypes
{
try
{
var documentPrototypes = LoadFromDocument(yaml.Documents[i], overwrite);
changedPrototypes.AddRange(documentPrototypes);
LoadFromDocument(yaml.Documents[i], overwrite, changed);
}
catch (Exception e)
{
@@ -606,13 +589,11 @@ namespace Robust.Shared.Prototypes
}
LoadedData?.Invoke(yaml, "anonymous prototypes YAML stream");
return changedPrototypes;
}
public List<IPrototype> LoadString(string str, bool overwrite = false)
public void LoadString(string str, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
return LoadFromStream(new StringReader(str), overwrite);
LoadFromStream(new StringReader(str), overwrite, changed);
}
public void RemoveString(string prototypes)
@@ -653,14 +634,14 @@ namespace Robust.Shared.Prototypes
}
}
private HashSet<IPrototype> LoadFromDocument(YamlDocument document, bool overwrite = false)
private void LoadFromDocument(YamlDocument document, bool overwrite = false, Dictionary<Type, HashSet<string>>? changed = null)
{
var changedPrototypes = new HashSet<IPrototype>();
var rootNode = (YamlSequenceNode) document.RootNode;
foreach (YamlMappingNode node in rootNode.Cast<YamlMappingNode>())
foreach (var node in rootNode.Cast<YamlMappingNode>())
{
var type = node.GetNode("type").AsString();
var datanode = node.ToDataNodeCast<MappingDataNode>();
var type = datanode.Get<ValueDataNode>("type").Value;
if (!_prototypeTypes.ContainsKey(type))
{
if (_ignoredPrototypeTypes.Contains(type))
@@ -672,30 +653,28 @@ namespace Robust.Shared.Prototypes
}
var prototypeType = _prototypeTypes[type];
var res = _serializationManager.Read(prototypeType, node.ToDataNode(), skipHook: true);
var prototype = (IPrototype) res.RawValue!;
if (!overwrite && _prototypes[prototypeType].ContainsKey(prototype.ID))
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: '{prototype.ID}'");
throw new PrototypeLoadException($"Duplicate ID: '{idNode.Value}'");
}
_prototypeResults[prototypeType][prototype.ID] = res;
if (prototype is IInheritingPrototype inheritingPrototype)
_prototypeResults[prototypeType][idNode.Value] = datanode;
if (prototypeType.IsAssignableTo(typeof(IInheritingPrototype)))
{
_inheritanceTrees[prototypeType].AddId(prototype.ID, inheritingPrototype.Parent, true);
}
else
{
//we call it here since it wont get called when pushing inheritance
res.CallAfterDeserializationHook();
datanode.TryGet<ValueDataNode>(ParentDataFieldAttribute.Name, out var parentNode);
_inheritanceTrees[prototypeType].AddId(idNode.Value, parentNode?.Value, true);
}
_prototypes[prototypeType][prototype.ID] = prototype;
changedPrototypes.Add(prototype);
if (changed == null) continue;
if (!changed.TryGetValue(prototypeType, out var set))
changed[prototypeType] = set = new HashSet<string>();
set.Add(idNode.Value);
}
return changedPrototypes;
}
public bool HasIndex<T>(string id) where T : class, IPrototype
@@ -725,6 +704,23 @@ namespace Robust.Shared.Prototypes
return index.TryGetValue(id, out prototype);
}
public bool HasMapping<T>(string id)
{
if (!_prototypeResults.TryGetValue(typeof(T), out var index))
{
throw new UnknownPrototypeException(id);
}
return index.ContainsKey(id);
}
public bool TryGetMapping(Type type, string id, [NotNullWhen(true)] out MappingDataNode? mappings)
{
var ret = _prototypeResults[type].TryGetValue(id, out var originalMappings);
mappings = originalMappings?.Copy();
return ret;
}
/// <inheritdoc />
public bool HasVariant(string variant)
{
@@ -805,13 +801,66 @@ namespace Robust.Shared.Prototypes
$"Duplicate prototype type ID: {attribute.Type}. Current: {_prototypeTypes[attribute.Type]}");
}
var foundIdAttribute = false;
var foundParentAttribute = false;
var foundAbstractAttribute = false;
foreach (var info in type.GetAllPropertiesAndFields())
{
var hasId = info.HasAttribute<IdDataFieldAttribute>();
var hasParent = info.HasAttribute<ParentDataFieldAttribute>();
if (hasId)
{
if (foundIdAttribute)
throw new InvalidImplementationException(type,
typeof(IPrototype),
$"Found two {nameof(IdDataFieldAttribute)}");
foundIdAttribute = true;
}
if (hasParent)
{
if (foundParentAttribute)
throw new InvalidImplementationException(type,
typeof(IInheritingPrototype),
$"Found two {nameof(ParentDataFieldAttribute)}");
foundParentAttribute = true;
}
if (hasId && hasParent)
throw new InvalidImplementationException(type,
typeof(IPrototype),
$"Prototype {type} has the Id- & ParentDatafield on single member {info.Name}");
if (info.HasAttribute<AbstractDataFieldAttribute>())
{
if (foundAbstractAttribute)
throw new InvalidImplementationException(type,
typeof(IInheritingPrototype),
$"Found two {nameof(AbstractDataFieldAttribute)}");
foundAbstractAttribute = true;
}
}
if (!foundIdAttribute)
throw new InvalidImplementationException(type,
typeof(IPrototype),
$"Did not find any member annotated with the {nameof(IdDataFieldAttribute)}");
if (type.IsAssignableTo(typeof(IInheritingPrototype)) && (!foundParentAttribute || !foundAbstractAttribute))
throw new InvalidImplementationException(type,
typeof(IInheritingPrototype),
$"Did not find any member annotated with the {nameof(ParentDataFieldAttribute)} and/or {nameof(AbstractDataFieldAttribute)}");
_prototypeTypes[attribute.Type] = type;
_prototypePriorities[type] = attribute.LoadPriority;
if (typeof(IPrototype).IsAssignableFrom(type))
{
_prototypes[type] = new Dictionary<string, IPrototype>();
_prototypeResults[type] = new Dictionary<string, DeserializationResult>();
_prototypeResults[type] = new Dictionary<string, MappingDataNode>();
if (typeof(IInheritingPrototype).IsAssignableFrom(type))
_inheritanceTrees[type] = new PrototypeInheritanceTree();
}

View File

@@ -6,7 +6,8 @@ namespace Robust.Shared.Serialization.Manager.Attributes
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[MeansImplicitAssignment]
[MeansImplicitUse(ImplicitUseKindFlags.Assign)]
public sealed class DataFieldAttribute : Attribute
[Virtual]
public class DataFieldAttribute : Attribute
{
public readonly string Tag;
public readonly int Priority;

View File

@@ -1,19 +1,15 @@
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Mapping;
namespace Robust.Shared.Serialization.Manager.Definition
{
public partial class DataDefinition
{
private delegate DeserializedFieldEntry[] DeserializeDelegate(
private delegate object PopulateDelegateSignature(
object target,
MappingDataNode mappingDataNode,
ISerializationManager serializationManager,
ISerializationContext? context,
bool skipHook);
private delegate DeserializationResult PopulateDelegateSignature(
object target,
DeserializedFieldEntry[] deserializationResults,
bool skipHook,
object?[] defaultValues);
private delegate MappingDataNode SerializeDelegateSignature(
@@ -29,10 +25,6 @@ namespace Robust.Shared.Serialization.Manager.Definition
ISerializationManager serializationManager,
ISerializationContext? context);
private delegate DeserializationResult CreateDefinitionDelegate(
object value,
DeserializedFieldEntry[] mappings);
private delegate TValue AccessField<TTarget, TValue>(ref TTarget target);
private delegate void AssignField<TTarget, TValue>(ref TTarget target, TValue? value);

View File

@@ -4,7 +4,6 @@ using System.Reflection;
using System.Reflection.Emit;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
@@ -14,20 +13,22 @@ namespace Robust.Shared.Serialization.Manager.Definition
{
public partial class DataDefinition
{
private DeserializeDelegate EmitDeserializationDelegate()
private PopulateDelegateSignature EmitPopulateDelegate()
{
DeserializedFieldEntry[] DeserializationDelegate(MappingDataNode mappingDataNode,
ISerializationManager serializationManager, ISerializationContext? serializationContext, bool skipHook)
object PopulateDelegate(
object target,
MappingDataNode mappingDataNode,
ISerializationManager serializationManager,
ISerializationContext? serializationContext,
bool skipHook,
object?[] defaultValues)
{
var mappedInfo = new DeserializedFieldEntry[BaseFieldDefinitions.Length];
for (var i = 0; i < BaseFieldDefinitions.Length; i++)
{
var fieldDefinition = BaseFieldDefinitions[i];
if (fieldDefinition.Attribute.ServerOnly && !IoCManager.Resolve<INetManager>().IsServer)
{
mappedInfo[i] = new DeserializedFieldEntry(false, fieldDefinition.InheritanceBehavior);
continue;
}
@@ -35,13 +36,14 @@ namespace Robust.Shared.Serialization.Manager.Definition
if (!mapped)
{
mappedInfo[i] = new DeserializedFieldEntry(mapped, fieldDefinition.InheritanceBehavior);
if (fieldDefinition.Attribute.Required)
throw new InvalidOperationException($"Required field {fieldDefinition.Attribute.Tag} of type {target.GetType()} wasn't mapped.");
continue;
}
var type = fieldDefinition.FieldType;
var node = mappingDataNode.Get(fieldDefinition.Attribute.Tag);
DeserializationResult result;
object? result;
if (fieldDefinition.Attribute.CustomTypeSerializer != null)
{
var foundInterface = false;
@@ -68,52 +70,17 @@ namespace Robust.Shared.Serialization.Manager.Definition
result = serializationManager.Read(type, node, serializationContext, skipHook);
}
var entry = new DeserializedFieldEntry(mapped, fieldDefinition.InheritanceBehavior, result);
mappedInfo[i] = entry;
}
return mappedInfo;
}
return DeserializationDelegate;
}
private PopulateDelegateSignature EmitPopulateDelegate()
{
// TODO Serialization: validate mappings array count
var constructor =
typeof(DeserializedDefinition<>).MakeGenericType(Type).GetConstructor(new[] {Type, typeof(DeserializedFieldEntry[])}) ??
throw new NullReferenceException();
var valueParam = Expression.Parameter(typeof(object), "value");
var valueParamCast = Expression.Convert(valueParam, Type);
var mappingParam = Expression.Parameter(typeof(DeserializedFieldEntry[]), "mapping");
var newExp = Expression.New(constructor, valueParamCast, mappingParam);
var createDefinitionDelegate = Expression.Lambda<CreateDefinitionDelegate>(newExp, valueParam, mappingParam).Compile();
DeserializationResult PopulateDelegate(
object target,
DeserializedFieldEntry[] deserializedFields,
object?[] defaultValues)
{
for (var i = 0; i < BaseFieldDefinitions.Length; i++)
{
var res = deserializedFields[i];
if (!res.Mapped) continue;
var defValue = defaultValues[i];
if (Equals(res.Result?.RawValue, defValue))
if (Equals(result, defValue))
{
continue;
}
FieldAssigners[i](ref target, res.Result?.RawValue);
FieldAssigners[i](ref target, result);
}
return createDefinitionDelegate(target, deserializedFields);
return target;
}
return PopulateDelegate;

View File

@@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -16,7 +15,6 @@ namespace Robust.Shared.Serialization.Manager.Definition
{
public sealed partial class DataDefinition
{
private readonly DeserializeDelegate _deserialize;
private readonly PopulateDelegateSignature _populate;
private readonly SerializeDelegateSignature _serialize;
private readonly CopyDelegateSignature _copy;
@@ -41,7 +39,6 @@ namespace Robust.Shared.Serialization.Manager.Definition
BaseFieldDefinitions = fields.ToImmutableArray();
DefaultValues = fieldDefs.Select(f => f.DefaultValue).ToArray();
_deserialize = EmitDeserializationDelegate();
_populate = EmitPopulateDelegate();
_serialize = EmitSerializeDelegate();
_copy = EmitCopyDelegate();
@@ -71,20 +68,14 @@ namespace Robust.Shared.Serialization.Manager.Definition
internal ImmutableArray<FieldDefinition> BaseFieldDefinitions { get; }
public DeserializationResult Populate(object target, DeserializedFieldEntry[] fields)
{
return _populate(target, fields, DefaultValues);
}
public DeserializationResult Populate(
public object Populate(
object target,
MappingDataNode mapping,
ISerializationManager serialization,
ISerializationContext? context,
bool skipHook)
{
var fields = _deserialize(mapping, serialization, context, skipHook);
return _populate(target, fields, DefaultValues);
return _populate(target, mapping, serialization, context, skipHook, DefaultValues);
}
public MappingDataNode Serialize(

View File

@@ -1,6 +1,6 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
@@ -25,7 +25,7 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="type">The type to check for.</param>
/// <returns>True if it does, false otherwise.</returns>
bool HasDataDefinition(Type type);
#region Validation
/// <summary>
@@ -59,52 +59,7 @@ namespace Robust.Shared.Serialization.Manager
#endregion
/// <summary>
/// Creates a deserialization result from a generic type and its fields,
/// populating the object.
/// </summary>
/// <param name="fields">The fields to use for deserialization.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <typeparam name="T">The type to populate.</typeparam>
/// <returns>A result with the populated type.</returns>
DeserializationResult CreateDataDefinition<T>(DeserializedFieldEntry[] fields, bool skipHook = false) where T : notnull, new();
#region Populate
/// <summary>
/// Creates a deserialization result from a generic type and its definition,
/// populating the object.
/// </summary>
/// <param name="obj">The object to populate.</param>
/// <param name="definition">The data to use for deserialization.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <typeparam name="T">The type of <see cref="obj"/> to populate.</typeparam>
/// <returns>A result with the populated object.</returns>
DeserializationResult PopulateDataDefinition<T>(T obj, DeserializedDefinition<T> definition, bool skipHook = false) where T : notnull, new();
/// <summary>
/// Creates a deserialization result from an object and its definition,
/// populating the object.
/// </summary>
/// <param name="obj">The object to populate.</param>
/// <param name="definition">The data to use for deserialization.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <returns>A result with the populated object.</returns>
DeserializationResult PopulateDataDefinition(object obj, IDeserializedDefinition definition, bool skipHook = false);
#endregion
#region Read
/// <summary>
/// Deserializes a node into an object, populating it.
/// </summary>
/// <param name="type">The type of object to populate.</param>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <returns>A result with the deserialized object.</returns>
DeserializationResult Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false);
/// <summary>
/// Deserializes a node into an object, populating it.
/// </summary>
@@ -112,20 +67,10 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="value">The value to read into. If none is supplied, a new object will be created.</param>
/// <returns>The deserialized object or null.</returns>
public object? ReadValue(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false);
/// <summary>
/// Deserializes a node into an object of the given <see cref="type"/>,
/// directly casting it to the given generic type <see cref="T"/>.
/// </summary>
/// <param name="type">The type of object to deserialize into.</param>
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <typeparam name="T">The generic type to cast the resulting object to.</typeparam>
/// <returns>The deserialized casted object, or null.</returns>
T? ReadValueCast<T>(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false);
public object? Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false,
object? value = null);
/// <summary>
/// Deserializes a node into a populated object of the given generic type <see cref="T"/>
@@ -133,12 +78,13 @@ namespace Robust.Shared.Serialization.Manager
/// <param name="node">The node to deserialize.</param>
/// <param name="context">The context to use, if any.</param>
/// <param name="skipHook">Whether or not to skip running <see cref="ISerializationHooks"/></param>
/// <param name="value">The value to read into. If none is supplied, a new object will be created.</param>
/// <typeparam name="T">The type of object to create and populate.</typeparam>
/// <returns>The deserialized object, or null.</returns>
T? ReadValue<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false);
T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, T? value = default);
DeserializationResult ReadWithTypeSerializer(Type value, Type serializer, DataNode node,
ISerializationContext? context = null, bool skipHook = false);
object? ReadWithTypeSerializer(Type type, Type serializer, DataNode node,
ISerializationContext? context = null, bool skipHook = false, object? value = null);
#endregion
@@ -253,5 +199,23 @@ namespace Robust.Shared.Serialization.Manager
Type GetConstantTypeFromTag(Type tagType);
#endregion
#region Composition
DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null);
public TNode PushComposition<TType, TNode>(TNode[] parents, TNode child, ISerializationContext? context = null) where TNode : DataNode
{
// ReSharper disable once CoVariantArrayConversion
return (TNode)PushComposition(typeof(TType), parents, child, context);
}
public TNode PushCompositionWithGenericNode<TNode>(Type type, TNode[] parents, TNode child, ISerializationContext? context = null) where TNode : DataNode
{
// ReSharper disable once CoVariantArrayConversion
return (TNode) PushComposition(type, parents, child, context);
}
#endregion
}
}

View File

@@ -1,24 +0,0 @@
namespace Robust.Shared.Serialization.Manager.Result
{
public abstract class DeserializationResult
{
public abstract object? RawValue { get; }
public abstract DeserializationResult PushInheritanceFrom(DeserializationResult source);
public abstract DeserializationResult Copy();
public abstract void CallAfterDeserializationHook();
public T Cast<T>() where T : DeserializationResult
{
if (this is T value) return value;
throw new InvalidDeserializedResultTypeException<T>(GetType());
}
}
public abstract class DeserializationResult<T> : DeserializationResult
{
public abstract T? Value { get; }
}
}

View File

@@ -1,71 +0,0 @@
using System;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedArray : DeserializationResult
{
public DeserializedArray(Array array, DeserializationResult[] mappings)
{
Value = array;
Mappings = mappings;
}
public Array Value { get; }
public DeserializationResult[] Mappings { get; }
public override object RawValue => Value;
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
var sourceCollection = source.Cast<DeserializedArray>();
var values = (Array) Activator.CreateInstance(Value.GetType(), Value.Length)!;
var results = new DeserializationResult[sourceCollection.Mappings.Length];
for (var i = 0; i < sourceCollection.Mappings.Length; i++)
{
var oldRes = sourceCollection.Mappings[i];
var newRes = oldRes.Copy();
values.SetValue(newRes.RawValue, i);
results[i] = newRes;
}
for (var i = 0; i < Mappings.Length; i++)
{
var oldRes = Mappings[i];
var newRes = oldRes.Copy();
values.SetValue(newRes.RawValue, i);
results[i] = newRes;
}
return new DeserializedArray(values, results);
}
public override DeserializationResult Copy()
{
var values = (Array) Activator.CreateInstance(Value.GetType(), Value.Length)!;
var results = new DeserializationResult[Mappings.Length];
for (var i = 0; i < Mappings.Length; i++)
{
var oldRes = Mappings[i];
var newRes = oldRes.Copy();
values.SetValue(newRes.RawValue, i);
results[i] = newRes;
}
return new DeserializedArray(values, results);
}
public override void CallAfterDeserializationHook()
{
foreach (var elem in Mappings)
{
elem.CallAfterDeserializationHook();
}
}
}
}

View File

@@ -1,73 +0,0 @@
using System.Collections.Generic;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedCollection<TCollection, TElement> : DeserializationResult<TCollection> where TCollection : IReadOnlyCollection<TElement>
{
public delegate TCollection Create(List<TElement> elements);
public DeserializedCollection(
TCollection value,
IEnumerable<DeserializationResult> mappings,
Create createDelegate)
{
Value = value;
Mappings = mappings;
CreateDelegate = createDelegate;
}
public override TCollection Value { get; }
public IEnumerable<DeserializationResult> Mappings { get; }
public override object RawValue => Value;
private Create CreateDelegate { get; }
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
var sourceCollection = source.Cast<DeserializedCollection<TCollection, TElement>>();
var valueList = new List<TElement>();
var resList = new List<DeserializationResult>();
foreach (var oldRes in sourceCollection.Mappings)
{
var newRes = oldRes.Copy().Cast<DeserializationResult<TElement>>();
valueList.Add(newRes.Value!);
resList.Add(newRes);
}
foreach (var oldRes in Mappings)
{
var newRes = oldRes.Copy().Cast<DeserializationResult<TElement>>();
valueList.Add(newRes.Value!);
resList.Add(newRes);
}
return new DeserializedCollection<TCollection, TElement>(CreateDelegate(valueList), resList, CreateDelegate);
}
public override DeserializationResult Copy()
{
var valueList = new List<TElement>();
var resList = new List<DeserializationResult>();
foreach (var oldRes in Mappings)
{
var newRes = oldRes.Copy();
valueList.Add((TElement) newRes.RawValue!);
resList.Add(newRes);
}
return new DeserializedCollection<TCollection, TElement>(CreateDelegate(valueList), resList, CreateDelegate);
}
public override void CallAfterDeserializationHook()
{
foreach (var val in Mappings)
{
val.CallAfterDeserializationHook();
}
}
}
}

View File

@@ -1,111 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using static Robust.Shared.Prototypes.EntityPrototype;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedComponentRegistry : DeserializationResult<ComponentRegistry>
{
public DeserializedComponentRegistry(
ComponentRegistry value,
IReadOnlyDictionary<DeserializationResult, DeserializationResult> mappings)
{
Value = value;
Mappings = mappings;
}
public override ComponentRegistry Value { get; }
public IReadOnlyDictionary<DeserializationResult, DeserializationResult> Mappings { get; }
public override object RawValue => Value;
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
var componentFactory = IoCManager.Resolve<IComponentFactory>();
var sourceRes = source.Cast<DeserializedComponentRegistry>();
var mappingDict = Mappings.ToDictionary(p => p.Key.Copy(), p => p.Value.Copy());
foreach (var (keyRes, valRes) in sourceRes.Mappings)
{
var newKeyRes = keyRes.Copy();
var newValueRes = valRes.Copy();
if (mappingDict.Any(p =>
{
var k1 = (string) newKeyRes.RawValue!;
var k2 = (string) p.Key.RawValue!;
if (k1 == k2)
{
return false;
}
var registration1 = componentFactory.GetRegistration(k1!);
var registration2 = componentFactory.GetRegistration(k2!);
foreach (var reference in registration1.References)
{
if (registration2.References.Contains(reference))
{
return true;
}
}
return false;
}))
{
continue;
}
var res = newKeyRes;
var oldEntry = mappingDict.FirstOrNull(p => Equals(p.Key.RawValue, res.RawValue));
if (oldEntry.HasValue)
{
newKeyRes = oldEntry.Value.Key.PushInheritanceFrom(newKeyRes);
newValueRes = oldEntry.Value.Value.PushInheritanceFrom(newValueRes);
mappingDict.Remove(oldEntry.Value.Key);
}
mappingDict.Add(newKeyRes, newValueRes);
}
var valueDict = new ComponentRegistry();
foreach (var (key, val) in mappingDict)
{
valueDict.Add((string) key.RawValue!, (IComponent) val.RawValue!);
}
return new DeserializedComponentRegistry(valueDict, mappingDict);
}
public override DeserializationResult Copy()
{
var registry = new ComponentRegistry();
var mappingDict = new Dictionary<DeserializationResult, DeserializationResult>();
foreach (var (keyRes, valRes) in Mappings)
{
var newKeyRes = keyRes.Copy();
var newValueRes = valRes.Copy();
registry.Add((string) newKeyRes.RawValue!, (IComponent) newValueRes.RawValue!);
mappingDict.Add(newKeyRes, newValueRes);
}
return new DeserializedComponentRegistry(registry, mappingDict);
}
public override void CallAfterDeserializationHook()
{
foreach (var (_, comp) in Mappings)
{
comp.CallAfterDeserializationHook();
}
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using Robust.Shared.IoC;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedDefinition<T> : DeserializationResult<T>, IDeserializedDefinition where T : notnull, new()
{
public DeserializedDefinition(T value, DeserializedFieldEntry[] mapping)
{
Value = value;
Mapping = mapping;
}
public override T Value { get; }
public DeserializedFieldEntry[] Mapping { get; }
public override object RawValue => Value;
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
var dataDef = source.Cast<DeserializedDefinition<T>>();
if (dataDef.Mapping.Length != Mapping.Length)
throw new ArgumentException($"Mapping length mismatch in PushInheritanceFrom ({typeof(T)})");
var newMapping = new DeserializedFieldEntry[Mapping.Length];
for (var i = 0; i < dataDef.Mapping.Length; i++)
{
newMapping[i] = Mapping[i].PushInheritanceFrom(dataDef.Mapping[i]);
}
return IoCManager.Resolve<ISerializationManager>().CreateDataDefinition<T>(newMapping, true);
}
public override DeserializationResult Copy()
{
var newMapping = new DeserializedFieldEntry[Mapping.Length];
for (var i = 0; i < Mapping.Length; i++)
{
newMapping[i] = Mapping[i].Copy();
}
return IoCManager.Resolve<ISerializationManager>().CreateDataDefinition<T>(newMapping, true);
}
public override void CallAfterDeserializationHook()
{
foreach (var fieldEntry in Mapping)
{
fieldEntry.Result?.CallAfterDeserializationHook();
}
if (Value is ISerializationHooks hooks)
hooks.AfterDeserialization();
}
}
}

View File

@@ -1,83 +0,0 @@
using System.Collections.Generic;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedDictionary<TDict, TKey, TValue> :
DeserializationResult<TDict>
where TKey : notnull
where TDict : IReadOnlyDictionary<TKey, TValue>
{
public delegate TDict Create(Dictionary<TKey, TValue> elements);
public DeserializedDictionary(
TDict value,
IReadOnlyDictionary<DeserializationResult, DeserializationResult> mappings,
Create createDelegate)
{
Value = value;
Mappings = mappings;
CreateDelegate = createDelegate;
}
public override TDict Value { get; }
public IReadOnlyDictionary<DeserializationResult, DeserializationResult> Mappings { get; }
public Create CreateDelegate { get; }
public override object RawValue => Value;
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
var sourceRes = source.Cast<DeserializedDictionary<TDict, TKey, TValue>>();
var valueDict = new Dictionary<TKey, TValue>();
var mappingDict = new Dictionary<DeserializationResult, DeserializationResult>();
foreach (var (keyRes, valRes) in sourceRes.Mappings)
{
var newKeyRes = keyRes.Copy();
var newValueRes = valRes.Copy();
valueDict.Add((TKey)newKeyRes.RawValue!, (TValue)newValueRes.RawValue!);
mappingDict.Add(newKeyRes, newValueRes);
}
foreach (var (keyRes, valRes) in Mappings)
{
var newKeyRes = keyRes.Copy();
var newValueRes = valRes.Copy();
valueDict.Add((TKey) newKeyRes.RawValue!, (TValue)newValueRes.RawValue!);
mappingDict.Add(newKeyRes, newValueRes);
}
return new DeserializedDictionary<TDict, TKey, TValue>(CreateDelegate(valueDict), mappingDict, CreateDelegate);
}
public override DeserializationResult Copy()
{
var valueDict = new Dictionary<TKey, TValue>();
var mappingDict = new Dictionary<DeserializationResult, DeserializationResult>();
foreach (var (keyRes, valRes) in Mappings)
{
var newKeyRes = keyRes.Copy();
var newValueRes = valRes.Copy();
valueDict.Add((TKey)newKeyRes.RawValue!, (TValue)newValueRes.RawValue!);
mappingDict.Add(newKeyRes, newValueRes);
}
return new DeserializedDictionary<TDict, TKey, TValue>(CreateDelegate(valueDict), mappingDict, CreateDelegate);
}
public override void CallAfterDeserializationHook()
{
foreach (var (key, val) in Mappings)
{
key.CallAfterDeserializationHook();
val.CallAfterDeserializationHook();
}
}
}
}

View File

@@ -1,49 +0,0 @@
using Robust.Shared.Serialization.Manager.Definition;
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedFieldEntry
{
public DeserializedFieldEntry(bool mapped, InheritanceBehavior inheritanceBehavior, DeserializationResult? result = null)
{
Mapped = mapped;
Result = result;
InheritanceBehavior = inheritanceBehavior;
}
public bool Mapped { get; }
public InheritanceBehavior InheritanceBehavior { get; }
public DeserializationResult? Result { get; }
public DeserializedFieldEntry PushInheritanceFrom(DeserializedFieldEntry fieldEntry)
{
if (Mapped)
{
if (InheritanceBehavior == InheritanceBehavior.Always)
{
if (Result != null)
{
return fieldEntry.Result != null
? new DeserializedFieldEntry(Mapped, InheritanceBehavior, Result.PushInheritanceFrom(fieldEntry.Result))
: Copy();
}
else
{
return fieldEntry.Copy();
}
}
return Copy();
}
return InheritanceBehavior == InheritanceBehavior.Never ? Copy() : fieldEntry.Copy();
}
public DeserializedFieldEntry Copy()
{
return new(Mapped, InheritanceBehavior, Result?.Copy());
}
}
}

View File

@@ -1,58 +0,0 @@
namespace Robust.Shared.Serialization.Manager.Result
{
public sealed class DeserializedValue : DeserializationResult
{
public DeserializedValue(object? value)
{
RawValue = value;
}
public override object? RawValue { get; }
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
return source.Copy().Cast<DeserializedValue>();
}
public override DeserializationResult Copy()
{
return new DeserializedValue(RawValue);
}
public override void CallAfterDeserializationHook()
{
if (RawValue is ISerializationHooks hooks)
hooks.AfterDeserialization();
}
}
public sealed class DeserializedValue<T> : DeserializationResult<T>
{
public DeserializedValue(T value)
{
Value = value;
}
public override T Value { get; }
public override object? RawValue => Value;
public override DeserializationResult PushInheritanceFrom(DeserializationResult source)
{
return source.Copy().Cast<DeserializedValue<T>>();
}
public override DeserializationResult Copy()
{
return new DeserializedValue<T>(Value);
}
public override void CallAfterDeserializationHook()
{
if (Value is ISerializationHooks hooks)
{
hooks.AfterDeserialization();
}
}
}
}

View File

@@ -1,7 +0,0 @@
namespace Robust.Shared.Serialization.Manager.Result
{
public interface IDeserializedDefinition
{
DeserializedFieldEntry[] Mapping { get; }
}
}

View File

@@ -1,34 +0,0 @@
using System;
using System.Runtime.Serialization;
using JetBrains.Annotations;
namespace Robust.Shared.Serialization.Manager.Result
{
[Virtual]
public class InvalidDeserializedResultTypeException<TExpected> : Exception
{
public readonly Type ReceivedType;
public override string Message => $"Invalid Type {ReceivedType} received. Expected {typeof(TExpected)}";
public InvalidDeserializedResultTypeException(Type receivedType)
{
ReceivedType = receivedType;
}
protected InvalidDeserializedResultTypeException([NotNull] SerializationInfo info, StreamingContext context, Type receivedType) : base(info, context)
{
ReceivedType = receivedType;
}
public InvalidDeserializedResultTypeException([CanBeNull] string? message, Type receivedType) : base(message)
{
ReceivedType = receivedType;
}
public InvalidDeserializedResultTypeException([CanBeNull] string? message, [CanBeNull] Exception? innerException, Type receivedType) : base(message, innerException)
{
ReceivedType = receivedType;
}
}
}

View File

@@ -0,0 +1,153 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.Utility;
namespace Robust.Shared.Serialization.Manager;
public partial class SerializationManager
{
private delegate DataNode PushCompositionDelegate(
Type type,
DataNode parent,
DataNode child,
ISerializationContext? context = null);
private readonly ConcurrentDictionary<(Type value, Type node), PushCompositionDelegate> _compositionPushers = new();
public DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null)
{
DebugTools.Assert(parents.All(x => x.GetType() == child.GetType()));
var pusher = GetOrCreatePushCompositionDelegate(type, child);
var node = child;
for (int i = 0; i < parents.Length; i++)
{
node = pusher(type, parents[i], node, context);
}
return node;
}
private PushCompositionDelegate GetOrCreatePushCompositionDelegate(Type type, DataNode node)
{
return _compositionPushers.GetOrAdd((type, node.GetType()), static (tuple, vfArgument) =>
{
var (value, nodeType) = tuple;
var (node, instance) = vfArgument;
var instanceConst = Expression.Constant(instance);
var dependencyCollectionConst = Expression.Constant(instance.DependencyCollection);
var typeParam = Expression.Parameter(typeof(Type), "type");
var parentParam = Expression.Parameter(typeof(DataNode), "parent");
var childParam = Expression.Parameter(typeof(DataNode), "child");
//todo paul serializers in the context should also override default serializers for array etc
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
Expression expression;
if (instance.TryGetTypeInheritanceHandler(value, nodeType, out var handler))
{
var readerType = typeof(ITypeInheritanceHandler<,>).MakeGenericType(value, nodeType);
var readerConst = Expression.Constant(handler, readerType);
expression = Expression.Call(
readerConst,
"PushInheritance",
Type.EmptyTypes,
instanceConst,
Expression.Convert(childParam, nodeType),
Expression.Convert(parentParam, nodeType),
dependencyCollectionConst,
contextParam);
}
else if (nodeType == typeof(MappingDataNode) && instance.TryGetDefinition(value, out var dataDefinition))
{
var definitionConst = Expression.Constant(dataDefinition, typeof(DataDefinition));
expression = Expression.Call(
instanceConst,
nameof(PushInheritanceDefinition),
Type.EmptyTypes,
Expression.Convert(childParam, nodeType),
Expression.Convert(parentParam, nodeType),
definitionConst,
contextParam);
}
else
{
expression = node switch
{
SequenceDataNode => Expression.Call(
instanceConst,
nameof(PushInheritanceSequence),
Type.EmptyTypes,
Expression.Convert(childParam, nodeType),
Expression.Convert(parentParam, nodeType)),
MappingDataNode => Expression.Call(
instanceConst,
nameof(PushInheritanceMapping),
Type.EmptyTypes,
Expression.Convert(childParam, nodeType),
Expression.Convert(parentParam, nodeType)),
_ => childParam
};
}
return Expression.Lambda<PushCompositionDelegate>(
expression,
typeParam,
parentParam,
childParam,
contextParam).Compile();
}, (node, this));
}
private SequenceDataNode PushInheritanceSequence(SequenceDataNode child, SequenceDataNode _)
{
return child; //todo implement different inheritancebehaviours for yamlfield
}
private MappingDataNode PushInheritanceMapping(MappingDataNode child, MappingDataNode _)
{
return child; //todo implement different inheritancebehaviours for yamlfield
}
private MappingDataNode PushInheritanceDefinition(MappingDataNode child, MappingDataNode parent,
DataDefinition definition, ISerializationContext? context = null)
{
var newMapping = child.Copy();
foreach (var field in definition.BaseFieldDefinitions)
{
if (field.InheritanceBehavior == InheritanceBehavior.Never) continue;
var key = new ValueDataNode(field.Attribute.Tag);
if (parent.TryGetValue(key, out var parentValue))
{
if (newMapping.TryGetValue(key, out var childValue))
{
if (field.InheritanceBehavior == InheritanceBehavior.Always)
{
newMapping[key] = PushComposition(field.FieldType, new[] { parentValue }, childValue, context);
}
}
else
{
newMapping.Add(key, parentValue);
}
}
}
return newMapping;
}
}

View File

@@ -2,7 +2,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq.Expressions;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
@@ -12,10 +11,11 @@ namespace Robust.Shared.Serialization.Manager
{
public partial class SerializationManager
{
private delegate DeserializationResult ReadSerializerDelegate(
private delegate object? ReadSerializerDelegate(
DataNode node,
ISerializationContext? context = null,
bool skipHook = false);
bool skipHook = false,
object? value = null);
private delegate DataNode WriteSerializerDelegate(
object value,
@@ -47,6 +47,7 @@ namespace Robust.Shared.Serialization.Manager
var nodeParam = Expression.Parameter(typeof(DataNode), "node");
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var valueParam = Expression.Parameter(typeof(object), "value");
var call = Expression.Call(
instanceParam,
@@ -54,13 +55,15 @@ namespace Robust.Shared.Serialization.Manager
new[] {tuple.value, tuple.node, tuple.serializer},
Expression.Convert(nodeParam, tuple.node),
contextParam,
skipHookParam);
skipHookParam,
valueParam);
return Expression.Lambda<ReadSerializerDelegate>(
call,
Expression.Convert(call, typeof(object)),
nodeParam,
contextParam,
skipHookParam).Compile();
skipHookParam,
valueParam).Compile();
}, this);
}
@@ -126,25 +129,27 @@ namespace Robust.Shared.Serialization.Manager
}, (common, source, target, serializer));
}
private DeserializationResult ReadWithSerializerRaw(
Type value,
private object? ReadWithSerializerRaw(
Type type,
DataNode node,
Type serializer,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? value = null)
{
return GetOrCreateReadSerializerDelegate(value, node.GetType(), serializer)(node, context, skipHook);
return GetOrCreateReadSerializerDelegate(type, node.GetType(), serializer)(node, context, skipHook, value);
}
private DeserializationResult ReadWithSerializer<T, TNode, TSerializer>(
private T ReadWithSerializer<T, TNode, TSerializer>(
TNode node,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? value = default)
where TSerializer : ITypeReader<T, TNode>
where TNode : DataNode
{
var serializer = (ITypeReader<T, TNode>) GetTypeSerializer(typeof(TSerializer));
return serializer.Read(this, node, DependencyCollection, skipHook, context);
return serializer.Read(this, node, DependencyCollection, skipHook, context, value == null ? default : (T)value);
}
private DataNode WriteWithSerializerRaw(

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
@@ -14,14 +14,37 @@ namespace Robust.Shared.Serialization.Manager
{
public partial class SerializationManager
{
private delegate DeserializationResult ReadDelegate(
private delegate object? ReadDelegate(
Type type,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false);
bool skipHook = false,
object? value = null);
private readonly ConcurrentDictionary<(Type value, Type node), ReadDelegate> _readers = new();
public T Read<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false, T? value = default) //todo paul this default should be null
{
return (T)Read(typeof(T), node, context, skipHook, value)!;
}
public object? Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false, object? value = null)
{
var val = GetOrCreateReader(type, node)(type, node, context, skipHook, value);
ReadNullCheck(type, val);
return val;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadNullCheck(Type type, object? val)
{
if (!type.IsNullable() && val == null)
{
throw new InvalidOperationException(
$"{nameof(Read)}-Call returned a null value for non-nullable type {type}");
}
}
private ReadDelegate GetOrCreateReader(Type value, DataNode node)
{
if (node.Tag?.StartsWith("!type:") ?? false)
@@ -42,8 +65,10 @@ namespace Robust.Shared.Serialization.Manager
var typeParam = Expression.Parameter(typeof(Type), "type");
var nodeParam = Expression.Parameter(typeof(DataNode), "node");
//todo paul serializers in the context should also override default serializers for array etc
var contextParam = Expression.Parameter(typeof(ISerializationContext), "context");
var skipHookParam = Expression.Parameter(typeof(bool), "skipHook");
var valueParam = Expression.Parameter(typeof(object), "value");
MethodCallExpression call;
@@ -53,12 +78,14 @@ namespace Robust.Shared.Serialization.Manager
switch (node)
{
case ValueDataNode when nullable:
case ValueDataNode:
call = Expression.Call(
instanceConst,
nameof(ReadArrayValue),
new[] { elementType },
Expression.Convert(nodeParam, typeof(ValueDataNode)));
Expression.Convert(nodeParam, typeof(ValueDataNode)),
contextParam,
skipHookParam);
break;
case SequenceDataNode seqNode:
var isSealed = elementType.IsPrimitive || elementType.IsEnum ||
@@ -140,7 +167,7 @@ namespace Robust.Shared.Serialization.Manager
nameof(ReadSelfSerialize),
new[] { value },
Expression.Convert(nodeParam, typeof(ValueDataNode)),
instantiatorConst)
instantiatorConst, valueParam)
};
}
else if (instance.TryGetTypeReader(value, nodeType, out var reader))
@@ -160,12 +187,13 @@ namespace Robust.Shared.Serialization.Manager
skipHookParam),
ValueDataNode when nullable && !value.IsValueType => Expression.Call(
instanceConst,
nameof(ReadWithTypeReaderNullable),
nameof(ReadWithTypeReaderNullableClass),
new[] { value },
Expression.Convert(nodeParam, typeof(ValueDataNode)),
readerConst,
contextParam,
skipHookParam),
skipHookParam,
valueParam),
_ => Expression.Call(
instanceConst,
nameof(ReadWithTypeReader),
@@ -173,7 +201,8 @@ namespace Robust.Shared.Serialization.Manager
Expression.Convert(nodeParam, nodeType),
readerConst,
contextParam,
skipHookParam)
skipHookParam,
valueParam)
};
}
else if (value.IsInterface || value.IsAbstract)
@@ -203,7 +232,8 @@ namespace Robust.Shared.Serialization.Manager
populateConst,
hooksConst,
contextParam,
skipHookParam),
skipHookParam,
valueParam),
ValueDataNode => Expression.Call(
instanceConst,
nameof(ReadGenericValue),
@@ -214,7 +244,8 @@ namespace Robust.Shared.Serialization.Manager
populateConst,
hooksConst,
contextParam,
skipHookParam),
skipHookParam,
valueParam),
MappingDataNode => Expression.Call(
instanceConst,
nameof(ReadGenericMapping),
@@ -225,53 +256,54 @@ namespace Robust.Shared.Serialization.Manager
populateConst,
hooksConst,
contextParam,
skipHookParam),
skipHookParam,
valueParam),
SequenceDataNode => throw new ArgumentException($"No mapping node provided for type {value} at line: {node.Start.Line}"),
_ => throw new ArgumentException($"Unknown node type {nodeType} provided. Expected mapping node at line: {node.Start.Line}")
};
}
return Expression.Lambda<ReadDelegate>(
call,
Expression.Convert(call, typeof(object)),
typeParam,
nodeParam,
contextParam,
skipHookParam).Compile();
skipHookParam,
valueParam).Compile();
}, (node, this));
}
private DeserializationResult ReadArrayValue<T>(ValueDataNode value)
private T[]? ReadArrayValue<T>(
ValueDataNode value,
ISerializationContext? context = null,
bool skipHook = false)
{
if (value.Value == "null")
{
return new DeserializedValue<T[]?>(null);
return null;
}
throw new InvalidNodeTypeException("Cannot read an array from a value data node that is not null.");
var array = new T[1];
array[0] = Read<T>(value, context, skipHook);
return array;
}
private DeserializationResult ReadArraySequence<T>(
private T[] ReadArraySequence<T>(
SequenceDataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var type = typeof(T);
var array = new T[node.Sequence.Count];
var results = new DeserializationResult[node.Sequence.Count];
for (var i = 0; i < node.Sequence.Count; i++)
{
var subNode = node.Sequence[i];
var result = Read(type, subNode, context, skipHook);
results[i] = result;
array[i] = (T) result.RawValue!;
array[i] = Read<T>(node.Sequence[i], context, skipHook);
}
return new DeserializedArray(array, results);
return array;
}
private DeserializationResult ReadArraySequenceSealed<T>(
private T[] ReadArraySequenceSealed<T>(
SequenceDataNode node,
ReadDelegate elementReader,
ISerializationContext? context = null,
@@ -279,90 +311,87 @@ namespace Robust.Shared.Serialization.Manager
{
var type = typeof(T);
var array = new T[node.Sequence.Count];
var results = new DeserializationResult[node.Sequence.Count];
for (var i = 0; i < node.Sequence.Count; i++)
{
var subNode = node.Sequence[i];
var result = elementReader(type, subNode, context, skipHook);
results[i] = result;
array[i] = (T) result.RawValue!;
ReadNullCheck(type, result);
array[i] = (T) result!;
}
return new DeserializedArray(array, results);
return array;
}
private DeserializationResult ReadEnumNullable<TEnum>(ValueDataNode node) where TEnum : struct
private TEnum? ReadEnumNullable<TEnum>(ValueDataNode node) where TEnum : struct
{
if (node.Value == "null")
{
return new DeserializedValue<TEnum?>(null);
return null;
}
var value = Enum.Parse<TEnum>(node.Value, true);
return new DeserializedValue<TEnum?>(value);
return ReadEnumValue<TEnum>(node);
}
private DeserializationResult ReadEnumValue<TEnum>(ValueDataNode node) where TEnum : struct
private TEnum ReadEnumValue<TEnum>(ValueDataNode node) where TEnum : struct
{
var value = Enum.Parse<TEnum>(node.Value, true);
return new DeserializedValue<TEnum>(value);
return Enum.Parse<TEnum>(node.Value, true);
}
private DeserializationResult ReadEnumSequence<TEnum>(SequenceDataNode node) where TEnum : struct
private TEnum ReadEnumSequence<TEnum>(SequenceDataNode node) where TEnum : struct
{
var value = Enum.Parse<TEnum>(string.Join(", ", node.Sequence), true);
return new DeserializedValue<TEnum>(value);
return Enum.Parse<TEnum>(string.Join(", ", node.Sequence), true);
}
private DeserializationResult ReadSelfSerialize<TValue>(
private TValue? ReadSelfSerialize<TValue>(
ValueDataNode node,
InstantiationDelegate<object> instantiator)
InstantiationDelegate<object> instantiator,
object? rawValue = null)
where TValue : ISelfSerialize
{
if (node.Value == "null")
{
return new DeserializedValue<TValue?>(default);
return default; //todo paul this default should be null
}
var value = (TValue) instantiator();
var value = (TValue) (rawValue ?? instantiator());
value.Deserialize(node.Value);
return new DeserializedValue<TValue?>(value);
return value;
}
private DeserializationResult ReadSelfSerializeNullableStruct<TValue>(
private TValue? ReadSelfSerializeNullableStruct<TValue>(
ValueDataNode node,
InstantiationDelegate<object> instantiator)
where TValue : struct, ISelfSerialize
{
if (node.Value == "null")
{
return new DeserializedValue<TValue?>(null);
return null;
}
var value = (TValue) instantiator();
value.Deserialize(node.Value);
return new DeserializedValue<TValue?>(value);
return value;
}
private DeserializationResult ReadWithTypeReaderNullable<TValue>(
private TValue? ReadWithTypeReaderNullableClass<TValue>(
ValueDataNode node,
ITypeReader<TValue, ValueDataNode> reader,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? value = null)
where TValue : class
{
if (node.Value == "null")
{
return new DeserializedValue<TValue?>(default);
return null;
}
return ReadWithTypeReader(node, reader, context, skipHook);
return ReadWithTypeReader(node, reader, context, skipHook, value);
}
private DeserializationResult ReadWithTypeReaderNullableStruct<TValue>(
private TValue? ReadWithTypeReaderNullableStruct<TValue>(
ValueDataNode node,
ITypeReader<TValue, ValueDataNode> reader,
ISerializationContext? context = null,
@@ -371,17 +400,18 @@ namespace Robust.Shared.Serialization.Manager
{
if (node.Value == "null")
{
return new DeserializedValue<TValue?>(null);
return null;
}
return ReadWithTypeReader(node, reader, context, skipHook);
}
private DeserializationResult ReadWithTypeReader<TValue, TNode>(
private TValue ReadWithTypeReader<TValue, TNode>(
TNode node,
ITypeReader<TValue, TNode> reader,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? value = null)
where TNode : DataNode
{
if (context != null &&
@@ -390,34 +420,36 @@ namespace Robust.Shared.Serialization.Manager
reader = (ITypeReader<TValue, TNode>) readerUnCast;
}
return reader.Read(this, node, DependencyCollection, skipHook, context);
return reader.Read(this, node, DependencyCollection, skipHook, context, value == null ? default : (TValue) value);
}
private DeserializationResult ReadGenericNullable<TValue>(
private TValue? ReadGenericNullable<TValue>(
ValueDataNode node,
InstantiationDelegate<object> instantiator,
DataDefinition? definition,
bool populate,
bool hooks,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? value = null)
{
if (node.Value == "null")
{
return new DeserializedValue<TValue?>(default);
return default; //todo paul this default should be null
}
return ReadGenericValue<TValue?>(node, instantiator, definition, populate, hooks, context, skipHook);
return ReadGenericValue<TValue>(node, instantiator, definition, populate, hooks, context, skipHook, value);
}
private DeserializationResult ReadGenericValue<TValue>(
private TValue ReadGenericValue<TValue>(
ValueDataNode node,
InstantiationDelegate<object> instantiator,
DataDefinition? definition,
bool populate,
bool hooks,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? instance = null)
{
var type = typeof(TValue);
@@ -425,7 +457,7 @@ namespace Robust.Shared.Serialization.Manager
context.TypeReaders.TryGetValue((typeof(TValue), typeof(ValueDataNode)), out var readerUnCast))
{
var reader = (ITypeReader<TValue, ValueDataNode>) readerUnCast;
return reader.Read(this, node, DependencyCollection, skipHook, context);
return reader.Read(this, node, DependencyCollection, skipHook, context, instance == null ? default : (TValue)instance);
}
if (definition == null)
@@ -433,7 +465,7 @@ namespace Robust.Shared.Serialization.Manager
throw new ArgumentException($"No data definition found for type {type} with node type {node.GetType()} when reading");
}
var instance = instantiator();
instance ??= instantiator();
if (populate)
{
@@ -445,36 +477,32 @@ namespace Robust.Shared.Serialization.Manager
throw new ArgumentException($"No mapping node provided for type {type} at line: {node.Start.Line}");
}
// If we get an empty ValueDataNode we just use an empty mapping
var mapping = new MappingDataNode();
var result = definition.Populate(instance, mapping, this, context, skipHook);
if (!skipHook && hooks)
{
((ISerializationHooks) result.RawValue!).AfterDeserialization();
((ISerializationHooks) instance).AfterDeserialization();
}
return result;
return (TValue) instance;
}
private DeserializationResult ReadGenericMapping<TValue>(
private TValue ReadGenericMapping<TValue>(
MappingDataNode node,
InstantiationDelegate<object> instantiator,
DataDefinition? definition,
bool populate,
bool hooks,
ISerializationContext? context = null,
bool skipHook = false)
bool skipHook = false,
object? instance = null)
{
var type = typeof(TValue);
var instance = instantiator();
instance ??= instantiator();
if (context != null &&
context.TypeReaders.TryGetValue((type, typeof(MappingDataNode)), out var readerUnCast))
{
var reader = (ITypeReader<TValue, MappingDataNode>) readerUnCast;
return reader.Read(this, node, DependencyCollection, skipHook, context);
return reader.Read(this, node, DependencyCollection, skipHook, context, (TValue?) instance);
}
if (definition == null)
@@ -487,47 +515,20 @@ namespace Robust.Shared.Serialization.Manager
((IPopulateDefaultValues) instance).PopulateDefaultValues();
}
var result = definition.Populate(instance, node, this, context, skipHook);
var result = (TValue)definition.Populate(instance, node, this, context, skipHook)!;
if (!skipHook && hooks)
{
((ISerializationHooks) result.RawValue!).AfterDeserialization();
((ISerializationHooks) result).AfterDeserialization();
}
return result;
}
public DeserializationResult Read(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false)
public object? ReadWithTypeSerializer(Type type, Type serializer, DataNode node, ISerializationContext? context = null,
bool skipHook = false, object? value = null)
{
return GetOrCreateReader(type, node)(type, node, context, skipHook);
}
public object? ReadValue(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false)
{
return Read(type, node, context, skipHook).RawValue;
}
public T? ReadValueCast<T>(Type type, DataNode node, ISerializationContext? context = null, bool skipHook = false)
{
var value = Read(type, node, context, skipHook);
if (value.RawValue == null)
{
return default;
}
return (T?) value.RawValue;
}
public T? ReadValue<T>(DataNode node, ISerializationContext? context = null, bool skipHook = false)
{
return ReadValueCast<T>(typeof(T), node, context, skipHook);
}
public DeserializationResult ReadWithTypeSerializer(Type value, Type serializer, DataNode node, ISerializationContext? context = null,
bool skipHook = false)
{
return ReadWithSerializerRaw(value, node, serializer, context, skipHook);
return ReadWithSerializerRaw(type, node, serializer, context, skipHook, value);
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Robust.Shared.Serialization.Manager;
public partial class SerializationManager
{
private readonly Dictionary<(Type Type, Type DataNodeType), object> _typeInheritanceHandlers = new();
private object? GetTypeInheritanceHandler(Type value, Type node)
{
if (_typeInheritanceHandlers.TryGetValue((value, node), out var handler))
{
return handler;
}
if (TryGetGenericInheritanceHandler(value, node, out handler))
{
return handler;
}
return null;
}
private bool TryGetTypeInheritanceHandler(Type value, Type node, [NotNullWhen(true)] out object? handler)
{
return (handler = GetTypeInheritanceHandler(value, node)) != null;
}
private bool TryGetGenericInheritanceHandler(Type type, Type node, [NotNullWhen(true)] out object? handler)
{
if (type.IsGenericType)
{
var typeDef = type.GetGenericTypeDefinition();
Type? serializerTypeDef = null;
foreach (var (key, val) in _genericInheritanceHandlerTypes)
{
if (typeDef.HasSameMetadataDefinitionAs(key.Type) && key.DataNodeType.IsAssignableFrom(node))
{
serializerTypeDef = val;
break;
}
}
if (serializerTypeDef == null)
{
handler = null;
return false;
}
var serializerType = serializerTypeDef.MakeGenericType(type.GetGenericArguments());
handler = RegisterSerializer(serializerType) ?? throw new NullReferenceException();
return true;
}
handler = null;
return false;
}
}

View File

@@ -10,6 +10,7 @@ namespace Robust.Shared.Serialization.Manager
public partial class SerializationManager
{
private readonly Dictionary<(Type Type, Type DataNodeType), Type> _genericReaderTypes = new();
private readonly Dictionary<(Type Type, Type DataNodeType), Type> _genericInheritanceHandlerTypes = new();
private readonly Dictionary<Type, Type> _genericWriterTypes = new();
private readonly Dictionary<Type, Type> _genericCopierTypes = new();
private readonly Dictionary<(Type Type, Type DataNodeType), Type> _genericValidatorTypes = new();
@@ -44,11 +45,14 @@ namespace Robust.Shared.Serialization.Manager
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ITypeCopier<>)).ToArray();
var validatorInterfaces = type.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ITypeValidator<,>)).ToArray();
var inheritanceHandlerInterfaces = type.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ITypeInheritanceHandler<,>)).ToArray();
if (readerInterfaces.Length == 0 &&
writerInterfaces.Length == 0 &&
copierInterfaces.Length == 0 &&
validatorInterfaces.Length == 0)
validatorInterfaces.Length == 0 &&
inheritanceHandlerInterfaces.Length == 0)
{
throw new InvalidOperationException(
"Tried to register TypeReader/Writer/Copier that had none of the interfaces inherited.");
@@ -84,6 +88,12 @@ namespace Robust.Shared.Serialization.Manager
Logger.ErrorS(LogCategory, $"Tried registering generic reader for type {validatorInterface.GetGenericArguments()[0]} and node {validatorInterface.GetGenericArguments()[1]} twice");
}
foreach (var inheritanceHandlerInterface in inheritanceHandlerInterfaces)
{
if (!_genericInheritanceHandlerTypes.TryAdd((inheritanceHandlerInterface.GetGenericArguments()[0], inheritanceHandlerInterface.GetGenericArguments()[1]), type))
Logger.ErrorS(LogCategory, $"Tried registering generic reader for type {inheritanceHandlerInterface.GetGenericArguments()[0]} and node {inheritanceHandlerInterface.GetGenericArguments()[1]} twice");
}
return null;
}
else
@@ -114,6 +124,12 @@ namespace Robust.Shared.Serialization.Manager
Logger.ErrorS(LogCategory, $"Tried registering reader for type {validatorInterface.GetGenericArguments()[0]} and node {validatorInterface.GetGenericArguments()[1]} twice");
}
foreach (var inheritanceHandlerInterface in inheritanceHandlerInterfaces)
{
if (!_typeInheritanceHandlers.TryAdd((inheritanceHandlerInterface.GetGenericArguments()[0], inheritanceHandlerInterface.GetGenericArguments()[1]), serializer))
Logger.ErrorS(LogCategory, $"Tried registering reader for type {inheritanceHandlerInterface.GetGenericArguments()[0]} and node {inheritanceHandlerInterface.GetGenericArguments()[1]} twice");
}
return serializer;
}
}

View File

@@ -14,7 +14,6 @@ using Robust.Shared.Log;
using Robust.Shared.Reflection;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Definition;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Sequence;
@@ -304,39 +303,6 @@ namespace Robust.Shared.Serialization.Manager
return ValidateNodeWith(typeof(TType), typeof(TSerializer), node, context);
}
public DeserializationResult CreateDataDefinition<T>(DeserializedFieldEntry[] fields, bool skipHook = false)
where T : notnull, new()
{
var obj = new T();
return PopulateDataDefinition(obj, new DeserializedDefinition<T>(obj, fields), skipHook);
}
public DeserializationResult PopulateDataDefinition<T>(T obj, DeserializedDefinition<T> definition, bool skipHook = false)
where T : notnull, new()
{
return PopulateDataDefinition(obj, (IDeserializedDefinition) definition, skipHook);
}
public DeserializationResult PopulateDataDefinition(object obj, IDeserializedDefinition definition, bool skipHook = false)
{
if (!TryGetDefinition(obj.GetType(), out var dataDefinition))
throw new ArgumentException($"Provided Type is not a data definition ({obj.GetType()})");
if (obj is IPopulateDefaultValues populateDefaultValues)
{
populateDefaultValues.PopulateDefaultValues();
}
var res = dataDefinition.Populate(obj, definition.Mapping);
if (!skipHook && res.RawValue is ISerializationHooks serializationHooksAfter)
{
serializationHooksAfter.AfterDeserialization();
}
return res;
}
internal DataDefinition? GetDefinition(Type type)
{
return DataDefinitions.TryGetValue(type, out var dataDefinition)
@@ -344,7 +310,7 @@ namespace Robust.Shared.Serialization.Manager
: null;
}
private bool TryGetDefinition(Type type, [NotNullWhen(true)] out DataDefinition? dataDefinition)
internal bool TryGetDefinition(Type type, [NotNullWhen(true)] out DataDefinition? dataDefinition)
{
dataDefinition = GetDefinition(type);
return dataDefinition != null;

View File

@@ -1,116 +1 @@
#nullable enable
using System;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
namespace Robust.Shared.Serialization.Manager
{
public static class SerializationManagerReadExtensions
{
public static T ReadValueOrThrow<T>(
this ISerializationManager manager,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
return manager.ReadValue<T>(node, context, skipHook) ?? throw new NullReferenceException();
}
public static T ReadValueOrThrow<T>(
this ISerializationManager manager,
Type type,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
return manager.ReadValueCast<T>(type, node, context, skipHook) ?? throw new NullReferenceException();
}
public static object ReadValueOrThrow(
this ISerializationManager manager,
Type type,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
return manager.ReadValue(type, node, context, skipHook) ?? throw new NullReferenceException();
}
public static (DeserializationResult result, object? value) ReadWithValue(
this ISerializationManager manager,
Type type, DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var result = manager.Read(type, node, context, skipHook);
return (result, result.RawValue);
}
public static (DeserializationResult result, T? value) ReadWithValue<T>(
this ISerializationManager manager,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var result = manager.Read(typeof(T), node, context, skipHook);
if (result.RawValue == null)
{
return (result, default);
}
return (result, (T) result.RawValue);
}
public static (DeserializationResult result, T? value) ReadWithValueCast<T>(
this ISerializationManager manager,
Type type,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var result = manager.Read(type, node, context, skipHook);
if (result.RawValue == null)
{
return (result, default);
}
return (result, (T) result.RawValue);
}
public static (T value, DeserializationResult result) ReadWithValueOrThrow<T>(
this ISerializationManager manager,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var result = manager.Read(typeof(T), node, context, skipHook);
if (result.RawValue == null)
{
throw new NullReferenceException();
}
return ((T) result.RawValue, result);
}
public static (T value, DeserializationResult result) ReadWithValueOrThrow<T>(
this ISerializationManager manager,
Type type,
DataNode node,
ISerializationContext? context = null,
bool skipHook = false)
{
var result = manager.Read(type, node, context, skipHook);
if (result.RawValue == null)
{
throw new NullReferenceException();
}
return ((T) result.RawValue, result);
}
}
}

View File

@@ -15,10 +15,14 @@ namespace Robust.Shared.Serialization.Markdown
End = end;
}
public abstract bool IsEmpty { get; }
public abstract DataNode Copy();
public abstract DataNode? Except(DataNode node);
public abstract DataNode PushInheritance(DataNode parent);
public override bool Equals(object? obj)
{
if (obj is not DataNode other)
@@ -45,9 +49,16 @@ namespace Robust.Shared.Serialization.Markdown
public abstract T? Except(T node);
public abstract T PushInheritance(T node);
public override DataNode? Except(DataNode node)
{
return node is not T tNode ? throw new InvalidNodeTypeException() : Except(tNode);
}
public override DataNode PushInheritance(DataNode parent)
{
return parent is not T tNode ? throw new InvalidNodeTypeException() : PushInheritance(tNode);
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
@@ -9,7 +10,7 @@ using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Serialization.Markdown.Mapping
{
public sealed class MappingDataNode : DataNode<MappingDataNode>
public sealed class MappingDataNode : DataNode<MappingDataNode>, IDictionary<DataNode, DataNode>
{
// To fetch nodes by key name with YAML, we NEED a YamlScalarNode.
// We use a thread local one to avoid allocating one every fetch, since we just replace the inner value.
@@ -51,6 +52,7 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
set => Add(new ValueDataNode(index), value);
}
//todo paul i dont think this is thread-safe
private static ValueDataNode GetFetchNode(string key)
{
var node = FetchNode.Value!;
@@ -64,16 +66,41 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return this;
}
public bool ContainsKey(DataNode key) => _children.ContainsKey(key);
bool IDictionary<DataNode, DataNode>.Remove(DataNode key) => _children.Remove(key);
public bool TryGetValue(DataNode key, [NotNullWhen(true)] out DataNode? value) => TryGet(key, out value);
public DataNode this[DataNode key]
{
get => _children[key];
set => _children[key] = value;
}
public ICollection<DataNode> Keys => _children.Keys;
public ICollection<DataNode> Values => _children.Values;
public DataNode Get(DataNode key)
{
return _children[key];
}
public T Get<T>(DataNode key) where T : DataNode
{
return (T) Get(key);
}
public DataNode Get(string key)
{
return Get(GetFetchNode(key));
}
public T Get<T>(string key) where T : DataNode
{
return Get<T>(GetFetchNode(key));
}
public bool TryGet(DataNode key, [NotNullWhen(true)] out DataNode? node)
{
if (_children.TryGetValue(key, out node))
@@ -85,11 +112,24 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return false;
}
public bool TryGet<T>(DataNode key, [NotNullWhen(true)] out T? node) where T : DataNode
{
node = null;
if (!TryGet(key, out var rawNode)) return false;
node = (T) rawNode;
return true;
}
public bool TryGet(string key, [NotNullWhen(true)] out DataNode? node)
{
return TryGet(GetFetchNode(key), out node);
}
public bool TryGet<T>(string key, [NotNullWhen(true)] out T? node) where T : DataNode
{
return TryGet(GetFetchNode(key), out node);
}
public bool Has(DataNode key)
{
return _children.ContainsKey(key);
@@ -100,6 +140,8 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return Has(GetFetchNode(key));
}
void IDictionary<DataNode, DataNode>.Add(DataNode key, DataNode value) => _children.Add(key, value);
public MappingDataNode Remove(DataNode key)
{
_children.Remove(key);
@@ -146,6 +188,8 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return newMapping;
}
public override bool IsEmpty => _children.Count == 0;
public override MappingDataNode Copy()
{
var newMapping = new MappingDataNode()
@@ -192,6 +236,21 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return mappingNode;
}
public override MappingDataNode PushInheritance(MappingDataNode node)
{
var newNode = Copy();
foreach (var (key, val) in node)
{
if(newNode.Has(key)) continue;
newNode[key.Copy()] = val.Copy();
}
return newNode;
}
public IEnumerator<KeyValuePair<DataNode, DataNode>> GetEnumerator() => _children.GetEnumerator();
public override int GetHashCode()
{
var code = new HashCode();
@@ -203,5 +262,26 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return code.ToHashCode();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(KeyValuePair<DataNode, DataNode> item) => _children.Add(item.Key, item.Value);
public void Clear() => _children.Clear();
public bool Contains(KeyValuePair<DataNode, DataNode> item) =>
((IDictionary<DataNode, DataNode>) _children).Contains(item);
public void CopyTo(KeyValuePair<DataNode, DataNode>[] array, int arrayIndex) =>
((IDictionary<DataNode, DataNode>) _children).CopyTo(array, arrayIndex);
public bool Remove(KeyValuePair<DataNode, DataNode> item) =>
((IDictionary<DataNode, DataNode>) _children).Remove(item);
public int Count => _children.Count;
public bool IsReadOnly => false;
}
}

View File

@@ -1,11 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Robust.Shared.Serialization.Markdown.Value;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Serialization.Markdown.Sequence
{
public sealed class SequenceDataNode : DataNode<SequenceDataNode>
public sealed class SequenceDataNode : DataNode<SequenceDataNode>, IList<DataNode>
{
private readonly List<DataNode> _nodes = new();
@@ -65,23 +66,44 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
public IReadOnlyList<DataNode> Sequence => _nodes;
public DataNode this[int index] => _nodes[index];
public int IndexOf(DataNode item) => _nodes.IndexOf(item);
public void Insert(int index, DataNode item) => _nodes.Insert(index, item);
public void RemoveAt(int index) => _nodes.RemoveAt(index);
public DataNode this[int index]
{
get => _nodes[index];
set => _nodes[index] = value;
}
public void Add(DataNode node)
{
_nodes.Add(node);
}
public void Remove(DataNode node)
public void Clear() => _nodes.Clear();
public bool Contains(DataNode item) => _nodes.Contains(item);
public void CopyTo(DataNode[] array, int arrayIndex) => _nodes.CopyTo(array, arrayIndex);
public bool Remove(DataNode node)
{
_nodes.Remove(node);
return _nodes.Remove(node);
}
public int Count => _nodes.Count;
public bool IsReadOnly => false;
public T Cast<T>(int index) where T : DataNode
{
return (T) this[index];
}
public override bool IsEmpty => _nodes.Count == 0;
public override SequenceDataNode Copy()
{
var newSequence = new SequenceDataNode()
@@ -99,6 +121,8 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
return newSequence;
}
public IEnumerator<DataNode> GetEnumerator() => _nodes.GetEnumerator();
public override int GetHashCode()
{
var code = new HashCode();
@@ -110,6 +134,11 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
return code.ToHashCode();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override SequenceDataNode? Except(SequenceDataNode node)
{
var newList = new List<DataNode>();
@@ -130,5 +159,16 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
return null;
}
public override SequenceDataNode PushInheritance(SequenceDataNode node)
{
var newNode = Copy();
foreach (var val in node)
{
newNode.Add(val.Copy());
}
return newNode;
}
}
}

View File

@@ -1,9 +1,13 @@
using System.Globalization;
using JetBrains.Annotations;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Serialization.Markdown.Value
{
public sealed class ValueDataNode : DataNode<ValueDataNode>
{
public ValueDataNode() : this(string.Empty) {}
public ValueDataNode(string value) : base(NodeMark.Invalid, NodeMark.Invalid)
{
Value = value;
@@ -17,6 +21,8 @@ namespace Robust.Shared.Serialization.Markdown.Value
public string Value { get; set; }
public override bool IsEmpty => Value == string.Empty;
public override ValueDataNode Copy()
{
return new(Value)
@@ -32,6 +38,11 @@ namespace Robust.Shared.Serialization.Markdown.Value
return node.Value == Value ? null : Copy();
}
public override ValueDataNode PushInheritance(ValueDataNode node)
{
return Copy();
}
public override bool Equals(object? obj)
{
return obj is ValueDataNode node && node.Value == Value;
@@ -46,5 +57,23 @@ namespace Robust.Shared.Serialization.Markdown.Value
{
return Value;
}
[Pure]
public int AsInt()
{
return int.Parse(Value, CultureInfo.InvariantCulture);
}
[Pure]
public float AsFloat()
{
return float.Parse(Value, CultureInfo.InvariantCulture);
}
[Pure]
public bool AsBool()
{
return bool.Parse(Value);
}
}
}

View File

@@ -4,7 +4,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -15,10 +14,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class AngleSerializer : ITypeSerializer<Angle, ValueDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
public Angle Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, Angle value = default)
{
var nodeContents = node.Value;
@@ -27,7 +26,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
CultureInfo.InvariantCulture))
: Angle.FromDegrees(double.Parse(nodeContents, CultureInfo.InvariantCulture));
return new DeserializedValue<Angle>(angle);
return angle;
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -4,7 +4,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -15,10 +14,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class Box2Serializer : ITypeSerializer<Box2, ValueDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
public Box2 Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, Box2 value = default)
{
var args = node.Value.Split(',');
@@ -32,7 +31,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
var r = float.Parse(args[2], CultureInfo.InvariantCulture);
var t = float.Parse(args[3], CultureInfo.InvariantCulture);
return new DeserializedValue<Box2>(new Box2(l, b, r, t));
return new Box2(l, b, r, t);
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -3,7 +3,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -14,16 +13,16 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class ColorSerializer : ITypeSerializer<Color, ValueDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
public Color Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, Color value = default)
{
var deserializedColor = Color.TryFromName(node.Value, out var color)
? color :
Color.FromHex(node.Value);
return new DeserializedValue<Color>(deserializedColor);
return deserializedColor;
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -7,29 +7,28 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
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.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.Utility;
using static Robust.Shared.Prototypes.EntityPrototype;
namespace Robust.Shared.Serialization.TypeSerializers.Implementations
{
[TypeSerializer]
public sealed class ComponentRegistrySerializer : ITypeSerializer<ComponentRegistry, SequenceDataNode>
public sealed class ComponentRegistrySerializer : ITypeSerializer<ComponentRegistry, SequenceDataNode>, ITypeInheritanceHandler<ComponentRegistry, SequenceDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager,
public ComponentRegistry Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, ComponentRegistry? components = null)
{
var factory = dependencies.Resolve<IComponentFactory>();
var components = new ComponentRegistry();
var mappings = new Dictionary<DeserializationResult, DeserializationResult>();
components ??= new ComponentRegistry();
foreach (var componentMapping in node.Sequence.Cast<MappingDataNode>())
{
@@ -59,10 +58,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
copy.Remove("type");
var type = factory.GetRegistration(compType).Type;
var read = serializationManager.ReadWithValueOrThrow<IComponent>(type, copy, skipHook: skipHook);
var read = (IComponent)serializationManager.Read(type, copy, skipHook: skipHook)!;
components[compType] = read.value;
mappings.Add(new DeserializedValue<string>(compType), read.result);
components[compType] = read;
}
var referenceTypes = new List<Type>();
@@ -82,7 +80,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
}
}
return new DeserializedComponentRegistry(components, mappings);
return components;
}
public ValidationNode Validate(ISerializationManager serializationManager,
@@ -179,5 +177,46 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
return target;
}
public SequenceDataNode PushInheritance(ISerializationManager serializationManager, SequenceDataNode child,
SequenceDataNode parent,
IDependencyCollection dependencies, ISerializationContext context)
{
var componentFactory = dependencies.Resolve<IComponentFactory>();
var newCompReg = child.Copy();
var newCompRegDict = ToTypeIndexedDictionary(newCompReg, componentFactory);
var parentDict = ToTypeIndexedDictionary(parent, componentFactory);
foreach (var (reg, mapping) in parentDict)
{
if (newCompRegDict.TryFirstOrNull(childReg => reg.References.Any(x => childReg.Key.References.Contains(x)), out var entry))
{
newCompReg[entry.Value.Value] = serializationManager.PushCompositionWithGenericNode(reg.Type,
new[] { parent[mapping] }, newCompReg[entry.Value.Value], context);
}
else
{
newCompReg.Add(parent[mapping]);
newCompRegDict[reg] = newCompReg.Count-1;
}
}
return newCompReg;
}
private Dictionary<IComponentRegistration, int> ToTypeIndexedDictionary(SequenceDataNode node, IComponentFactory componentFactory)
{
var dict = new Dictionary<IComponentRegistration, int>();
for (var i = 0; i < node.Count; i++)
{
var mapping = (MappingDataNode)node[i];
var type = mapping.Get<ValueDataNode>("type").Value;
var availability = componentFactory.GetComponentAvailability(type);
if(availability == ComponentAvailability.Ignore) continue;
dict.Add(componentFactory.GetRegistration(type), i);
}
return dict;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -18,11 +17,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
return Enum.TryParse(constType, node.Value, out _) ? new ValidatedValueNode(node) : new ErrorNode(node, "Failed parsing constant.", false);
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, int value = default)
{
var constType = serializationManager.GetConstantTypeFromTag(typeof(TTag));
return new DeserializedValue((int) Enum.Parse(constType, node.Value));
return (int) Enum.Parse(constType, node.Value);
}
public DataNode Write(ISerializationManager serializationManager, int value, bool alwaysWrite = false,

View File

@@ -1,7 +1,6 @@
using System;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -19,11 +18,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
return Enum.TryParse(flagType, node.Value, out _) ? new ValidatedValueNode(node) : new ErrorNode(node, "Failed parsing flag.", false);
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, int value = default)
{
var flagType = serializationManager.GetFlagTypeFromTag(typeof(TTag));
return new DeserializedValue((int)Enum.Parse(flagType, node.Value));
return (int)Enum.Parse(flagType, node.Value);
}
public DataNode Write(ISerializationManager serializationManager, int value, bool alwaysWrite = false,
@@ -80,8 +79,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
return new ValidatedValueNode(node);
}
public DeserializationResult Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public int Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, int value = default)
{
var flagType = serializationManager.GetFlagTypeFromTag(typeof(TTag));
var flags = 0;
@@ -92,7 +91,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom
flags |= (int) Enum.Parse(flagType, valueDataNode.Value);
}
return new DeserializedValue(flags);
return flags;
}
}
}

View File

@@ -3,7 +3,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -62,25 +61,28 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return Validate(serializationManager, node, dependencies, context);
}
DeserializationResult ITypeReader<Dictionary<string, TValue>, MappingDataNode>.Read(
Dictionary<string, TValue> ITypeReader<Dictionary<string, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context)
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context,
Dictionary<string, TValue>? value)
{
return _dictionarySerializer.Read(serializationManager, node, dependencies, skipHook, context);
return _dictionarySerializer.Read(serializationManager, node, dependencies, skipHook, context, value);
}
DeserializationResult ITypeReader<SortedDictionary<string, TValue>, MappingDataNode>.Read(
SortedDictionary<string, TValue> ITypeReader<SortedDictionary<string, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context)
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context,
SortedDictionary<string, TValue>? value)
{
return _dictionarySerializer.Read(serializationManager, node, dependencies, skipHook, context);
return ((ITypeReader<SortedDictionary<string, TValue>, MappingDataNode>)_dictionarySerializer).Read(serializationManager, node, dependencies, skipHook, context, value);
}
DeserializationResult ITypeReader<IReadOnlyDictionary<string, TValue>, MappingDataNode>.Read(
IReadOnlyDictionary<string, TValue> ITypeReader<IReadOnlyDictionary<string, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context)
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context,
IReadOnlyDictionary<string, TValue>? value)
{
return _dictionarySerializer.Read(serializationManager, node, dependencies, skipHook, context);
return ((ITypeReader<IReadOnlyDictionary<string, TValue>, MappingDataNode>)_dictionarySerializer).Read(serializationManager, node, dependencies, skipHook, context, value);
}
public DataNode Write(ISerializationManager serializationManager, Dictionary<string, TValue> value,

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -22,27 +22,26 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return ValidateInternal(serializationManager, node, dependencies, context);
}
public DeserializationResult Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public ImmutableList<string> Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
ImmutableList<string>? rawValue = null)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableList<string>)}. Ignoring...");
var builder = ImmutableList.CreateBuilder<string>();
var mappings = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var result = _prototypeSerializer.Read(
builder.Add(_prototypeSerializer.Read(
serializationManager,
(ValueDataNode) dataNode,
dependencies,
skipHook,
context);
builder.Add((string) result.RawValue!);
mappings.Add(result);
context));
}
return new DeserializedCollection<ImmutableList<string>, string>(builder.ToImmutable(), mappings,
ImmutableList.CreateRange);
return builder.ToImmutable();
}
public DataNode Write(ISerializationManager serializationManager, ImmutableList<string> value, bool alwaysWrite = false,

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -24,31 +24,29 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return ValidateInternal(serializationManager, node, dependencies, context);
}
DeserializationResult ITypeReader<IReadOnlyCollection<string>, SequenceDataNode>.Read(
IReadOnlyCollection<string> ITypeReader<IReadOnlyCollection<string>, SequenceDataNode>.Read(
ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, IReadOnlyCollection<string>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(IReadOnlyCollection<string>)}. Ignoring...");
var list = new List<string>();
var mappings = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var result = _prototypeSerializer.Read(
list.Add(_prototypeSerializer.Read(
serializationManager,
(ValueDataNode) dataNode,
dependencies,
skipHook,
context);
list.Add((string) result.RawValue!);
mappings.Add(result);
context));
}
return new DeserializedCollection<List<string>, string>(list, mappings,
elements => new List<string>(elements));
return list;
}
DataNode ITypeWriter<IReadOnlyCollection<string>>.Write(

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -35,31 +35,29 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return new List<string>(source);
}
DeserializationResult ITypeReader<IReadOnlyList<string>, SequenceDataNode>.Read(
IReadOnlyList<string> ITypeReader<IReadOnlyList<string>, SequenceDataNode>.Read(
ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, IReadOnlyList<string>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(IReadOnlyList<string>)}. Ignoring...");
var list = new List<string>();
var mappings = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var result = _prototypeSerializer.Read(
list.Add(_prototypeSerializer.Read(
serializationManager,
(ValueDataNode) dataNode,
dependencies,
skipHook,
context);
list.Add((string) result.RawValue!);
mappings.Add(result);
context));
}
return new DeserializedCollection<IReadOnlyList<string>, string>(list, mappings,
elements => new List<string>(elements));
return list;
}
ValidationNode ITypeValidator<IReadOnlyList<string>, SequenceDataNode>.Validate(

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -62,31 +61,25 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return ValidateInternal(serializationManager, node, dependencies, context);
}
DeserializationResult ITypeReader<List<string>, SequenceDataNode>.Read(
ISerializationManager serializationManager,
List<string> ITypeReader<List<string>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, List<string>? list)
{
var list = new List<string>();
var mappings = new List<DeserializationResult>();
list ??= new List<string>();
foreach (var dataNode in node.Sequence)
{
var result = _prototypeSerializer.Read(
list.Add(_prototypeSerializer.Read(
serializationManager,
(ValueDataNode) dataNode,
dependencies,
skipHook,
context);
list.Add((string) result.RawValue!);
mappings.Add(result);
context));
}
return new DeserializedCollection<List<string>, string>(list, mappings,
elements => new List<string>(elements));
return list;
}
DataNode ITypeWriter<List<string>>.Write(

View File

@@ -1,10 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -38,9 +38,13 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return new ValidatedSequenceNode(list);
}
public DeserializationResult Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public PrototypeFlags<T> Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
PrototypeFlags<T>? rawValue = null)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(PrototypeFlags<T>)}. Ignoring...");
var flags = new List<string>(node.Sequence.Count);
foreach (var dataNode in node.Sequence)
@@ -51,7 +55,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
flags.Add(value.Value);
}
return new DeserializedValue<PrototypeFlags<T>>(new PrototypeFlags<T>(flags));
return new PrototypeFlags<T>(flags);
}
public DataNode Write(ISerializationManager serializationManager, PrototypeFlags<T> value, bool alwaysWrite = false,
@@ -72,10 +76,14 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return serializationManager.ValidateNodeWith<string, PrototypeIdSerializer<T>, ValueDataNode>(node, context);
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public PrototypeFlags<T> Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
PrototypeFlags<T>? rawValue = null)
{
return new DeserializedValue<PrototypeFlags<T>>(new PrototypeFlags<T>(node.Value));
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(PrototypeFlags<T>)}. Ignoring...");
return new PrototypeFlags<T>(node.Value);
}
}
}

View File

@@ -1,7 +1,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -14,15 +13,15 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, ISerializationContext? context = null)
{
return dependencies.Resolve<IPrototypeManager>().HasIndex<TPrototype>(node.Value)
return dependencies.Resolve<IPrototypeManager>().HasMapping<TPrototype>(node.Value)
? new ValidatedValueNode(node)
: new ErrorNode(node, $"PrototypeID {node.Value} for type {typeof(TPrototype)} not found");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public string Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, string? value = default)
{
return new DeserializedValue<string>(node.Value);
return node.Value;
}
public DataNode Write(ISerializationManager serializationManager, string value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@ using System.Collections.Generic;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -33,26 +32,23 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
return new ValidatedSequenceNode(list);
}
public DeserializationResult Read(ISerializationManager serializationManager, SequenceDataNode node, IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public HashSet<string> Read(ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null,
HashSet<string>? set = null)
{
var set = new HashSet<string>();
var mappings = new List<DeserializationResult>();
set ??= new HashSet<string>();
foreach (var dataNode in node.Sequence)
{
var result = _prototypeSerializer.Read(
set.Add(_prototypeSerializer.Read(
serializationManager,
(ValueDataNode) dataNode,
dependencies,
skipHook,
context);
set.Add((string) result.RawValue!);
mappings.Add(result);
context));
}
return new DeserializedCollection<HashSet<string>, string>(set, mappings,
elements => new HashSet<string>(elements));
return set;
}
public DataNode Write(ISerializationManager serializationManager, HashSet<string> value, bool alwaysWrite = false, ISerializationContext? context = null)

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -14,11 +13,11 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class FormattedMessageSerializer : ITypeSerializer<FormattedMessage, ValueDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager,
public FormattedMessage Read(ISerializationManager serializationManager,
ValueDataNode node, IDependencyCollection dependencies, bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, FormattedMessage? value = default)
{
return new DeserializedValue<FormattedMessage>(FormattedMessage.FromMarkup(node.Value));
return FormattedMessage.FromMarkup(node.Value);
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -37,22 +37,19 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return mappingNode;
}
public DeserializationResult Read(ISerializationManager serializationManager,
MappingDataNode node, IDependencyCollection dependencies, bool skipHook, ISerializationContext? context)
public Dictionary<TKey, TValue> Read(ISerializationManager serializationManager,
MappingDataNode node, IDependencyCollection dependencies, bool skipHook, ISerializationContext? context,
Dictionary<TKey, TValue>? dict)
{
var dict = new Dictionary<TKey, TValue>();
var mappedFields = new Dictionary<DeserializationResult, DeserializationResult>();
dict ??= new Dictionary<TKey, TValue>();
foreach (var (key, value) in node.Children)
{
var (keyVal, keyResult) = serializationManager.ReadWithValueOrThrow<TKey>(key, context, skipHook);
var (valueResult, valueVal) = serializationManager.ReadWithValueCast<TValue>(typeof(TValue), value, context, skipHook);
dict.Add(keyVal, valueVal!);
mappedFields.Add(keyResult, valueResult);
dict.Add(serializationManager.Read<TKey>(key, context, skipHook),
serializationManager.Read<TValue>(value, context, skipHook));
}
return new DeserializedDictionary<Dictionary<TKey, TValue>, TKey, TValue>(dict, mappedFields, dictInstance => dictInstance);
return dict;
}
ValidationNode ITypeValidator<SortedDictionary<TKey, TValue>, MappingDataNode>.Validate(
@@ -108,46 +105,39 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return InterfaceWrite(serializationManager, value.ToDictionary(k => k.Key, v => v.Value), alwaysWrite, context);
}
DeserializationResult
IReadOnlyDictionary<TKey, TValue>
ITypeReader<IReadOnlyDictionary<TKey, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context)
bool skipHook, ISerializationContext? context, IReadOnlyDictionary<TKey, TValue>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(IReadOnlyDictionary<TKey, TValue>)}. Ignoring...");
var dict = new Dictionary<TKey, TValue>();
var mappedFields = new Dictionary<DeserializationResult, DeserializationResult>();
foreach (var (key, value) in node.Children)
{
var (keyVal, keyResult) = serializationManager.ReadWithValueOrThrow<TKey>(key, context, skipHook);
var (valueResult, valueVal) = serializationManager.ReadWithValueCast<TValue>(typeof(TValue), value, context, skipHook);
dict.Add(keyVal, valueVal!);
mappedFields.Add(keyResult, valueResult);
dict.Add(serializationManager.Read<TKey>(key, context, skipHook), serializationManager.Read<TValue>(value, context, skipHook));
}
return new DeserializedDictionary<IReadOnlyDictionary<TKey, TValue>, TKey, TValue>(dict, mappedFields, dictInstance => dictInstance);
return dict;
}
DeserializationResult
SortedDictionary<TKey, TValue>
ITypeReader<SortedDictionary<TKey, TValue>, MappingDataNode>.Read(
ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context)
bool skipHook, ISerializationContext? context, SortedDictionary<TKey, TValue>? dict)
{
var dict = new SortedDictionary<TKey, TValue>();
var mappedFields = new Dictionary<DeserializationResult, DeserializationResult>();
dict ??= new SortedDictionary<TKey, TValue>();
foreach (var (key, value) in node.Children)
{
var (keyVal, keyResult) = serializationManager.ReadWithValueOrThrow<TKey>(key, context, skipHook);
var (valueResult, valueVal) = serializationManager.ReadWithValueCast<TValue>(typeof(TValue), value, context, skipHook);
dict.Add(keyVal, valueVal!);
mappedFields.Add(keyResult, valueResult);
dict.Add(serializationManager.Read<TKey>(key, context, skipHook), serializationManager.Read<TValue>(value, context, skipHook));
}
return new DeserializedDictionary<SortedDictionary<TKey, TValue>, TKey, TValue>(dict, mappedFields, dictInstance => new SortedDictionary<TKey, TValue>(dictInstance));
return dict;
}
[MustUseReturnValue]

View File

@@ -4,9 +4,9 @@ using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -19,24 +19,20 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
ITypeSerializer<HashSet<T>, SequenceDataNode>,
ITypeSerializer<ImmutableHashSet<T>, SequenceDataNode>
{
DeserializationResult ITypeReader<HashSet<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
HashSet<T> ITypeReader<HashSet<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, HashSet<T>? set)
{
var set = new HashSet<T>();
var mappings = new List<DeserializationResult>();
set ??= new HashSet<T>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(dataNode, context, skipHook);
set.Add(value);
mappings.Add(result);
set.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<HashSet<T>, T>(set, mappings, elements => new HashSet<T>(elements));
return set;
}
ValidationNode ITypeValidator<ImmutableHashSet<T>, SequenceDataNode>.Validate(
@@ -83,25 +79,23 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return sequence;
}
DeserializationResult ITypeReader<ImmutableHashSet<T>, SequenceDataNode>.Read(
ImmutableHashSet<T> ITypeReader<ImmutableHashSet<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, ImmutableHashSet<T>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableHashSet<T>)}. Ignoring...");
var set = ImmutableHashSet.CreateBuilder<T>();
var mappings = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(dataNode, context, skipHook);
set.Add(value);
mappings.Add(result);
set.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<ImmutableHashSet<T>, T>(set.ToImmutable(), mappings, elements => ImmutableHashSet.Create(elements.ToArray()));
return set.ToImmutable();
}
[MustUseReturnValue]

View File

@@ -2,9 +2,9 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Sequence;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -59,23 +59,20 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return WriteInternal(serializationManager, value, alwaysWrite, context);
}
DeserializationResult ITypeReader<List<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
List<T> ITypeReader<List<T>, SequenceDataNode>.Read(ISerializationManager serializationManager,
SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context)
ISerializationContext? context, List<T>? list)
{
var list = new List<T>();
var results = new List<DeserializationResult>();
list ??= new List<T>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(typeof(T), dataNode, context, skipHook);
list.Add(value);
results.Add(result);
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<List<T>, T>(list, results, elements => elements);
return list;
}
ValidationNode ITypeValidator<ImmutableList<T>, SequenceDataNode>.Validate(
@@ -116,59 +113,58 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
return new ValidatedSequenceNode(list);
}
DeserializationResult ITypeReader<IReadOnlyList<T>, SequenceDataNode>.Read(
IReadOnlyList<T> ITypeReader<IReadOnlyList<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context)
bool skipHook, ISerializationContext? context, IReadOnlyList<T>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(IReadOnlySet<T>)}. Ignoring...");
var list = new List<T>();
var results = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(dataNode, context, skipHook);
list.Add(value);
results.Add(result);
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<IReadOnlyList<T>, T>(list, results, l => l);
return list;
}
DeserializationResult ITypeReader<IReadOnlyCollection<T>, SequenceDataNode>.Read(
IReadOnlyCollection<T> ITypeReader<IReadOnlyCollection<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context)
bool skipHook, ISerializationContext? context, IReadOnlyCollection<T>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(IReadOnlyCollection<T>)}. Ignoring...");
var list = new List<T>();
var results = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(dataNode, context, skipHook);
list.Add(value);
results.Add(result);
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<IReadOnlyCollection<T>, T>(list, results, l => l);
return list;
}
DeserializationResult ITypeReader<ImmutableList<T>, SequenceDataNode>.Read(
ImmutableList<T> ITypeReader<ImmutableList<T>, SequenceDataNode>.Read(
ISerializationManager serializationManager, SequenceDataNode node,
IDependencyCollection dependencies,
bool skipHook, ISerializationContext? context)
bool skipHook, ISerializationContext? context, ImmutableList<T>? rawValue)
{
if(rawValue != null)
Logger.Warning($"Provided value to a Read-call for a {nameof(ImmutableList<T>)}. Ignoring...");
var list = ImmutableList.CreateBuilder<T>();
var results = new List<DeserializationResult>();
foreach (var dataNode in node.Sequence)
{
var (value, result) = serializationManager.ReadWithValueOrThrow<T>(dataNode, context, skipHook);
list.Add(value);
results.Add(result);
list.Add(serializationManager.Read<T>(dataNode, context, skipHook));
}
return new DeserializedCollection<ImmutableList<T>,T>(list.ToImmutable(), results, elements => ImmutableList.Create(elements.ToArray()));
return list.ToImmutable();
}
[MustUseReturnValue]

View File

@@ -4,7 +4,6 @@ using System.Linq;
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
@@ -15,19 +14,19 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
[TypeSerializer]
public sealed class ValueTupleSerializer<T1, T2> : ITypeSerializer<ValueTuple<T1, T2>, MappingDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, MappingDataNode node,
public (T1, T2) Read(ISerializationManager serializationManager, MappingDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, (T1, T2) val = default)
{
if (node.Children.Count != 1)
throw new InvalidMappingException("Less than or more than 1 mappings provided to ValueTupleSerializer");
var entry = node.Children.First();
var v1 = serializationManager.ReadValueOrThrow<T1>(entry.Key, context, skipHook);
var v2 = serializationManager.ReadValueOrThrow<T2>(entry.Value, context, skipHook);
var v1 = serializationManager.Read<T1>(entry.Key, context, skipHook, val.Item1);
var v2 = serializationManager.Read<T2>(entry.Value, context, skipHook, val.Item2);
return new DeserializedValue<ValueTuple<T1, T2>>(new ValueTuple<T1, T2>(v1, v2));
return (v1, v2);
}
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,

View File

@@ -4,7 +4,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -15,13 +14,13 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
[TypeSerializer]
public sealed class MapIdSerializer : ITypeSerializer<MapId, ValueDataNode>
{
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
public MapId Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies,
bool skipHook,
ISerializationContext? context = null)
ISerializationContext? context = null, MapId value = default)
{
var val = int.Parse(node.Value, CultureInfo.InvariantCulture);
return new DeserializedValue<MapId>(new MapId(val));
return new MapId(val);
}
public ValidationNode Validate(ISerializationManager serializationManager, ValueDataNode node,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing boolean value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public bool Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, bool value = default)
{
return new DeserializedValue<bool>(bool.Parse(node.Value));
return bool.Parse(node.Value);
}
public DataNode Write(ISerializationManager serializationManager, bool value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing byte value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public byte Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, byte value = default)
{
return new DeserializedValue<byte>(byte.Parse(node.Value, CultureInfo.InvariantCulture));
return byte.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, byte value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing char value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public char Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, char value = default)
{
return new DeserializedValue<char>(char.Parse(node.Value));
return char.Parse(node.Value);
}
public DataNode Write(ISerializationManager serializationManager, char value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing decimal value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public decimal Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, decimal value = default)
{
return new DeserializedValue<decimal>(decimal.Parse(node.Value, CultureInfo.InvariantCulture));
return decimal.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, decimal value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing double value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public double Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, double value = default)
{
return new DeserializedValue<double>(double.Parse(node.Value, CultureInfo.InvariantCulture));
return double.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, double value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing float value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public float Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, float value = default)
{
return new DeserializedValue<float>(float.Parse(node.Value, CultureInfo.InvariantCulture));
return float.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, float value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing int value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public int Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, int value = default)
{
return new DeserializedValue<int>(int.Parse(node.Value, CultureInfo.InvariantCulture));
return int.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, int value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing long value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public long Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, long value = default)
{
return new DeserializedValue<long>(long.Parse(node.Value, CultureInfo.InvariantCulture));
return long.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, long value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing signed byte value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public sbyte Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, sbyte value = default)
{
return new DeserializedValue<sbyte>(sbyte.Parse(node.Value, CultureInfo.InvariantCulture));
return sbyte.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, sbyte value, bool alwaysWrite = false,

View File

@@ -2,7 +2,6 @@
using Robust.Shared.IoC;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.Manager.Result;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
@@ -21,10 +20,10 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Primitive
: new ErrorNode(node, $"Failed parsing short value: {node.Value}");
}
public DeserializationResult Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
public short Read(ISerializationManager serializationManager, ValueDataNode node,
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null, short value = default)
{
return new DeserializedValue<short>(short.Parse(node.Value, CultureInfo.InvariantCulture));
return short.Parse(node.Value, CultureInfo.InvariantCulture);
}
public DataNode Write(ISerializationManager serializationManager, short value, bool alwaysWrite = false,

Some files were not shown because too many files have changed in this diff Show More