/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.logic.spawner;
import org.terasology.math.Region3i;
import org.terasology.math.TeraMath;
import org.terasology.math.geom.BaseVector2i;
import org.terasology.math.geom.SpiralIterable;
import org.terasology.math.geom.Vector2i;
import org.terasology.math.geom.Vector3f;
import org.terasology.math.geom.Vector3i;
import org.terasology.world.generation.Region;
import org.terasology.world.generation.World;
import org.terasology.world.generation.facets.SeaLevelFacet;
import org.terasology.world.generation.facets.SurfaceHeightFacet;
public abstract class AbstractSpawner implements Spawner {
/**
* Tries to find a suitable spawning point based on {@link SurfaceHeightFacet} and {@link SeaLevelFacet}.
* @param searchRadius the radius within a suitable spawning point will be searched
* @param world the facet-based world
* @param pos the desired 2D position in that world
* @return a 3D position above the surface and sea level or <code>null</code> if none was found
* @throws IllegalStateException if no SurfaceHeightFacet can be created.
*/
protected Vector3f findSpawnPosition(World world, Vector2i pos, int searchRadius) {
Vector3i ext = new Vector3i(searchRadius, 1, searchRadius);
Vector3i desiredPos = new Vector3i(pos.getX(), 1, pos.getY());
// try and find somewhere in this region a spot to land
Region3i spawnArea = Region3i.createFromCenterExtents(desiredPos, ext);
Region worldRegion = world.getWorldData(spawnArea);
// check if generation uses sea level and surface height facets
SurfaceHeightFacet surfaceHeightFacet = worldRegion.getFacet(SurfaceHeightFacet.class);
if (surfaceHeightFacet == null) {
throw new IllegalStateException("surface height facet not found");
}
SeaLevelFacet seaLevelFacet = worldRegion.getFacet(SeaLevelFacet.class);
int seaLevel = (seaLevelFacet != null) ? seaLevelFacet.getSeaLevel() : 0;
int spiralRad = searchRadius / 2 - 1;
SpiralIterable spiral = SpiralIterable.clockwise(pos).maxRadius(spiralRad).scale(2).build();
for (BaseVector2i test : spiral) {
float val = surfaceHeightFacet.getWorld(test.getX(), test.getY());
int height = TeraMath.floorToInt(val);
if (height >= seaLevel) {
return new Vector3f(test.getX(), height, test.getY());
}
}
// nothing above sea level found
float y = surfaceHeightFacet.getWorld(pos.getX(), pos.getY());
return new Vector3f(pos.getX(), y, pos.getY());
}
}