elevation is gone but this time I'm not doing the crab rave meme

This commit is contained in:
Anuken
2019-01-10 21:45:18 -05:00
parent 84e754dd10
commit ae3aa20508
28 changed files with 182 additions and 655 deletions

View File

@@ -1,374 +0,0 @@
package io.anuke.mindustry.maps;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.IntArray;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.RandomXS128;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.math.geom.Point2;
import io.anuke.arc.util.Structs;
import io.anuke.arc.util.noise.RidgedPerlin;
import io.anuke.arc.util.noise.Simplex;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.OreBlock;
import static io.anuke.mindustry.Vars.*;
public class WorldGenerator{
private static final int baseSeed = 0;
private int oreIndex = 0;
private Simplex sim = new Simplex(baseSeed);
private Simplex sim2 = new Simplex(baseSeed + 1);
private Simplex sim3 = new Simplex(baseSeed + 2);
private RidgedPerlin rid = new RidgedPerlin(baseSeed + 4, 1);
private RandomXS128 random = new RandomXS128(baseSeed + 3);
private GenResult result = new GenResult();
private ObjectMap<Block, Block> decoration;
public WorldGenerator(){
decoration = ObjectMap.of(
Blocks.grass, Blocks.shrub,
Blocks.stone, Blocks.rock,
Blocks.ice, Blocks.icerock,
Blocks.snow, Blocks.icerock,
Blocks.blackstone, Blocks.blackrock
);
}
/**Loads raw map tile data into a Tile[][] array, setting up multiblocks, cliffs and ores. */
public void loadTileData(Tile[][] tiles, MapTileData data, boolean genOres, int seed){
data.position(0, 0);
TileDataMarker marker = data.newDataMarker();
for(int y = 0; y < data.height(); y++){
for(int x = 0; x < data.width(); x++){
data.read(marker);
tiles[x][y] = new Tile(x, y, marker.floor, marker.wall == Blocks.blockpart.id ? 0 : marker.wall, marker.rotation, marker.team, marker.elevation);
}
}
prepareTiles(tiles);
generateOres(tiles, seed, genOres, null);
}
/**'Prepares' a tile array by:<br>
* - setting up multiblocks<br>
* - updating cliff data<br>
* - removing ores on cliffs<br>
* Usually used before placing structures on a tile array.*/
public void prepareTiles(Tile[][] tiles){
//find multiblocks
IntArray multiblocks = new IntArray();
for(int x = 0; x < tiles.length; x++){
for(int y = 0; y < tiles[0].length; y++){
Tile tile = tiles[x][y];
if(tile.block().isMultiblock()){
multiblocks.add(tile.pos());
}
}
}
//place multiblocks now
for(int i = 0; i < multiblocks.size; i++){
int pos = multiblocks.get(i);
int x = Pos.x(pos);
int y = Pos.y(pos);
Block result = tiles[x][y].block();
Team team = tiles[x][y].getTeam();
int offsetx = -(result.size - 1) / 2;
int offsety = -(result.size - 1) / 2;
for(int dx = 0; dx < result.size; dx++){
for(int dy = 0; dy < result.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!(worldx == x && worldy == y)){
Tile toplace = world.tile(worldx, worldy);
if(toplace != null){
toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety));
toplace.setTeam(team);
}
}
}
}
}
//update cliffs, occlusion data
for(int x = 0; x < tiles.length; x++){
for(int y = 0; y < tiles[0].length; y++){
Tile tile = tiles[x][y];
tile.updateOcclusion();
//fix things on cliffs that shouldn't be
if(tile.block() != Blocks.air && tile.hasCliffs() && !tile.block().isMultiblock() && tile.block() != Blocks.blockpart){
tile.setBlock(Blocks.air);
}
//remove ore veins on cliffs
if(tile.floor() instanceof OreBlock && tile.hasCliffs()){
tile.setFloor(((OreBlock)tile.floor()).base);
}
}
}
}
public void playRandomMap(){
ui.loadLogic(() -> {
logic.reset();
int sx = (short)Mathf.range(Short.MAX_VALUE/2);
int sy = (short)Mathf.range(Short.MAX_VALUE/2);
int width = 256;
int height = 256;
Array<Point2> spawns = new Array<>();
Array<Item> ores = Item.getAllOres();
if(state.mode.isPvp){
int scaling = 10;
spawns.add(new Point2(width/scaling, height/scaling));
spawns.add(new Point2(width - 1 - width/scaling, height - 1 - height/scaling));
}else{
spawns.add(new Point2(width/2, height/2));
}
Tile[][] tiles = world.createTiles(width, height);
world.setMap(new Map("Generated Map", width, height));
world.beginMapLoad();
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
generateTile(result, sx, sy, x, y, true, spawns, ores);
tiles[x][y] = new Tile(x, y, result.floor.id, result.wall.id, (byte)0, (byte)0, result.elevation);
}
}
prepareTiles(tiles);
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
Tile tile = tiles[x][y];
byte elevation = tile.getElevation();
for(Point2 point : Geometry.d4){
if(!Structs.inBounds(x + point.x, y + point.y, width, height)) continue;
if(tiles[x + point.x][y + point.y].getElevation() < elevation){
if(sim2.octaveNoise2D(1, 1, 1.0 / 8, x, y) > 0.8){
tile.setElevation(-1);
}
break;
}
}
}
}
world.setBlock(tiles[spawns.get(0).x][spawns.get(0).y], Blocks.core, Team.blue);
world.setBlock(tiles[spawns.get(0).x][spawns.get(0).y - 3], Blocks.launchPad, Team.blue);
if(state.mode.isPvp){
world.setBlock(tiles[spawns.get(1).x][spawns.get(1).y], Blocks.core, Team.red);
}
world.endMapLoad();
logic.play();
});
}
public void generateOres(Tile[][] tiles, long seed, boolean genOres, Array<Item> usedOres){
oreIndex = 0;
if(genOres){
Array<OreEntry> baseOres = Array.with(
new OreEntry(Items.copper, 0.3f, seed),
new OreEntry(Items.coal, 0.284f, seed),
new OreEntry(Items.lead, 0.28f, seed),
new OreEntry(Items.titanium, 0.27f, seed),
new OreEntry(Items.thorium, 0.26f, seed)
);
Array<OreEntry> ores = new Array<>();
if(usedOres == null){
ores.addAll(baseOres);
}else{
for(Item item : usedOres){
ores.add(baseOres.find(entry -> entry.item == item));
}
}
for(int x = 0; x < tiles.length; x++){
for(int y = 0; y < tiles[0].length; y++){
Tile tile = tiles[x][y];
if(!tile.floor().hasOres || tile.hasCliffs() || tile.block() != Blocks.air){
continue;
}
for(int i = ores.size - 1; i >= 0; i--){
OreEntry entry = ores.get(i);
if(entry.noise.octaveNoise2D(1, 0.7, 1f / (4 + i * 2), x, y) / 4f +
Math.abs(0.5f - entry.noise.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), x, y)) > 0.48f &&
Math.abs(0.5f - entry.noise.octaveNoise2D(1, 1, 1f / (55 + i * 4), x, y)) > 0.22f){
tile.setFloor((Floor) OreBlock.get(tile.floor(), entry.item));
break;
}
}
}
}
}
}
public GenResult generateTile(int sectorX, int sectorY, int localX, int localY){
return generateTile(sectorX, sectorY, localX, localY, true);
}
public GenResult generateTile(int sectorX, int sectorY, int localX, int localY, boolean detailed){
return generateTile(result, sectorX, sectorY, localX, localY, detailed, null, null);
}
/**
* Gets the generation result from a specific sector at specific coordinates.
* @param result where to put the generation results
* @param sectorX X of the sector in terms of sector coordinates
* @param sectorY Y of the sector in terms of sector coordinates
* @param localX X in terms of local sector tile coordinates
* @param localY Y in terms of local sector tile coordinates
* @param detailed whether the tile result is 'detailed' (e.g. previews should not be detailed)
* @param spawnpoints list of player spawnpoints, can be null
* @return the GenResult passed in with its values modified
*/
public GenResult generateTile(GenResult result, int sectorX, int sectorY, int localX, int localY, boolean detailed, Array<Point2> spawnpoints, Array<Item> ores){
int x = sectorX * sectorSize + localX + Short.MAX_VALUE;
int y = sectorY * sectorSize + localY + Short.MAX_VALUE;
Block floor;
Block wall = Blocks.air;
double ridge = rid.getValue(x, y, 1f / 400f);
double iceridge = rid.getValue(x+99999, y, 1f / 300f) + sim3.octaveNoise2D(2, 1f, 1f/14f, x, y)/11f;
double elevation = elevationOf(x, y, detailed);
double temp =
+ sim3.octaveNoise2D(detailed ? 12 : 9, 0.6, 1f / 1100f, x - 120, y);
double lake = sim2.octaveNoise2D(1, 1, 1f / 110f, x, y);
elevation -= Math.pow(lake + 0.15, 5);
int lerpDst = 20;
lerpDst *= lerpDst;
float minDst = Float.MAX_VALUE;
if(detailed && spawnpoints != null){
for(Point2 p : spawnpoints){
float dst = Mathf.dst2(p.x, p.y, localX, localY);
minDst = Math.min(minDst, dst);
if(dst < lerpDst){
float targetElevation = Math.max(0.86f, (float)elevationOf(sectorX * sectorSize + p.x + Short.MAX_VALUE, sectorY * sectorSize + p.y + Short.MAX_VALUE, true));
elevation = Mathf.lerp((float)elevation, targetElevation, Mathf.clamp(1.5f*(1f-(dst / lerpDst))));
}
}
}
if(elevation < 0.7){
floor = Blocks.deepwater;
}else if(elevation < 0.79){
floor = Blocks.water;
}else if(elevation < 0.85){
floor = Blocks.sand;
}else if (elevation < 2.5 && temp > 0.5){
floor = Blocks.sand;
}else if(temp < 0.42){
floor = Blocks.snow;
}else if(temp < 0.5){
floor = Blocks.stone;
}else if(temp < 0.6){
floor = Blocks.grass;
}else if(temp + ridge/2f < 0.8 || elevation < 1.3){
floor = Blocks.blackstone;
if(iceridge > 0.25 && minDst > lerpDst/1.5f){
elevation ++;
}
}else{
floor = Blocks.blackstone;
}
if(elevation > 3.3 && iceridge > 0.25 && temp < 0.6f){
elevation ++;
floor = Blocks.ice;
}
if(((Floor)floor).liquidDrop != null){
elevation = 0;
}
if(detailed && wall == Blocks.air && decoration.containsKey(floor) && random.chance(0.03)){
wall = decoration.get(floor);
}
if(ores != null && ((Floor) floor).hasOres){
int offsetX = x - 4, offsetY = y + 23;
for(int i = ores.size - 1; i >= 0; i--){
Item entry = ores.get(i);
if(Math.abs(0.5f - sim.octaveNoise2D(2, 0.7, 1f / (50 + i * 2), offsetX, offsetY)) > 0.23f &&
Math.abs(0.5f - sim2.octaveNoise2D(1, 1, 1f / (40 + i * 4), offsetX, offsetY)) > 0.32f){
floor = OreBlock.get(floor, entry);
break;
}
}
}
result.wall = wall;
result.floor = floor;
result.elevation = (byte) Math.max(elevation, 0);
return result;
}
double elevationOf(int x, int y, boolean detailed){
double ridge = rid.getValue(x, y, 1f / 400f);
return sim.octaveNoise2D(detailed ? 7 : 5, 0.62, 1f / 800, x, y) * 6.1 - 1 - ridge;
}
public static class GenResult{
public Block floor, wall;
public byte elevation;
}
public class OreEntry{
final float frequency;
final Item item;
final Simplex noise;
final RidgedPerlin ridge;
final int index;
OreEntry(Item item, float frequency, long seed){
this.frequency = frequency;
this.item = item;
this.noise = new Simplex(seed + oreIndex);
this.ridge = new RidgedPerlin((int)(seed + oreIndex), 2);
this.index = oreIndex++;
}
}
}

View File

@@ -0,0 +1,14 @@
package io.anuke.mindustry.maps.generators;
import io.anuke.mindustry.world.Tile;
public abstract class Generator{
public final int width, height;
public Generator(int width, int height){
this.width = width;
this.height = height;
}
public abstract void generate(Tile[][] tiles);
}

View File

@@ -0,0 +1,33 @@
package io.anuke.mindustry.maps.generators;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
public abstract class RandomGenerator extends Generator{
protected Block floor;
protected Block block;
public RandomGenerator(int width, int height, Block floor){
super(width, height);
this.floor = floor;
}
@Override
public void generate(Tile[][] tiles){
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
floor = Blocks.air;
block = Blocks.air;
generate(x, y);
tiles[x][y].setFloor((Floor) floor);
tiles[x][y].setBlock(block);
}
}
}
/**Sets {@link #floor} and {@link #block} to the correct values as output.
* Before this method is called, both are set to {@link Blocks#air} as defaults.*/
public abstract void generate(int x, int y);
}