mirror of
https://github.com/BentoBoxWorld/Boxed.git
synced 2025-01-05 18:37:48 +01:00
Custom biomes and updated blueprint.
This commit is contained in:
parent
f8e8656b86
commit
36a776945c
@ -81,6 +81,7 @@ Setting ocean biomes to higher height numbers will result in the ocean floor bei
|
||||
A lot of these numbers are rough guesses right now and if you come up with better values, please share them!
|
||||
|
||||
|
||||
|
||||
## Custom Advancements
|
||||
To find out how to add custom advacements to your server, watch the tutorial video [here](https://www.youtube.com/watch?v=zNzQvIbweQs)!
|
||||
|
||||
|
||||
|
@ -31,7 +31,8 @@ import world.bentobox.boxed.generators.chunks.AbstractBoxedChunkGenerator;
|
||||
import world.bentobox.boxed.generators.chunks.BoxedChunkGenerator;
|
||||
|
||||
/**
|
||||
* Generates the biomes for the seed world
|
||||
* Generates the biomes for the seed world. A seed world is the template for the chunks that
|
||||
* are used to generate areas for the players to play it.s
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@ -50,11 +51,12 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
|
||||
private final Boxed addon;
|
||||
private final Biome defaultBiome;
|
||||
private Map<Pair<Integer, Integer>, Biome> biomeCache = new HashMap<>();
|
||||
|
||||
protected final int dist;
|
||||
|
||||
private final int offsetX;
|
||||
private final int offsetZ;
|
||||
private final int spawnX;
|
||||
private final int spawnZ;
|
||||
protected final Map<BlockFace, SortedMap<Double, Biome>> quadrants;
|
||||
private final AbstractBoxedChunkGenerator seedGen;
|
||||
|
||||
@ -63,9 +65,15 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
this.addon = boxed;
|
||||
this.defaultBiome = defaultBiome;
|
||||
this.seedGen = seedGen;
|
||||
dist = addon.getSettings().getIslandDistance();
|
||||
offsetX = addon.getSettings().getIslandXOffset();
|
||||
offsetZ = addon.getSettings().getIslandZOffset();
|
||||
// These fields are used to determine the biomes around the spawn point
|
||||
this.dist = addon.getSettings().getIslandDistance();
|
||||
if (env.equals(Environment.NORMAL)) {
|
||||
spawnX = addon.getSettings().getSeedX();
|
||||
spawnZ = addon.getSettings().getSeedZ();
|
||||
} else {
|
||||
spawnX = addon.getSettings().getNetherSeedX();
|
||||
spawnZ = addon.getSettings().getNetherSeedZ();
|
||||
}
|
||||
// Load the config
|
||||
File biomeFile = new File(addon.getDataFolder(), "biomes.yml");
|
||||
// Check if it exists and if not, save it from the jar
|
||||
@ -90,29 +98,34 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
return en == null ? null : en.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* x, y, and z are block coordinates
|
||||
*/
|
||||
@Override
|
||||
public Biome getBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
// Custom biomes are not 3D yet
|
||||
if (y < DEPTH) {
|
||||
Biome result = getVanillaBiome(worldInfo, x, y, z);
|
||||
return Objects.requireNonNull(result);
|
||||
}
|
||||
Biome result = getMappedBiome(x,z);
|
||||
if (result == null || result.equals(Biome.CUSTOM)) {
|
||||
result = getVanillaBiome(worldInfo, x, y, z);
|
||||
|
||||
}
|
||||
return Objects.requireNonNull(result);
|
||||
return this.getMappedBiome(worldInfo, x, y, z);
|
||||
}
|
||||
|
||||
private @NonNull Biome getVanillaBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
// Vanilla biomes
|
||||
/**
|
||||
* Get the vanilla biome at this coordinate
|
||||
* @param worldInfo world info
|
||||
* @param x x
|
||||
* @param y y
|
||||
* @param z z
|
||||
* @return Biome
|
||||
*/
|
||||
@NonNull
|
||||
private Biome getVanillaBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
// Get the chunk coordinates
|
||||
int chunkX = BoxedChunkGenerator.repeatCalc(x >> 4);
|
||||
int chunkZ = BoxedChunkGenerator.repeatCalc(z >> 4);
|
||||
// Get the stored snapshot
|
||||
ChunkSnapshot snapshot = this.seedGen.getChunk(chunkX, chunkZ);
|
||||
if (snapshot == null) {
|
||||
// This snapshot is not stored...
|
||||
return defaultBiome;
|
||||
}
|
||||
// Get the in-chunk coordinates
|
||||
int xx = Math.floorMod(x, 16);
|
||||
int zz = Math.floorMod(z, 16);
|
||||
int yy = Math.max(Math.min(y * 4, worldInfo.getMaxHeight()), worldInfo.getMinHeight()); // To handle bug in Spigot
|
||||
@ -121,26 +134,40 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
return Objects.requireNonNull(b);
|
||||
}
|
||||
|
||||
private Map<Pair<Integer, Integer>, Biome> biomeCache = new HashMap<>();
|
||||
/**
|
||||
* Get the mapped 2D biome at position x,z
|
||||
* @param worldInfo world info
|
||||
* @param x - block coord
|
||||
* @param y - block coord
|
||||
* @param z - block coord
|
||||
* @return Biome
|
||||
*/
|
||||
private Biome getMappedBiome(int x, int z) {
|
||||
private Biome getMappedBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
|
||||
// Custom biomes are not 3D yet
|
||||
if (y < DEPTH) {
|
||||
Biome result = getVanillaBiome(worldInfo, x, y, z);
|
||||
return Objects.requireNonNull(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Biomes go around the island centers
|
||||
*
|
||||
*/
|
||||
|
||||
// Try to get the cached value
|
||||
Biome result = biomeCache.get((new Pair<Integer, Integer>(x,z)));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
Vector s = new Vector(x, 0, z);
|
||||
Vector l = getClosestIsland(s);
|
||||
//BentoBox.getInstance().logDebug("Closest island is " + Util.xyz(l));
|
||||
Vector l = new Vector(spawnX,0,spawnZ);
|
||||
double dis = l.distance(s);
|
||||
if (dis > dist * 2) {
|
||||
// Only customize biomes around the spawn location
|
||||
return getVanillaBiome(worldInfo, x, y, z);
|
||||
}
|
||||
// Provide custom biomes
|
||||
double d = dis / dist; // Normalize
|
||||
Vector direction = s.subtract(l);
|
||||
if (direction.getBlockX() <= 0 && direction.getBlockZ() <= 0) {
|
||||
@ -152,6 +179,12 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
} else {
|
||||
result = getQuadrantBiome(BlockFace.SOUTH_EAST, d);
|
||||
}
|
||||
|
||||
if (result == null || result.equals(Biome.CUSTOM)) {
|
||||
result = getVanillaBiome(worldInfo, x, y, z);
|
||||
|
||||
}
|
||||
// Cache good result
|
||||
biomeCache.put(new Pair<Integer, Integer>(x,z), result);
|
||||
return result;
|
||||
|
||||
@ -164,23 +197,17 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the island center closest to this vector
|
||||
* @param v - vector
|
||||
* @return island center vector (no y value)
|
||||
* Loads the custom biomes from the config file
|
||||
* @param config - Yaml configuration object
|
||||
* @param sector - the direction section to load
|
||||
* @return
|
||||
*/
|
||||
private Vector getClosestIsland(Vector v) {
|
||||
int d = dist * 2;
|
||||
long x = Math.round((double) v.getBlockX() / d) * d + offsetX;
|
||||
long z = Math.round((double) v.getBlockZ() / d) * d + offsetZ;
|
||||
return new Vector(x, 0, z);
|
||||
}
|
||||
|
||||
private SortedMap<Double, Biome> loadQuad(YamlConfiguration config, String string) {
|
||||
private SortedMap<Double, Biome> loadQuad(YamlConfiguration config, String sector) {
|
||||
SortedMap<Double, Biome> result = new TreeMap<>();
|
||||
if (!config.contains(string)) {
|
||||
if (!config.contains(sector)) {
|
||||
return result;
|
||||
}
|
||||
for (String ring : config.getStringList(string)) {
|
||||
for (String ring : config.getStringList(sector)) {
|
||||
String[] split = ring.split(":");
|
||||
if (split.length == 2) {
|
||||
try {
|
||||
@ -194,7 +221,7 @@ public abstract class AbstractSeedBiomeProvider extends BiomeProvider {
|
||||
result.put(d, biome);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
addon.logError(string + ": " + split[0] + " does not seem to be a double. For integers add a .0 to the end");
|
||||
addon.logError(sector + ": " + split[0] + " does not seem to be a double. For integers add a .0 to the end");
|
||||
}
|
||||
} else {
|
||||
addon.logError(ring + " must be in the format ratio:biome where ratio is a double.");
|
||||
|
@ -75,7 +75,8 @@ public class BoxedSeedChunkGenerator extends AbstractBoxedChunkGenerator {
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateStructures() {
|
||||
return env.equals(Environment.NETHER); // We allow structures in the Nether
|
||||
return true;
|
||||
//return env.equals(Environment.NETHER); // We allow structures in the Nether
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,8 +15,10 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.advancement.AdvancementProgress;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -25,6 +27,7 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerAdvancementDoneEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerPortalEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
||||
|
||||
@ -46,6 +49,7 @@ public class AdvancementListener implements Listener {
|
||||
|
||||
private final Boxed addon;
|
||||
private final Advancement netherAdvancement;
|
||||
private final Advancement netherFortressAdvancement;
|
||||
private final Advancement endAdvancement;
|
||||
private final Advancement netherRoot;
|
||||
private final Advancement endRoot;
|
||||
@ -57,6 +61,7 @@ public class AdvancementListener implements Listener {
|
||||
this.addon = addon;
|
||||
this.netherAdvancement = getAdvancement("minecraft:story/enter_the_nether");
|
||||
this.endAdvancement = getAdvancement("minecraft:story/enter_the_end");
|
||||
this.netherFortressAdvancement = getAdvancement("minecraft:nether/find_fortress");
|
||||
this.netherRoot = getAdvancement("minecraft:nether/root");
|
||||
this.endRoot = getAdvancement("minecraft:end/root");
|
||||
}
|
||||
@ -172,6 +177,16 @@ public class AdvancementListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onNetherFortress(PlayerMoveEvent e) {
|
||||
if (!Util.sameWorld(e.getPlayer().getWorld(), addon.getNetherWorld())) {
|
||||
return;
|
||||
}
|
||||
if (e.getTo().getBlock().getRelative(BlockFace.DOWN).getType().equals(Material.NETHER_BRICK)) {
|
||||
giveAdv(e.getPlayer(), netherFortressAdvancement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void giveAdv(Player player, Advancement adv) {
|
||||
if (adv != null && !player.getAdvancementProgress(adv).isDone()) {
|
||||
|
@ -9,16 +9,18 @@ distribution:
|
||||
- 0.65:JUNGLE
|
||||
- 0.8:BAMBOO_JUNGLE
|
||||
- 1.0:MANGROVE_SWAMP
|
||||
- 2.0:CUSTOM
|
||||
south-east:
|
||||
- 0.05:CUSTOM
|
||||
- 0.08:SUNFLOWER_PLAINS
|
||||
- 0.8:SUNFLOWER_PLAINS
|
||||
- 0.2:FLOWER_FOREST
|
||||
- 0.3:SAVANNA
|
||||
- 0.4:BEACH
|
||||
- 0.5:CUSTOM
|
||||
- 0.5:COLD_OCEAN
|
||||
north-west:
|
||||
- 2.0:CUSTOM
|
||||
- 0.05:CUSTOM
|
||||
- 0.8:WARM_OCEAN
|
||||
- 1.5:COLD_OCEAN
|
||||
- 2.0:OCEAN
|
||||
south-west:
|
||||
- 0.04:CUSTOM
|
||||
- 0.05:DARK_FOREST
|
||||
@ -32,10 +34,9 @@ distribution:
|
||||
- 0.7:TAIGA
|
||||
- 1.1:SNOWY_PLAINS
|
||||
- 2.1:SNOWY_TAIGA
|
||||
- 2.2:CUSTOM
|
||||
nether:
|
||||
north-east:
|
||||
- 0.03:CUSTOM
|
||||
- 0.1:CUSTOM
|
||||
- 0.14:CRIMSON_FOREST
|
||||
- 0.26:NETHER_WASTES
|
||||
- 0.51:WARPED_FOREST
|
||||
@ -55,7 +56,7 @@ distribution:
|
||||
- 1.9:BASALT_DELTAS
|
||||
- 2.0:NETHER_WASTES
|
||||
north-west:
|
||||
- 0.03:CUSTOM
|
||||
- 0.10:CUSTOM
|
||||
- 0.15:CRIMSON_FOREST
|
||||
- 0.20:NETHER_WASTES
|
||||
- 0.3:WARPED_FOREST
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user