From 7fe7fadebe8cb169515d152c9c0051afdf7f606b Mon Sep 17 00:00:00 2001 From: SnappingOpossum Date: Mon, 1 Jun 2026 13:09:17 +1000 Subject: [PATCH 1/3] Make SpawnNextToOrDrop use Entity, allow an offset, and delay initialisation. --- .../GameObjects/ClientEntityManager.Spawn.cs | 5 ++-- .../GameObjects/EntityManager.Spawn.cs | 24 +++++++++---------- .../GameObjects/EntitySystem.Proxy.cs | 17 ++++++------- .../GameObjects/IEntityManager.Spawn.cs | 8 +++---- .../SharedTransformSystem.Component.cs | 4 ++-- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Robust.Client/GameObjects/ClientEntityManager.Spawn.cs b/Robust.Client/GameObjects/ClientEntityManager.Spawn.cs index a83ef38a9..c4694061e 100644 --- a/Robust.Client/GameObjects/ClientEntityManager.Spawn.cs +++ b/Robust.Client/GameObjects/ClientEntityManager.Spawn.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -69,9 +70,9 @@ public override bool PredictedTrySpawnInContainer( return true; } - public override EntityUid PredictedSpawnNextToOrDrop(string? protoName, EntityUid target, TransformComponent? xform = null, ComponentRegistry? overrides = null) + public override EntityUid PredictedSpawnNextToOrDrop(EntProtoId? protoName, Entity target, Vector2 offset = default, ComponentRegistry? overrides = null) { - var ent = SpawnNextToOrDrop(protoName, target, xform, overrides); + var ent = SpawnNextToOrDrop(protoName, target, offset, overrides); FlagPredicted(ent); return ent; } diff --git a/Robust.Shared/GameObjects/EntityManager.Spawn.cs b/Robust.Shared/GameObjects/EntityManager.Spawn.cs index 94a86489b..8fe1092aa 100644 --- a/Robust.Shared/GameObjects/EntityManager.Spawn.cs +++ b/Robust.Shared/GameObjects/EntityManager.Spawn.cs @@ -3,11 +3,11 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; using Robust.Shared.Collections; using Robust.Shared.Containers; using Robust.Shared.Maths; -using Robust.Shared.Serialization; namespace Robust.Shared.GameObjects; @@ -141,9 +141,9 @@ public bool TrySpawnNextTo( if (!xform.ParentUid.IsValid()) return false; - if (!_containers.TryGetContainingContainer(target, out var container)) + if (!_containers.TryGetContainingContainer((target, xform), out var container)) { - uid = SpawnNextToOrDrop(protoName, target, xform, overrides); + uid = SpawnNextToOrDrop(protoName, (target, xform), overrides: overrides); return true; } @@ -183,15 +183,15 @@ public bool TrySpawnInContainer( return false; } - public EntityUid SpawnNextToOrDrop(string? protoName, EntityUid target, TransformComponent? xform = null, ComponentRegistry? overrides = null) + public EntityUid SpawnNextToOrDrop(EntProtoId? protoName, Entity target, Vector2 offset = default, ComponentRegistry? overrides = null) { - xform ??= TransformQuery.GetComponent(target); - if (!xform.ParentUid.IsValid()) - return Spawn(protoName); + if (!TransformQuery.Resolve(target, ref target.Comp) || + !target.Comp.ParentUid.IsValid()) + return Spawn(protoName, overrides); - var doMapInit = _mapSystem.IsInitialized(xform.MapUid); - var uid = Spawn(protoName, overrides, doMapInit); - _xforms.DropNextTo(uid, target); + var uid = CreateEntityUninitialized(protoName, out var meta, overrides); + _xforms.DropNextTo(uid, target, offset); + InitializeAndStartEntity((uid, meta), _mapSystem.IsInitialized(target.Comp.MapUid)); return uid; } @@ -275,9 +275,9 @@ public virtual bool PredictedTrySpawnInContainer( return TrySpawnInContainer(protoName, containerUid, containerId, out uid, containerComp, overrides); } - public virtual EntityUid PredictedSpawnNextToOrDrop(string? protoName, EntityUid target, TransformComponent? xform = null, ComponentRegistry? overrides = null) + public virtual EntityUid PredictedSpawnNextToOrDrop(EntProtoId? protoName, Entity target, Vector2 offset = default, ComponentRegistry? overrides = null) { - return SpawnNextToOrDrop(protoName, target, xform, overrides); + return SpawnNextToOrDrop(protoName, target, offset, overrides); } public virtual EntityUid PredictedSpawnInContainerOrDrop( diff --git a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs index 8a264e687..b175da8cd 100644 --- a/Robust.Shared/GameObjects/EntitySystem.Proxy.cs +++ b/Robust.Shared/GameObjects/EntitySystem.Proxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; using JetBrains.Annotations; using Robust.Shared.Containers; @@ -969,12 +970,12 @@ protected bool TrySpawnNextTo( [MethodImpl(MethodImplOptions.AggressiveInlining)] [ProxyFor(typeof(EntityManager))] protected EntityUid SpawnNextToOrDrop( - string? protoName, - EntityUid target, - TransformComponent? xform = null, + EntProtoId? protoName, + Entity target, + Vector2 offset = default, ComponentRegistry? overrides = null) { - return EntityManager.SpawnNextToOrDrop(protoName, target, xform, overrides); + return EntityManager.SpawnNextToOrDrop(protoName, target, offset, overrides); } /// @@ -1044,12 +1045,12 @@ protected bool PredictedTrySpawnNextTo( [MethodImpl(MethodImplOptions.AggressiveInlining)] [ProxyFor(typeof(EntityManager))] protected EntityUid PredictedSpawnNextToOrDrop( - string? protoName, - EntityUid target, - TransformComponent? xform = null, + EntProtoId? protoName, + Entity target, + Vector2 offset = default, ComponentRegistry? overrides = null) { - return EntityManager.PredictedSpawnNextToOrDrop(protoName, target, xform, overrides); + return EntityManager.PredictedSpawnNextToOrDrop(protoName, target, offset, overrides); } /// diff --git a/Robust.Shared/GameObjects/IEntityManager.Spawn.cs b/Robust.Shared/GameObjects/IEntityManager.Spawn.cs index 9a973cb4f..234a3e210 100644 --- a/Robust.Shared/GameObjects/IEntityManager.Spawn.cs +++ b/Robust.Shared/GameObjects/IEntityManager.Spawn.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Robust.Shared.Collections; +using System.Numerics; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Maths; @@ -100,8 +100,8 @@ bool TrySpawnNextTo( /// instead attempt to spawn the entity next to the target's parent. /// EntityUid SpawnNextToOrDrop( - string? protoName, - EntityUid target, - TransformComponent? xform = null, + EntProtoId? protoName, + Entity target, + Vector2 offset = default, ComponentRegistry? overrides = null); } diff --git a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs index 2fa10c984..01d06434b 100644 --- a/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs +++ b/Robust.Shared/GameObjects/Systems/SharedTransformSystem.Component.cs @@ -1634,7 +1634,7 @@ private void OnGridAdd(EntityUid uid, TransformComponent component, GridAddEvent /// this will attempt to insert that entity into the same container. Otherwise it will attach the entity to the /// grid or map at the same world-position as the target entity. /// - public void DropNextTo(Entity entity, Entity target) + public void DropNextTo(Entity entity, Entity target, Vector2 offset = default) { var xform = entity.Comp; if (!XformQuery.Resolve(entity, ref xform)) @@ -1647,7 +1647,7 @@ public void DropNextTo(Entity entity, Entity Date: Mon, 1 Jun 2026 13:28:59 +1000 Subject: [PATCH 2/3] Add some release notes --- RELEASE-NOTES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index e60a7b1ed..b6ff6f5e3 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -35,15 +35,15 @@ END TEMPLATE--> ### Breaking changes -*None yet* +- SpawnNextToOrDrop methods have been changed to take `EntProtoId?, Entity, Vector2 = default` instead of `string?, EntityUid, TransformComponent? null`. Because of this, some `Entity`s will need to first be explicity converted into `EntityUid`s. ### New features -*None yet* +- SpawnNextToOrDrop methods can now offset their spawns by passing in a Vector2. This offset is always relative to the target. ### Bugfixes -*None yet* +- SpawnNextToOrDrop no longer initialises entities in nullspace. ### Other From ea52ec0d80f1d428404b4820ab12eb6054462f5f Mon Sep 17 00:00:00 2001 From: SnappingOpossum Date: Mon, 1 Jun 2026 20:04:35 +1000 Subject: [PATCH 3/3] Saw 6192 so make sure the components initialise before interacting with containers --- RELEASE-NOTES.md | 2 +- Robust.Shared/GameObjects/EntityManager.Spawn.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index b6ff6f5e3..d242f1e07 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -43,7 +43,7 @@ END TEMPLATE--> ### Bugfixes -- SpawnNextToOrDrop no longer initialises entities in nullspace. +- SpawnNextToOrDrop no longer runs mapinit on entities in nullspace. ### Other diff --git a/Robust.Shared/GameObjects/EntityManager.Spawn.cs b/Robust.Shared/GameObjects/EntityManager.Spawn.cs index 8fe1092aa..df62e04e2 100644 --- a/Robust.Shared/GameObjects/EntityManager.Spawn.cs +++ b/Robust.Shared/GameObjects/EntityManager.Spawn.cs @@ -190,8 +190,10 @@ public EntityUid SpawnNextToOrDrop(EntProtoId? protoName, Entity