Fix overflow algo again so small ammounts don't spread infinitely (aka Infinite Cum Works) (#6796)

This commit is contained in:
Ygg01
2022-02-20 20:54:05 +01:00
committed by GitHub
parent 538fa5ccbc
commit c76ee013b0
3 changed files with 387 additions and 45 deletions

View File

@@ -0,0 +1,184 @@
#nullable enable
using System;
using System.Threading.Tasks;
using Content.Server.Fluids.Components;
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using NUnit.Framework;
using Robust.Server.Maps;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Content.IntegrationTests.Tests.Fluids;
[TestFixture]
[TestOf(typeof(FluidSpreaderSystem))]
public sealed class FluidSpill : ContentIntegrationTest
{
private const string SpillMapsYml = "Maps/Test/floor3x3.yml";
private static PuddleComponent? GetPuddle(IEntityManager entityManager, IMapGrid mapGrid, Vector2i pos)
{
foreach (var uid in mapGrid.GetAnchoredEntities(pos))
{
if (entityManager.TryGetComponent(uid, out PuddleComponent puddleComponent))
return puddleComponent;
}
return null;
}
private readonly Direction[] _dirs =
{
Direction.East,
Direction.SouthEast,
Direction.South,
Direction.SouthWest,
Direction.West,
Direction.NorthWest,
Direction.North,
Direction.NorthEast,
};
private readonly Vector2i _origin = new(-1, -1);
[Test]
public async Task SpillEvenlyTest()
{
// --- Setup
var server = StartServer();
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var mapLoader = server.ResolveDependency<IMapLoader>();
var entityManager = server.ResolveDependency<IEntityManager>();
var spillSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<SpillableSystem>();
var gameTiming = server.ResolveDependency<IGameTiming>();
MapId mapId;
IMapGrid? grid = null;
await server.WaitPost(() =>
{
mapId = mapManager.CreateMap();
grid = mapLoader.LoadBlueprint(mapId, SpillMapsYml)!;
});
if (grid == null)
{
Assert.Fail($"Test blueprint {SpillMapsYml} not found.");
return;
}
await server.WaitAssertion(() =>
{
var solution = new Solution("Water", FixedPoint2.New(100));
var tileRef = grid.GetTileRef(_origin);
var puddle = spillSystem.SpillAt(tileRef, solution, "PuddleSmear");
Assert.That(puddle, Is.Not.Null);
Assert.That(GetPuddle(entityManager, grid, _origin), Is.Not.Null);
});
var sTimeToWait = (int) Math.Ceiling(2f * gameTiming.TickRate);
await server.WaitRunTicks(sTimeToWait);
server.Assert(() =>
{
var puddle = GetPuddle(entityManager, grid, _origin);
Assert.That(puddle, Is.Not.Null);
Assert.That(puddle!.CurrentVolume, Is.EqualTo(FixedPoint2.New(20)));
foreach (var direction in _dirs)
{
var newPos = _origin.Offset(direction);
var sidePuddle = GetPuddle(entityManager, grid, newPos);
Assert.That(sidePuddle, Is.Not.Null);
Assert.That(sidePuddle!.CurrentVolume, Is.EqualTo(FixedPoint2.New(10)));
}
});
await server.WaitIdleAsync();
}
[Test]
public async Task SpillSmallOverflowTest()
{
// --- Setup
var server = StartServer();
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var mapLoader = server.ResolveDependency<IMapLoader>();
var entityManager = server.ResolveDependency<IEntityManager>();
var spillSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<SpillableSystem>();
var gameTiming = server.ResolveDependency<IGameTiming>();
MapId mapId;
IMapGrid? grid = null;
await server.WaitPost(() =>
{
mapId = mapManager.CreateMap();
grid = mapLoader.LoadBlueprint(mapId, SpillMapsYml)!;
});
if (grid == null)
{
Assert.Fail($"Test blueprint {SpillMapsYml} not found.");
return;
}
await server.WaitAssertion(() =>
{
var solution = new Solution("Water", FixedPoint2.New(20.01));
var tileRef = grid.GetTileRef(_origin);
var puddle = spillSystem.SpillAt(tileRef, solution, "PuddleSmear");
Assert.That(puddle, Is.Not.Null);
});
if (grid == null)
{
Assert.Fail($"Test blueprint {SpillMapsYml} not found.");
return;
}
var sTimeToWait = (int) Math.Ceiling(2f * gameTiming.TickRate);
await server.WaitRunTicks(sTimeToWait);
server.Assert(() =>
{
var puddle = GetPuddle(entityManager, grid, _origin);
Assert.That(puddle, Is.Not.Null);
Assert.That(puddle!.CurrentVolume, Is.EqualTo(FixedPoint2.New(20)));
// we don't know where a spill would happen
// but there should be only one
var emptyField = 0;
var fullField = 0;
foreach (var direction in _dirs)
{
var newPos = _origin.Offset(direction);
var sidePuddle = GetPuddle(entityManager, grid, newPos);
if (sidePuddle == null)
{
emptyField++;
}
else if (sidePuddle.CurrentVolume == FixedPoint2.Epsilon)
{
fullField++;
}
}
Assert.That(emptyField, Is.EqualTo(7));
Assert.That(fullField, Is.EqualTo(1));
});
await server.WaitIdleAsync();
}
}

View File

@@ -37,9 +37,6 @@ public sealed class FluidSpreaderSystem : EntitySystem
puddleComponent.SolutionName, puddleComponent.SolutionName,
out puddleSolution)) return; out puddleSolution)) return;
if (puddleSolution.CurrentVolume <= puddleComponent.OverflowVolume)
return;
var spreaderComponent = EntityManager.EnsureComponent<FluidSpreaderComponent>(puddleComponent.Owner); var spreaderComponent = EntityManager.EnsureComponent<FluidSpreaderComponent>(puddleComponent.Owner);
spreaderComponent.OverflownSolution = puddleSolution; spreaderComponent.OverflownSolution = puddleSolution;
spreaderComponent.Enabled = true; spreaderComponent.Enabled = true;
@@ -88,6 +85,13 @@ public sealed class FluidSpreaderSystem : EntitySystem
private void SpreadFluid(EntityUid suid) private void SpreadFluid(EntityUid suid)
{ {
EntityUid GetOrCreate(EntityUid uid, string prototype, IMapGrid grid, Vector2i pos)
{
return uid == EntityUid.Invalid
? EntityManager.SpawnEntity(prototype, grid.GridTileToWorld(pos))
: uid;
}
PuddleComponent? puddleComponent = null; PuddleComponent? puddleComponent = null;
MetaDataComponent? metadataOriginal = null; MetaDataComponent? metadataOriginal = null;
TransformComponent? transformOrig = null; TransformComponent? transformOrig = null;
@@ -97,22 +101,31 @@ public sealed class FluidSpreaderSystem : EntitySystem
return; return;
var prototypeName = metadataOriginal.EntityPrototype!.ID; var prototypeName = metadataOriginal.EntityPrototype!.ID;
var puddles = new List<PuddleComponent> { puddleComponent };
var visitedTiles = new HashSet<Vector2i>(); var visitedTiles = new HashSet<Vector2i>();
if (!_mapManager.TryGetGrid(transformOrig.GridID, out var mapGrid)) if (!_mapManager.TryGetGrid(transformOrig.GridID, out var mapGrid))
return; return;
while (puddles.Count > 0 // skip origin puddle
var nextToExpand = new List<PuddlePlacer>(9);
ExpandPuddle(suid, visitedTiles, mapGrid, nextToExpand);
while (nextToExpand.Count > 0
&& spreader.OverflownSolution.CurrentVolume > FixedPoint2.Zero) && spreader.OverflownSolution.CurrentVolume > FixedPoint2.Zero)
{ {
var nextToExpand = new List<(Vector2i, EntityUid?)>(); // we need to clamp to prevent spreading 0u fluids, while never going over spill limit
var divided = FixedPoint2.Clamp(spreader.OverflownSolution.CurrentVolume / nextToExpand.Count,
FixedPoint2.Epsilon, puddleComponent.OverflowVolume);
var divided = spreader.OverflownSolution.CurrentVolume / puddles.Count; foreach (var posAndUid in nextToExpand)
foreach (var puddle in puddles)
{ {
var puddleUid = GetOrCreate(posAndUid.Uid, prototypeName, mapGrid, posAndUid.Pos);
if (!TryComp(puddleUid, out PuddleComponent? puddle))
continue;
posAndUid.Uid = puddleUid;
if (puddle.CurrentVolume >= puddle.OverflowVolume) continue; if (puddle.CurrentVolume >= puddle.OverflowVolume) continue;
// -puddle.OverflowLeft is guaranteed to be >= 0 // -puddle.OverflowLeft is guaranteed to be >= 0
@@ -122,52 +135,56 @@ public sealed class FluidSpreaderSystem : EntitySystem
puddle.Owner, puddle.Owner,
spreader.OverflownSolution.SplitSolution(split), spreader.OverflownSolution.SplitSolution(split),
false, false, puddle); false, false, puddle);
}
// if solution is spent do not explore // if solution is spent do not explore
if (spreader.OverflownSolution.CurrentVolume <= FixedPoint2.Zero) if (spreader.OverflownSolution.CurrentVolume <= FixedPoint2.Zero)
continue; return;
}
// find edges // find edges
foreach (var puddle in puddles) nextToExpand = ExpandPuddles(nextToExpand, visitedTiles, mapGrid);
{ }
TransformComponent? transform = null; }
if (!Resolve(puddle.Owner, ref transform, false)) private List<PuddlePlacer> ExpandPuddles(List<PuddlePlacer> toExpand,
continue; HashSet<Vector2i> visitedTiles,
IMapGrid mapGrid)
{
var nextToExpand = new List<PuddlePlacer>(9);
foreach (var puddlePlacer in toExpand)
{
ExpandPuddle(puddlePlacer.Uid, visitedTiles, mapGrid, nextToExpand, puddlePlacer.Pos);
}
// prepare next set of puddles to be expanded return nextToExpand;
var puddlePos = transform.Coordinates.ToVector2i(EntityManager, _mapManager); }
foreach (var direction in SharedDirectionExtensions.RandomDirections().ToArray())
{
var newPos = puddlePos.Offset(direction);
if (visitedTiles.Contains(newPos))
continue;
visitedTiles.Add(newPos); private void ExpandPuddle(EntityUid puddle,
HashSet<Vector2i> visitedTiles,
IMapGrid mapGrid,
List<PuddlePlacer> nextToExpand,
Vector2i? pos = null)
{
TransformComponent? transform = null;
if (CanExpand(newPos, mapGrid, out var uid)) if (pos == null && !Resolve(puddle, ref transform, false))
nextToExpand.Add((newPos, uid)); {
} return;
} }
puddles = new List<PuddleComponent>(); var puddlePos = pos ?? transform!.Coordinates.ToVector2i(EntityManager, _mapManager);
// prepare edges for next iteration // prepare next set of puddles to be expanded
foreach (var (pos, uid) in nextToExpand) foreach (var direction in SharedDirectionExtensions.RandomDirections().ToArray())
{ {
if (spreader.OverflownSolution.CurrentVolume <= FixedPoint2.Zero) var newPos = puddlePos.Offset(direction);
continue; if (visitedTiles.Contains(newPos))
continue;
var puddleUid = uid!.Value; visitedTiles.Add(newPos);
var coordinate = mapGrid.GridTileToWorld(pos);
if (uid == EntityUid.Invalid)
{
puddleUid = EntityManager.SpawnEntity(prototypeName, coordinate);
}
puddles.Add(EntityManager.GetComponent<PuddleComponent>(puddleUid)); if (CanExpand(newPos, mapGrid, out var uid))
} nextToExpand.Add(new PuddlePlacer(newPos, (EntityUid) uid));
} }
} }
@@ -205,3 +222,16 @@ public sealed class FluidSpreaderSystem : EntitySystem
return true; return true;
} }
} }
// Helper to allow mutable pair of (Pos, Uid)
internal sealed class PuddlePlacer
{
internal Vector2i Pos;
internal EntityUid Uid;
public PuddlePlacer(Vector2i pos, EntityUid uid)
{
Pos = pos;
Uid = uid;
}
}

View File

@@ -0,0 +1,128 @@
meta:
format: 2
name: DemoStation
author: Space-Wizards
postmapinit: false
tilemap:
0: space
1: floor_asteroid_coarse_sand0
2: floor_asteroid_coarse_sand1
3: floor_asteroid_coarse_sand2
4: floor_asteroid_coarse_sand_dug
5: floor_asteroid_sand
6: floor_asteroid_tile
7: floor_bar
8: floor_blue
9: floor_blue_circuit
10: floor_clown
11: floor_dark
12: floor_elevator_shaft
13: floor_freezer
14: floor_glass
15: floor_gold
16: floor_grass
17: floor_green_circuit
18: floor_hydro
19: floor_kitchen
20: floor_laundry
21: floor_lino
22: floor_mime
23: floor_mono
24: floor_reinforced
25: floor_rglass
26: floor_rock_vault
27: floor_showroom
28: floor_silver
29: floor_snow
30: floor_steel
31: floor_steel_dirty
32: floor_techmaint
33: floor_white
34: floor_wood
35: lattice
36: plating
37: underplating
grids:
- settings:
chunksize: 16
tilesize: 1
chunks:
- ind: "-1,-1"
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAHgAAAA==
- ind: "-1,0"
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
- ind: "0,0"
tiles: BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
- ind: "0,-1"
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
entities:
- uid: 0
components:
- parent: null
type: Transform
- index: 0
type: MapGrid
- linearDamping: 0.1
fixedRotation: False
bodyType: Dynamic
type: Physics
- fixtures:
- shape: !type:PolygonShape
vertices:
- -0.01,0.01
- -0.01,0.99
- -1.99,0.99
- -1.99,0.01
id: grid_chunk--1.99-0.01
mask:
- MapGrid
layer:
- MapGrid
mass: 7.7616
restitution: 0.1
- shape: !type:PolygonShape
vertices:
- 0.99,0.01
- 0.99,0.99
- 0.01,0.99
- 0.01,0.01
id: grid_chunk-0.01-0.01
mask:
- MapGrid
layer:
- MapGrid
mass: 3.8416002
restitution: 0.1
- shape: !type:PolygonShape
vertices:
- 0.99,-1.99
- 0.99,-0.01
- 0.01,-0.01
- 0.01,-1.99
id: grid_chunk-0.01--1.99
mask:
- MapGrid
layer:
- MapGrid
mass: 7.7616
restitution: 0.1
- shape: !type:PolygonShape
vertices:
- -0.01,-1.99
- -0.01,-0.01
- -1.99,-0.01
- -1.99,-1.99
id: grid_chunk--1.99--1.99
mask:
- MapGrid
layer:
- MapGrid
mass: 15.681601
restitution: 0.1
type: Fixtures
- gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
type: Gravity
- chunkCollection: {}
type: DecalGrid
...