diff --git a/Content.Client/Sprite/RandomSpriteSystem.cs b/Content.Client/Sprite/RandomSpriteSystem.cs index a38d543b4a..30c0f8622e 100644 --- a/Content.Client/Sprite/RandomSpriteSystem.cs +++ b/Content.Client/Sprite/RandomSpriteSystem.cs @@ -41,18 +41,23 @@ public sealed class RandomSpriteSystem : SharedRandomSpriteSystem foreach (var layer in component.Selected) { - object key; + int index; if (_reflection.TryParseEnumReference(layer.Key, out var @enum)) { - key = @enum; + if (!sprite.LayerMapTryGet(@enum, out index, logError: true)) + return; } - else + else if (!sprite.LayerMapTryGet(layer.Key, out index)) { - key = layer.Key; + if (layer.Key is not string strKey || !int.TryParse(strKey, out index)) + { + Logger.Error($"Invalid key `{layer.Key}` for entity with random sprite {ToPrettyString(uid)}"); + return; + } } - sprite.LayerSetState(key, layer.Value.State); - sprite.LayerSetColor(key, layer.Value.Color ?? Color.White); + sprite.LayerSetState(index, layer.Value.State); + sprite.LayerSetColor(index, layer.Value.Color ?? Color.White); } } } diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index b0db5461cc..98dd0c9dae 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -46,14 +46,14 @@ namespace Content.IntegrationTests.Tests } }); - await server.WaitRunTicks(5); + await server.WaitRunTicks(15); await server.WaitPost(() => { var entityMetas = entityMan.EntityQuery(true).ToList(); foreach (var meta in entityMetas) { - if(!entityMan.Deleted(meta.Owner)) + if(!meta.EntityDeleted) entityMan.DeleteEntity(meta.Owner); } @@ -67,7 +67,7 @@ namespace Content.IntegrationTests.Tests { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Destructive = true}); var server = pairTracker.Pair.Server; - + var map = await PoolManager.CreateTestMap(pairTracker); IEntityManager entityMan = null; await server.WaitPost(() => @@ -81,21 +81,18 @@ namespace Content.IntegrationTests.Tests .Where(p=>!p.Abstract) .Select(p => p.ID) .ToList(); - var mapId = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(mapId); - var coord = new EntityCoordinates(grid.Owner, 0, 0); foreach (var protoId in protoIds) { - entityMan.SpawnEntity(protoId, coord); + entityMan.SpawnEntity(protoId, map.GridCoords); } }); - await server.WaitRunTicks(5); + await server.WaitRunTicks(15); await server.WaitPost(() => { var entityMetas = entityMan.EntityQuery(true).ToList(); foreach (var meta in entityMetas) { - if(!entityMan.Deleted(meta.Owner)) + if(!meta.EntityDeleted) entityMan.DeleteEntity(meta.Owner); } @@ -103,6 +100,54 @@ namespace Content.IntegrationTests.Tests }); await pairTracker.CleanReturnAsync(); } + + /// + /// Variant of that also launches a client and dirties + /// all components on every entity. + /// + [Test] + public async Task SpawnAndDirtyAllEntities() + { + await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { NoClient = false, Destructive = true }); + var server = pairTracker.Pair.Server; + var map = await PoolManager.CreateTestMap(pairTracker); + IEntityManager entityMan = null; + + await server.WaitPost(() => + { + entityMan = IoCManager.Resolve(); + + var prototypeMan = IoCManager.Resolve(); + var protoIds = prototypeMan + .EnumeratePrototypes() + .Where(p => !p.Abstract) + .Select(p => p.ID) + .ToList(); + foreach (var protoId in protoIds) + { + var ent = entityMan.SpawnEntity(protoId, map.GridCoords); + foreach (var (netId, component) in entityMan.GetNetComponents(ent)) + { + entityMan.Dirty(component); + } + } + }); + await server.WaitRunTicks(15); + await server.WaitPost(() => + { + var entityMetas = entityMan.EntityQuery(true).ToList(); + foreach (var meta in entityMetas) + { + if (!meta.EntityDeleted) + entityMan.DeleteEntity(meta.Owner); + } + + Assert.That(entityMan.EntityCount, Is.Zero); + }); + await pairTracker.CleanReturnAsync(); + } + + [Test] public async Task AllComponentsOneToOneDeleteTest() { diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index 1160d0fac8..2925f67c29 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -86,7 +86,7 @@ namespace Content.Server.Decals return; // Should this be a full component state or a delta-state? - if (args.FromTick <= component.CreationTick && args.FromTick <= component.ForceTick) + if (args.FromTick <= component.CreationTick || args.FromTick <= component.ForceTick) { args.State = new DecalGridState(component.ChunkCollection.ChunkCollection); return; diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index c7801ab685..6acef242f2 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -361,7 +361,8 @@ namespace Content.Server.GameTicking } // AAAAAAAAAAAAA - _sawmill.Error("Found no observer spawn points!"); + // This should be an error, if it didn't cause tests to start erroring when they delete a player. + _sawmill.Warning("Found no observer spawn points!"); return EntityCoordinates.Invalid; } #endregion diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index 099a682b01..ca4851b652 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -102,9 +102,11 @@ public sealed class MindSystem : EntitySystem } // TODO refactor observer spawning. + // please. if (!spawnPosition.IsValid(EntityManager)) { - Logger.ErrorS("mind", $"Entity \"{ToPrettyString(uid)}\" for {mind.Mind?.CharacterName} was deleted, and no applicable spawn location is available."); + // This should be an error, if it didn't cause tests to start erroring when they delete a player. + Logger.WarningS("mind", $"Entity \"{ToPrettyString(uid)}\" for {mind.Mind?.CharacterName} was deleted, and no applicable spawn location is available."); return; } diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml index 26dcad7693..fac0b44ccb 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml @@ -33,20 +33,21 @@ name: bar sign suffix: Random -- type: entity - id: LargeBarSign - name: large bar sign - noSpawn: true - components: - - type: Clickable - - type: InteractionOutline - - type: Sprite - drawdepth: WallTops - sprite: Structures/Wallmounts/sylphs.rsi - state: sylph - - type: ApcPowerReceiver - - type: ExtensionCableReceiver - - type: BarSign +# Missing appearance components & various other sprite issues. +#- type: entity +# id: LargeBarSign +# name: large bar sign +# noSpawn: true +# components: +# - type: Clickable +# - type: InteractionOutline +# - type: Sprite +# drawdepth: WallTops +# sprite: Structures/Wallmounts/sylphs.rsi +# state: sylph +# - type: ApcPowerReceiver +# - type: ExtensionCableReceiver +# - type: BarSign - type: entity parent: BaseBarSign