Пример #1
0
        /// <summary>Check if a mover is above a static object by physics heightmap</summary>
        private static bool DoAboveCheck(AnimationSet staticAnimationSet, AnimationSet moverAnimationSet, Position staticPosition, Position moverPosition, bool staticFlipX, bool moverFlipX)
        {
            HeightmapView heightmapView = new HeightmapView(staticAnimationSet.Heightmap, staticPosition, staticFlipX);

            if (!heightmapView.BoundsZ.Contains(moverPosition.Z))
            {
                return(false); // out of range
            }
            var staticRangeX = heightmapView.BoundsX;
            var moverRangeX  = new Range(moverAnimationSet.physicsStartX, moverAnimationSet.physicsEndX).MaybeFlip(moverFlipX) + moverPosition.X;
            var rangeX       = moverRangeX.Clip(staticRangeX.start, staticRangeX.end);

            for (int x = rangeX.start; x < rangeX.end; x++)
            {
                int height = heightmapView.GetUnelevatedHeightAt(x, moverPosition.Z);
                if (height == 0 || height == Heightmap.Infinity)
                {
                    continue;
                }

                height += heightmapView.position.Y;
                if (moverPosition.Y >= height)
                {
                    return(true); // <- above the object at at least one position
                }
            }

            return(false);
        }
Пример #2
0
        public void DrawHeightmapFlat(HeightmapView heightmapView, SortedList <int, Color> heightColorGradient)
        {
            int startX, endX;

            HeightmapDrawRangeHelper(heightmapView, out startX, out endX);
            if (endX <= startX)
            {
                return; // Off screen
            }
            int xFlipFactor = heightmapView.flipX ? -1 : 1;

            for (int z = heightmapView.heightmap.EndZ - 1; z >= heightmapView.heightmap.StartZ; z--) // From back to front of heightmap
            {
                for (int x = startX; x < endX; x++)
                {
                    byte height = heightmapView.heightmap[x * xFlipFactor, z];
                    if (height == heightmapView.heightmap.DefaultHeight)
                    {
                        continue;
                    }

                    // Draw top surface
                    DrawPixel(new Position(heightmapView.position.X + x, 0, heightmapView.position.Z + z),
                              heightColorGradient.GetColorFromGradient(height + heightmapView.position.Y), 0);
                }
            }
        }
Пример #3
0
        private bool IsRestingOn(int top, int bottom)
        {
            var bottomHeightmapView = new HeightmapView(moverHeightmaps[bottom], moverInitialPositions[bottom],
                                                        moverInitialFacingLeft[bottom]);
            var targetY = moverInitialPositions[top].Y - bottomHeightmapView.position.Y;

            if (targetY <= 0
                )         // <- This is just safety if external range checks didn't exclude something correctly (this was a bug with infinite-height objects, before I made them unstackable -AR)
            {
                return(false);
            }

            if (moverHeightmaps[top] != null)
            {
                //
                // Heightmap vs Heightmap

                var topHeightmapView = new HeightmapView(moverHeightmaps[top],
                                                         new Position(moverInitialPositions[top].X, 0, moverInitialPositions[top].Z),
                                                         moverInitialFacingLeft[top]);
                var xzIntersection = Rectangle.Intersect(bottomHeightmapView.Bounds, topHeightmapView.Bounds);

                for (var z = 0; z < xzIntersection.Height; z++)
                {
                    for (var x = 0; x < xzIntersection.Width; x++)
                    {
                        var xx = x + xzIntersection.X;
                        var zz = z + xzIntersection.Y;

                        if (topHeightmapView.GetUnelevatedHeightAt(xx, zz) != 0)
                        {
                            if (bottomHeightmapView.GetUnelevatedHeightAt(xx, zz) == targetY)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }
            else
            {
                //
                // Heightmap vs Character

                for (var x = moverBoundsX[top].start; x < moverBoundsX[top].end; x++)
                {
                    if (bottomHeightmapView.GetUnelevatedHeightAt(x, moverInitialPositions[top].Z) == targetY)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #4
0
        public static int GetDistanceSquaredToLocalPlayer(AnimationSet animationSet, Position position, bool facingLeft, IGameState gameState, int localPlayerBits)
        {
            int bestDistanceSquared = Int32.MaxValue;

            if (animationSet != null && animationSet.Heightmap != null) // Sound source has some (spatial) volume
            {
                var       heightmapView = new HeightmapView(animationSet.Heightmap, position, facingLeft);
                Rectangle heightmapXZ   = heightmapView.Bounds;

                // TODO: Stop assuming a height, and get a real AABB from the heightmap (requires Heightmap cache its own AABB)
                const int guessHeight   = 50;
                AABB      heightmapAABB = new AABB(heightmapXZ.Left, heightmapXZ.Right - 1,
                                                   position.Y, position.Y + guessHeight, heightmapXZ.Y, heightmapXZ.Y + heightmapXZ.Height - 1);


                for (int i = 0; i < gameState.MaxPlayers; i++) // For each possible player
                {
                    if (((1 << i) & localPlayerBits) != 0)     // This player is interactive locally
                    {
                        var playerPosition = gameState.GetPlayerPosition(i);
                        if (playerPosition != null)
                        {
                            int distanceSquared = heightmapAABB.DistanceSquaredTo(playerPosition.Value);
                            if (distanceSquared < bestDistanceSquared)
                            {
                                bestDistanceSquared = distanceSquared;
                            }
                        }
                    }
                }
            }
            else // Sound source is a point source
            {
                for (int i = 0; i < gameState.MaxPlayers; i++) // For each possible player
                {
                    if (((1 << i) & localPlayerBits) != 0) // This player is interactive locally
                    {
                        var playerPosition = gameState.GetPlayerPosition(i);
                        if (playerPosition != null)
                        {
                            int distanceSquared = Position.DistanceSquared(position, playerPosition.Value);
                            if (distanceSquared < bestDistanceSquared)
                            {
                                bestDistanceSquared = distanceSquared;
                            }
                        }
                    }
                }
            }

            return(bestDistanceSquared);
        }
Пример #5
0
 /// <summary>Constrain rendering to the display bounds</summary>
 void HeightmapDrawRangeHelper(HeightmapView heightmapView, out int startX, out int endX)
 {
     if (heightmapView.flipX)
     {
         startX = Math.Max(1 - heightmapView.heightmap.EndX, displayBounds.Left - heightmapView.position.X);
         endX   = Math.Min(1 - heightmapView.heightmap.StartX, displayBounds.Right - heightmapView.position.X);
     }
     else
     {
         startX = Math.Max(heightmapView.heightmap.StartX, displayBounds.Left - heightmapView.position.X);
         endX   = Math.Min(heightmapView.heightmap.EndX, displayBounds.Right - heightmapView.position.X);
     }
 }
Пример #6
0
        private bool SolidVsSolidIntersection(int first, int second)
        {
            // NOTE: Calling code has done a bounds check on all three axes

            var firstHeightmapView = new HeightmapView(moverHeightmaps[first], moverInitialPositions[first],
                                                       moverInitialFacingLeft[first]);
            var secondHeightmapView = new HeightmapView(moverHeightmaps[second], moverInitialPositions[second],
                                                        moverInitialFacingLeft[second]);

            var xzIntersection = Rectangle.Intersect(firstHeightmapView.Bounds, secondHeightmapView.Bounds);

            for (var z = 0; z < xzIntersection.Height; z++)
            {
                for (var x = 0; x < xzIntersection.Width; x++)
                {
                    var xx = x + xzIntersection.X;
                    var zz = z + xzIntersection.Y;

                    var firstHeight  = firstHeightmapView.GetUnelevatedHeightAt(xx, zz);
                    var secondHeight = secondHeightmapView.GetUnelevatedHeightAt(xx, zz);

                    if (firstHeight == 0 || secondHeight == 0)
                    {
                        continue;
                    }

                    if (firstHeight == Heightmap.Infinity)
                    {
                        firstHeight = MaximumHeight;
                    }
                    if (secondHeight == Heightmap.Infinity)
                    {
                        secondHeight = MaximumHeight;
                    }

                    var firstRangeY  = new Range(firstHeightmapView.position.Y, firstHeightmapView.position.Y + firstHeight);
                    var secondRangeY = new Range(secondHeightmapView.position.Y,
                                                 secondHeightmapView.position.Y + secondHeight);
                    if (Range.Overlaps(firstRangeY, secondRangeY))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #7
0
        public void DrawHeightmapSolid(HeightmapView heightmapView, SortedList <int, Color> heightColorGradient)
        {
            int startX, endX;

            HeightmapDrawRangeHelper(heightmapView, out startX, out endX);
            if (endX <= startX)
            {
                return; // Off screen
            }
            int xFlipFactor = heightmapView.flipX ? -1 : 1;

            for (int z = heightmapView.heightmap.EndZ - 1; z >= heightmapView.heightmap.StartZ; z--) // From back to front of heightmap
            {
                for (int x = startX; x < endX; x++)
                {
                    byte height = heightmapView.heightmap[x * xFlipFactor, z];
                    if (height == heightmapView.heightmap.DefaultHeight)
                    {
                        continue;
                    }

                    byte nextHeight = heightmapView.heightmap[x * xFlipFactor, z - 1];
                    if (nextHeight != heightmapView.heightmap.DefaultHeight && nextHeight > height)
                    {
                        continue; // Next row will cover this one entirely
                    }
                    // Draw top surface
                    const int zTestOffset = 1; // <- The top surface should be "under" any other pixels
                    DrawPixel(heightmapView.position + new Position(x, height, z),
                              heightColorGradient.GetColorFromGradient(height + heightmapView.position.Y), zTestOffset);

                    if (nextHeight != heightmapView.heightmap.DefaultHeight && nextHeight == height)
                    {
                        continue; // Next row covers this one's "solid" section
                    }
                    // Draw solidness
                    for (int h = height + heightmapView.position.Y - 1; h >= heightmapView.position.Y; h--)
                    {
                        Color c = Color.Lerp(heightColorGradient.GetColorFromGradient(h), Color.Black, 0.6f);
                        DrawPixel(new Position(heightmapView.position.X + x, h, heightmapView.position.Z + z), c, 0);
                    }
                }
            }
        }
Пример #8
0
        private bool SolidVsCharacterIntersection(int solid, int character)
        {
            // NOTE: Calling code has done a bounds check on all three axes

            var heightmapView = new HeightmapView(moverHeightmaps[solid], moverInitialPositions[solid],
                                                  moverInitialFacingLeft[solid]);
            var heightmapRangeX = heightmapView.BoundsX;

            var characterX = moverInitialPositions[character].X;
            var characterY = moverInitialPositions[character].Y;
            var characterZ = moverInitialPositions[character].Z;

            var characterRangeX = new Range(characterX + moverCharacterPhysics[character].startX,
                                            characterX + moverCharacterPhysics[character].endX);
            var characterRangeY = new Range(characterY, characterY + moverCharacterPhysics[character].height);

            Debug.Assert(heightmapView.BoundsZ.Contains(characterZ));

            var xIntersection = heightmapRangeX.Clip(characterRangeX.start, characterRangeX.end);

            for (var x = xIntersection.start; x < xIntersection.end; x++)
            {
                var solidHeight = heightmapView.GetUnelevatedHeightAt(x, characterZ);

                if (solidHeight == 0)
                {
                    continue;
                }

                if (solidHeight == Heightmap.Infinity)
                {
                    solidHeight = MaximumHeight;
                }

                var solidRangeY = new Range(heightmapView.position.Y, heightmapView.position.Y + solidHeight);
                if (Range.Overlaps(solidRangeY, characterRangeY))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #9
0
        public void DrawShadowReceiver(DrawContext context, Sprite whitemask, ShadowReceiver shadowReceiver, Position shadowReceiverPosition, bool shadowReceiverFlipX)
        {
            Bounds receiverBounds = new Bounds(whitemask.WorldSpaceBounds).MaybeFlipX(shadowReceiverFlipX) + shadowReceiverPosition.ToWorldZero;

            bool startedReceivingShadows = false;

            // For each shadow caster:
            Debug.Assert(shadowCasterXBounds.Count == shadowCasters.Count);
            for (int i = 0; i < shadowCasterXBounds.Count; i++)
            {
                StartEnd casterWorldXBounds = shadowCasterXBounds[i];
                if (casterWorldXBounds.start >= receiverBounds.endX || receiverBounds.startX >= casterWorldXBounds.end)
                {
                    continue; // Horizontally out of range
                }
                var shadowCaster = shadowCasters[i];

                // Determine the ground height of the shadow:
                int groundHeight;
                if (shadowReceiver.heightmap.HasData)
                {
                    var heightmapView = new HeightmapView(shadowReceiver.heightmap, shadowReceiverPosition, shadowReceiverFlipX);
                    int startX        = shadowCaster.position.X + shadowCaster.physicsStartX;
                    int endX          = shadowCaster.position.X + shadowCaster.physicsEndX;
                    if (endX <= startX)
                    {
                        endX = startX + 1; // <- whoops our shadow caster has no width... quick fix-up for now...
                    }
                    groundHeight = heightmapView.GetHeightForShadow(startX, endX, shadowCaster.position.Z, shadowReceiver.heightmapExtendDirection);
                }
                else
                {
                    groundHeight = shadowReceiver.heightmap.DefaultHeight + shadowReceiverPosition.Y;
                }

                int shadowDifference = shadowCaster.position.Y - groundHeight;


                // NOTE: shadowOffset is pre-flipped
                Position shadowPosition = new Position(shadowCaster.position.X, groundHeight, shadowCaster.position.Z) + shadowCaster.shadowOffset;


                if (shadowCaster.shadows[0].startHeight > shadowDifference)
                {
                    continue; // Out of range
                }
                int shadowIndex = 0;
                while (shadowIndex + 1 < shadowCaster.shadows.Count)
                {
                    if (shadowCaster.shadows[shadowIndex + 1].startHeight > shadowDifference)
                    {
                        break;
                    }
                    shadowIndex++;
                }
                Sprite shadowSprite;
                if (!shadowCaster.shadows[shadowIndex].shadowSpriteRef.ResolveBestEffort(out shadowSprite))
                {
                    continue;
                }


                // Determine whether the shadow overlaps the whitemask
                Bounds shadowBounds        = new Bounds(shadowSprite.WorldSpaceBounds).MaybeFlipX(shadowCaster.flipX) + shadowPosition.ToWorldZero;
                Bounds worldZeroDrawBounds = Bounds.Intersection(receiverBounds, shadowBounds);
                if (!worldZeroDrawBounds.HasPositiveArea)
                {
                    continue;
                }

                if (!startedReceivingShadows)
                {
                    startedReceivingShadows = true;
                    context.SetupShadowReceiver(whitemask, shadowReceiver, shadowReceiverPosition, shadowReceiverFlipX);
                }


                // Drawing with clipping:
                {
                    Rectangle clipRect = new Rectangle // <- Region within the source rectangle (NOTE: initially with Y+ up, we fix later)
                    {
                        X      = worldZeroDrawBounds.startX - shadowBounds.startX,
                        Y      = worldZeroDrawBounds.startY - shadowBounds.startY,
                        Width  = worldZeroDrawBounds.endX - worldZeroDrawBounds.startX,
                        Height = worldZeroDrawBounds.endY - worldZeroDrawBounds.startY,
                    };

                    // Flipping:
                    if (shadowCaster.flipX)
                    {
                        clipRect.X = shadowSprite.sourceRectangle.Width - (clipRect.X + clipRect.Width); // RegionFlipX
                    }
                    // IMPORTANT: Convert clipRect from Y+ Up coordinates to correct Texel coordinates
                    clipRect.Y = shadowSprite.sourceRectangle.Height - (clipRect.Y + clipRect.Height); // RegionFlipY

                    // Turn it into a source rectangle within the texture:
                    clipRect.X += shadowSprite.sourceRectangle.X;
                    clipRect.Y += shadowSprite.sourceRectangle.Y;

                    Vector2 displayPosition = new Vector2(worldZeroDrawBounds.startX, -(worldZeroDrawBounds.startY + clipRect.Height));
                    // NOTE: don't need to consider origin, because it's built into the draw bounds
                    context.SpriteBatch.Draw(shadowSprite.texture, displayPosition, clipRect, shadowCaster.color, 0f, Vector2.Zero, 1,
                                             shadowCaster.flipX ? SpriteEffects.FlipHorizontally : SpriteEffects.None, 0);
                }
            }


            if (startedReceivingShadows)
            {
                context.TeardownShadowReceiver();
            }
        }
Пример #10
0
        public void DoSeparation(UpdateContext updateContext)
        {
            //
            // Process anyone requesting to be updated before separation
            //

            foreach (var i in collidersToUpdateBeforeSeparation)
            {
                Actor         actor         = (Actor)colliderEntries[i].owner; // <- will always succeed, because we registered it that way
                HeightmapView heightmapView = new HeightmapView(actor.animationSet.Heightmap, actor.position, actor.facingLeft);
                ChangeCollider(i, heightmapView);
            }



            //
            // Remove everyone from static geometry
            //

            for (int i = 0; i < moverCount; i++)
            {
                if (moverWeDoNotMove[i])
                {
                    continue;
                }

                if (moverActors[i].IncomingConnection != null)
                {
                    continue; // Don't separate if we're attached to someone
                }
                var cpi = moverCharacterPhysics[i];
                int simpleGroundHeight = CharacterPhysics.GroundHeight(ref cpi, this, moverActors[i].position, true);
                if (simpleGroundHeight <= moverActors[i].position.Y)
                {
                    continue; // We are in open space
                }
                //
                // Oh no! We are stuck in the level!
                //


                // Attempt 1: Move back to start point, and then try moving to new position:
                //            (Doing this first, to try to prevent tunneling behaviour - also probably faster than TryToFitNearestInZSlice)
                Position moveDelta = moverActors[i].position - moverInitialPositions[i];
                if (moveDelta != Position.Zero && // <- Can't undo non-moves.
                    moveDelta.ManhattenLength <= 8)        // <- Don't try to undo huge moves, as they may be teleports/animations, and we could get snagged on the way there.
                {
                    var groundHeightAtInitial = CharacterPhysics.GroundHeight(ref cpi, this, moverInitialPositions[i], true);
                    if (groundHeightAtInitial <= moverInitialPositions[i].Y) // <- OK at initial position
                    {
                        // Attempt to move towards target:
                        Position target = moverActors[i].position;
                        moverActors[i].position = moverInitialPositions[i];

                        CharacterPhysics.TryMove(ref moverCharacterPhysics[i], this, moveDelta, false, ref moverActors[i].position, true);

                        continue; // Success!
                    }
                }

                // Attempt 2: Attempt to extricate ourselves from the situation directly
                #region // a whole bunch of code
                {
                    int  statsZSliceCount = 0;
                    long statsVoxelCount  = 0;

                    Position desiredPosition = moverActors[i].position;

                    // Ensure we didn't come out of the level entirely
                    if (desiredPosition.X < StartX)
                    {
                        desiredPosition.X = StartX;
                    }
                    if (desiredPosition.X >= EndX)
                    {
                        desiredPosition.X = EndX - 1;
                    }
                    if (desiredPosition.Y < 0)
                    {
                        desiredPosition.Y = 0;
                    }
                    if (desiredPosition.Z < StartZ)
                    {
                        desiredPosition.Z = StartZ;
                    }
                    if (desiredPosition.Z >= EndZ)
                    {
                        desiredPosition.Z = EndZ - 1;
                    }

                    // Grab the nearest point on our current plane:
                    const int maxRadiusXY = 128;
                    Point     nearest     = TryToFitNearestInZSlice(moverCharacterPhysics[i].startX, moverCharacterPhysics[i].endX, moverCharacterPhysics[i].height,
                                                                    desiredPosition.X, desiredPosition.Y, moverActors[i].position.Y,
                                                                    desiredPosition.X - maxRadiusXY, desiredPosition.X + maxRadiusXY, desiredPosition.Z, desiredPosition.Y - maxRadiusXY, desiredPosition.Y + maxRadiusXY,
                                                                    moverActors[i], true);
                    statsZSliceCount++;
                    statsVoxelCount += (maxRadiusXY * maxRadiusXY * 4);

                    Position bestPosition;
                    int      bestDistance;
                    if (nearest != NoFitFound)
                    {
                        bestDistance = Math.Abs(desiredPosition.X - nearest.X) + Math.Abs(desiredPosition.Y - nearest.Y);
                        bestPosition = new Position(nearest.X, nearest.Y, desiredPosition.Z);

                        // Debugging: If check that we're not ending up back in the same place (why did we try to separate, if we fit?)
                        //            If this assert fires, there is a bug in the separation algorithm.
                        // NOTE: checks vs non-clipped position!
                        Debug.Assert(Position.ManhattenDistance(moverActors[i].position, bestPosition) > 0,
                                     "SEPARATION DID NOTHING. Actor is: " + moverActors[i].ToString()
                                     + "\n\nIf you can reproduce this, please report to Andrew. Otherwise hit \"Ignore\" and carry on.");
                    }
                    else
                    {
                        bestPosition = default(Position);
                        bestDistance = int.MaxValue;
                    }


                    // Search forwards and backwards for better positions on nearby planes:
                    const int maxRadiusZ        = 10;
                    int       searchBoundStartZ = Math.Max(StartZ, desiredPosition.Z - maxRadiusZ);
                    int       searchBoundEndZ   = Math.Min(EndZ, desiredPosition.Z + maxRadiusZ);

                    // Searching forwards:  (NOTE: Copy-paste with searching backwards)
                    int searchZ = desiredPosition.Z - 1;
                    // NOTE: Checking vs bestDistance each time, so we might be able to early-out
                    while (searchZ >= searchBoundStartZ && (desiredPosition.Z - searchZ) < bestDistance) // <- IMPORTANT: not doing maths on bestDistance, as it can be int.MaxValue!
                    {
                        Debug.Assert(bestDistance > 0);
                        int radiusXY = Math.Min(bestDistance, maxRadiusXY); // <- hopefully reduces search range

                        nearest = TryToFitNearestInZSlice(moverCharacterPhysics[i].startX, moverCharacterPhysics[i].endX, moverCharacterPhysics[i].height,
                                                          desiredPosition.X, desiredPosition.Y, moverActors[i].position.Y,
                                                          desiredPosition.X - radiusXY, desiredPosition.X + radiusXY, searchZ, desiredPosition.Y - radiusXY, desiredPosition.Y + radiusXY,
                                                          moverActors[i], true);
                        statsZSliceCount++;
                        statsVoxelCount += (radiusXY * radiusXY * 4);

                        if (nearest != NoFitFound)
                        {
                            int distance = Math.Abs(desiredPosition.X - nearest.X) + Math.Abs(desiredPosition.Y - nearest.Y) + Math.Abs(desiredPosition.Z - searchZ);
                            if (distance < bestDistance)
                            {
                                bestDistance = distance;
                                bestPosition = new Position(nearest.X, nearest.Y, searchZ);
                            }
                        }

                        searchZ--;
                    }

                    // Searching backwards:  (NOTE: Copy-paste with searching forwards)
                    searchZ = desiredPosition.Z + 1;
                    // NOTE: Checking vs bestDistance each time, so we might be able to early-out
                    while (searchZ < searchBoundEndZ && (searchZ - desiredPosition.Z) < bestDistance) // <- IMPORTANT: not doing maths on bestDistance, as it can be int.MaxValue!
                    {
                        Debug.Assert(bestDistance > 0);
                        int radiusXY = Math.Min(bestDistance, maxRadiusXY); // <- hopefully reduces search range

                        nearest = TryToFitNearestInZSlice(moverCharacterPhysics[i].startX, moverCharacterPhysics[i].endX, moverCharacterPhysics[i].height,
                                                          desiredPosition.X, desiredPosition.Y, moverActors[i].position.Y,
                                                          desiredPosition.X - radiusXY, desiredPosition.X + radiusXY, searchZ, desiredPosition.Y - radiusXY, desiredPosition.Y + radiusXY,
                                                          moverActors[i], true);
                        statsZSliceCount++;
                        statsVoxelCount += (radiusXY * radiusXY * 4);

                        if (nearest != NoFitFound)
                        {
                            int distance = Math.Abs(desiredPosition.X - nearest.X) + Math.Abs(desiredPosition.Y - nearest.Y) + Math.Abs(desiredPosition.Z - searchZ);
                            if (distance < bestDistance)
                            {
                                bestDistance = distance;
                                bestPosition = new Position(nearest.X, nearest.Y, searchZ);
                            }
                        }

                        searchZ++;
                    }

#if DEBUG                                                                                                      // Separation stats
                    {
                        bool isActuallyTheMainSimulation = (updateContext.DebugNetworkUnsafeHasLocalSettings); // <- Somewhat hacky mechanisim so we don't get debug writes for "alternate universes" when debugging
                        if (isActuallyTheMainSimulation)
                        {
                            Debug.WriteLine("Separation of \"" + moverActors[i] + "\" searched " + statsZSliceCount + " Z slices, checking "
                                            + statsVoxelCount + " voxels; moved from " + moverActors[i].position + " to " + bestPosition + ".");
                        }
                    }
#endif

                    if (bestDistance != int.MaxValue) // <- Did we find a suitable position?
                    {
                        moverActors[i].position = bestPosition;
                        continue;
                    }
                }
                #endregion


                //
                // At this point... holy crap... how did you manage to get an object here??
                //

                stuckObjects.Add(moverActors[i]); // <- game state can deal with it.
            }
        }