Add EntityFeature to StructureConfig.

This commit is contained in:
dfsek
2020-11-04 20:40:58 -07:00
parent e82e8cb17d
commit d0891a0f95
16 changed files with 268 additions and 23 deletions

View File

@@ -1,7 +1,7 @@
package com.dfsek.terra;
import com.dfsek.terra.async.AsyncStructureFinder;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.util.StructureTypeEnum;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Entity;

View File

@@ -4,7 +4,7 @@ import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.structure.Structure;
import org.bukkit.Bukkit;
import org.bukkit.Location;

View File

@@ -3,7 +3,7 @@ package com.dfsek.terra.command.biome;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeSnowConfig;
import com.dfsek.terra.config.lang.LangUtil;

View File

@@ -3,7 +3,7 @@ package com.dfsek.terra.command.structure;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.async.AsyncStructureFinder;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.generation.TerraChunkGenerator;
import org.bukkit.Bukkit;
@@ -12,7 +12,6 @@ import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.command.WorldCommand;

View File

@@ -11,7 +11,7 @@ import com.dfsek.terra.config.genconfig.CarverConfig;
import com.dfsek.terra.config.genconfig.FloraConfig;
import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.config.genconfig.PaletteConfig;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.config.genconfig.TreeConfig;
import com.dfsek.terra.config.genconfig.biome.AbstractBiomeConfig;
import com.dfsek.terra.config.genconfig.biome.BiomeConfig;

View File

@@ -7,7 +7,7 @@ import com.dfsek.terra.config.TerraConfig;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.config.exception.NotFoundException;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.generation.UserDefinedDecorator;
import com.dfsek.terra.generation.UserDefinedGenerator;
import org.bukkit.configuration.InvalidConfigurationException;

View File

@@ -0,0 +1,59 @@
package com.dfsek.terra.config.genconfig.structure;
import com.dfsek.terra.Debug;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.exception.ConfigException;
import com.dfsek.terra.structure.features.EntityFeature;
import com.dfsek.terra.structure.features.Feature;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.entity.EntityType;
import org.polydev.gaea.math.Range;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class EntityFeatureConfig implements FeatureConfig {
private final EntityFeature feature;
@SuppressWarnings("unchecked")
public EntityFeatureConfig(Map<String, Object> items) throws InvalidConfigurationException {
if(! items.containsKey("entity")) throw new ConfigException("No EntityType specified!", "EntityFeature");
if(! items.containsKey("amount")) throw new ConfigException("No amount specified!", "EntityFeature");
if(! items.containsKey("attempts")) throw new ConfigException("Attempts not specified!", "EntityFeature");
if(! items.containsKey("in-height")) throw new ConfigException("Spawn Checking Height not specified!", "EntityFeature");
if(! items.containsKey("spawnable-on")) throw new ConfigException("No Spawnable-on materials specified!", "EntityFeature");
if(! items.containsKey("spawnable-in")) throw new ConfigException("No Spawnable-in materials specified!", "EntityFeature");
EntityType type;
try {
type = EntityType.valueOf((String) items.get("entity"));
} catch(IllegalArgumentException e) {
throw new InvalidConfigurationException("No such EntityType: " + items.get("entity"));
} catch(ClassCastException e) {
throw new InvalidConfigurationException("Error in Entity Configuration!");
}
int attempts = (Integer) items.get("attempts");
int height = (Integer) items.get("in-height");
Range amount;
try {
Map<String, Integer> amountMap = (Map<String, Integer>) items.get("amount");
amount = new Range(amountMap.get("min"), amountMap.get("max"));
} catch(ClassCastException e) {
throw new InvalidConfigurationException("Error in Amount Configuration!");
}
Set<Material> on = ConfigUtil.toBlockData((List<String>) items.get("spawnable-on"), "SpawnableOn", "");
Set<Material> in = ConfigUtil.toBlockData((List<String>) items.get("spawnable-in"), "SpawnableIn", "");
this.feature = new EntityFeature(type, amount, attempts, on, in, height);
Debug.info("Loaded EntityFeature with type: " + type);
}
@Override
public Feature getFeature() {
return feature;
}
}

View File

@@ -0,0 +1,8 @@
package com.dfsek.terra.config.genconfig.structure;
import com.dfsek.terra.config.TerraConfigSection;
import com.dfsek.terra.structure.features.Feature;
public interface FeatureConfig {
Feature getFeature();
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.config.genconfig;
package com.dfsek.terra.config.genconfig.structure;
import com.dfsek.terra.Debug;
import com.dfsek.terra.config.TerraConfig;
@@ -9,6 +9,7 @@ import com.dfsek.terra.config.exception.NotFoundException;
import com.dfsek.terra.population.StructurePopulator;
import com.dfsek.terra.procgen.GridSpawn;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.features.Feature;
import org.apache.commons.io.FileUtils;
import org.bukkit.configuration.InvalidConfigurationException;
import org.json.simple.parser.ParseException;
@@ -19,7 +20,9 @@ import org.polydev.gaea.structures.loot.LootTable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@@ -31,8 +34,11 @@ public class StructureConfig extends TerraConfig {
private final Range searchStart;
private final Range bound;
private final Map<Integer, LootTable> loot = new HashMap<>();
private final List<Feature> features;
StructurePopulator.SearchType type;
@SuppressWarnings("unchecked")
public StructureConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException {
super(file, config);
if(! contains("id")) throw new ConfigException("No ID specified!", "null");
@@ -76,6 +82,16 @@ public class StructureConfig extends TerraConfig {
}
}
features = new ArrayList<>();
if(contains("features")) {
for(Map<?, ?> map : getMapList("features")) {
for(Map.Entry<?, ?> entry : map.entrySet()) {
if(entry.getKey().equals("ENTITY_FEATURE"))
features.add(new EntityFeatureConfig((Map<String, Object>) entry.getValue()).getFeature());
}
}
}
spawn = new GridSpawn(getInt("spawn.width", 500), getInt("spawn.padding", 100));
searchStart = new Range(getInt("spawn.start.min", 72), getInt("spawn.start.max", 72));
bound = new Range(getInt("spawn.bound.min", 48), getInt("spawn.bound.max", 72));
@@ -86,6 +102,10 @@ public class StructureConfig extends TerraConfig {
}
}
public List<Feature> getFeatures() {
return features;
}
@Override
public String getID() {
return id;

View File

@@ -132,11 +132,9 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
private void load(World w) {
try {
popMan.loadBlocks(w);
} catch(IOException e) {
if(e instanceof FileNotFoundException) {
LangUtil.log("warning.no-population", Level.WARNING);
} else e.printStackTrace();
} catch(ClassNotFoundException e) {
} catch(FileNotFoundException e) {
LangUtil.log("warning.no-population", Level.WARNING);
} catch(IOException | ClassNotFoundException e) {
e.printStackTrace();
}
popMap.put(w, popMan);

View File

@@ -6,10 +6,11 @@ import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.config.genconfig.structure.StructureConfig;
import com.dfsek.terra.procgen.math.Vector2;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureContainedInventory;
import com.dfsek.terra.structure.features.Feature;
import com.dfsek.terra.util.structure.RotationUtil;
import org.bukkit.Chunk;
import org.bukkit.Location;
@@ -67,6 +68,7 @@ public class StructurePopulator extends BlockPopulator {
Debug.stack(e);
}
}
for(Feature f : conf.getFeatures()) f.apply(struc, spawn, chunk); // Apply features.
break;
}
}

View File

@@ -0,0 +1,118 @@
package com.dfsek.terra.structure.features;
import com.dfsek.terra.Debug;
import com.dfsek.terra.structure.Structure;
import com.dfsek.terra.structure.StructureInfo;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.math.Range;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class EntityFeature implements Feature {
private final EntityType type;
private final Range amount;
private final int attempts;
private final Set<Material> in;
private final Set<Material> stand;
private final int inSize;
public EntityFeature(EntityType type, Range amount, int attempts, Set<Material> stand, Set<Material> in, int inSize) {
this.type = type;
this.amount = amount;
this.attempts = attempts;
this.in = in;
this.stand = stand;
this.inSize = inSize;
}
@Override
public void apply(Structure structure, Location l, Chunk chunk) {
Random random = new Random(MathUtil.getCarverChunkSeed(chunk.getX(), chunk.getZ(), chunk.getWorld().getSeed()));
int amountSpawn = amount.get(random);
StructureInfo info = structure.getStructureInfo();
Range x = new Range(0, info.getSizeZ());
Range y = new Range(0, info.getSizeY());
Range z = new Range(0, info.getSizeZ());
int cx = info.getCenterX();
int cz = info.getCenterZ();
for(int i = 0; i < amountSpawn && i < attempts; i++) {
int yv = y.get(random);
Location attempt = l.clone().add(x.get(random)-cx, yv, z.get(random)-cz);
if(!isInChunk(chunk, attempt)) continue; // Don't attempt spawn if not in current chunk.
boolean canSpawn = false;
while(yv >= 0 && attempt.getBlockY() >= l.getBlockY()) { // Go down, see if valid spawns exist.
canSpawn = true;
Block on = attempt.getBlock();
attempt.subtract(0, 1, 0);
yv--;
if(!stand.contains(on.getType())) continue;
for(int j = 1; j < inSize + 1; j++) if(! in.contains(on.getRelative(BlockFace.UP, j).getType())) canSpawn = false;
if(canSpawn) break;
}
if(canSpawn) {
Debug.info("Spawning entity at " + attempt);
chunk.getWorld().spawnEntity(attempt.add(0.5, 1, 0.5), type); // Add 0.5 to X & Z so entity spawns in center of block.
}
}
}
private static boolean isInChunk(Chunk c, Location l) {
return Math.floorDiv(l.getBlockX(), 16) == c.getX() && Math.floorDiv(l.getBlockZ(), 16) == c.getZ();
}
@Override
public void apply(Structure structure, Location l, Random random) {
int amountSpawn = amount.get(random);
StructureInfo info = structure.getStructureInfo();
Range x = new Range(0, info.getSizeZ());
Range y = new Range(0, info.getSizeY());
Range z = new Range(0, info.getSizeZ());
int cx = info.getCenterX();
int cz = info.getCenterZ();
for(int i = 0; i < amountSpawn && i < attempts; i++) {
int yv = y.get(random);
Location attempt = l.clone().add(x.get(random)-cx, yv, z.get(random)-cz);
boolean canSpawn = false;
while(yv >= 0 && attempt.getBlockY() >= l.getBlockY()) { // Go down, see if valid spawns exist.
canSpawn = true;
Block on = attempt.getBlock();
attempt.subtract(0, 1, 0);
yv--;
if(!stand.contains(on.getType())) continue;
for(int j = 1; j < inSize + 1; j++) if(! in.contains(on.getRelative(BlockFace.UP, j).getType())) canSpawn = false;
if(canSpawn) break;
}
if(canSpawn) {
Debug.info("Spawning entity at " + attempt);
l.getWorld().spawnEntity(attempt.add(0.5, 1, 0.5), type); // Add 0.5 to X & Z so entity spawns in center of block.
}
}
}
public static class SpawnRule {
}
}

View File

@@ -0,0 +1,12 @@
package com.dfsek.terra.structure.features;
import com.dfsek.terra.structure.Structure;
import org.bukkit.Chunk;
import org.bukkit.Location;
import java.util.Random;
public interface Feature {
void apply(Structure structure, Location l, Chunk chunk);
void apply(Structure structure, Location l, Random random);
}