mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b146b1b82c | ||
|
|
2f8f4f2f7a | ||
|
|
7365a59bd9 | ||
|
|
37560f663b | ||
|
|
bd489e9218 | ||
|
|
33166e8866 | ||
|
|
ed16032280 | ||
|
|
cf785c886b | ||
|
|
6f28c396cf | ||
|
|
b631f408f2 | ||
|
|
34f4cf9452 | ||
|
|
6a4e4cf3b4 | ||
|
|
8aefa5c53e | ||
|
|
2cfc981aa3 | ||
|
|
4987c324d9 | ||
|
|
5450ddd0ba | ||
|
|
378a10678c | ||
|
|
2e0735b92f | ||
|
|
5756d15333 | ||
|
|
b6f74b8dea | ||
|
|
3800c5707e | ||
|
|
8f49785b4e |
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
<!-- This file automatically reset by Tools/version.py -->
|
||||
|
||||
|
||||
@@ -54,6 +54,53 @@ END TEMPLATE-->
|
||||
*None yet*
|
||||
|
||||
|
||||
## 254.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* Yaml mappings/dictionaries now only support string keys instead of generic nodes
|
||||
* Several MappingDataNode method arguments or return values now use strings instead of a DataNode object
|
||||
* The MappingDataNode class has various helper methods that still accept a ValueDataNode, but these methods are marked as obsolete and may be removed in the future.
|
||||
* yaml validators should use `MappingDataNode.GetKeyNode()` when validating mapping keys, so that errors can print node start & end information
|
||||
* ValueTuple yaml serialization has changed
|
||||
* Previously they would get serialized into a single mapping with one entry (i.e., `{foo : bar }`
|
||||
* Now they serialize into a sequence (i.e., `[foo, bar]`
|
||||
* The ValueTuple serializer will still try to read mappings, but due to the MappingDataNode this may fail if the previously serialized "key" can't be read as a simple string
|
||||
|
||||
### New features
|
||||
|
||||
* Add cvar to disable tile edges.
|
||||
* Add GetContainingContainers method to ContainerSystem to recursively get containers upwards on an entity.
|
||||
|
||||
### Internal
|
||||
|
||||
* Make component lifecycle methods use generics.
|
||||
|
||||
|
||||
## 253.0.0
|
||||
|
||||
### New features
|
||||
|
||||
* Add a new `SerializationManager.PushComposition()` overload that takes in a single parent instead of an array of parents.
|
||||
* `BoundUserInterfaceMessageAttempt` once again gets raised as a broadcast event, in addition to being directed.
|
||||
* This effectively reverts the breaking part of the changes made in v252.0.0
|
||||
* Fix CreateDistanceJoint using an int instead of a float for minimum distance.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* Fix deferred component removal not setting the component's life stage to `ComponentLifeStage.Stopped` if the component has not yet been initialised.
|
||||
* Fix some `EntitySystem.Resolve()` overloads not respecting the optional `logMissing` argument.
|
||||
* Fix screen-space overlays not being useable without first initializing/starting entity manager & systems
|
||||
* ItemList is now significantly optimized. VV's `AddComponent` window in particular should be much faster.
|
||||
* Fix some more MapValidator fields.
|
||||
* Fix popup text overflowing the sides of the screen.
|
||||
* Improve location reporting for non-writeable datafields via analyzer.
|
||||
|
||||
### Other
|
||||
|
||||
* TestPoint now uses generics rather than IPhysShape directly.
|
||||
|
||||
|
||||
## 252.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
@@ -87,4 +87,66 @@ public sealed class DataDefinitionAnalyzerTest
|
||||
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldNoVVReadWriteRule).WithSpan(35, 17, 35, 50).WithArguments("Bad", "Foo")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReadOnlyFieldTest()
|
||||
{
|
||||
const string code = """
|
||||
using System;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Robust.Shared.Serialization.Manager.Attributes
|
||||
{
|
||||
public class DataFieldBaseAttribute : Attribute;
|
||||
public class DataFieldAttribute : DataFieldBaseAttribute;
|
||||
public sealed class DataDefinitionAttribute : Attribute;
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public sealed partial class Foo
|
||||
{
|
||||
[DataField]
|
||||
public readonly int Bad;
|
||||
|
||||
[DataField]
|
||||
public int Good;
|
||||
}
|
||||
""";
|
||||
|
||||
await Verifier(code,
|
||||
// /0/Test0.cs(15,12): error RA0019: Data field Bad in data definition Foo is readonly
|
||||
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldWritableRule).WithSpan(15, 12, 15, 20).WithArguments("Bad", "Foo")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReadOnlyPropertyTest()
|
||||
{
|
||||
const string code = """
|
||||
using System;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Robust.Shared.Serialization.Manager.Attributes
|
||||
{
|
||||
public class DataFieldBaseAttribute : Attribute;
|
||||
public class DataFieldAttribute : DataFieldBaseAttribute;
|
||||
public sealed class DataDefinitionAttribute : Attribute;
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public sealed partial class Foo
|
||||
{
|
||||
[DataField]
|
||||
public int Bad { get; }
|
||||
|
||||
[DataField]
|
||||
public int Good { get; private set; }
|
||||
}
|
||||
""";
|
||||
|
||||
await Verifier(code,
|
||||
// /0/Test0.cs(15,20): error RA0020: Data field property Bad in data definition Foo does not have a setter
|
||||
VerifyCS.Diagnostic(DataDefinitionAnalyzer.DataFieldPropertyWritableRule).WithSpan(15, 20, 15, 28).WithArguments("Bad", "Foo")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
"Make sure to mark any type containing a nested data definition as partial."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldWritableRule = new(
|
||||
public static readonly DiagnosticDescriptor DataFieldWritableRule = new(
|
||||
Diagnostics.IdDataFieldWritable,
|
||||
"Data field must not be readonly",
|
||||
"Data field {0} in data definition {1} is readonly",
|
||||
@@ -51,7 +51,7 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
"Make sure to remove the readonly modifier."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
|
||||
public static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
|
||||
Diagnostics.IdDataFieldPropertyWritable,
|
||||
"Data field property must have a setter",
|
||||
"Data field property {0} in data definition {1} does not have a setter",
|
||||
@@ -149,7 +149,8 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
|
||||
if (IsReadOnlyDataField(type, fieldSymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
|
||||
TryGetModifierLocation(field, SyntaxKind.ReadOnlyKeyword, out var location);
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, location, fieldSymbol.Name, type.Name));
|
||||
}
|
||||
|
||||
if (HasRedundantTag(fieldSymbol))
|
||||
@@ -185,7 +186,8 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
|
||||
if (IsReadOnlyDataField(type, propertySymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
|
||||
var location = property.AccessorList != null ? property.AccessorList.GetLocation() : property.GetLocation();
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, location, propertySymbol.Name, type.Name));
|
||||
}
|
||||
|
||||
if (HasRedundantTag(propertySymbol))
|
||||
@@ -285,6 +287,20 @@ public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryGetModifierLocation(MemberDeclarationSyntax syntax, SyntaxKind modifierKind, out Location location)
|
||||
{
|
||||
foreach (var modifier in syntax.Modifiers)
|
||||
{
|
||||
if (modifier.IsKind(modifierKind))
|
||||
{
|
||||
location = modifier.GetLocation();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
location = syntax.GetLocation();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsReadOnlyMember(ITypeSymbol type, ISymbol member)
|
||||
{
|
||||
if (member is IFieldSymbol field)
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#if DEBUG
|
||||
using Robust.Client.Debugging;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
public sealed class DebugAnchoredCommand : LocalizedCommands
|
||||
public sealed class DebugAnchoredCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly DebugAnchoringSystem _system = default!;
|
||||
|
||||
public override string Command => "showanchored";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<DebugAnchoringSystem>().Enabled ^= true;
|
||||
_system.Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#if DEBUG
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
internal sealed class LightDebugCommand : LocalizedCommands
|
||||
internal sealed class LightDebugCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly DebugLightTreeSystem _system = default!;
|
||||
|
||||
public override string Command => "lightbb";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<DebugLightTreeSystem>().Enabled ^= true;
|
||||
_system.Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Console.Commands
|
||||
{
|
||||
public sealed class ShowPlayerVelocityCommand : LocalizedCommands
|
||||
public sealed class ShowPlayerVelocityCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystems = default!;
|
||||
[Dependency] private readonly ShowPlayerVelocityDebugSystem _system = default!;
|
||||
|
||||
public override string Command => "showplayervelocity";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
_entitySystems.GetEntitySystem<ShowPlayerVelocityDebugSystem>().Enabled ^= true;
|
||||
_system.Enabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,21 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public sealed class ShowSpriteBBCommand : LocalizedCommands
|
||||
public sealed class ShowSpriteBBCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly SpriteBoundsSystem _system = default!;
|
||||
|
||||
public override string Command => "showspritebb";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<SpriteBoundsSystem>().Enabled ^= true;
|
||||
_system.Enabled ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SpriteBoundsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||
[Dependency] private readonly SpriteTreeSystem _spriteTree = default!;
|
||||
|
||||
@@ -40,7 +42,7 @@ namespace Robust.Client.GameObjects
|
||||
if (_enabled)
|
||||
{
|
||||
DebugTools.AssertNull(_overlay);
|
||||
_overlay = new SpriteBoundsOverlay(_spriteTree, _entityManager);
|
||||
_overlay = new SpriteBoundsOverlay(_spriteTree, _xformSystem);
|
||||
_overlayManager.AddOverlay(_overlay);
|
||||
}
|
||||
else
|
||||
@@ -59,13 +61,13 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly SharedTransformSystem _xformSystem;
|
||||
private SpriteTreeSystem _renderTree;
|
||||
|
||||
public SpriteBoundsOverlay(SpriteTreeSystem renderTree, IEntityManager entityManager)
|
||||
public SpriteBoundsOverlay(SpriteTreeSystem renderTree, SharedTransformSystem xformSystem)
|
||||
{
|
||||
_renderTree = renderTree;
|
||||
_entityManager = entityManager;
|
||||
_xformSystem = xformSystem;
|
||||
}
|
||||
|
||||
protected internal override void Draw(in OverlayDrawArgs args)
|
||||
@@ -76,7 +78,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
foreach (var (sprite, xform) in _renderTree.QueryAabb(currentMap, viewport))
|
||||
{
|
||||
var (worldPos, worldRot) = xform.GetWorldPositionRotation();
|
||||
var (worldPos, worldRot) = _xformSystem.GetWorldPositionRotation(xform);
|
||||
var bounds = sprite.CalculateRotatedBoundingBox(worldPos, worldRot, args.Viewport.Eye?.Rotation ?? default);
|
||||
|
||||
// Get scaled down bounds used to indicate the "south" of a sprite.
|
||||
|
||||
@@ -303,7 +303,7 @@ namespace Robust.Client.GameObjects
|
||||
while (parent.IsValid() && (!spriteOccluded || !lightOccluded))
|
||||
{
|
||||
var parentXform = TransformQuery.GetComponent(parent);
|
||||
if (TryComp<ContainerManagerComponent>(parent, out var manager) && manager.TryGetContainer(child, out var container))
|
||||
if (TryComp<ContainerManagerComponent>(parent, out var manager) && TryGetContainingContainer(parent, child, out var container, manager))
|
||||
{
|
||||
spriteOccluded = spriteOccluded || !container.ShowContents;
|
||||
lightOccluded = lightOccluded || container.OccludesLight;
|
||||
@@ -344,7 +344,7 @@ namespace Robust.Client.GameObjects
|
||||
var childLightOccluded = lightOccluded;
|
||||
|
||||
// We already know either sprite or light is not occluding so need to check container.
|
||||
if (manager.TryGetContainer(child, out var container))
|
||||
if (TryGetContainingContainer(entity, child, out var container, manager))
|
||||
{
|
||||
childSpriteOccluded = childSpriteOccluded || !container.ShowContents;
|
||||
childLightOccluded = childLightOccluded || container.OccludesLight;
|
||||
|
||||
@@ -2,24 +2,24 @@ using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Robust.Shared.Utility;
|
||||
using Color = Robust.Shared.Maths.Color;
|
||||
|
||||
namespace Robust.Client.GameObjects;
|
||||
|
||||
public sealed class DebugEntityLookupCommand : LocalizedCommands
|
||||
public sealed class DebugEntityLookupCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly DebugEntityLookupSystem _system = default!;
|
||||
|
||||
public override string Command => "togglelookup";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
EntitySystem.Get<DebugEntityLookupSystem>().Enabled ^= true;
|
||||
_system.Enabled ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace Robust.Client.GameObjects
|
||||
if (_enabled)
|
||||
{
|
||||
_lightOverlay = new DebugLightOverlay(
|
||||
EntitySystem.Get<EntityLookupSystem>(),
|
||||
EntityManager.System<EntityLookupSystem>(),
|
||||
IoCManager.Resolve<IEyeManager>(),
|
||||
IoCManager.Resolve<IMapManager>(),
|
||||
Get<LightTreeSystem>());
|
||||
EntityManager.System<LightTreeSystem>());
|
||||
|
||||
overlayManager.AddOverlay(_lightOverlay);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public sealed class EyeSystem : SharedEyeSystem
|
||||
eyeComponent.Target = null;
|
||||
}
|
||||
|
||||
eyeComponent.Eye.Position = xform.MapPosition;
|
||||
eyeComponent.Eye.Position = TransformSystem.GetMapCoordinates(xform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,8 @@ namespace Robust.Client.Graphics
|
||||
/// <inheritdoc />
|
||||
public ScreenCoordinates CoordinatesToScreen(EntityCoordinates point)
|
||||
{
|
||||
return MapToScreen(point.ToMap(_entityManager, _entityManager.System<SharedTransformSystem>()));
|
||||
var transformSystem = _entityManager.System<SharedTransformSystem>();
|
||||
return MapToScreen(transformSystem.ToMapCoordinates(point));
|
||||
}
|
||||
|
||||
public ScreenCoordinates MapToScreen(MapCoordinates point)
|
||||
|
||||
@@ -30,6 +30,23 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private int _indicesPerChunk(MapChunk chunk) => chunk.ChunkSize * chunk.ChunkSize * GetQuadBatchIndexCount();
|
||||
|
||||
private List<Entity<MapGridComponent>> _grids = new();
|
||||
private bool _drawTileEdges;
|
||||
|
||||
private void RenderTileEdgesChanges(bool value)
|
||||
{
|
||||
_drawTileEdges = value;
|
||||
if (!value)
|
||||
return;
|
||||
|
||||
// Dirty all Edges
|
||||
foreach (var gridData in _mapChunkData.Values)
|
||||
{
|
||||
foreach (var chunk in gridData.Values)
|
||||
{
|
||||
chunk.EdgeDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _drawGrids(Viewport viewport, Box2 worldAABB, Box2Rotated worldBounds, IEye eye)
|
||||
{
|
||||
@@ -81,6 +98,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
_updateChunkMesh(mapGrid, chunk, datum);
|
||||
|
||||
if (!_drawTileEdges)
|
||||
continue;
|
||||
|
||||
// Dirty edge tiles for next step.
|
||||
datum.EdgeDirty = true;
|
||||
|
||||
@@ -99,17 +119,16 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
enumerator = mapSystem.GetMapChunks(mapGrid.Owner, mapGrid.Comp, worldBounds);
|
||||
|
||||
// Handle edge sprites.
|
||||
while (enumerator.MoveNext(out var chunk))
|
||||
if (_drawTileEdges)
|
||||
{
|
||||
var datum = data[chunk.Indices];
|
||||
|
||||
if (!datum.EdgeDirty)
|
||||
continue;
|
||||
|
||||
_updateChunkEdges(mapGrid, chunk, datum);
|
||||
enumerator = mapSystem.GetMapChunks(mapGrid.Owner, mapGrid.Comp, worldBounds);
|
||||
while (enumerator.MoveNext(out var chunk))
|
||||
{
|
||||
var datum = data[chunk.Indices];
|
||||
if (datum.EdgeDirty)
|
||||
_updateChunkEdges(mapGrid, chunk, datum);
|
||||
}
|
||||
}
|
||||
|
||||
enumerator = mapSystem.GetMapChunks(mapGrid.Owner, mapGrid.Comp, worldBounds);
|
||||
@@ -129,7 +148,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
if (datum.EdgeCount > 0)
|
||||
if (_drawTileEdges && datum.EdgeCount > 0)
|
||||
{
|
||||
BindVertexArray(datum.EdgeVAO);
|
||||
CheckGlError();
|
||||
@@ -138,7 +157,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
GL.DrawElements(GetQuadGLPrimitiveType(), datum.EdgeCount * GetQuadBatchIndexCount(), DrawElementsType.UnsignedShort, 0);
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
requiresFlush = false;
|
||||
@@ -274,7 +292,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
var gridX = x + chunkOriginScaled.X;
|
||||
var gridY = y + chunkOriginScaled.Y;
|
||||
var tile = chunk.GetTile(x, y);
|
||||
var tileDef = _tileDefinitionManager[tile.TypeId];
|
||||
if (!_tileDefinitionManager.TryGetDefinition(tile.TypeId, out var tileDef))
|
||||
continue;
|
||||
|
||||
// Edge render
|
||||
for (var nx = -1; nx <= 1; nx++)
|
||||
@@ -288,7 +307,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
if (!maps.TryGetTile(grid.Comp, neighborIndices, out var neighborTile))
|
||||
continue;
|
||||
|
||||
var neighborDef = _tileDefinitionManager[neighborTile.TypeId];
|
||||
if (!_tileDefinitionManager.TryGetDefinition(neighborTile.TypeId, out var neighborDef))
|
||||
continue;
|
||||
|
||||
// If it's the same tile then no edge to be drawn.
|
||||
if (tile.TypeId == neighborTile.TypeId || neighborDef.EdgeSprites.Count == 0)
|
||||
|
||||
@@ -123,9 +123,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private void RenderSingleWorldOverlay(Overlay overlay, Viewport vp, OverlaySpace space, in Box2 worldBox, in Box2Rotated worldBounds)
|
||||
{
|
||||
// Check that entity manager has started.
|
||||
// This is required for us to be able to use MapSystem.
|
||||
DebugTools.Assert(_entityManager.Started, "Entity manager should be started/initialized before rendering world-space overlays");
|
||||
|
||||
DebugTools.Assert(space != OverlaySpace.ScreenSpaceBelowWorld && space != OverlaySpace.ScreenSpace);
|
||||
|
||||
var mapId = vp.Eye!.Position.MapId;
|
||||
var mapId = vp.Eye?.Position.MapId ?? MapId.Nullspace;
|
||||
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), _mapSystem.GetMapOrInvalid(mapId), mapId, worldBox, worldBounds);
|
||||
|
||||
if (!overlay.BeforeDraw(args))
|
||||
@@ -152,6 +156,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private void RenderOverlays(Viewport vp, OverlaySpace space, in Box2 worldBox, in Box2Rotated worldBounds)
|
||||
{
|
||||
DebugTools.Assert(space != OverlaySpace.ScreenSpaceBelowWorld && space != OverlaySpace.ScreenSpace);
|
||||
using (DebugGroup($"Overlays: {space}"))
|
||||
{
|
||||
foreach (var overlay in GetOverlaysForSpace(space))
|
||||
@@ -176,9 +181,18 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
var worldBounds = CalcWorldBounds(vp);
|
||||
var worldAABB = worldBounds.CalcBoundingBox();
|
||||
var mapId = vp.Eye!.Position.MapId;
|
||||
var mapId = vp.Eye?.Position.MapId ?? MapId.Nullspace;
|
||||
var mapUid = EntityUid.Invalid;
|
||||
|
||||
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, _mapSystem.GetMapOrInvalid(mapId), mapId, worldAABB, worldBounds);
|
||||
// Screen space overlays may be getting used before entity manager & entity systems have been initialized.
|
||||
// This might mean that _mapSystem is currently null.
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||
if (_entityManager.Started && _mapSystem != null)
|
||||
mapUid = _mapSystem.GetMapOrInvalid(mapId);
|
||||
|
||||
DebugTools.Assert(_mapSystem != null || !_entityManager.Started);
|
||||
|
||||
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, mapUid, mapId, worldAABB, worldBounds);
|
||||
|
||||
foreach (var overlay in list)
|
||||
{
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_cfg.OnValueChanged(CVars.LightSoftShadows, SoftShadowsChanged, true);
|
||||
_cfg.OnValueChanged(CVars.MaxLightCount, MaxLightsChanged, true);
|
||||
_cfg.OnValueChanged(CVars.MaxOccluderCount, MaxOccludersChanged, true);
|
||||
_cfg.OnValueChanged(CVars.RenderTileEdges, RenderTileEdgesChanges, true);
|
||||
// I can't be bothered to tear down and set these threads up in a cvar change handler.
|
||||
|
||||
// Windows and Linux can be trusted to not explode with threaded windowing,
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Robust.Client.Input
|
||||
[Dependency] private readonly IUserInterfaceManagerInternal _uiMgr = default!;
|
||||
[Dependency] private readonly IConsoleHost _console = default!;
|
||||
[Dependency] private readonly ISerializationManager _serialization = default!;
|
||||
private ISawmill _logger = default!;
|
||||
|
||||
private bool _currentlyFindingViewport;
|
||||
|
||||
@@ -114,6 +115,8 @@ namespace Robust.Client.Input
|
||||
/// <inheritdoc />
|
||||
public void Initialize()
|
||||
{
|
||||
_logger = Logger.GetSawmill("input");
|
||||
|
||||
NetworkBindMap = new BoundKeyMap(_reflectionManager);
|
||||
NetworkBindMap.PopulateKeyFunctionsMap();
|
||||
|
||||
@@ -130,7 +133,7 @@ namespace Robust.Client.Input
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorS("input", "Failed to load user keybindings: " + e);
|
||||
_logger.Error("Failed to load user keybindings: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,8 +534,7 @@ namespace Robust.Client.Input
|
||||
|
||||
if (reg.Type != KeyBindingType.Command && !NetworkBindMap.FunctionExists(reg.Function.FunctionName))
|
||||
{
|
||||
Logger.DebugS("input", "Key function in {0} does not exist: '{1}'.", file,
|
||||
reg.Function);
|
||||
_logger.Debug("Key function in {0} does not exist: '{1}'.", file, reg.Function);
|
||||
invalid = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,13 @@ namespace Robust.Client.Placement.Modes
|
||||
return;
|
||||
}
|
||||
|
||||
var mapId = MouseCoords.GetMapId(pManager.EntityManager);
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
var mapId = transformSys.GetMapId(MouseCoords);
|
||||
|
||||
var snapToEntities = EntitySystem.Get<EntityLookupSystem>().GetEntitiesInRange(MouseCoords, SnapToRange)
|
||||
var snapToEntities = pManager.EntityManager.System<EntityLookupSystem>()
|
||||
.GetEntitiesInRange(MouseCoords, SnapToRange)
|
||||
.Where(entity => pManager.EntityManager.GetComponent<MetaDataComponent>(entity).EntityPrototype == pManager.CurrentPrototype && pManager.EntityManager.GetComponent<TransformComponent>(entity).MapID == mapId)
|
||||
.OrderBy(entity => (pManager.EntityManager.GetComponent<TransformComponent>(entity).WorldPosition - MouseCoords.ToMapPos(pManager.EntityManager, pManager.EntityManager.System<SharedTransformSystem>())).LengthSquared())
|
||||
.OrderBy(entity => (transformSys.GetWorldPosition(entity) - transformSys.ToMapCoordinates(MouseCoords).Position).LengthSquared())
|
||||
.ToList();
|
||||
|
||||
if (snapToEntities.Count == 0)
|
||||
@@ -51,10 +53,11 @@ namespace Robust.Client.Placement.Modes
|
||||
|
||||
var closestBounds = component.BaseRSI.Size;
|
||||
|
||||
var closestPos = transformSys.GetWorldPosition(closestTransform);
|
||||
var closestRect =
|
||||
Box2.FromDimensions(
|
||||
closestTransform.WorldPosition.X - closestBounds.X / 2f,
|
||||
closestTransform.WorldPosition.Y - closestBounds.Y / 2f,
|
||||
closestPos.X - closestBounds.X / 2f,
|
||||
closestPos.Y - closestBounds.Y / 2f,
|
||||
closestBounds.X, closestBounds.Y);
|
||||
|
||||
var sides = new[]
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace Robust.Client.Placement.Modes
|
||||
{
|
||||
MouseCoords = ScreenToCursorGrid(mouseScreen);
|
||||
|
||||
var gridIdOpt = MouseCoords.GetGridUid(pManager.EntityManager);
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
var gridIdOpt = transformSys.GetGrid(MouseCoords);
|
||||
SnapSize = 1f;
|
||||
if (gridIdOpt is EntityUid gridId && gridId.IsValid())
|
||||
{
|
||||
|
||||
@@ -16,8 +16,10 @@ namespace Robust.Client.Placement.Modes
|
||||
{
|
||||
MouseCoords = ScreenToCursorGrid(mouseScreen);
|
||||
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
|
||||
var tileSize = 1f;
|
||||
var gridIdOpt = MouseCoords.GetGridUid(pManager.EntityManager);
|
||||
var gridIdOpt = transformSys.GetGrid(MouseCoords);
|
||||
|
||||
if (gridIdOpt is EntityUid gridId && gridId.IsValid())
|
||||
{
|
||||
|
||||
@@ -16,9 +16,11 @@ namespace Robust.Client.Placement.Modes
|
||||
{
|
||||
MouseCoords = ScreenToCursorGrid(mouseScreen);
|
||||
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
|
||||
var tileSize = 1f;
|
||||
|
||||
var gridIdOpt = MouseCoords.GetGridUid(pManager.EntityManager);
|
||||
var gridIdOpt = transformSys.GetGrid(MouseCoords);
|
||||
if (gridIdOpt is EntityUid gridId && gridId.IsValid())
|
||||
{
|
||||
var mapGrid = pManager.EntityManager.GetComponent<MapGridComponent>(gridId);
|
||||
|
||||
@@ -121,8 +121,8 @@ namespace Robust.Client.Placement
|
||||
{
|
||||
if (!coordinate.IsValid(pManager.EntityManager))
|
||||
return; // Just some paranoia just in case
|
||||
var worldPos = coordinate.ToMapPos(pManager.EntityManager, transformSys);
|
||||
var worldRot = pManager.EntityManager.GetComponent<TransformComponent>(coordinate.EntityId).WorldRotation + dirAng;
|
||||
var worldPos = transformSys.ToMapCoordinates(coordinate).Position;
|
||||
var worldRot = transformSys.GetWorldRotation(coordinate.EntityId) + dirAng;
|
||||
|
||||
sprite.Color = IsValidPosition(coordinate) ? ValidPlaceColor : InvalidPlaceColor;
|
||||
var rot = args.Viewport.Eye?.Rotation ?? default;
|
||||
@@ -230,7 +230,7 @@ namespace Robust.Client.Placement
|
||||
|
||||
var range = pManager.CurrentPermission!.Range;
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
if (range > 0 && !pManager.EntityManager.GetComponent<TransformComponent>(controlled).Coordinates.InRange(pManager.EntityManager, transformSys, coordinates, range))
|
||||
if (range > 0 && !transformSys.InRange(pManager.EntityManager.GetComponent<TransformComponent>(controlled).Coordinates, coordinates, range))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -239,7 +239,7 @@ namespace Robust.Client.Placement
|
||||
{
|
||||
var bounds = pManager.ColliderAABB;
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
var mapCoords = coordinates.ToMap(pManager.EntityManager, transformSys);
|
||||
var mapCoords = transformSys.ToMapCoordinates(coordinates);
|
||||
var (x, y) = mapCoords.Position;
|
||||
|
||||
var collisionBox = Box2.FromDimensions(
|
||||
@@ -248,7 +248,9 @@ namespace Robust.Client.Placement
|
||||
bounds.Width,
|
||||
bounds.Height);
|
||||
|
||||
return EntitySystem.Get<SharedPhysicsSystem>().TryCollideRect(collisionBox, mapCoords.MapId);
|
||||
return pManager.EntityManager
|
||||
.System<SharedPhysicsSystem>()
|
||||
.TryCollideRect(collisionBox, mapCoords.MapId);
|
||||
}
|
||||
|
||||
protected Vector2 ScreenToWorld(Vector2 point)
|
||||
@@ -265,10 +267,8 @@ namespace Robust.Client.Placement
|
||||
{
|
||||
var mapCoords = pManager.EyeManager.PixelToMap(coords.Position);
|
||||
var transformSys = pManager.EntityManager.System<SharedTransformSystem>();
|
||||
|
||||
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid))
|
||||
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var gridUid, out _))
|
||||
{
|
||||
|
||||
return transformSys.ToCoordinates(mapCoords);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Robust.Client.Timing;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -56,7 +54,7 @@ namespace Robust.Client.Prototypes
|
||||
using var _ = _timing.StartStateApplicationArea();
|
||||
ReloadPrototypes([file]);
|
||||
|
||||
Logger.Info($"Reloaded prototypes in {sw.ElapsedMilliseconds} ms");
|
||||
Sawmill.Info($"Reloaded prototypes in {sw.ElapsedMilliseconds} ms");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Numerics;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -83,9 +84,23 @@ namespace Robust.Client.UserInterface.Controls
|
||||
_updateScrollbarVisibility();
|
||||
}
|
||||
|
||||
public void Add(IEnumerable<Item> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
if(item.Owner != this) throw new ArgumentException("Item is owned by another ItemList!");
|
||||
|
||||
_itemList.Add(item);
|
||||
|
||||
item.OnSelected += Select;
|
||||
item.OnDeselected += Deselect;
|
||||
}
|
||||
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
public void Add(Item item)
|
||||
{
|
||||
if (item == null) return;
|
||||
if(item.Owner != this) throw new ArgumentException("Item is owned by another ItemList!");
|
||||
|
||||
_itemList.Add(item);
|
||||
@@ -93,9 +108,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
item.OnSelected += Select;
|
||||
item.OnDeselected += Deselect;
|
||||
|
||||
RecalculateContentHeight();
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
_scrollBar.MoveToEnd();
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
public void AddItems(IEnumerable<string> texts, Texture? icon = null, bool selectable = true, object? metadata = null)
|
||||
{
|
||||
var items = new ValueList<Item>();
|
||||
|
||||
foreach (var text in texts)
|
||||
{
|
||||
items.Add(new Item(this) {Text = text, Icon = icon, Selectable = selectable, Metadata = metadata});
|
||||
}
|
||||
|
||||
Add(items);
|
||||
}
|
||||
|
||||
public Item AddItem(string text, Texture? icon = null, bool selectable = true, object? metadata = null)
|
||||
@@ -107,11 +132,15 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var item in _itemList.ToArray())
|
||||
// Handle this manually so we can just clear all at once.
|
||||
foreach (var item in _itemList)
|
||||
{
|
||||
Remove(item);
|
||||
item.OnSelected -= Select;
|
||||
item.OnDeselected -= Deselect;
|
||||
}
|
||||
|
||||
_itemList.Clear();
|
||||
Recalculate();
|
||||
_totalContentHeight = 0;
|
||||
}
|
||||
|
||||
@@ -125,25 +154,35 @@ namespace Robust.Client.UserInterface.Controls
|
||||
_itemList.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
private void InternalRemoveAt(int index)
|
||||
{
|
||||
if (_itemList.Count <= index)
|
||||
return;
|
||||
|
||||
// If you modify this then also make sure to update Clear!
|
||||
var item = _itemList[index];
|
||||
_itemList.RemoveAt(index);
|
||||
|
||||
item.OnSelected -= Select;
|
||||
item.OnDeselected -= Deselect;
|
||||
}
|
||||
|
||||
public bool Remove(Item item)
|
||||
{
|
||||
if (item == null) return false;
|
||||
|
||||
var value = _itemList.Remove(item);
|
||||
|
||||
item.OnSelected -= Select;
|
||||
item.OnDeselected -= Deselect;
|
||||
|
||||
RecalculateContentHeight();
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
_scrollBar.MoveToEnd();
|
||||
Recalculate();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Remove(this[index]);
|
||||
InternalRemoveAt(index);
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
public IEnumerator<Item> GetEnumerator()
|
||||
@@ -161,16 +200,24 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return _itemList.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, Item item)
|
||||
private void InternalInsert(int index, Item item)
|
||||
{
|
||||
if (item == null) return;
|
||||
if(item.Owner != this) throw new ArgumentException("Item is owned by another ItemList!");
|
||||
|
||||
_itemList.Insert(index, item);
|
||||
|
||||
item.OnSelected += Select;
|
||||
item.OnDeselected += Deselect;
|
||||
}
|
||||
|
||||
public void Insert(int index, Item item)
|
||||
{
|
||||
InternalInsert(index, item);
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
private void Recalculate()
|
||||
{
|
||||
RecalculateContentHeight();
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
_scrollBar.MoveToEnd();
|
||||
@@ -191,7 +238,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
SetItems(newItems, (a,b) => string.Compare(a.Text, b.Text));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// This variant allows for a custom equality operator to compare items, when
|
||||
/// comparing the Item text is not desired.
|
||||
@@ -215,13 +261,13 @@ namespace Robust.Client.UserInterface.Controls
|
||||
else if (cmpResult > 0)
|
||||
{
|
||||
// Item exists in our list, but not in `newItems`. Remove it.
|
||||
RemoveAt(i);
|
||||
InternalRemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
else if (cmpResult < 0)
|
||||
{
|
||||
// A new entry which doesn't exist in our list. Insert it.
|
||||
Insert(i + 1, newItems[j]);
|
||||
InternalInsert(i + 1, newItems[j]);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
@@ -229,16 +275,18 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// Any remaining items in our list don't exist in `newItems` so remove them
|
||||
while (i >= 0)
|
||||
{
|
||||
RemoveAt(i);
|
||||
InternalRemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
|
||||
// And finally, any remaining items in `newItems` don't exist in our list. Create them.
|
||||
while (j >= 0)
|
||||
{
|
||||
Insert(0, newItems[j]);
|
||||
InternalInsert(0, newItems[j]);
|
||||
j--;
|
||||
}
|
||||
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
// Without this attribute, this would compile into a property called "Item", causing problems with the Item class.
|
||||
@@ -290,9 +338,12 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public void ClearSelected(int? except = null)
|
||||
{
|
||||
foreach (var item in GetSelected())
|
||||
for (var i = 0; i < _itemList.Count; i++)
|
||||
{
|
||||
if(IndexOf(item) == except) continue;
|
||||
if (i == except)
|
||||
continue;
|
||||
|
||||
var item = _itemList[i];
|
||||
item.Selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Profiling;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface;
|
||||
internal sealed partial class UserInterfaceManager
|
||||
@@ -61,7 +61,7 @@ internal sealed partial class UserInterfaceManager
|
||||
Title = string.IsNullOrEmpty(title) ? Loc.GetString("popup-title") : title,
|
||||
};
|
||||
|
||||
var label = new Label { Text = contents };
|
||||
var label = new RichTextLabel { Text = $"[color=white]{FormattedMessage.EscapeText(contents)}[/color]" };
|
||||
|
||||
var vBox = new BoxContainer
|
||||
{
|
||||
|
||||
@@ -2,11 +2,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.ViewVariables
|
||||
{
|
||||
@@ -51,15 +55,19 @@ namespace Robust.Client.ViewVariables
|
||||
_lastSearch = search;
|
||||
EntryItemList.ClearSelected();
|
||||
EntryItemList.Clear();
|
||||
|
||||
AddButton.Disabled = true;
|
||||
var items = new ValueList<string>();
|
||||
|
||||
foreach (var component in _entries)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(search) && !component.Contains(search, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
|
||||
EntryItemList.AddItem(component);
|
||||
items.Add(component);
|
||||
}
|
||||
|
||||
EntryItemList.AddItems(items);
|
||||
}
|
||||
|
||||
private void OnSearchTextChanged(LineEdit.LineEditEventArgs obj)
|
||||
|
||||
@@ -268,7 +268,6 @@ namespace Robust.Server.Physics
|
||||
newGrids[i] = newGridUid;
|
||||
|
||||
// Keep same origin / velocity etc; this makes updating a lot faster and easier.
|
||||
_xformSystem.SetWorldPosition(newGridXform, gridPos);
|
||||
_xformSystem.SetWorldPositionRotation(newGridUid, gridPos, gridRot, newGridXform);
|
||||
var splitBody = _bodyQuery.GetComponent(newGridUid);
|
||||
_physics.SetLinearVelocity(newGridUid, mapBody.LinearVelocity, body: splitBody);
|
||||
|
||||
@@ -968,6 +968,13 @@ namespace Robust.Shared
|
||||
public static readonly CVarDef<string> RenderFOVColor =
|
||||
CVarDef.Create("render.fov_color", Color.Black.ToHex(), CVar.REPLICATED | CVar.SERVER);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to render tile edges, which is where some tiles can partially overlap other adjacent tiles on a grid.
|
||||
/// E.g., snow tiles partly extending beyond their own tile to blend together with different adjacent tiles types.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> RenderTileEdges =
|
||||
CVarDef.Create("render.tile_edges", true, CVar.CLIENTONLY);
|
||||
|
||||
/*
|
||||
* CONTROLS
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ sealed class AddMapCommand : LocalizedEntityCommands
|
||||
|
||||
sealed class RemoveMapCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IMapManager _map = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _systems = default!;
|
||||
|
||||
public override string Command => "rmmap";
|
||||
public override bool RequireServerOrSingleplayer => true;
|
||||
@@ -51,14 +51,15 @@ sealed class RemoveMapCommand : LocalizedCommands
|
||||
}
|
||||
|
||||
var mapId = new MapId(int.Parse(args[0]));
|
||||
var mapSystem = _systems.GetEntitySystem<SharedMapSystem>();
|
||||
|
||||
if (!_map.MapExists(mapId))
|
||||
if (!mapSystem.MapExists(mapId))
|
||||
{
|
||||
shell.WriteError($"Map {mapId.Value} does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
_map.DeleteMap(mapId);
|
||||
mapSystem.DeleteMap(mapId);
|
||||
shell.WriteLine($"Map {mapId.Value} was removed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ internal sealed class TeleportCommand : LocalizedEntityCommands
|
||||
[Dependency] private readonly IMapManager _map = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
public override string Command => "tp";
|
||||
public override bool RequireServerOrSingleplayer => true;
|
||||
@@ -46,7 +47,7 @@ internal sealed class TeleportCommand : LocalizedEntityCommands
|
||||
else
|
||||
mapId = transform.MapID;
|
||||
|
||||
if (!_map.MapExists(mapId))
|
||||
if (!_mapSystem.MapExists(mapId))
|
||||
{
|
||||
shell.WriteError($"Map {mapId} doesn't exist!");
|
||||
return;
|
||||
@@ -60,9 +61,11 @@ internal sealed class TeleportCommand : LocalizedEntityCommands
|
||||
}
|
||||
else
|
||||
{
|
||||
var mapEnt = _map.GetMapEntityIdOrThrow(mapId);
|
||||
_transform.SetWorldPosition((entity, transform), position);
|
||||
_transform.SetParent(entity, transform, mapEnt);
|
||||
if (_mapSystem.TryGetMap(mapId, out var mapEnt))
|
||||
{
|
||||
_transform.SetWorldPosition((entity, transform), position);
|
||||
_transform.SetParent(entity, transform, mapEnt.Value);
|
||||
}
|
||||
}
|
||||
|
||||
shell.WriteLine($"Teleported {shell.Player} to {mapId}:{posX},{posY}.");
|
||||
|
||||
@@ -530,6 +530,39 @@ namespace Robust.Shared.Containers
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full chain of containers containing the entity passed in, from innermost to outermost.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The resulting collection includes the container directly containing the entity (if any),
|
||||
/// the container containing that container, and so on until reaching the outermost container.
|
||||
/// </remarks>
|
||||
public IEnumerable<BaseContainer> GetContainingContainers(Entity<TransformComponent?> ent)
|
||||
{
|
||||
if (!ent.Owner.IsValid())
|
||||
yield break;
|
||||
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
yield break;
|
||||
|
||||
var child = ent.Owner;
|
||||
var parent = ent.Comp.ParentUid;
|
||||
|
||||
while (parent.IsValid())
|
||||
{
|
||||
if (((MetaQuery.GetComponent(child).Flags & MetaDataFlags.InContainer) == MetaDataFlags.InContainer) &&
|
||||
_managerQuery.TryGetComponent(parent, out var conManager) &&
|
||||
TryGetContainingContainer(parent, child, out var parentContainer, conManager))
|
||||
{
|
||||
yield return parentContainer;
|
||||
}
|
||||
|
||||
var parentXform = TransformQuery.GetComponent(parent);
|
||||
child = parent;
|
||||
parent = parentXform.ParentUid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top-most container in the hierarchy for this entity, if it exists.
|
||||
/// </summary>
|
||||
|
||||
@@ -475,7 +475,7 @@ public sealed class EntityDeserializer :
|
||||
|
||||
foreach (var (key, value) in tileMap.Children)
|
||||
{
|
||||
var yamlTileId = ((ValueDataNode) key).AsInt();
|
||||
var yamlTileId = int.Parse(key, CultureInfo.InvariantCulture);
|
||||
var tileName = ((ValueDataNode) value).Value;
|
||||
if (migrations.TryGetValue(tileName, out var @new))
|
||||
tileName = @new;
|
||||
|
||||
@@ -155,9 +155,9 @@ public sealed class EntitySerializer : ISerializationContext,
|
||||
public event IsSerializableDelegate? OnIsSerializeable;
|
||||
public delegate void IsSerializableDelegate(Entity<MetaDataComponent> ent, ref bool serializable);
|
||||
|
||||
public EntitySerializer(IDependencyCollection _dependency, SerializationOptions options)
|
||||
public EntitySerializer(IDependencyCollection dependency, SerializationOptions options)
|
||||
{
|
||||
_dependency.InjectDependencies(this);
|
||||
dependency.InjectDependencies(this);
|
||||
|
||||
_log = _logMan.GetSawmill("entity_serializer");
|
||||
SerializerProvider.RegisterSerializer(this);
|
||||
|
||||
@@ -69,7 +69,7 @@ internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingData
|
||||
|
||||
var tileDefinitionManager = dependencies.Resolve<ITileDefinitionManager>();
|
||||
|
||||
node.TryGetValue(new ValueDataNode("version"), out var versionNode);
|
||||
node.TryGetValue("version", out var versionNode);
|
||||
var version = ((ValueDataNode?) versionNode)?.AsInt() ?? 1;
|
||||
|
||||
for (ushort y = 0; y < chunk.ChunkSize; y++)
|
||||
|
||||
@@ -595,12 +595,23 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (!_deleteSet.Add(component))
|
||||
{
|
||||
// already deferred deletion
|
||||
// Already deferring deletion
|
||||
DebugTools.Assert(component.LifeStage >= ComponentLifeStage.Stopped);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.LifeStage >= ComponentLifeStage.Initialized && component.LifeStage <= ComponentLifeStage.Running)
|
||||
DebugTools.Assert(component.LifeStage >= ComponentLifeStage.Added);
|
||||
|
||||
if (component.LifeStage is >= ComponentLifeStage.Initialized and < ComponentLifeStage.Stopping)
|
||||
LifeShutdown(uid, component, _componentFactory.GetIndex(component.GetType()));
|
||||
else if (component.LifeStage == ComponentLifeStage.Added)
|
||||
{
|
||||
// The component was added, but never initialized or started. It's kinda weird to add and then
|
||||
// immediately defer-remove a component, but oh well. Let's just set the life stage directly and not
|
||||
// raise shutdown events? The removal events will still get called later.
|
||||
// This is also what LifeShutdown() would also do, albeit behind a DebugAssert.
|
||||
component.LifeStage = ComponentLifeStage.Stopped;
|
||||
}
|
||||
#if EXCEPTION_TOLERANCE
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -14,8 +14,9 @@ public partial class EntityManager
|
||||
/// Increases the life stage from <see cref="ComponentLifeStage.PreAdd" /> to <see cref="ComponentLifeStage.Added" />,
|
||||
/// after raising a <see cref="ComponentAdd"/> event.
|
||||
/// </summary>
|
||||
internal void LifeAddToEntity(EntityUid uid, IComponent component, CompIdx idx)
|
||||
internal void LifeAddToEntity<T>(EntityUid uid, T component, CompIdx idx) where T : IComponent
|
||||
{
|
||||
DebugTools.Assert(!_deleteSet.Contains(component));
|
||||
DebugTools.Assert(component.LifeStage == ComponentLifeStage.PreAdd);
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
@@ -32,8 +33,9 @@ public partial class EntityManager
|
||||
/// Increases the life stage from <see cref="ComponentLifeStage.Added" /> to <see cref="ComponentLifeStage.Initialized" />,
|
||||
/// calling <see cref="Initialize" />.
|
||||
/// </summary>
|
||||
internal void LifeInitialize(EntityUid uid, IComponent component, CompIdx idx)
|
||||
internal void LifeInitialize<T>(EntityUid uid, T component, CompIdx idx) where T : IComponent
|
||||
{
|
||||
DebugTools.Assert(!_deleteSet.Contains(component));
|
||||
DebugTools.Assert(component.LifeStage == ComponentLifeStage.Added);
|
||||
|
||||
component.LifeStage = ComponentLifeStage.Initializing;
|
||||
@@ -45,8 +47,9 @@ public partial class EntityManager
|
||||
/// Increases the life stage from <see cref="ComponentLifeStage.Initialized" /> to
|
||||
/// <see cref="ComponentLifeStage.Running" />, calling <see cref="Startup" />.
|
||||
/// </summary>
|
||||
internal void LifeStartup(EntityUid uid, IComponent component, CompIdx idx)
|
||||
internal void LifeStartup<T>(EntityUid uid, T component, CompIdx idx) where T : IComponent
|
||||
{
|
||||
DebugTools.Assert(!_deleteSet.Contains(component));
|
||||
DebugTools.Assert(component.LifeStage == ComponentLifeStage.Initialized);
|
||||
|
||||
component.LifeStage = ComponentLifeStage.Starting;
|
||||
@@ -61,7 +64,7 @@ public partial class EntityManager
|
||||
/// <remarks>
|
||||
/// Components are allowed to remove themselves in their own Startup function.
|
||||
/// </remarks>
|
||||
internal void LifeShutdown(EntityUid uid, IComponent component, CompIdx idx)
|
||||
internal void LifeShutdown<T>(EntityUid uid, T component, CompIdx idx) where T : IComponent
|
||||
{
|
||||
DebugTools.Assert(component.LifeStage is >= ComponentLifeStage.Initializing and < ComponentLifeStage.Stopping);
|
||||
|
||||
@@ -81,7 +84,7 @@ public partial class EntityManager
|
||||
/// Increases the life stage from <see cref="ComponentLifeStage.Stopped" /> to <see cref="ComponentLifeStage.Deleted" />,
|
||||
/// calling <see cref="Component.OnRemove" />.
|
||||
/// </summary>
|
||||
internal void LifeRemoveFromEntity(EntityUid uid, IComponent component, CompIdx idx)
|
||||
internal void LifeRemoveFromEntity<T>(EntityUid uid, T component, CompIdx idx) where T : IComponent
|
||||
{
|
||||
// can be called at any time after PreAdd, including inside other life stage events.
|
||||
DebugTools.Assert(component.LifeStage != ComponentLifeStage.PreAdd);
|
||||
|
||||
@@ -79,7 +79,7 @@ public partial class EntityManager
|
||||
throw new InvalidOperationException($"Tried to spawn entity {protoName} on invalid coordinates {coordinates}.");
|
||||
|
||||
var entity = CreateEntityUninitialized(protoName, coordinates, overrides, rotation);
|
||||
InitializeAndStartEntity(entity, coordinates.GetMapId(this));
|
||||
InitializeAndStartEntity(entity, _xforms.GetMapId(coordinates));
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public partial class EntityManager
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EntityUid SpawnAtPosition(string? protoName, EntityCoordinates coordinates, ComponentRegistry? overrides = null)
|
||||
=> Spawn(protoName, coordinates.ToMap(this, _xforms), overrides);
|
||||
=> Spawn(protoName, _xforms.ToMapCoordinates(coordinates), overrides);
|
||||
|
||||
public bool TrySpawnNextTo(
|
||||
string? protoName,
|
||||
|
||||
@@ -37,18 +37,22 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
/// <inheritdoc cref="Resolve{TComp}(Robust.Shared.GameObjects.EntityUid,ref TComp?,bool)"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected bool Resolve(EntityUid uid, [NotNullWhen(true)] ref MetaDataComponent? component,
|
||||
protected bool Resolve(
|
||||
EntityUid uid,
|
||||
[NotNullWhen(true)] ref MetaDataComponent? component,
|
||||
bool logMissing = true)
|
||||
{
|
||||
return EntityManager.MetaQuery.Resolve(uid, ref component);
|
||||
return EntityManager.MetaQuery.Resolve(uid, ref component, logMissing);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Resolve{TComp}(Robust.Shared.GameObjects.EntityUid,ref TComp?,bool)"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected bool Resolve(EntityUid uid, [NotNullWhen(true)] ref TransformComponent? component,
|
||||
protected bool Resolve(
|
||||
EntityUid uid,
|
||||
[NotNullWhen(true)] ref TransformComponent? component,
|
||||
bool logMissing = true)
|
||||
{
|
||||
return EntityManager.TransformQuery.Resolve(uid, ref component);
|
||||
return EntityManager.TransformQuery.Resolve(uid, ref component, logMissing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -429,7 +429,7 @@ public sealed partial class EntityLookupSystem
|
||||
float arcWidth,
|
||||
LookupFlags flags = DefaultFlags)
|
||||
{
|
||||
var position = coordinates.ToMap(EntityManager, _transform);
|
||||
var position = _transform.ToMapCoordinates(coordinates);
|
||||
|
||||
return GetEntitiesInArc(position, range, direction, arcWidth, flags);
|
||||
}
|
||||
@@ -628,7 +628,7 @@ public sealed partial class EntityLookupSystem
|
||||
if (!coordinates.IsValid(EntityManager))
|
||||
return false;
|
||||
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
return AnyEntitiesIntersecting(mapPos, flags);
|
||||
}
|
||||
|
||||
@@ -637,13 +637,13 @@ public sealed partial class EntityLookupSystem
|
||||
if (!coordinates.IsValid(EntityManager))
|
||||
return false;
|
||||
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
return AnyEntitiesInRange(mapPos, range, flags);
|
||||
}
|
||||
|
||||
public HashSet<EntityUid> GetEntitiesIntersecting(EntityCoordinates coordinates, LookupFlags flags = DefaultFlags)
|
||||
{
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
return GetEntitiesIntersecting(mapPos, flags);
|
||||
}
|
||||
|
||||
@@ -656,7 +656,7 @@ public sealed partial class EntityLookupSystem
|
||||
|
||||
public void GetEntitiesInRange(EntityCoordinates coordinates, float range, HashSet<EntityUid> entities, LookupFlags flags = DefaultFlags)
|
||||
{
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
|
||||
if (mapPos.MapId == MapId.Nullspace)
|
||||
return;
|
||||
|
||||
@@ -621,7 +621,7 @@ public sealed partial class EntityLookupSystem
|
||||
|
||||
public void GetEntitiesInRange<T>(EntityCoordinates coordinates, float range, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
||||
{
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
GetEntitiesInRange(mapPos, range, entities, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Robust.Shared.GameObjects;
|
||||
public abstract class SharedEyeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedViewSubscriberSystem _views = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ public abstract partial class SharedMapSystem
|
||||
}
|
||||
|
||||
// Check if mappos intersects a grid.
|
||||
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
||||
|
||||
if (_mapInternal.TryFindGridAt(mapPos, out var gridUid, out gridComponent))
|
||||
{
|
||||
|
||||
@@ -1222,7 +1222,7 @@ public abstract partial class SharedMapSystem
|
||||
{
|
||||
#if DEBUG
|
||||
var mapId = _xformQuery.GetComponent(uid).MapID;
|
||||
DebugTools.Assert(mapId == coords.GetMapId(EntityManager));
|
||||
DebugTools.Assert(mapId == _transform.GetMapId(coords));
|
||||
#endif
|
||||
|
||||
return SnapGridLocalCellFor(uid, grid, LocalToGrid(uid, grid, coords));
|
||||
@@ -1432,7 +1432,7 @@ public abstract partial class SharedMapSystem
|
||||
{
|
||||
#if DEBUG
|
||||
var mapId = _xformQuery.GetComponent(uid).MapID;
|
||||
DebugTools.Assert(mapId == coords.GetMapId(EntityManager));
|
||||
DebugTools.Assert(mapId == _transform.GetMapId(coords));
|
||||
#endif
|
||||
var local = LocalToGrid(uid, grid, coords);
|
||||
|
||||
@@ -1454,7 +1454,7 @@ public abstract partial class SharedMapSystem
|
||||
{
|
||||
return position.EntityId == uid
|
||||
? position.Position
|
||||
: WorldToLocal(uid, grid, position.ToMapPos(EntityManager, _transform));
|
||||
: WorldToLocal(uid, grid, _transform.ToMapCoordinates(position).Position);
|
||||
}
|
||||
|
||||
public bool CollidesWithGrid(EntityUid uid, MapGridComponent grid, Vector2i indices)
|
||||
|
||||
@@ -121,6 +121,11 @@ public abstract class SharedUserInterfaceSystem : EntitySystem
|
||||
if (msg.Message is not CloseBoundInterfaceMessage && ui.RequireInputValidation)
|
||||
{
|
||||
var attempt = new BoundUserInterfaceMessageAttempt(sender, uid, msg.UiKey, msg.Message);
|
||||
|
||||
RaiseLocalEvent(attempt);
|
||||
if (attempt.Cancelled)
|
||||
return;
|
||||
|
||||
RaiseLocalEvent(uid, attempt);
|
||||
if (attempt.Cancelled)
|
||||
return;
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace Robust.Shared.Map.Commands;
|
||||
/// </summary>
|
||||
public sealed class AmbientLightCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _systems = default!;
|
||||
|
||||
public string Command => $"setambientlight";
|
||||
@@ -32,10 +31,11 @@ public sealed class AmbientLightCommand : IConsoleCommand
|
||||
}
|
||||
|
||||
var mapId = new MapId(mapInt);
|
||||
var mapSystem = _systems.GetEntitySystem<SharedMapSystem>();
|
||||
|
||||
if (!_mapManager.MapExists(mapId))
|
||||
if (!mapSystem.MapExists(mapId))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-parse-failure-mapid"));
|
||||
shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", mapId.Value)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ public sealed class AmbientLightCommand : IConsoleCommand
|
||||
}
|
||||
|
||||
var color = Color.FromSrgb(new Color(r, g, b, a));
|
||||
var mapSystem = _systems.GetEntitySystem<SharedMapSystem>();
|
||||
mapSystem.SetAmbientLight(mapId, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,9 @@ public sealed class FixtureSerializer : ITypeSerializer<Dictionary<string, Fixtu
|
||||
|
||||
foreach (var subNode in node)
|
||||
{
|
||||
var key = (ValueDataNode)subNode.Key;
|
||||
|
||||
if (!keys.Add(key.Value))
|
||||
if (!keys.Add(subNode.Key))
|
||||
{
|
||||
seq.Add(new ErrorNode(subNode.Key, $"Found duplicate fixture ID {key.Value}"));
|
||||
seq.Add(new ErrorNode(new ValueDataNode(subNode.Key), $"Found duplicate fixture ID {subNode.Key}"));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -50,10 +48,8 @@ public sealed class FixtureSerializer : ITypeSerializer<Dictionary<string, Fixtu
|
||||
|
||||
foreach (var subNode in node)
|
||||
{
|
||||
var key = (ValueDataNode)subNode.Key;
|
||||
|
||||
var fixture = serializationManager.Read<Fixture>(subNode.Value, hookCtx, context, notNullableOverride: true);
|
||||
value.Add(key.Value, fixture);
|
||||
value.Add(subNode.Key, fixture);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Robust.Shared.Physics.Systems
|
||||
/// <summary>
|
||||
/// Tests whether a particular point is contained in the shape.
|
||||
/// </summary>
|
||||
public bool TestPoint(IPhysShape shape, Transform xform, Vector2 worldPoint)
|
||||
public bool TestPoint<T>(T shape, Transform xform, Vector2 worldPoint) where T : IPhysShape
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
|
||||
@@ -19,11 +19,11 @@ public abstract partial class SharedJointSystem : EntitySystem
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private EntityQuery<JointComponent> _jointsQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private EntityQuery<JointRelayTargetComponent> _relayQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
// To avoid issues with component states we'll queue up all dirty joints and check it every tick to see if
|
||||
// we can delete the component.
|
||||
@@ -37,7 +37,6 @@ public abstract partial class SharedJointSystem : EntitySystem
|
||||
|
||||
_jointsQuery = GetEntityQuery<JointComponent>();
|
||||
_relayQuery = GetEntityQuery<JointRelayTargetComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
UpdatesOutsidePrediction = true;
|
||||
|
||||
@@ -237,7 +236,7 @@ public abstract partial class SharedJointSystem : EntitySystem
|
||||
string? id = null,
|
||||
TransformComponent? xformA = null,
|
||||
TransformComponent? xformB = null,
|
||||
int? minimumDistance = null)
|
||||
float? minimumDistance = null)
|
||||
{
|
||||
if (!Resolve(bodyA, ref xformA) || !Resolve(bodyB, ref xformB))
|
||||
{
|
||||
@@ -247,8 +246,8 @@ public abstract partial class SharedJointSystem : EntitySystem
|
||||
anchorA ??= Vector2.Zero;
|
||||
anchorB ??= Vector2.Zero;
|
||||
|
||||
var vecA = Vector2.Transform(anchorA.Value, xformA.WorldMatrix);
|
||||
var vecB = Vector2.Transform(anchorB.Value, xformB.WorldMatrix);
|
||||
var vecA = Vector2.Transform(anchorA.Value, _transform.GetWorldMatrix(xformA));
|
||||
var vecB = Vector2.Transform(anchorB.Value, _transform.GetWorldMatrix(xformB));
|
||||
var length = (vecA - vecB).Length();
|
||||
if (minimumDistance != null)
|
||||
length = Math.Max(minimumDistance.Value, length);
|
||||
@@ -347,7 +346,7 @@ public abstract partial class SharedJointSystem : EntitySystem
|
||||
if (!Resolve(uid, ref xform))
|
||||
return Vector2.Zero;
|
||||
|
||||
return Physics.Transform.MulT(new Quaternion2D((float) xform.WorldRotation.Theta), worldVector);
|
||||
return Physics.Transform.MulT(new Quaternion2D((float) _transform.GetWorldRotation(xform).Theta), worldVector);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -535,7 +535,7 @@ public partial class SharedPhysicsSystem
|
||||
DirtyFields(uid, body, null, nameof(PhysicsComponent.Force), nameof(PhysicsComponent.Torque));
|
||||
}
|
||||
|
||||
_broadphase.RegenerateContacts(uid, body, manager, xform);
|
||||
_broadphase.RegenerateContacts((uid, body, manager, xform));
|
||||
|
||||
if (body.Initialized)
|
||||
{
|
||||
|
||||
@@ -661,8 +661,8 @@ public abstract partial class SharedPhysicsSystem
|
||||
var aUid = contact.EntityA;
|
||||
var bUid = contact.EntityB;
|
||||
|
||||
SetAwake(aUid, bodyA, true);
|
||||
SetAwake(bUid, bodyB, true);
|
||||
SetAwake((aUid, bodyA), true);
|
||||
SetAwake((bUid, bodyB), true);
|
||||
}
|
||||
|
||||
ArrayPool<bool>.Shared.Return(wake);
|
||||
@@ -788,7 +788,7 @@ public abstract partial class SharedPhysicsSystem
|
||||
if (!PhysicsQuery.Resolve(entity.Owner, ref entity.Comp))
|
||||
return;
|
||||
|
||||
_broadphase.RegenerateContacts(entity.Owner, entity.Comp);
|
||||
_broadphase.RegenerateContacts(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1045,7 +1045,10 @@ public abstract partial class SharedPhysicsSystem
|
||||
// May reparent object and change body's velocity.
|
||||
if (!float.IsNaN(position.X) && !float.IsNaN(position.Y))
|
||||
{
|
||||
_transform.SetLocalPositionRotation(xform, xform.LocalPosition + position, xform.LocalRotation + angle);
|
||||
_transform.SetLocalPositionRotation(uid,
|
||||
xform.LocalPosition + position,
|
||||
xform.LocalRotation + angle,
|
||||
xform);
|
||||
}
|
||||
|
||||
if (physicsDirtied)
|
||||
|
||||
@@ -137,6 +137,7 @@ namespace Robust.Shared.Physics.Systems
|
||||
/// <summary>
|
||||
/// Get all entities colliding with a certain body.
|
||||
/// </summary>
|
||||
[Obsolete("Use EntityLookupSystem")]
|
||||
public IEnumerable<PhysicsComponent> GetCollidingEntities(MapId mapId, in Box2 worldAABB)
|
||||
{
|
||||
if (mapId == MapId.Nullspace) return Array.Empty<PhysicsComponent>();
|
||||
@@ -169,6 +170,7 @@ namespace Robust.Shared.Physics.Systems
|
||||
/// <summary>
|
||||
/// Get all entities colliding with a certain body.
|
||||
/// </summary>
|
||||
[Obsolete("Use EntityLookupSystem")]
|
||||
public IEnumerable<Entity<PhysicsComponent>> GetCollidingEntities(MapId mapId, in Box2Rotated worldBounds)
|
||||
{
|
||||
if (mapId == MapId.Nullspace)
|
||||
|
||||
@@ -45,7 +45,7 @@ public abstract partial class SharedPhysicsSystem
|
||||
if (!coordinates.IsValid(EntityManager))
|
||||
return Vector2.Zero;
|
||||
|
||||
var mapUid = coordinates.GetMapUid(EntityManager);
|
||||
var mapUid = _transform.GetMap(coordinates);
|
||||
var parent = coordinates.EntityId;
|
||||
var localPos = coordinates.Position;
|
||||
|
||||
|
||||
@@ -342,8 +342,7 @@ public partial class PrototypeManager
|
||||
{
|
||||
if (abstractNode is not ValueDataNode abstractValueNode)
|
||||
{
|
||||
mapping.Remove(abstractNode);
|
||||
mapping.Add("abstract", "true");
|
||||
mapping["abstract"] = new ValueDataNode("true");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -408,16 +408,26 @@ namespace Robust.Shared.Prototypes
|
||||
if (nonPushedParent)
|
||||
continue;
|
||||
|
||||
var parentMaps = new MappingDataNode[parents.Length];
|
||||
for (var i = 0; i < parentMaps.Length; i++)
|
||||
if (parents.Length == 1)
|
||||
{
|
||||
parentMaps[i] = kindData.Results[parents[i]];
|
||||
kindData.Results[id] = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
kindData.Results[parents[0]],
|
||||
kindData.RawResults[id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parentMaps = new MappingDataNode[parents.Length];
|
||||
for (var i = 0; i < parentMaps.Length; i++)
|
||||
{
|
||||
parentMaps[i] = kindData.Results[parents[i]];
|
||||
}
|
||||
|
||||
kindData.Results[id] = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
parentMaps,
|
||||
kindData.RawResults[id]);
|
||||
kindData.Results[id] = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
parentMaps,
|
||||
kindData.RawResults[id]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -629,16 +639,26 @@ namespace Robust.Shared.Prototypes
|
||||
{
|
||||
if (tree.TryGetParents(id, out var parents))
|
||||
{
|
||||
var parentNodes = new MappingDataNode[parents.Length];
|
||||
for (var i = 0; i < parents.Length; i++)
|
||||
if (parents.Length == 1)
|
||||
{
|
||||
parentNodes[i] = results[parents[i]].Result;
|
||||
datum.Result = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
results[parents[0]].Result,
|
||||
datum.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parentNodes = new MappingDataNode[parents.Length];
|
||||
for (var i = 0; i < parents.Length; i++)
|
||||
{
|
||||
parentNodes[i] = results[parents[i]].Result;
|
||||
}
|
||||
|
||||
datum.Result = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
parentNodes,
|
||||
datum.Result);
|
||||
datum.Result = _serializationManager.PushCompositionWithGenericNode(
|
||||
kind,
|
||||
parentNodes,
|
||||
datum.Result);
|
||||
}
|
||||
}
|
||||
|
||||
if (tree.TryGetChildren(id, out var children))
|
||||
|
||||
@@ -112,7 +112,7 @@ public sealed class ReplayData
|
||||
ClientSideRecording = clientSideRecording;
|
||||
YamlData = yamlData;
|
||||
|
||||
if (YamlData.TryGet(new ValueDataNode(ReplayConstants.MetaKeyRecordedBy), out ValueDataNode? node)
|
||||
if (YamlData.TryGet(ReplayConstants.MetaKeyRecordedBy, out ValueDataNode? node)
|
||||
&& Guid.TryParse(node.Value, out var guid))
|
||||
{
|
||||
Recorder = new NetUserId(guid);
|
||||
|
||||
@@ -266,27 +266,21 @@ namespace Robust.Shared.Serialization.Manager.Definition
|
||||
|
||||
foreach (var (key, val) in mapping.Children)
|
||||
{
|
||||
if (key is not ValueDataNode valueDataNode)
|
||||
if (!TryGetIndex(key, out var idx))
|
||||
{
|
||||
validatedMapping.Add(new ErrorNode(key, "Key not ValueDataNode."), new InconclusiveNode(val));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TryGetIndex(valueDataNode.Value, out var idx))
|
||||
{
|
||||
if (TryGetIncludeMappingPair(includeValidations, valueDataNode.Value, out var validatedNotFoundPair))
|
||||
if (TryGetIncludeMappingPair(includeValidations, key, out var validatedNotFoundPair))
|
||||
{
|
||||
validatedMapping.Add(validatedNotFoundPair.Key, validatedNotFoundPair.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
var error = new FieldNotFoundErrorNode(valueDataNode, typeof(T));
|
||||
var error = new FieldNotFoundErrorNode(mapping.GetKeyNode(key), typeof(T));
|
||||
|
||||
validatedMapping.Add(error, new InconclusiveNode(val));
|
||||
continue;
|
||||
}
|
||||
|
||||
var keyValidated = serialization.ValidateNode<string>(key, context);
|
||||
var keyValidated = serialization.ValidateNode<string>(mapping.GetKeyNode(key), context);
|
||||
|
||||
ValidationNode valNode;
|
||||
if (IsNull(val))
|
||||
@@ -295,7 +289,7 @@ namespace Robust.Shared.Serialization.Manager.Definition
|
||||
{
|
||||
var error = new ErrorNode(
|
||||
val,
|
||||
$"Field \"{valueDataNode.Value}\" had null value despite not being annotated as nullable.");
|
||||
$"Field \"{key}\" had null value despite not being annotated as nullable.");
|
||||
|
||||
validatedMapping.Add(keyValidated, error);
|
||||
continue;
|
||||
@@ -309,7 +303,7 @@ namespace Robust.Shared.Serialization.Manager.Definition
|
||||
}
|
||||
|
||||
//include node errors override successful nodes on the main datadef
|
||||
if (valNode is not ErrorNode && TryGetIncludeMappingPair(includeValidations, valueDataNode.Value, out var validatedPair))
|
||||
if (valNode is not ErrorNode && TryGetIncludeMappingPair(includeValidations, key, out var validatedPair))
|
||||
{
|
||||
if (validatedPair.Value is ErrorNode)
|
||||
{
|
||||
|
||||
@@ -421,6 +421,7 @@ namespace Robust.Shared.Serialization.Manager
|
||||
#region Composition
|
||||
|
||||
DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null);
|
||||
DataNode PushComposition(Type type, DataNode parent, DataNode child, ISerializationContext? context = null);
|
||||
|
||||
public TNode PushComposition<TType, TNode>(TNode[] parents, TNode child, ISerializationContext? context = null) where TNode : DataNode
|
||||
{
|
||||
@@ -428,6 +429,12 @@ namespace Robust.Shared.Serialization.Manager
|
||||
return (TNode)PushComposition(typeof(TType), parents, child, context);
|
||||
}
|
||||
|
||||
public TNode PushComposition<TType, TNode>(TNode parent, TNode child, ISerializationContext? context = null)
|
||||
where TNode : DataNode
|
||||
{
|
||||
return (TNode) PushComposition(typeof(TType), parent, child, context);
|
||||
}
|
||||
|
||||
TNode PushInheritance<TType, TNode>(ITypeInheritanceHandler<TType, TNode> inheritanceHandler, TNode parent, TNode child,
|
||||
ISerializationContext? context = null) where TNode : DataNode;
|
||||
|
||||
@@ -441,6 +448,12 @@ namespace Robust.Shared.Serialization.Manager
|
||||
return (TNode) PushComposition(type, parents, child, context);
|
||||
}
|
||||
|
||||
public TNode PushCompositionWithGenericNode<TNode>(Type type, TNode parent, TNode child, ISerializationContext? context = null)
|
||||
where TNode : DataNode
|
||||
{
|
||||
return (TNode) PushComposition(type, parent, child, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple <see cref="MappingDataNode"/> inheritance pusher clones data and overrides a parent's values with
|
||||
/// the child's.
|
||||
|
||||
@@ -24,27 +24,23 @@ public partial class SerializationManager
|
||||
|
||||
private readonly ConcurrentDictionary<(Type value, Type node), PushCompositionDelegate> _compositionPushers = new();
|
||||
|
||||
public DataNode PushComposition(Type type, DataNode[] parents, DataNode child, ISerializationContext? context = null)
|
||||
public DataNode PushComposition(
|
||||
Type type,
|
||||
DataNode[] parents,
|
||||
DataNode child,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
// TODO SERIALIZATION
|
||||
// Add variant that doesn't require a parent array.
|
||||
|
||||
// TODO SERIALIZATION
|
||||
// Change inheritance pushing so that it modifies the passed in child. This avoids re-creating the child
|
||||
// multiple times when there are multiple children.
|
||||
// multiple times when there are multiple parents.
|
||||
//
|
||||
// I.e., change the PushCompositionDelegate signature to not have a return value, and also add an override
|
||||
// of this method that modified the given child.
|
||||
// of this method that modifies the given child.
|
||||
|
||||
if (parents.Length == 0)
|
||||
return child.Copy();
|
||||
|
||||
DebugTools.Assert(parents.All(x => x.GetType() == child.GetType()));
|
||||
|
||||
|
||||
// the child.Clone() statement to the beginning here, then make the delegate modify the clone.
|
||||
// Currently pusing more than one parent requires multiple unnecessary clones.
|
||||
|
||||
var pusher = GetOrCreatePushCompositionDelegate(type, child);
|
||||
|
||||
var node = child;
|
||||
@@ -61,6 +57,22 @@ public partial class SerializationManager
|
||||
return node;
|
||||
}
|
||||
|
||||
public DataNode PushComposition(
|
||||
Type type,
|
||||
DataNode parent,
|
||||
DataNode child,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
DebugTools.AssertEqual(parent.GetType(), child.GetType());
|
||||
var pusher = GetOrCreatePushCompositionDelegate(type, child);
|
||||
|
||||
var newNode = pusher(type, parent, child, context);
|
||||
|
||||
// Currently delegate pusher should be returning a new instance, and not modifying the passed in child.
|
||||
DebugTools.Assert(!ReferenceEquals(newNode, child));
|
||||
return newNode;
|
||||
}
|
||||
|
||||
private PushCompositionDelegate GetOrCreatePushCompositionDelegate(Type type, DataNode node)
|
||||
{
|
||||
return _compositionPushers.GetOrAdd((type, node.GetType()), static (tuple, vfArgument) =>
|
||||
@@ -178,14 +190,15 @@ public partial class SerializationManager
|
||||
{
|
||||
// tag is set on data definition creation
|
||||
if(!processedTags.Add(dfa.Tag!)) continue; //tag was already processed, probably because we are using the same tag in an include
|
||||
var key = new ValueDataNode(dfa.Tag);
|
||||
|
||||
var key = dfa.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);
|
||||
newMapping[key] = PushComposition(field.FieldType, parentValue, childValue, context);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using YamlDotNet.Core;
|
||||
@@ -28,6 +29,7 @@ namespace Robust.Shared.Serialization.Markdown
|
||||
/// </summary>
|
||||
public abstract DataNode? Except(DataNode node);
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public abstract DataNode PushInheritance(DataNode parent);
|
||||
|
||||
public T CopyCast<T>() where T : DataNode
|
||||
@@ -60,6 +62,7 @@ namespace Robust.Shared.Serialization.Markdown
|
||||
|
||||
public abstract T? Except(T node);
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public abstract T PushInheritance(T node);
|
||||
|
||||
public override DataNode? Except(DataNode node)
|
||||
@@ -67,6 +70,7 @@ namespace Robust.Shared.Serialization.Markdown
|
||||
return node is not T tNode ? throw new InvalidNodeTypeException() : Except(tNode);
|
||||
}
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public override DataNode PushInheritance(DataNode parent)
|
||||
{
|
||||
return parent is not T tNode ? throw new InvalidNodeTypeException() : PushInheritance(tNode);
|
||||
|
||||
@@ -25,10 +25,7 @@ public static class DataNodeHelpers
|
||||
|
||||
foreach (var (k, v) in node)
|
||||
{
|
||||
foreach (var child in GetAllNodes(k))
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
yield return node.GetKeyNode(k);
|
||||
|
||||
foreach (var child in GetAllNodes(v))
|
||||
{
|
||||
|
||||
@@ -85,6 +85,16 @@ public static class DataNodeParser
|
||||
return node;
|
||||
}
|
||||
|
||||
private static string ParseKey(Parser parser)
|
||||
{
|
||||
var ev = parser.Consume<Scalar>();
|
||||
|
||||
if (!ev.Anchor.IsEmpty)
|
||||
throw new NotSupportedException();
|
||||
|
||||
return ev.Value;
|
||||
}
|
||||
|
||||
private static SequenceDataNode ParseSequence(Parser parser, DocumentState state)
|
||||
{
|
||||
var ev = parser.Consume<SequenceStart>();
|
||||
@@ -124,12 +134,11 @@ public static class DataNodeParser
|
||||
MappingEnd mapEnd;
|
||||
while (!parser.TryConsume(out mapEnd))
|
||||
{
|
||||
var key = Parse(parser, state);
|
||||
var key = ParseKey(parser);
|
||||
var value = Parse(parser, state);
|
||||
|
||||
node.Add(key, value);
|
||||
|
||||
unresolvedAlias |= key is DataNodeAlias;
|
||||
unresolvedAlias |= value is DataNodeAlias;
|
||||
}
|
||||
|
||||
@@ -173,17 +182,16 @@ public static class DataNodeParser
|
||||
|
||||
private static void ResolveMappingAliases(MappingDataNode mapping, DocumentState state)
|
||||
{
|
||||
var swaps = new ValueList<(DataNode key, DataNode value)>();
|
||||
var swaps = new ValueList<(string key, DataNode value)>();
|
||||
|
||||
foreach (var (key, value) in mapping)
|
||||
{
|
||||
if (key is not DataNodeAlias && value is not DataNodeAlias)
|
||||
if (value is not DataNodeAlias valueAlias)
|
||||
return;
|
||||
|
||||
var newKey = key is DataNodeAlias keyAlias ? ResolveAlias(keyAlias, state) : key;
|
||||
var newValue = value is DataNodeAlias valueAlias ? ResolveAlias(valueAlias, state) : value;
|
||||
var newValue = ResolveAlias(valueAlias, state);
|
||||
|
||||
swaps.Add((newKey, newValue));
|
||||
swaps.Add((key, newValue));
|
||||
mapping.Remove(key);
|
||||
}
|
||||
|
||||
@@ -242,6 +250,7 @@ public static class DataNodeParser
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public override DataNode PushInheritance(DataNode parent)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
|
||||
@@ -5,25 +5,30 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Robust.Shared.Serialization.Markdown.Value;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
{
|
||||
public sealed class MappingDataNode : DataNode<MappingDataNode>, IDictionary<DataNode, DataNode>
|
||||
public sealed class MappingDataNode : DataNode<MappingDataNode>, IDictionary<string, 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.
|
||||
// Obviously thread local to avoid threading issues.
|
||||
private static readonly ThreadLocal<ValueDataNode> FetchNode =
|
||||
new(() => new ValueDataNode(""));
|
||||
private readonly Dictionary<string, DataNode> _children;
|
||||
private readonly List<KeyValuePair<string,DataNode>> _list;
|
||||
|
||||
private readonly Dictionary<DataNode, DataNode> _children;
|
||||
private readonly List<KeyValuePair<DataNode,DataNode>> _list;
|
||||
/// <summary>
|
||||
/// ValueDataNodes associated with each key. This is used for yaml validation / error reporting.
|
||||
/// I.e., if a key is meant to be an EntityPrototype ID, we want to print an error that points to the
|
||||
/// corresponding yaml lines.
|
||||
/// </summary>
|
||||
private IReadOnlyDictionary<string, ValueDataNode>? _keyNodes;
|
||||
// TODO avoid populating this unless we are running the yaml linter?
|
||||
|
||||
public IReadOnlyDictionary<DataNode, DataNode> Children => _children;
|
||||
public override bool IsEmpty => _children.Count == 0;
|
||||
public int Count => _children.Count;
|
||||
public bool IsReadOnly => false;
|
||||
public IReadOnlyDictionary<string, DataNode> Children => _children;
|
||||
|
||||
public MappingDataNode() : base(NodeMark.Invalid, NodeMark.Invalid)
|
||||
{
|
||||
@@ -41,113 +46,106 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
{
|
||||
_children = new(mapping.Children.Count);
|
||||
_list = new(mapping.Children.Count);
|
||||
foreach (var (key, val) in mapping.Children)
|
||||
var keyNodes = new Dictionary<string, ValueDataNode>(mapping.Children.Count);
|
||||
foreach (var (keyNode, val) in mapping.Children)
|
||||
{
|
||||
Add(key.ToDataNode(), val.ToDataNode());
|
||||
if (keyNode is not YamlScalarNode scalarNode)
|
||||
throw new NotSupportedException("Mapping data nodes must have a scalar keys");
|
||||
|
||||
var valueNode = new ValueDataNode(scalarNode);
|
||||
Add(valueNode.Value, val.ToDataNode());
|
||||
keyNodes.Add(valueNode.Value, valueNode);
|
||||
}
|
||||
|
||||
_keyNodes = keyNodes;
|
||||
Tag = mapping.Tag.IsEmpty ? null : mapping.Tag.Value;
|
||||
}
|
||||
|
||||
public MappingDataNode(Dictionary<DataNode, DataNode> nodes) : base(NodeMark.Invalid, NodeMark.Invalid)
|
||||
public MappingDataNode(Dictionary<string, DataNode> nodes) : base(NodeMark.Invalid, NodeMark.Invalid)
|
||||
{
|
||||
_children = new(nodes.Count);
|
||||
_list = new(nodes.Count);
|
||||
foreach (var (key, val) in nodes)
|
||||
{
|
||||
Add(key, val);
|
||||
}
|
||||
_children = new(nodes);
|
||||
_list = new(_children);
|
||||
}
|
||||
|
||||
public KeyValuePair<DataNode, DataNode> this[int key] => _list[key];
|
||||
|
||||
public DataNode this[string index]
|
||||
{
|
||||
get => Get(index);
|
||||
set => Add(index, value);
|
||||
}
|
||||
public KeyValuePair<string, DataNode> this[int key] => _list[key];
|
||||
|
||||
public MappingDataNode Add(string key, DataNode node)
|
||||
{
|
||||
Add(new ValueDataNode(key), node);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static ValueDataNode GetFetchNode(string key)
|
||||
{
|
||||
var node = FetchNode.Value!;
|
||||
node.Value = key;
|
||||
return node;
|
||||
}
|
||||
|
||||
public MappingDataNode Add(DataNode key, DataNode node)
|
||||
{
|
||||
_children.Add(key, node);
|
||||
_list.Add(new(key, node));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataNode this[DataNode key]
|
||||
public DataNode this[string key]
|
||||
{
|
||||
get => _children[key];
|
||||
set
|
||||
{
|
||||
if (_children.TryAdd(key, value))
|
||||
{
|
||||
_list.Add(new( key, value));
|
||||
_list.Add(new(key, value));
|
||||
return;
|
||||
}
|
||||
|
||||
var i = _list.IndexOf(new(key, _children[key]));
|
||||
_list[i] = new(key, value);
|
||||
var index = IndexOf(key);
|
||||
if (index == -1)
|
||||
throw new Exception("Key exists in Children, but not list?");
|
||||
|
||||
_list[index] = new(key, value);
|
||||
_children[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void IDictionary<DataNode, DataNode>.Add(DataNode key, DataNode value) => Add(key, value);
|
||||
public int IndexOf(string key)
|
||||
{
|
||||
// TODO MappingDataNode
|
||||
// Consider having a Dictionary<string,int> for faster lookups?
|
||||
// IndexOf() gets called in Remove(), which itself gets called frequently (e.g., per serialized component,
|
||||
// per entity, when loading a map.
|
||||
//
|
||||
// Then again, if most mappings only contain 1-4 entries, this list search is comparable in speed, reduces
|
||||
// allocations, and makes adding/inserting entries faster.
|
||||
|
||||
public bool ContainsKey(DataNode key) => _children.ContainsKey(key);
|
||||
for (var index = 0; index < _list.Count; index++)
|
||||
{
|
||||
if (_list[index].Key == key)
|
||||
return index;
|
||||
}
|
||||
|
||||
bool IDictionary<DataNode, DataNode>.Remove(DataNode key)
|
||||
=> ((IDictionary<DataNode, DataNode>)this).Remove(key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool TryGetValue(DataNode key, [NotNullWhen(true)] out DataNode? value) => TryGet(key, out value);
|
||||
void IDictionary<string, DataNode>.Add(string key, DataNode value) => Add(key, value);
|
||||
|
||||
public ICollection<DataNode> Keys => _list.Select(x => x.Key).ToArray();
|
||||
public bool ContainsKey(string key) => _children.ContainsKey(key);
|
||||
|
||||
bool IDictionary<string, DataNode>.Remove(string key)
|
||||
=> ((IDictionary<string, DataNode>)this).Remove(key);
|
||||
|
||||
public bool TryGetValue(string key, [NotNullWhen(true)] out DataNode? value)
|
||||
=> TryGet(key, out value);
|
||||
|
||||
// TODO consider changing these to unsorted collections
|
||||
// I.e., just redirect to _children.Keys to avoid hidden linq & allocations.
|
||||
public ICollection<string> Keys => _list.Select(x => x.Key).ToArray();
|
||||
public ICollection<DataNode> Values => _list.Select(x => x.Value).ToArray();
|
||||
|
||||
public DataNode Get(DataNode key)
|
||||
public DataNode Get(string key)
|
||||
{
|
||||
return _children[key];
|
||||
}
|
||||
|
||||
public T Get<T>(DataNode key) where T : DataNode
|
||||
public T Get<T>(string key) where T : DataNode
|
||||
{
|
||||
return (T) Get(key);
|
||||
}
|
||||
|
||||
public DataNode Get(string key)
|
||||
public bool TryGet(string key, [NotNullWhen(true)] out DataNode? node)
|
||||
{
|
||||
return Get(GetFetchNode(key));
|
||||
return _children.TryGetValue(key, out node);
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGet<T>(DataNode key, [NotNullWhen(true)] out T? node) where T : DataNode
|
||||
public bool TryGet<T>(string key, [NotNullWhen(true)] out T? node) where T : DataNode
|
||||
{
|
||||
node = null;
|
||||
if (!TryGet(key, out var rawNode) || rawNode is not T castNode)
|
||||
@@ -156,41 +154,27 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
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)
|
||||
public bool Has(string key)
|
||||
{
|
||||
return _children.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool Has(string key)
|
||||
public bool Remove(string key)
|
||||
{
|
||||
return Has(GetFetchNode(key));
|
||||
if (!_children.Remove(key))
|
||||
return false;
|
||||
|
||||
var index = IndexOf(key);
|
||||
if (index == -1)
|
||||
throw new Exception("Key exists in Children, but not list?");
|
||||
|
||||
_list.RemoveAt(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public MappingDataNode Remove(DataNode key)
|
||||
public T Cast<T>(string key) where T : DataNode
|
||||
{
|
||||
if (_children.Remove(key, out var val))
|
||||
_list.Remove(new(key, val));
|
||||
return this;
|
||||
}
|
||||
|
||||
public MappingDataNode Remove(string key)
|
||||
{
|
||||
return Remove(GetFetchNode(key));
|
||||
}
|
||||
|
||||
public T Cast<T>(string index) where T : DataNode
|
||||
{
|
||||
return (T) this[index];
|
||||
return (T) this[key];
|
||||
}
|
||||
|
||||
public YamlMappingNode ToYaml()
|
||||
@@ -199,7 +183,23 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
|
||||
foreach (var (key, val) in _list)
|
||||
{
|
||||
mapping.Add(key.ToYamlNode(), val.ToYamlNode());
|
||||
YamlScalarNode yamlKeyNode;
|
||||
if (_keyNodes != null && _keyNodes.TryGetValue(key, out var keyNode))
|
||||
{
|
||||
yamlKeyNode = (YamlScalarNode)keyNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is matches the ValueDataNode -> YamlScalarNode cast operator
|
||||
yamlKeyNode = new(key)
|
||||
{
|
||||
Style = ValueDataNode.IsNullLiteral(key) || string.IsNullOrWhiteSpace(key)
|
||||
? ScalarStyle.DoubleQuoted
|
||||
: ScalarStyle.Any
|
||||
};
|
||||
}
|
||||
|
||||
mapping.Add(yamlKeyNode, val.ToYamlNode());
|
||||
}
|
||||
|
||||
mapping.Tag = Tag;
|
||||
@@ -207,6 +207,11 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public ValueDataNode GetKeyNode(string key)
|
||||
{
|
||||
return _keyNodes?.GetValueOrDefault(key) ?? new ValueDataNode(key);
|
||||
}
|
||||
|
||||
public MappingDataNode Merge(MappingDataNode otherMapping)
|
||||
{
|
||||
var newMapping = Copy();
|
||||
@@ -227,12 +232,12 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
if (!skipDuplicates || !Has(key))
|
||||
{
|
||||
// Intentionally raises an ArgumentException
|
||||
Add(key.Copy(), val.Copy());
|
||||
Add(key, val.Copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertAt(int index, DataNode key, DataNode value)
|
||||
public void InsertAt(int index, string key, DataNode value)
|
||||
{
|
||||
if (index > _list.Count || index < 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@@ -243,20 +248,6 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
_list.Insert(index, new(key, value));
|
||||
}
|
||||
|
||||
public void InsertAt(int index, string key, DataNode value)
|
||||
{
|
||||
if (index > _list.Count || index < 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
var k = new ValueDataNode(key);
|
||||
if (!_children.TryAdd(k, value))
|
||||
throw new InvalidOperationException($"Already contains key {key}");
|
||||
|
||||
_list.Insert(index, new(k, value));
|
||||
}
|
||||
|
||||
public override bool IsEmpty => _children.Count == 0;
|
||||
|
||||
public override MappingDataNode Copy()
|
||||
{
|
||||
var newMapping = new MappingDataNode(_children.Count)
|
||||
@@ -268,9 +259,10 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
|
||||
foreach (var (key, val) in _list)
|
||||
{
|
||||
newMapping.Add(key.Copy(), val.Copy());
|
||||
newMapping.Add(key, val.Copy());
|
||||
}
|
||||
|
||||
newMapping._keyNodes = _keyNodes;
|
||||
return newMapping;
|
||||
}
|
||||
|
||||
@@ -308,17 +300,13 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
|
||||
foreach (var (key, val) in _list)
|
||||
{
|
||||
var other = node._list.FirstOrNull(p => p.Key.Equals(key));
|
||||
if (other == null)
|
||||
if (!node._children.TryGetValue(key, out var otherVal))
|
||||
{
|
||||
mappingNode.Add(key.Copy(), val.Copy());
|
||||
mappingNode.Add(key, val.Copy());
|
||||
}
|
||||
else
|
||||
else if (val.Except(otherVal) is { } newValue)
|
||||
{
|
||||
// We recursively call except on the values and keep only the differences.
|
||||
var newValue = val.Except(other.Value.Value);
|
||||
if (newValue == null) continue;
|
||||
mappingNode.Add(key.Copy(), newValue);
|
||||
mappingNode.Add(key, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,18 +324,8 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
|
||||
foreach (var (key, val) in _list)
|
||||
{
|
||||
var other = node._list.FirstOrNull(p => p.Key.Equals(key));
|
||||
|
||||
if (other == null)
|
||||
{
|
||||
mappingNode.Add(key.Copy(), val.Copy());
|
||||
}
|
||||
else
|
||||
{
|
||||
// We only keep the entry if the values are not equal
|
||||
if (!val.Equals(other.Value.Value))
|
||||
mappingNode.Add(key.Copy(), val.Copy());
|
||||
}
|
||||
if (!node._children.TryGetValue(key, out var otherVal) || !val.Equals(otherVal))
|
||||
mappingNode.Add(key, val.Copy());
|
||||
}
|
||||
|
||||
return mappingNode._children.Count == 0 ? null : mappingNode;
|
||||
@@ -384,34 +362,24 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
if (_children.Count != other._children.Count)
|
||||
return false;
|
||||
|
||||
if (Tag != other.Tag)
|
||||
return false;
|
||||
|
||||
foreach (var (key, otherValue) in other)
|
||||
{
|
||||
if (!_children.TryGetValue(key, out var ownValue) ||
|
||||
!otherValue.Equals(ownValue))
|
||||
if (!_children.TryGetValue(key, out var ownValue)
|
||||
|| !otherValue.Equals(ownValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Tag == other.Tag;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override MappingDataNode PushInheritance(MappingDataNode node)
|
||||
{
|
||||
var newNode = Copy();
|
||||
foreach (var (key, val) in node)
|
||||
{
|
||||
if(_children.ContainsKey(key))
|
||||
continue;
|
||||
|
||||
newNode.Remove(key);
|
||||
newNode.Add(key.Copy(), val.Copy());
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<DataNode, DataNode>> GetEnumerator() => _list.GetEnumerator();
|
||||
public List<KeyValuePair<string, DataNode>>.Enumerator GetEnumerator() => _list.GetEnumerator();
|
||||
IEnumerator<KeyValuePair<string, DataNode>> IEnumerable<KeyValuePair<string, DataNode>>.GetEnumerator() =>
|
||||
_list.GetEnumerator();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
@@ -430,7 +398,7 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<DataNode, DataNode> item) => Add(item.Key, item.Value);
|
||||
public void Add(KeyValuePair<string, DataNode> item) => Add(item.Key, item.Value);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
@@ -438,18 +406,31 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
_list.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<DataNode, DataNode> item) => _children.ContainsKey(item.Key);
|
||||
public bool Contains(KeyValuePair<string, DataNode> item) => _children.ContainsKey(item.Key);
|
||||
|
||||
public void CopyTo(KeyValuePair<DataNode, DataNode>[] array, int arrayIndex)
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public override MappingDataNode PushInheritance(MappingDataNode node)
|
||||
{
|
||||
var newNode = Copy();
|
||||
foreach (var (key, val) in node)
|
||||
{
|
||||
if (_children.ContainsKey(key))
|
||||
continue;
|
||||
|
||||
newNode.Remove(key);
|
||||
newNode.Add(key, val.Copy());
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, DataNode>[] array, int arrayIndex)
|
||||
=> _list.CopyTo(array, arrayIndex);
|
||||
|
||||
public bool Remove(KeyValuePair<DataNode, DataNode> item)
|
||||
=> ((IDictionary<DataNode, DataNode>)this).Remove(item.Key);
|
||||
public bool Remove(KeyValuePair<string, DataNode> item)
|
||||
=> ((IDictionary<string, DataNode>) this).Remove(item.Key);
|
||||
|
||||
public int Count => _children.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public bool TryAdd(DataNode key, DataNode value)
|
||||
public bool TryAdd(string key, DataNode value)
|
||||
{
|
||||
if (!_children.TryAdd(key, value))
|
||||
return false;
|
||||
@@ -458,7 +439,7 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryAddCopy(DataNode key, DataNode value)
|
||||
public bool TryAddCopy(string key, DataNode value)
|
||||
{
|
||||
ref var entry = ref CollectionsMarshal.GetValueRefOrAddDefault(_children, key, out var exists);
|
||||
if (exists)
|
||||
@@ -468,5 +449,52 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
_list.Add(new(key, entry));
|
||||
return true;
|
||||
}
|
||||
|
||||
// These methods are probably fine to keep around as helper methods, but are currently marked as obsolete
|
||||
// so that people don't uneccesarily allocate a ValueDataNode. I.e., to prevent people from using code like
|
||||
// mapping.TryGet(new ValueDataNode("key"), ...)
|
||||
#region ValueDataNode Helpers
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool TryGet(ValueDataNode key, [NotNullWhen(true)] out DataNode? value)
|
||||
=> TryGet(key.Value, out value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public DataNode this[ValueDataNode key]
|
||||
{
|
||||
get => this[key.Value];
|
||||
set => this[key.Value] = value;
|
||||
}
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool TryGetValue(ValueDataNode key, [NotNullWhen(true)] out DataNode? value)
|
||||
=> TryGet(key.Value, out value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool TryGet<T>(ValueDataNode key, [NotNullWhen(true)] out T? node) where T : DataNode
|
||||
=> TryGet(key.Value, out node);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool Has(ValueDataNode key) => Has(key.Value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public T Cast<T>(ValueDataNode key) where T : DataNode => Cast<T>(key.Value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public void Add(KeyValuePair<ValueDataNode, DataNode> item) => Add(item.Key, item.Value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public MappingDataNode Add(ValueDataNode key, DataNode node) => Add(key.Value, node);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public void InsertAt(int index, ValueDataNode key, DataNode value) => InsertAt(index, key.Value, value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool Contains(KeyValuePair<ValueDataNode, DataNode> item) => _children.ContainsKey(item.Key.Value);
|
||||
|
||||
[Obsolete("Use string keys instead of ValueDataNode")]
|
||||
public bool Remove(ValueDataNode key) => Remove(key.Value);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,21 +6,15 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
|
||||
{
|
||||
public static class MappingDataNodeExtensions
|
||||
{
|
||||
public static MappingDataNode Add(this MappingDataNode mapping, string key, DataNode node)
|
||||
{
|
||||
mapping.Add(new ValueDataNode(key), node);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public static MappingDataNode Add(this MappingDataNode mapping, string key, string value)
|
||||
{
|
||||
mapping.Add(new ValueDataNode(key), new ValueDataNode(value));
|
||||
mapping.Add(key, new ValueDataNode(value));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public static MappingDataNode Add(this MappingDataNode mapping, string key, List<string> sequence)
|
||||
{
|
||||
mapping.Add(new ValueDataNode(key), new SequenceDataNode(sequence));
|
||||
mapping.Add(key, new SequenceDataNode(sequence));
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,8 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
|
||||
return newSequence;
|
||||
}
|
||||
|
||||
public IEnumerator<DataNode> GetEnumerator() => _nodes.GetEnumerator();
|
||||
public List<DataNode>.Enumerator GetEnumerator() => _nodes.GetEnumerator();
|
||||
IEnumerator<DataNode> IEnumerable<DataNode>.GetEnumerator() => _nodes.GetEnumerator();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
@@ -192,6 +193,7 @@ namespace Robust.Shared.Serialization.Markdown.Sequence
|
||||
return true;
|
||||
}
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public override SequenceDataNode PushInheritance(SequenceDataNode node)
|
||||
{
|
||||
var newNode = Copy();
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Robust.Shared.Serialization.Markdown.Value
|
||||
|
||||
public override bool IsEmpty => string.IsNullOrWhiteSpace(Value);
|
||||
|
||||
private static bool IsNullLiteral(string? value) => value != null && value.Trim().ToLower() is "null" ;
|
||||
public static bool IsNullLiteral(string? value) => value != null && value.Trim().ToLower() is "null" ;
|
||||
|
||||
public override ValueDataNode Copy()
|
||||
{
|
||||
@@ -76,6 +76,7 @@ namespace Robust.Shared.Serialization.Markdown.Value
|
||||
return node.Value == Value ? null : Copy();
|
||||
}
|
||||
|
||||
[Obsolete("Use SerializationManager.PushComposition()")]
|
||||
public override ValueDataNode PushInheritance(ValueDataNode node)
|
||||
{
|
||||
return Copy();
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations
|
||||
{
|
||||
newCompReg[idx] = serializationManager.PushCompositionWithGenericNode(
|
||||
reg.Type,
|
||||
new[] { parent[mapping] },
|
||||
parent[mapping],
|
||||
newCompReg[idx],
|
||||
context);
|
||||
|
||||
|
||||
@@ -11,30 +11,25 @@ using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
/// <summary>
|
||||
/// A custom type serializer for reading a set of types that inherit from some base type.
|
||||
/// A custom type serializer for reading a set of types that inherit from some base type.
|
||||
/// </summary>
|
||||
public sealed class AbstractDictionarySerializer<TValue> : ITypeSerializer<Dictionary<Type, TValue>, MappingDataNode>
|
||||
public sealed class AbstractDictionarySerializer<TValue> : ITypeSerializer<Dictionary<Type, TValue>, MappingDataNode>
|
||||
where TValue : notnull
|
||||
{
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||
{
|
||||
{
|
||||
var mapping = new Dictionary<ValidationNode, ValidationNode>();
|
||||
foreach (var (keyNode, valueNode) in node.Children)
|
||||
foreach (var (key, valueNode) in node.Children)
|
||||
{
|
||||
if (keyNode is not ValueDataNode key)
|
||||
{
|
||||
mapping.Add(new ErrorNode(keyNode, $"Expected {nameof(ValueDataNode)} but was {keyNode.GetType()}"), new ValidatedValueNode(valueNode));
|
||||
continue;
|
||||
}
|
||||
var type = serializationManager.ReflectionManager.YamlTypeTagLookup(typeof(TValue), key.Value);
|
||||
var type = serializationManager.ReflectionManager.YamlTypeTagLookup(typeof(TValue), key);
|
||||
if (type == null)
|
||||
{
|
||||
mapping.Add(new ErrorNode(keyNode, $"Could not resolve type: {key.Value}"), new ValidatedValueNode(valueNode));
|
||||
mapping.Add(new ErrorNode(node.GetKeyNode(key), $"Could not resolve type: {key}"), new ValidatedValueNode(valueNode));
|
||||
continue;
|
||||
}
|
||||
|
||||
mapping.Add(new ValidatedValueNode(key), serializationManager.ValidateNode(type, valueNode, context));
|
||||
|
||||
mapping.Add(new ValidatedValueNode(node.GetKeyNode(key)), serializationManager.ValidateNode(type, valueNode, context));
|
||||
}
|
||||
|
||||
return new ValidatedMappingNode(mapping);
|
||||
@@ -44,10 +39,9 @@ public sealed class AbstractDictionarySerializer<TValue> : ITypeSerializer<Dicti
|
||||
SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<Dictionary<Type, TValue>>? instanceProvider = null)
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new Dictionary<Type, TValue>();
|
||||
foreach (var (keyNode, valueNode) in node.Children)
|
||||
foreach (var (key, valueNode) in node.Children)
|
||||
{
|
||||
var key = (ValueDataNode) keyNode;
|
||||
var type = serializationManager.ReflectionManager.YamlTypeTagLookup(typeof(TValue), key.Value)!;
|
||||
var type = serializationManager.ReflectionManager.YamlTypeTagLookup(typeof(TValue), key)!;
|
||||
var value = (TValue) serializationManager.Read(type, valueNode, hookCtx, context, notNullableOverride:true)!;
|
||||
dict.Add(type, value);
|
||||
}
|
||||
@@ -62,8 +56,14 @@ public sealed class AbstractDictionarySerializer<TValue> : ITypeSerializer<Dicti
|
||||
|
||||
foreach (var (key, val) in value)
|
||||
{
|
||||
// TODO SERIALIZATION
|
||||
// Add some way to directly return a string w/o allocating a ValueDataNode
|
||||
var keyNode = serializationManager.WriteValue(key.Name, alwaysWrite, context, notNullableOverride: true);
|
||||
if (keyNode is not ValueDataNode valueNode)
|
||||
throw new NotSupportedException();
|
||||
|
||||
mappingNode.Add(
|
||||
serializationManager.WriteValue(key.Name, alwaysWrite, context, notNullableOverride:true),
|
||||
valueNode.Value,
|
||||
serializationManager.WriteValue(key, val, alwaysWrite, context));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,8 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
|
||||
|
||||
foreach (var (key, val) in node.Children)
|
||||
{
|
||||
if (key is not ValueDataNode value)
|
||||
{
|
||||
mapping.Add(new ErrorNode(key, $"Cannot cast node {key} to ValueDataNode."), serializationManager.ValidateNode<TValue>(val, context));
|
||||
continue;
|
||||
}
|
||||
|
||||
mapping.Add(PrototypeSerializer.Validate(serializationManager, value, dependencies, context), serializationManager.ValidateNode<TValue>(val, context));
|
||||
var keyNode = new ValueDataNode(key);
|
||||
mapping.Add(PrototypeSerializer.Validate(serializationManager, keyNode, dependencies, context), serializationManager.ValidateNode<TValue>(val, context));
|
||||
}
|
||||
|
||||
return new ValidatedMappingNode(mapping);
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Pro
|
||||
{
|
||||
var mapping = new Dictionary<ValidationNode, ValidationNode>();
|
||||
|
||||
foreach (var (key, val) in node.Children)
|
||||
foreach (var (k, val) in node.Children)
|
||||
{
|
||||
var key = node.GetKeyNode(k);
|
||||
if (val is not ValueDataNode value)
|
||||
{
|
||||
mapping.Add(new ErrorNode(val, $"Cannot cast node {val} to ValueDataNode."), serializationManager.ValidateNode<TValue>(key, context));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -8,6 +9,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
|
||||
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.Serialization.TypeSerializers.Interfaces;
|
||||
|
||||
namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
|
||||
@@ -59,7 +61,7 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
var mapping = new Dictionary<ValidationNode, ValidationNode>();
|
||||
foreach (var (key, val) in node.Children)
|
||||
{
|
||||
mapping.Add(serializationManager.ValidateNode<TKey>(key, context),
|
||||
mapping.Add(serializationManager.ValidateNode<TKey>(node.GetKeyNode(key), context),
|
||||
serializationManager.ValidateNode<TValue>(val, context));
|
||||
}
|
||||
|
||||
@@ -79,8 +81,14 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
var mappingNode = new MappingDataNode();
|
||||
foreach (var (key, val) in value)
|
||||
{
|
||||
// TODO SERIALIZATION
|
||||
// Add some way to directly return a string w/o allocating a ValueDataNode
|
||||
var keyNode = serializationManager.WriteValue(key, alwaysWrite, context);
|
||||
if (keyNode is not ValueDataNode valueNode)
|
||||
throw new NotSupportedException("Yaml mapping keys must serialize to a ValueDataNode (i.e. a string)");
|
||||
|
||||
mappingNode.Add(
|
||||
serializationManager.WriteValue(key, alwaysWrite, context),
|
||||
valueNode.Value,
|
||||
serializationManager.WriteValue(val, alwaysWrite, context));
|
||||
}
|
||||
|
||||
@@ -128,9 +136,11 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new Dictionary<TKey, TValue>();
|
||||
|
||||
var keyNode = new ValueDataNode();
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
|
||||
keyNode.Value = key;
|
||||
dict.Add(serializationManager.Read<TKey>(keyNode, hookCtx, context),
|
||||
serializationManager.Read<TValue>(value, hookCtx, context));
|
||||
}
|
||||
|
||||
@@ -149,9 +159,11 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
|
||||
var array = new KeyValuePair<TKey, TValue>[node.Children.Count];
|
||||
int i = 0;
|
||||
var keyNode = new ValueDataNode();
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
var k = serializationManager.Read<TKey>(key, hookCtx, context);
|
||||
keyNode.Value = key;
|
||||
var k = serializationManager.Read<TKey>(keyNode, hookCtx, context);
|
||||
var v = serializationManager.Read<TValue>(value, hookCtx, context);
|
||||
array[i++] = new(k,v);
|
||||
}
|
||||
@@ -174,9 +186,11 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
|
||||
var dict = new Dictionary<TKey, TValue>();
|
||||
|
||||
var keyNode = new ValueDataNode();
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
|
||||
keyNode.Value = key;
|
||||
dict.Add(serializationManager.Read<TKey>(keyNode, hookCtx, context),
|
||||
serializationManager.Read<TValue>(value, hookCtx, context));
|
||||
}
|
||||
|
||||
@@ -190,10 +204,12 @@ public sealed class DictionarySerializer<TKey, TValue> :
|
||||
ISerializationManager.InstantiationDelegate<SortedDictionary<TKey, TValue>>? instanceProvider)
|
||||
{
|
||||
var dict = instanceProvider != null ? instanceProvider() : new SortedDictionary<TKey, TValue>();
|
||||
var keyNode = new ValueDataNode();
|
||||
|
||||
foreach (var (key, value) in node.Children)
|
||||
{
|
||||
dict.Add(serializationManager.Read<TKey>(key, hookCtx, context),
|
||||
keyNode.Value = key;
|
||||
dict.Add(serializationManager.Read<TKey>(keyNode, hookCtx, context),
|
||||
serializationManager.Read<TValue>(value, hookCtx, context));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,40 +6,67 @@ 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.TypeSerializers.Interfaces;
|
||||
|
||||
namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
{
|
||||
[TypeSerializer]
|
||||
public sealed class ValueTupleSerializer<T1, T2> : ITypeSerializer<ValueTuple<T1, T2>, MappingDataNode>, ITypeCopyCreator<ValueTuple<T1, T2>>
|
||||
public sealed class ValueTupleSerializer<T1, T2> :
|
||||
ITypeReader<ValueTuple<T1, T2>, MappingDataNode>,
|
||||
ITypeSerializer<ValueTuple<T1, T2>, SequenceDataNode>,
|
||||
ITypeCopyCreator<ValueTuple<T1, T2>>
|
||||
{
|
||||
public (T1, T2) Read(ISerializationManager serializationManager, MappingDataNode node,
|
||||
public (T1, T2) Read(
|
||||
ISerializationManager serializationManager,
|
||||
MappingDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
ISerializationContext? context = null, ISerializationManager.InstantiationDelegate<(T1, T2)>? val = null)
|
||||
ISerializationContext? context = null,
|
||||
ISerializationManager.InstantiationDelegate<(T1, T2)>? instanceProvider = null)
|
||||
{
|
||||
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.Read<T1>(entry.Key, hookCtx, context);
|
||||
var v1 = serializationManager.Read<T1>(node.GetKeyNode(entry.Key), hookCtx, context);
|
||||
var v2 = serializationManager.Read<T2>(entry.Value, hookCtx, context);
|
||||
|
||||
return (v1, v2);
|
||||
}
|
||||
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||
public (T1, T2) Read(
|
||||
ISerializationManager serializationManager,
|
||||
SequenceDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
ISerializationContext? context = null,
|
||||
ISerializationManager.InstantiationDelegate<(T1, T2)>? val = null)
|
||||
{
|
||||
if (node.Count != 2)
|
||||
throw new InvalidMappingException("Sequence must contain exactly 2 elements.");
|
||||
|
||||
var v1 = serializationManager.Read<T1>(node[0], hookCtx, context);
|
||||
var v2 = serializationManager.Read<T2>(node[1], hookCtx, context);
|
||||
|
||||
return (v1, v2);
|
||||
}
|
||||
|
||||
public ValidationNode Validate(
|
||||
ISerializationManager serializationManager,
|
||||
MappingDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
if (node.Children.Count != 1) return new ErrorNode(node, "More or less than 1 Mapping for ValueTuple found.");
|
||||
if (node.Children.Count != 1)
|
||||
return new ErrorNode(node, "More or less than 1 Mapping for ValueTuple found.");
|
||||
|
||||
var entry = node.Children.First();
|
||||
var dict = new Dictionary<ValidationNode, ValidationNode>
|
||||
{
|
||||
{
|
||||
serializationManager.ValidateNode<T1>(entry.Key, context),
|
||||
serializationManager.ValidateNode<T1>(node.GetKeyNode(entry.Key), context),
|
||||
serializationManager.ValidateNode<T2>(entry.Value, context)
|
||||
}
|
||||
};
|
||||
@@ -47,21 +74,44 @@ namespace Robust.Shared.Serialization.TypeSerializers.Implementations.Generic
|
||||
return new ValidatedMappingNode(dict);
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, (T1, T2) value,
|
||||
IDependencyCollection dependencies, bool alwaysWrite = false,
|
||||
public ValidationNode Validate(
|
||||
ISerializationManager serializationManager,
|
||||
SequenceDataNode node,
|
||||
IDependencyCollection dependencies,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
var mapping = new MappingDataNode();
|
||||
if (node.Count != 2)
|
||||
throw new InvalidMappingException("Sequence must contain exactly 2 elements.");
|
||||
|
||||
mapping.Add(
|
||||
serializationManager.WriteValue<T1>(value.Item1, alwaysWrite, context),
|
||||
serializationManager.WriteValue<T2>(value.Item2, alwaysWrite, context));
|
||||
var seq = new List<ValidationNode>
|
||||
{
|
||||
serializationManager.ValidateNode<T1>(node[0], context),
|
||||
serializationManager.ValidateNode<T2>(node[1], context)
|
||||
};
|
||||
|
||||
return mapping;
|
||||
return new ValidatedSequenceNode(seq);
|
||||
}
|
||||
|
||||
public (T1, T2) CreateCopy(ISerializationManager serializationManager, (T1, T2) source,
|
||||
IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
public DataNode Write(
|
||||
ISerializationManager serializationManager,
|
||||
(T1, T2) value,
|
||||
IDependencyCollection dependencies,
|
||||
bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
return new SequenceDataNode(new List<DataNode>
|
||||
{
|
||||
serializationManager.WriteValue(value.Item1, alwaysWrite, context),
|
||||
serializationManager.WriteValue(value.Item2, alwaysWrite, context)
|
||||
});
|
||||
}
|
||||
|
||||
public (T1, T2) CreateCopy(
|
||||
ISerializationManager serializationManager,
|
||||
(T1, T2) source,
|
||||
IDependencyCollection dependencies,
|
||||
SerializationHookContext hookCtx,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
return (serializationManager.CreateCopy(source.Item1, hookCtx, context),
|
||||
serializationManager.CreateCopy(source.Item2, hookCtx, context));
|
||||
|
||||
@@ -51,24 +51,29 @@ namespace Robust.UnitTesting.Shared.Physics
|
||||
TransformComponent xform = default!;
|
||||
PhysicsComponent entityTwoPhysics = default!;
|
||||
|
||||
EntityUid? entityOne = null;
|
||||
EntityUid? entityTwo = null;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mapSystem.CreateMap(out mapId);
|
||||
grid = mapManager.CreateGridEntity(mapId);
|
||||
mapSystem.SetTile(grid, Vector2i.Zero, new Tile(1));
|
||||
|
||||
var entityOne = entManager.SpawnEntity("CollisionWakeTestItem", new MapCoordinates(Vector2.One * 2f, mapId));
|
||||
entityOnePhysics = entManager.GetComponent<PhysicsComponent>(entityOne);
|
||||
xform = entManager.GetComponent<TransformComponent>(entityOne);
|
||||
entityOne = entManager.SpawnEntity("CollisionWakeTestItem", new MapCoordinates(Vector2.One * 2f, mapId));
|
||||
entityOnePhysics = entManager.GetComponent<PhysicsComponent>(entityOne.Value);
|
||||
xform = entManager.GetComponent<TransformComponent>(entityOne.Value);
|
||||
mapSystem.TryGetMap(mapId, out var mapUid);
|
||||
Assert.That(xform.ParentUid == mapUid);
|
||||
|
||||
var entityTwo = entManager.SpawnEntity("CollisionWakeTestItem", new EntityCoordinates(grid, new Vector2(0.5f, 0.5f)));
|
||||
entityTwoPhysics = entManager.GetComponent<PhysicsComponent>(entityTwo);
|
||||
Assert.That(entManager.GetComponent<TransformComponent>(entityTwo).ParentUid == grid.Owner);
|
||||
entityTwo = entManager.SpawnEntity("CollisionWakeTestItem", new EntityCoordinates(grid, new Vector2(0.5f, 0.5f)));
|
||||
entityTwoPhysics = entManager.GetComponent<PhysicsComponent>(entityTwo.Value);
|
||||
Assert.That(entManager.GetComponent<TransformComponent>(entityTwo.Value).ParentUid == grid.Owner);
|
||||
|
||||
});
|
||||
|
||||
Assert.That(entityOne, Is.Not.Null);
|
||||
Assert.That(entityTwo, Is.Not.Null);
|
||||
|
||||
// Item 1 Should still be collidable
|
||||
await server.WaitRunTicks(1);
|
||||
|
||||
@@ -77,8 +82,8 @@ namespace Robust.UnitTesting.Shared.Physics
|
||||
Assert.That(entityOnePhysics.Awake, Is.EqualTo(false));
|
||||
Assert.That(entityOnePhysics.CanCollide, Is.EqualTo(true));
|
||||
|
||||
xform.LocalPosition = new Vector2(0.5f, 0.5f);
|
||||
xform.AttachParent(grid);
|
||||
transformSystem.SetLocalPosition(entityOne.Value, new Vector2(0.5f, 0.5f), xform);
|
||||
transformSystem.SetParent(entityOne.Value, xform, grid);
|
||||
|
||||
// Entity 2 should immediately not be collidable on spawn
|
||||
Assert.That(entityTwoPhysics.Awake, Is.EqualTo(false));
|
||||
@@ -92,8 +97,8 @@ namespace Robust.UnitTesting.Shared.Physics
|
||||
Assert.That(entityOnePhysics.Awake, Is.EqualTo(false));
|
||||
Assert.That(entityOnePhysics.CanCollide, Is.EqualTo(false));
|
||||
|
||||
xform.LocalPosition = Vector2.One * 2f;
|
||||
xform.AttachParent(mapManager.GetMapEntityId(mapId));
|
||||
transformSystem.SetLocalPosition(entityOne.Value, Vector2.One * 2f);
|
||||
transformSystem.SetParent(entityOne.Value, xform, mapSystem.GetMapOrInvalid(mapId));
|
||||
});
|
||||
|
||||
// Juussttt in case we'll re-parent it to the map and check its collision is back on.
|
||||
|
||||
@@ -69,10 +69,10 @@ public sealed partial class ManagerTests : SerializationTest
|
||||
}, //ISelfSerialize
|
||||
new object[]
|
||||
{
|
||||
new MappingDataNode(new Dictionary<DataNode, DataNode>
|
||||
new MappingDataNode(new Dictionary<string, DataNode>
|
||||
{
|
||||
{ new ValueDataNode("one"), new ValueDataNode("valueOne") },
|
||||
{ new ValueDataNode("two"), new SequenceDataNode("2", "3") },
|
||||
{ "one", new ValueDataNode("valueOne") },
|
||||
{ "two", new SequenceDataNode("2", "3") },
|
||||
}){Tag = $"!type:{nameof(DataDefClass)}"},
|
||||
() => (IDataDefBaseInterface)new DataDefClass
|
||||
{
|
||||
@@ -112,10 +112,10 @@ public sealed partial class ManagerTests : SerializationTest
|
||||
}, //array
|
||||
new object[]
|
||||
{
|
||||
new MappingDataNode(new Dictionary<DataNode, DataNode>
|
||||
new MappingDataNode(new Dictionary<string, DataNode>
|
||||
{
|
||||
{ new ValueDataNode("one"), new ValueDataNode("valueOne") },
|
||||
{ new ValueDataNode("two"), new SequenceDataNode("2", "3") },
|
||||
{ "one", new ValueDataNode("valueOne") },
|
||||
{ "two", new SequenceDataNode("2", "3") },
|
||||
}),
|
||||
() => new DataDefClass
|
||||
{
|
||||
@@ -204,10 +204,10 @@ public sealed partial class ManagerTests : SerializationTest
|
||||
{
|
||||
new object[]
|
||||
{
|
||||
new MappingDataNode(new Dictionary<DataNode, DataNode>()
|
||||
new MappingDataNode(new Dictionary<string, DataNode>()
|
||||
{
|
||||
{ new ValueDataNode("one"), new ValueDataNode("valueOne") },
|
||||
{ new ValueDataNode("two"), new SequenceDataNode("2", "3") },
|
||||
{ "one", new ValueDataNode("valueOne") },
|
||||
{ "two", new SequenceDataNode("2", "3") },
|
||||
}),
|
||||
() => new DataDefStruct
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ public sealed partial class ReadValueProviderTests : SerializationTest
|
||||
public void DataDefinitionMappingBaseTest()
|
||||
{
|
||||
var data = "someData";
|
||||
var mapping = new MappingDataNode(new Dictionary<DataNode, DataNode>{{ new ValueDataNode("data"), new ValueDataNode(data) }})
|
||||
var mapping = new MappingDataNode(new Dictionary<string, DataNode>{{ "data", new ValueDataNode(data) }})
|
||||
{
|
||||
Tag = $"!type:{nameof(DataDefinitionValueProviderTestDummy)}"
|
||||
};
|
||||
|
||||
@@ -21,6 +21,8 @@ proto:
|
||||
---
|
||||
entity:
|
||||
uid: int()
|
||||
paused: bool(required=False)
|
||||
mapInit: bool(required=False)
|
||||
components: list(comp())
|
||||
missingComponents: list(str(), required=False)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user