mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Add a method for copying components (#5654)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -1075,6 +1075,97 @@ namespace Robust.Shared.GameObjects
|
||||
return TryGetComponent(uid.Value, netId, out component, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryCopyComponent<T>(EntityUid source, EntityUid target, ref T? sourceComponent, [NotNullWhen(true)] out T? targetComp, MetaDataComponent? meta = null) where T : IComponent
|
||||
{
|
||||
if (!MetaQuery.Resolve(target, ref meta))
|
||||
{
|
||||
targetComp = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sourceComponent == null && !TryGetComponent(source, out sourceComponent))
|
||||
{
|
||||
targetComp = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
targetComp = CopyComponentInternal(source, target, sourceComponent, meta);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryCopyComponents(
|
||||
EntityUid source,
|
||||
EntityUid target,
|
||||
MetaDataComponent? meta = null,
|
||||
params Type[] sourceComponents)
|
||||
{
|
||||
if (!MetaQuery.TryGetComponent(source, out meta))
|
||||
return false;
|
||||
|
||||
var allCopied = true;
|
||||
|
||||
foreach (var type in sourceComponents)
|
||||
{
|
||||
if (!TryGetComponent(source, type, out var srcComp))
|
||||
{
|
||||
allCopied = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
CopyComponent(source, target, srcComp, meta: meta);
|
||||
}
|
||||
|
||||
return allCopied;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IComponent CopyComponent(EntityUid source, EntityUid target, IComponent sourceComponent, MetaDataComponent? meta = null)
|
||||
{
|
||||
if (!MetaQuery.Resolve(target, ref meta))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return CopyComponentInternal(source, target, sourceComponent, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T CopyComponent<T>(EntityUid source, EntityUid target, T sourceComponent,MetaDataComponent? meta = null) where T : IComponent
|
||||
{
|
||||
if (!MetaQuery.Resolve(target, ref meta))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return CopyComponentInternal(source, target, sourceComponent, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CopyComponents(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params IComponent[] sourceComponents)
|
||||
{
|
||||
if (!MetaQuery.Resolve(target, ref meta))
|
||||
return;
|
||||
|
||||
foreach (var comp in sourceComponents)
|
||||
{
|
||||
CopyComponentInternal(source, target, comp, meta);
|
||||
}
|
||||
}
|
||||
|
||||
private T CopyComponentInternal<T>(EntityUid source, EntityUid target, T sourceComponent, MetaDataComponent meta) where T : IComponent
|
||||
{
|
||||
var compReg = ComponentFactory.GetRegistration(sourceComponent.GetType());
|
||||
var component = (T)ComponentFactory.GetComponent(compReg);
|
||||
|
||||
_serManager.CopyTo(sourceComponent, ref component, notNullableOverride: true);
|
||||
component.Owner = target;
|
||||
|
||||
AddComponentInternal(target, component, compReg, true, false, meta);
|
||||
return component;
|
||||
}
|
||||
|
||||
public EntityQuery<TComp1> GetEntityQuery<TComp1>() where TComp1 : IComponent
|
||||
{
|
||||
var comps = _entTraitArray[CompIdx.ArrayIndex<TComp1>()];
|
||||
|
||||
@@ -565,6 +565,52 @@ public partial class EntitySystem
|
||||
|
||||
#endregion
|
||||
|
||||
#region Component Copy
|
||||
|
||||
/// <inheritdoc cref="IEntityManager.TryCopyComponent"/>
|
||||
protected bool TryCopyComponent<T>(
|
||||
EntityUid source,
|
||||
EntityUid target,
|
||||
ref T? sourceComponent,
|
||||
[NotNullWhen(true)] out T? targetComp,
|
||||
MetaDataComponent? meta = null) where T : IComponent
|
||||
{
|
||||
return EntityManager.TryCopyComponent(source, target, ref sourceComponent, out targetComp, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEntityManager.TryCopyComponents"/>
|
||||
protected bool TryCopyComponents(
|
||||
EntityUid source,
|
||||
EntityUid target,
|
||||
MetaDataComponent? meta = null,
|
||||
params Type[] sourceComponents)
|
||||
{
|
||||
return EntityManager.TryCopyComponents(source, target, meta, sourceComponents);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEntityManager.CopyComponent"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected IComponent CopyComp(EntityUid source, EntityUid target, IComponent sourceComponent, MetaDataComponent? meta = null)
|
||||
{
|
||||
return EntityManager.CopyComponent(source, target, sourceComponent, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEntityManager.CopyComponent{T}"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected T CopyComp<T>(EntityUid source, EntityUid target, T sourceComponent, MetaDataComponent? meta = null) where T : IComponent
|
||||
{
|
||||
return EntityManager.CopyComponent(source, target, sourceComponent, meta);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IEntityManager.CopyComponents"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected void CopyComps(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params IComponent[] sourceComponents)
|
||||
{
|
||||
EntityManager.CopyComponents(source, target, meta, sourceComponents);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Component Has
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -358,6 +358,51 @@ namespace Robust.Shared.GameObjects
|
||||
/// <returns>If the component existed in the entity.</returns>
|
||||
bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, [NotNullWhen(true)] out IComponent? component, MetaDataComponent? meta = null);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to run <see cref="CopyComponents"/> without throwing if the component doesn't exist.
|
||||
/// </summary>
|
||||
bool TryCopyComponent<T>(
|
||||
EntityUid source,
|
||||
EntityUid target,
|
||||
ref T? sourceComponent,
|
||||
[NotNullWhen(true)] out T? targetComp,
|
||||
MetaDataComponent? meta = null) where T : IComponent;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to run <see cref="CopyComponents"/> without throwing if the components don't exist.
|
||||
/// </summary>
|
||||
bool TryCopyComponents(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params Type[] sourceComponents);
|
||||
|
||||
/// <summary>
|
||||
/// Copy a single component from source to target entity.
|
||||
/// </summary>
|
||||
/// <param name="source">The source entity to copy from.</param>
|
||||
/// <param name="target">The target entity to copy to.</param>
|
||||
/// <param name="sourceComponent">The source component instance to copy.</param>
|
||||
/// <param name="component">The copied component if successful.</param>
|
||||
/// <param name="meta">Optional metadata of the target entity.</param>
|
||||
IComponent CopyComponent(EntityUid source, EntityUid target, IComponent sourceComponent, MetaDataComponent? meta = null);
|
||||
|
||||
/// <summary>
|
||||
/// Copy a single component from source to target entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of component to copy.</typeparam>
|
||||
/// <param name="source">The source entity to copy from.</param>
|
||||
/// <param name="target">The target entity to copy to.</param>
|
||||
/// <param name="sourceComponent">The source component instance to copy.</param>
|
||||
/// <param name="component">The copied component if successful.</param>
|
||||
/// <param name="meta">Optional metadata of the target entity.</param>
|
||||
T CopyComponent<T>(EntityUid source, EntityUid target, T sourceComponent, MetaDataComponent? meta = null) where T : IComponent;
|
||||
|
||||
/// <summary>
|
||||
/// Copy multiple components from source to target entity using existing component instances.
|
||||
/// </summary>
|
||||
/// <param name="source">The source entity to copy from.</param>
|
||||
/// <param name="target">The target entity to copy to.</param>
|
||||
/// <param name="meta">Optional metadata of the target entity.</param>
|
||||
/// <param name="sourceComponents">Array of component instances to copy.</param>
|
||||
void CopyComponents(EntityUid source, EntityUid target, MetaDataComponent? meta = null, params IComponent[] sourceComponents);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cached struct enumerator with the specified component.
|
||||
/// </summary>
|
||||
|
||||
128
Robust.UnitTesting/Shared/GameObjects/EntityManagerCopyTests.cs
Normal file
128
Robust.UnitTesting/Shared/GameObjects/EntityManagerCopyTests.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.GameObjects;
|
||||
|
||||
[TestFixture]
|
||||
public sealed partial class EntityManagerCopyTests
|
||||
{
|
||||
[Test]
|
||||
public void CopyComponentGeneric()
|
||||
{
|
||||
var instant = RobustServerSimulation.NewSimulation();
|
||||
instant.RegisterComponents(fac =>
|
||||
{
|
||||
fac.RegisterClass<AComponent>();
|
||||
});
|
||||
|
||||
var sim = instant.InitializeInstance();
|
||||
var entManager = sim.Resolve<IEntityManager>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
|
||||
var original = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
var comp = entManager.AddComponent<AComponent>(original);
|
||||
|
||||
Assert.That(comp.Value, Is.EqualTo(false));
|
||||
comp.Value = true;
|
||||
|
||||
var target = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
Assert.That(!entManager.HasComponent<AComponent>(target));
|
||||
|
||||
var targetComp = entManager.CopyComponent(original, target, comp);
|
||||
|
||||
Assert.That(targetComp!.Owner == target);
|
||||
Assert.That(targetComp.Value, Is.EqualTo(comp.Value));
|
||||
Assert.That(!ReferenceEquals(comp, targetComp));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyComponentNonGeneric()
|
||||
{
|
||||
var instant = RobustServerSimulation.NewSimulation();
|
||||
instant.RegisterComponents(fac =>
|
||||
{
|
||||
fac.RegisterClass<AComponent>();
|
||||
});
|
||||
|
||||
var sim = instant.InitializeInstance();
|
||||
var entManager = sim.Resolve<IEntityManager>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
|
||||
var original = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
var comp = entManager.AddComponent<AComponent>(original);
|
||||
|
||||
Assert.That(comp.Value, Is.EqualTo(false));
|
||||
comp.Value = true;
|
||||
|
||||
var target = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
Assert.That(!entManager.HasComponent<AComponent>(target));
|
||||
|
||||
var targetComp = entManager.CopyComponent(original, target, (IComponent) comp);
|
||||
|
||||
Assert.That(targetComp!.Owner == target);
|
||||
Assert.That(((AComponent) targetComp).Value, Is.EqualTo(comp.Value));
|
||||
Assert.That(!ReferenceEquals(comp, targetComp));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyComponentMultiple()
|
||||
{
|
||||
var instant = RobustServerSimulation.NewSimulation();
|
||||
instant.RegisterComponents(fac =>
|
||||
{
|
||||
fac.RegisterClass<AComponent>();
|
||||
fac.RegisterClass<BComponent>();
|
||||
});
|
||||
|
||||
var sim = instant.InitializeInstance();
|
||||
var entManager = sim.Resolve<IEntityManager>();
|
||||
var mapSystem = entManager.System<SharedMapSystem>();
|
||||
|
||||
mapSystem.CreateMap(out var mapId);
|
||||
|
||||
var original = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
var comp = entManager.AddComponent<AComponent>(original);
|
||||
var comp2 = entManager.AddComponent<BComponent>(original);
|
||||
|
||||
Assert.That(comp.Value, Is.EqualTo(false));
|
||||
comp.Value = true;
|
||||
|
||||
var target = entManager.Spawn(null, new MapCoordinates(Vector2.Zero, mapId));
|
||||
Assert.That(!entManager.HasComponent<AComponent>(target));
|
||||
|
||||
entManager.CopyComponents(original, target, null, comp, comp2);
|
||||
var targetComp = entManager.GetComponent<AComponent>(target);
|
||||
var targetComp2 = entManager.GetComponent<BComponent>(target);
|
||||
|
||||
Assert.That(targetComp!.Owner == target);
|
||||
Assert.That(targetComp.Value, Is.EqualTo(comp.Value));
|
||||
|
||||
Assert.That(targetComp2!.Owner == target);
|
||||
Assert.That(targetComp2.Value, Is.EqualTo(comp2.Value));
|
||||
|
||||
Assert.That(!ReferenceEquals(comp, targetComp));
|
||||
Assert.That(!ReferenceEquals(comp2, targetComp2));
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
private sealed partial class AComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool Value = false;
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
private sealed partial class BComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool Value = false;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.GameObjects
|
||||
{
|
||||
[TestFixture, Parallelizable]
|
||||
sealed class EntityManagerTests
|
||||
sealed partial class EntityManagerTests
|
||||
{
|
||||
private static ISimulation SimulationFactory()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user