diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index 1f9c0b4c2f..1e75cd27a2 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -72,7 +72,7 @@ namespace Content.IntegrationTests.Tests.Body await server.WaitPost(() => { mapId = mapManager.CreateMap(); - grid = mapLoader.LoadBlueprint(mapId, testMapName).gridId; + grid = mapLoader.LoadGrid(mapId, testMapName).gridId; }); Assert.NotNull(grid, $"Test blueprint {testMapName} not found."); @@ -144,7 +144,7 @@ namespace Content.IntegrationTests.Tests.Body await server.WaitPost(() => { mapId = mapManager.CreateMap(); - grid = mapLoader.LoadBlueprint(mapId, testMapName).gridId; + grid = mapLoader.LoadGrid(mapId, testMapName).gridId; }); Assert.NotNull(grid, $"Test blueprint {testMapName} not found."); diff --git a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs index 256a41e902..2a42f36047 100644 --- a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs @@ -27,10 +27,10 @@ namespace Content.IntegrationTests.Tests { // TODO: Properly find the "main" station grid. var grid0 = mapManager.GetAllGrids().First(); - mapLoader.SaveBlueprint(grid0.GridEntityId, "save load save 1.yml"); + mapLoader.SaveGrid(grid0.GridEntityId, "save load save 1.yml"); var mapId = mapManager.CreateMap(); - var grid = mapLoader.LoadBlueprint(mapId, "save load save 1.yml").gridId; - mapLoader.SaveBlueprint(grid!.Value, "save load save 2.yml"); + var grid = mapLoader.LoadGrid(mapId, "save load save 1.yml").gridId; + mapLoader.SaveGrid(grid!.Value, "save load save 2.yml"); }); await server.WaitIdleAsync(); diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index c30a7d70c5..390f9dcd6d 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -287,7 +287,7 @@ public sealed partial class CargoSystem var possibleNames = _protoMan.Index(prototype.NameDataset).Values; var name = _random.Pick(possibleNames); - var (_, shuttleUid) = _loader.LoadBlueprint(CargoMap.Value, prototype.Path.ToString()); + var (_, shuttleUid) = _loader.LoadGrid(CargoMap.Value, prototype.Path.ToString()); var xform = Transform(shuttleUid!.Value); MetaData(shuttleUid!.Value).EntityName = name; diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 8af49e18db..6ec7fab1dc 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -25,7 +25,7 @@ namespace Content.Server.GameTicking { private const string ObserverPrototypeName = "MobObserver"; - [ViewVariables(VVAccess.ReadWrite), Obsolete("Due for removal when observer spawning is refactored.")] + [ViewVariables(VVAccess.ReadWrite), Obsolete("Due for removal when observer spawning is refactored.")] // See also: MindComponent's OnShutdown shitcode private EntityCoordinates _spawnPoint; /// @@ -280,7 +280,11 @@ namespace Content.Server.GameTicking #region Spawn Points public EntityCoordinates GetObserverSpawnPoint() { - var location = _spawnPoint; + // TODO rename this to TryGetObserverSpawnPoint to make it clear that the result might be invalid. Or at + // least try try more fallback values, like randomly spawning them in any available map or just creating a + // "we fucked up" map. Its better than dumping them into the void. + + var location = _spawnPoint.IsValid(EntityManager) ? _spawnPoint : EntityCoordinates.Invalid; _possiblePositions.Clear(); diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 3ca27a4a46..bf748a9aa1 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -195,7 +195,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var shuttlePath = "/Maps/infiltrator.yml"; var mapId = _mapManager.CreateMap(); - var (_, outpost) = _mapLoader.LoadBlueprint(mapId, "/Maps/nukieplanet.yml"); + var (_, outpost) = _mapLoader.LoadGrid(mapId, "/Maps/nukieplanet.yml"); if (outpost == null) { @@ -204,7 +204,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem } // Listen I just don't want it to overlap. - var (_, shuttleId) = _mapLoader.LoadBlueprint(mapId, shuttlePath, new MapLoadOptions() + var (_, shuttleId) = _mapLoader.LoadGrid(mapId, shuttlePath, new MapLoadOptions() { Offset = Vector2.One * 1000f, }); diff --git a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs index 8cf8f2711a..55df00c3fd 100644 --- a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs @@ -155,7 +155,7 @@ public sealed class PiratesRuleSystem : GameRuleSystem aabb.Union(aabbs[i]); } - var (_, gridId) = _mapLoader.LoadBlueprint(GameTicker.DefaultMap, map, new MapLoadOptions + var (_, gridId) = _mapLoader.LoadGrid(GameTicker.DefaultMap, map, new MapLoadOptions { Offset = aabb.Center + MathF.Max(aabb.Height / 2f, aabb.Width / 2f) * 2.5f }); diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index 423b5d0167..be7656a6b9 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -80,8 +80,11 @@ public sealed class MindSystem : EntitySystem } else if (mind.GhostOnShutdown) { + // Changing an entities parents while deleting is VERY sus. This WILL throw exceptions. + // TODO: just find the applicable spawn position dirctly without actually updating the transform's parent. Transform(uid).AttachToGridOrMap(); var spawnPosition = Transform(uid).Coordinates; + // Use a regular timer here because the entity has probably been deleted. Timer.Spawn(0, () => { @@ -96,6 +99,13 @@ public sealed class MindSystem : EntitySystem spawnPosition = _gameTicker.GetObserverSpawnPoint(); } + // TODO refactor observer spawning. + if (!spawnPosition.IsValid(EntityManager)) + { + Logger.ErrorS("mind", $"Entity \"{ToPrettyString(uid)}\" for {mind.Mind?.CharacterName} was deleted, and no applicable spawn location is available."); + return; + } + var ghost = Spawn("MobObserver", spawnPosition); var ghostComponent = Comp(ghost); _ghostSystem.SetCanReturnToBody(ghostComponent, false); diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index ffbd630daf..103ee1b810 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -288,7 +288,7 @@ namespace Content.Server.Salvage Offset = spl.Position }; - var (_, salvageEntityId) = _mapLoader.LoadBlueprint(spl.MapId, map.MapPath.ToString(), opts); + var (_, salvageEntityId) = _mapLoader.LoadGrid(spl.MapId, map.MapPath.ToString(), opts); if (salvageEntityId == null) { Report(component.Owner, component.SalvageChannel, "salvage-system-announcement-spawn-debris-disintegrated"); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.EmergencyShuttle.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.EmergencyShuttle.cs index 547d218143..43885e6151 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.EmergencyShuttle.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.EmergencyShuttle.cs @@ -404,7 +404,7 @@ public sealed partial class ShuttleSystem if (!string.IsNullOrEmpty(centComPath)) { - var (_, centcomm) = _loader.LoadBlueprint(_centComMap.Value, "/Maps/centcomm.yml"); + var (_, centcomm) = _loader.LoadGrid(_centComMap.Value, "/Maps/centcomm.yml"); _centCom = centcomm; if (_centCom != null) @@ -426,7 +426,7 @@ public sealed partial class ShuttleSystem if (!_emergencyShuttleEnabled || _centComMap == null || component.EmergencyShuttle != null) return; // Load escape shuttle - var (_, shuttle) = _loader.LoadBlueprint(_centComMap.Value, component.EmergencyShuttlePath.ToString(), new MapLoadOptions() + var (_, shuttle) = _loader.LoadGrid(_centComMap.Value, component.EmergencyShuttlePath.ToString(), new MapLoadOptions() { // Should be far enough... right? I'm too lazy to bounds check CentCom rn. Offset = new Vector2(500f + _shuttleIndex, 0f) diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index c3800febc9..182b0ba84f 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -835,6 +835,13 @@ namespace Content.Shared.Interaction return false; } + if (!Exists(userEntity)) + { + Logger.WarningS("system.interaction", + $"Client attempted interaction with a non-existent attached entity. Session={session}, entity={userEntity}"); + return false; + } + return true; } } diff --git a/Resources/engineCommandPerms.yml b/Resources/engineCommandPerms.yml index cc887175ae..e45db7182f 100644 --- a/Resources/engineCommandPerms.yml +++ b/Resources/engineCommandPerms.yml @@ -66,14 +66,14 @@ - Flags: MAPPING Commands: - addmap - - loadbp + - loadgrid - loadmap - pausemap - querymappaused - rmgrid - rmmap - mapinit - - savebp + - savegrid - savemap - tpgrid - gridtc