diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs index adb8b8677c..00b6e8f00e 100644 --- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs @@ -1,10 +1,14 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Content.Server.GameObjects.Components.Fluids; using Content.Shared.Chemistry; using Content.Shared.Utility; using NUnit.Framework; using Robust.Server.Interfaces.Timing; +using Robust.Shared.GameObjects.Components.Timers; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.Map; namespace Content.IntegrationTests.Tests.Fluids @@ -91,7 +95,6 @@ namespace Content.IntegrationTests.Tests.Fluids server.Assert(() => { - var gridId = new GridId(1); var coordinates = grid.ToCoordinates(); var solution = new Solution("water", ReagentUnit.New(20)); var puddle = solution.SpillAt(coordinates, "PuddleSmear"); @@ -100,5 +103,128 @@ namespace Content.IntegrationTests.Tests.Fluids await server.WaitIdleAsync(); } + + [Test] + public async Task PuddlePauseTest() + { + var server = StartServer(); + + await server.WaitIdleAsync(); + + var sMapManager = server.ResolveDependency(); + var sPauseManager = server.ResolveDependency(); + var sTileDefinitionManager = server.ResolveDependency(); + var sGameTiming = server.ResolveDependency(); + var sEntityManager = server.ResolveDependency(); + + MapId sMapId = default; + IMapGrid sGrid = null; + GridId sGridId = default; + IEntity sGridEntity = null; + EntityCoordinates sCoordinates = default; + TimerComponent sTimerComponent = null; + + // Spawn a paused map with one tile to spawn puddles on + await server.WaitPost(() => + { + sMapId = sMapManager.CreateMap(); + sPauseManager.SetMapPaused(sMapId, true); + sGrid = sMapManager.CreateGrid(sMapId); + sGridId = sGrid.Index; + sGridEntity = sEntityManager.GetEntity(sGrid.GridEntityId); + sGridEntity.Paused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1444 + + var tileDefinition = sTileDefinitionManager["underplating"]; + var tile = new Tile(tileDefinition.TileId); + sCoordinates = sGrid.ToCoordinates(); + + sGrid.SetTile(sCoordinates, tile); + }); + + // Check that the map and grid are paused + await server.WaitAssertion(() => + { + Assert.True(sPauseManager.IsGridPaused(sGridId)); + Assert.True(sPauseManager.IsMapPaused(sMapId)); + Assert.True(sGridEntity.Paused); + }); + + float sEvaporateTime = default; + PuddleComponent sPuddle = null; + ReagentUnit sPuddleStartingVolume = default; + + // Spawn a puddle + await server.WaitAssertion(() => + { + var solution = new Solution("water", ReagentUnit.New(20)); + sPuddle = solution.SpillAt(sCoordinates, "PuddleSmear"); + + // Check that the puddle was created + Assert.NotNull(sPuddle); + + sPuddle.Owner.Paused = true; // See https://github.com/space-wizards/RobustToolbox/issues/1445 + + Assert.True(sPuddle.Owner.Paused); + + // Check that the puddle is going to evaporate + Assert.Positive(sPuddle.EvaporateTime); + + // Should have a timer component added to it for evaporation + Assert.True(sPuddle.Owner.TryGetComponent(out sTimerComponent)); + + sEvaporateTime = sPuddle.EvaporateTime; + sPuddleStartingVolume = sPuddle.CurrentVolume; + }); + + // Wait enough time for it to evaporate if it was unpaused + var sTimeToWait = (5 + (int) Math.Ceiling(sEvaporateTime * sGameTiming.TickRate)) * 2; + await server.WaitRunTicks(sTimeToWait); + + // No evaporation due to being paused + await server.WaitAssertion(() => + { + Assert.True(sPuddle.Owner.Paused); + Assert.True(sPuddle.Owner.TryGetComponent(out sTimerComponent)); + + // Check that the puddle still exists + Assert.False(sPuddle.Owner.Deleted); + }); + + // Unpause the map + await server.WaitPost(() => + { + sPauseManager.SetMapPaused(sMapId, false); + }); + + // Check that the map, grid and puddle are unpaused + await server.WaitAssertion(() => + { + Assert.False(sPauseManager.IsMapPaused(sMapId)); + Assert.False(sPauseManager.IsGridPaused(sGridId)); + Assert.False(sPuddle.Owner.Paused); + + // Check that the puddle still exists + Assert.False(sPuddle.Owner.Deleted); + }); + + // Wait enough time for it to evaporate + await server.WaitRunTicks(sTimeToWait); + + // Puddle evaporation should have ticked + await server.WaitAssertion(() => + { + // Check that the puddle is unpaused + Assert.False(sPuddle.Owner.Paused); + + // Check that the puddle has evaporated some of its volume + Assert.That(sPuddle.CurrentVolume, Is.LessThan(sPuddleStartingVolume)); + + // If its new volume is zero it should have been deleted + if (sPuddle.CurrentVolume == ReagentUnit.Zero) + { + Assert.True(sPuddle.Deleted); + } + }); + } } } diff --git a/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs b/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs index 0a3de896c6..d3f3275c53 100644 --- a/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs @@ -64,7 +64,11 @@ namespace Content.Server.GameObjects.Components.Fluids set => _slipThreshold = value; } - private float _evaporateTime; + /// + /// The time that it will take this puddle to evaporate, in seconds. + /// + public float EvaporateTime { get; private set; } + private string _spillSound; /// @@ -104,7 +108,7 @@ namespace Content.Server.GameObjects.Components.Fluids { serializer.DataFieldCached(ref _spillSound, "spill_sound", "/Audio/Effects/Fluids/splat.ogg"); serializer.DataField(ref _overflowVolume, "overflow_volume", ReagentUnit.New(20)); - serializer.DataField(ref _evaporateTime, "evaporate_time", 5.0f); + serializer.DataField(this, x => x.EvaporateTime, "evaporate_time", 5.0f); // Long-term probably have this based on the underlying reagents serializer.DataField(ref _evaporateThreshold, "evaporate_threshold", ReagentUnit.New(20)); serializer.DataField(ref _spriteVariants, "variants", 1); @@ -251,7 +255,7 @@ namespace Content.Server.GameObjects.Components.Fluids _evaporationToken = new CancellationTokenSource(); // KYS to evaporate - Owner.SpawnTimer(TimeSpan.FromSeconds(_evaporateTime), Evaporate, _evaporationToken.Token); + Owner.SpawnTimer(TimeSpan.FromSeconds(EvaporateTime), Evaporate, _evaporationToken.Token); } private void UpdateSlip()