private static Vector2D?FindClosestPosition(Vector2D position) { var physicsSpace = ServerWorldService.GetPhysicsSpace(); var collisionGroup = CollisionGroup.Default; if (IsValidPosition( // round position position.ToVector2Ushort().ToVector2D())) { // can teleport right there return(position); } // check nearby tiles var tile = ServerWorldService.GetTile(position.ToVector2Ushort()); foreach (var neighborTile in tile.EightNeighborTiles) { if (!neighborTile.IsValidTile) { continue; } var neighborTilePosition = neighborTile.Position.ToVector2D(); if (IsValidPosition(neighborTilePosition)) { return(neighborTilePosition); } } return(null); // Local function for checking if the position is valid. bool IsValidPosition(Vector2D pos) { using var objectsNearby = physicsSpace.TestRectangle( // include some padding, otherwise the check will include border-objects position: pos + (0.01, 0.01), size: (0.98, 0.98), collisionGroup: collisionGroup, sendDebugEvent: false); if (objectsNearby.Count > 0) { return(false); } var posTile = Server.World.GetTile(pos.ToVector2Ushort()); return(ServerCharacterSpawnHelper.IsValidSpawnTile(posTile, checkNeighborTiles: false)); } }
protected virtual bool ServerIsValidSpawnPosition(Vector2D worldPosition) { const double noObstaclesCheckRadius = 1.5; var physicsSpace = Server.World.GetPhysicsSpace(); foreach (var _ in physicsSpace.TestCircle(worldPosition, radius: noObstaclesCheckRadius, CollisionGroups.Default, sendDebugEvent: false).EnumerateAndDispose()) { // position is not valid for spawning return(false); } return(ServerCharacterSpawnHelper.IsValidSpawnTile( Api.Server.World.GetTile(worldPosition.ToVector2Ushort()), checkNeighborTiles: true)); }
public static void ServerTrySpawnMobsCustom( IProtoCharacter protoMob, ICollection <ICharacter> spawnedCollection, int countToSpawn, RectangleInt excludeBounds, int maxSpawnDistanceFromExcludeBounds, double noObstaclesCheckRadius, int maxAttempts) { if (countToSpawn <= 0) { return; } var spawnBounds = excludeBounds.Inflate(maxSpawnDistanceFromExcludeBounds, maxSpawnDistanceFromExcludeBounds); var physicsSpace = Api.Server.World.GetPhysicsSpace(); while (maxAttempts-- > 0) { var position = new Vector2D(spawnBounds.Left + RandomHelper.NextDouble() * spawnBounds.Width, spawnBounds.Bottom + RandomHelper.NextDouble() * spawnBounds.Height); if (IsTooClose(position)) { continue; } var character = ServerTrySpawnMob(position); if (character is null) { // cannot spawn there continue; } spawnedCollection.Add(character); countToSpawn--; if (countToSpawn == 0) { return; } } bool IsTooClose(in Vector2D position) => position.X >= excludeBounds.X && position.Y >= excludeBounds.Y && position.X < excludeBounds.X + excludeBounds.Width && position.Y < excludeBounds.Y + excludeBounds.Height; ICharacter ServerTrySpawnMob(Vector2D worldPosition) { foreach (var _ in physicsSpace.TestCircle(worldPosition, radius: noObstaclesCheckRadius, CollisionGroups.Default, sendDebugEvent: false).EnumerateAndDispose()) { // position is not valid for spawning return(null); } if (!ServerCharacterSpawnHelper.IsValidSpawnTile( Api.Server.World.GetTile(worldPosition.ToVector2Ushort()), checkNeighborTiles: true)) { return(null); } return(Api.Server.Characters.SpawnCharacter(protoMob, worldPosition)); } }