diff --git a/.settings/.gitignore b/.settings/.gitignore index 6cb3d6d..1de83a6 100644 --- a/.settings/.gitignore +++ b/.settings/.gitignore @@ -1,2 +1,3 @@ /org.eclipse.core.resources.prefs /org.eclipse.jdt.core.prefs +/org.eclipse.m2e.core.prefs diff --git a/src/main/java/world/bentobox/boxed/Boxed.java b/src/main/java/world/bentobox/boxed/Boxed.java index 0c1cec6..2bfec90 100644 --- a/src/main/java/world/bentobox/boxed/Boxed.java +++ b/src/main/java/world/bentobox/boxed/Boxed.java @@ -51,6 +51,7 @@ public class Boxed extends GameModeAddon { private Config configObject = new Config<>(this, Settings.class); private AdvancementsManager advManager; private DeleteGen delChunks; + private ChunkGenerator netherChunkGenerator; @Override public void onLoad() { @@ -69,6 +70,7 @@ public class Boxed extends GameModeAddon { } // Chunk generator chunkGenerator = new BoxedChunkGenerator(this).getGenerator(); + netherChunkGenerator = new BoxedChunkGenerator(this).getNetherGenerator(); // Register commands playerCommand = new DefaultPlayerCommand(this) {}; @@ -163,7 +165,7 @@ public class Boxed extends GameModeAddon { if (getServer().getWorld(worldName + NETHER) == null) { log("Creating Boxed's Nether..."); } - netherWorld = settings.isNetherIslands() ? getWorld(worldName, World.Environment.NETHER, chunkGenerator) : getWorld(worldName, World.Environment.NETHER, null); + netherWorld = settings.isNetherIslands() ? getWorld(worldName, World.Environment.NETHER, netherChunkGenerator) : getWorld(worldName, World.Environment.NETHER, null); } // Make the end if it does not exist if (settings.isEndGenerate()) { @@ -187,9 +189,7 @@ public class Boxed extends GameModeAddon { worldName2 = env.equals(World.Environment.THE_END) ? worldName2 + THE_END : worldName2; World w = WorldCreator.name(worldName2).type(WorldType.FLAT).environment(env).generator(chunkGenerator2).createWorld(); // Backup world - if (env.equals(Environment.NORMAL)) { - WorldCreator.name(worldName2 + "_bak").type(WorldType.FLAT).environment(env).generator(chunkGenerator2).createWorld(); - } + WorldCreator.name(worldName2 + "_bak").type(WorldType.FLAT).environment(env).generator(chunkGenerator2).createWorld(); // Set spawn rates if (w != null) { setSpawnRates(w); @@ -216,7 +216,7 @@ public class Boxed extends GameModeAddon { } if (getSettings().getTicksPerMonsterSpawns() > 0) { w.setTicksPerMonsterSpawns(getSettings().getTicksPerMonsterSpawns()); - } + } } @Override @@ -229,7 +229,7 @@ public class Boxed extends GameModeAddon { if (id != null && id.equals("delete")) { return delChunks; } - return chunkGenerator; + return worldName.endsWith("_nether") ? netherChunkGenerator : chunkGenerator; } @Override diff --git a/src/main/java/world/bentobox/boxed/Settings.java b/src/main/java/world/bentobox/boxed/Settings.java index 6943068..c47dce4 100644 --- a/src/main/java/world/bentobox/boxed/Settings.java +++ b/src/main/java/world/bentobox/boxed/Settings.java @@ -146,16 +146,6 @@ public class Settings implements WorldSettings { @ConfigEntry(path = "world.default-game-mode") private GameMode defaultGameMode = GameMode.SURVIVAL; - @ConfigComment("The default biome for the overworld") - @ConfigEntry(path = "world.default-biome") - private Biome defaultBiome = Biome.PLAINS; - @ConfigComment("The default biome for the nether world (this may affect what mobs can spawn)") - @ConfigEntry(path = "world.default-nether-biome") - private Biome defaultNetherBiome = Enums.getIfPresent(Biome.class, "NETHER").or(Enums.getIfPresent(Biome.class, "NETHER_WASTES").or(Biome.BADLANDS)); - @ConfigComment("The default biome for the end world (this may affect what mobs can spawn)") - @ConfigEntry(path = "world.default-end-biome") - private Biome defaultEndBiome = Biome.THE_END; - @ConfigComment("The maximum number of players a player can ban at any one time in this game mode.") @ConfigComment("The permission boxed.ban.maxlimit.X where X is a number can also be used per player") @ConfigComment("-1 = unlimited") @@ -624,7 +614,7 @@ public class Settings implements WorldSettings { */ @Override public boolean isNetherIslands() { - return false; + return true; } /** @@ -1243,20 +1233,6 @@ public class Settings implements WorldSettings { return false; } - /** - * @return default biome - */ - public Biome getDefaultBiome() { - return defaultBiome; - } - - /** - * @param defaultBiome the defaultBiome to set - */ - public void setDefaultBiome(Biome defaultBiome) { - this.defaultBiome = defaultBiome; - } - /** * @return the banLimit */ @@ -1647,34 +1623,6 @@ public class Settings implements WorldSettings { this.mobLimitSettings = mobLimitSettings; } - /** - * @return the defaultNetherBiome - */ - public Biome getDefaultNetherBiome() { - return defaultNetherBiome; - } - - /** - * @param defaultNetherBiome the defaultNetherBiome to set - */ - public void setDefaultNetherBiome(Biome defaultNetherBiome) { - this.defaultNetherBiome = defaultNetherBiome; - } - - /** - * @return the defaultEndBiome - */ - public Biome getDefaultEndBiome() { - return defaultEndBiome; - } - - /** - * @param defaultEndBiome the defaultEndBiome to set - */ - public void setDefaultEndBiome(Biome defaultEndBiome) { - this.defaultEndBiome = defaultEndBiome; - } - /** * @return the seed */ diff --git a/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java b/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java index 9a719b6..6f6b517 100644 --- a/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java +++ b/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java @@ -15,10 +15,14 @@ public class BoxedChunkGenerator { private final WorldRef wordRef; private final Boxed addon; + private WorldRef wordRefNether; + private WorldRef wordRefEnd; public BoxedChunkGenerator(Boxed addon) { this.addon = addon; wordRef = WorldRef.ofName(addon.getSettings().getWorldName()); + wordRefNether = WorldRef.ofName(addon.getSettings().getWorldName() + "_nether"); + wordRefEnd = WorldRef.ofName(addon.getSettings().getWorldName() + "_end"); } public ChunkGenerator getGenerator() { @@ -26,7 +30,7 @@ public class BoxedChunkGenerator { .getInstance(addon.getPlugin(), 0, 5) .createCustomGenerator(wordRef, generator -> { // Set the noise generator - generator.setBaseNoiseGenerator(new BasicWorldGenerator(addon, addon.getSettings().getSeed())); + generator.setBaseNoiseGenerator(new OverWorldGenerator(addon, addon.getSettings().getSeed())); if (addon.getSettings().isAllowStructures()) { generator.getWorldDecorator().withoutDefaultDecorations(DecorationType.SURFACE_STRUCTURES); } @@ -37,4 +41,20 @@ public class BoxedChunkGenerator { }); } + public ChunkGenerator getNetherGenerator() { + return WorldGeneratorApi + .getInstance(addon.getPlugin(), 0, 5) + .createCustomGenerator(wordRefNether, generator -> { + // Set the noise generator + generator.setBaseNoiseGenerator(new NetherGenerator(addon, addon.getSettings().getSeed())); + if (addon.getSettings().isAllowStructures()) { + generator.getWorldDecorator().withoutDefaultDecorations(DecorationType.SURFACE_STRUCTURES); + } + if (addon.getSettings().isAllowStrongholds()) { + generator.getWorldDecorator().withoutDefaultDecorations(DecorationType.STRONGHOLDS); + } + generator.setBiomeGenerator(new NetherBiomeGenerator(addon)); + }); + } + } diff --git a/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java b/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java new file mode 100644 index 0000000..7337244 --- /dev/null +++ b/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java @@ -0,0 +1,145 @@ +package world.bentobox.boxed.generators; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.bukkit.block.Biome; +import org.bukkit.block.BlockFace; +import org.bukkit.util.Vector; + +import nl.rutgerkok.worldgeneratorapi.BiomeGenerator; +import world.bentobox.boxed.Boxed; + +/** + * @author tastybento + * + */ +public class NetherBiomeGenerator implements BiomeGenerator { + + private static final double ONE = 0.05; + private static final double TWO = 0.25; + private static final double THREE = 0.5; + private static final double FOUR = 0.75; + private static final double FIVE = 1.0; + private static final double SIX = 1.25; + private static final double SEVEN = 1.50; + private static final double EIGHT = 1.75; + private static final double LAST = 2.0; + + + private static final TreeMap NORTH_EAST = new TreeMap<>(); + static { + NORTH_EAST.put(ONE, Biome.BASALT_DELTAS); + NORTH_EAST.put(TWO, Biome.CRIMSON_FOREST); + NORTH_EAST.put(THREE, Biome.SOUL_SAND_VALLEY); + NORTH_EAST.put(FOUR, Biome.WARPED_FOREST); + NORTH_EAST.put(FIVE, Biome.BASALT_DELTAS); + NORTH_EAST.put(SIX, Biome.CRIMSON_FOREST); + NORTH_EAST.put(SEVEN, Biome.SOUL_SAND_VALLEY); + NORTH_EAST.put(EIGHT, Biome.WARPED_FOREST); + NORTH_EAST.put(LAST, Biome.NETHER_WASTES); + } + private static final TreeMap SOUTH_EAST = new TreeMap<>(); + static { + SOUTH_EAST.put(ONE, Biome.NETHER_WASTES); + SOUTH_EAST.put(TWO, Biome.BASALT_DELTAS); + SOUTH_EAST.put(THREE, Biome.SOUL_SAND_VALLEY); + SOUTH_EAST.put(FOUR, Biome.WARPED_FOREST); + SOUTH_EAST.put(FIVE, Biome.NETHER_WASTES); + SOUTH_EAST.put(SIX, Biome.BASALT_DELTAS); + SOUTH_EAST.put(SEVEN, Biome.SOUL_SAND_VALLEY); + SOUTH_EAST.put(EIGHT, Biome.WARPED_FOREST); + SOUTH_EAST.put(LAST, Biome.CRIMSON_FOREST); + } + + private static final TreeMap NORTH_WEST = new TreeMap<>(); + static { + NORTH_WEST.put(ONE, Biome.NETHER_WASTES); + NORTH_WEST.put(TWO, Biome.NETHER_WASTES); + NORTH_WEST.put(THREE, Biome.SOUL_SAND_VALLEY); + NORTH_WEST.put(FOUR, Biome.WARPED_FOREST); + NORTH_WEST.put(FIVE, Biome.BASALT_DELTAS); + NORTH_WEST.put(SIX, Biome.CRIMSON_FOREST); + NORTH_WEST.put(SEVEN, Biome.SOUL_SAND_VALLEY); + NORTH_WEST.put(EIGHT, Biome.WARPED_FOREST); + NORTH_WEST.put(LAST, Biome.NETHER_WASTES); + } + + private static final TreeMap SOUTH_WEST = new TreeMap<>(); + static { + SOUTH_WEST.put(ONE, Biome.NETHER_WASTES); + SOUTH_WEST.put(TWO, Biome.SOUL_SAND_VALLEY); + SOUTH_WEST.put(THREE, Biome.WARPED_FOREST); + SOUTH_WEST.put(FOUR, Biome.SOUL_SAND_VALLEY); + SOUTH_WEST.put(FIVE, Biome.BASALT_DELTAS); + SOUTH_WEST.put(SIX, Biome.CRIMSON_FOREST); + SOUTH_WEST.put(SEVEN, Biome.WARPED_FOREST); + SOUTH_WEST.put(EIGHT, Biome.SOUL_SAND_VALLEY); + SOUTH_WEST.put(LAST, Biome.NETHER_WASTES); + } + private static final Map> QUADRANTS; + static { + Map> q = new EnumMap<>(BlockFace.class); + q.put(BlockFace.NORTH_EAST, NORTH_EAST); + q.put(BlockFace.NORTH_WEST, NORTH_WEST); + q.put(BlockFace.SOUTH_EAST, SOUTH_EAST); + q.put(BlockFace.SOUTH_WEST, SOUTH_WEST); + QUADRANTS = Collections.unmodifiableMap(q); + } + + + private final Boxed addon; + private final int dist; + private final int offsetX; + private final int offsetZ; + + + public NetherBiomeGenerator(Boxed boxed) { + this.addon = boxed; + dist = addon.getSettings().getIslandDistance(); + offsetX = addon.getSettings().getIslandXOffset(); + offsetZ = addon.getSettings().getIslandZOffset(); + } + + @Override + public Biome getZoomedOutBiome(int x, int y, int z) { + /* + * The given x, y and z coordinates are scaled down by a factor of 4. So when Minecraft + * wants to know the biome at x=112, it will ask the biome generator for a biome at x=112/4=28. + */ + /* + * Biomes go around the island centers + * + */ + Vector s = new Vector(x * 4, 0, z * 4); + Vector l = getClosestIsland(s); + double dis = l.distanceSquared(s); + double d = dis / (dist * dist); + Vector direction = s.subtract(l); + if (direction.getBlockX() <= 0 && direction.getBlockZ() <= 0) { + return getBiome(BlockFace.NORTH_WEST, d); + } else if (direction.getBlockX() > 0 && direction.getBlockZ() <= 0) { + return getBiome(BlockFace.NORTH_EAST, d); + } else if (direction.getBlockX() <= 0 && direction.getBlockZ() > 0) { + return getBiome(BlockFace.SOUTH_WEST, d); + } + return getBiome(BlockFace.SOUTH_EAST, d); + } + + private Biome getBiome(BlockFace dir, double d) { + Entry en = ((TreeMap) QUADRANTS.get(dir)).ceilingEntry(d); + return en == null ? Biome.NETHER_WASTES : en.getValue(); + } + + 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); + } + +} diff --git a/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java b/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java new file mode 100644 index 0000000..d4b4ede --- /dev/null +++ b/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java @@ -0,0 +1,79 @@ +package world.bentobox.boxed.generators; + +import java.io.File; + +import org.bukkit.Material; +import org.bukkit.block.Biome; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.util.noise.PerlinNoiseGenerator; + +import nl.rutgerkok.worldgeneratorapi.BaseNoiseGenerator; +import nl.rutgerkok.worldgeneratorapi.BiomeGenerator; +import world.bentobox.boxed.Boxed; + +/** + * Generates the Nether + * @author tastybento + * + */ +public class NetherGenerator implements BaseNoiseGenerator { + + private final PerlinNoiseGenerator mainNoiseGenerator; + private final Boxed addon; + private final YamlConfiguration config; + + + public NetherGenerator(Boxed addon, long seed) { + this.addon = addon; + // Initialize the noise generator based on the world seed + this.mainNoiseGenerator = new PerlinNoiseGenerator(seed); + // Load the config + File biomeFile = new File(addon.getDataFolder(), "biomes.yml"); + if (!biomeFile.exists()) { + addon.saveResource("biomes.yml", true); + } + config = YamlConfiguration.loadConfiguration(biomeFile); + } + + @Override + public TerrainSettings getTerrainSettings() { + TerrainSettings ts = new TerrainSettings(); + ts.stoneBlock = Material.NETHERRACK.createBlockData(); + ts.waterBlock = Material.LAVA.createBlockData(); + return ts; + } + + @Override + public void getNoise(BiomeGenerator biomeGenerator, double[] buffer, int scaledX, int scaledZ) { + // Repeat on an island boundary + int dist = addon.getSettings().getIslandDistance(); + double noiseScaleHorizontal = 10D; + double height = 8D; + Biome biome = biomeGenerator.getZoomedOutBiome(scaledX, scaledZ); + if (biome == null) { + // edge of island + biome = Biome.NETHER_WASTES; + height = 6; + } else { + noiseScaleHorizontal = config.getDouble("nether.biomes." + biome.name() + ".scale", 10D); + height = config.getDouble("nether.biomes." + biome.name() + ".height", 8D); + } + double x = ((((double)scaledX*4) % dist) / 4) / noiseScaleHorizontal; + double z = ((((double)scaledZ*4) % dist) / 4) / noiseScaleHorizontal; + + for (int y = 0; y < buffer.length; y++) { + double noise = this.mainNoiseGenerator.noise(x, y, z); + double heightOffset = height - y; + buffer[y] = noise + heightOffset; + } + // Ceiling + x = ((((double)scaledX*4) % dist) / 4); + z = ((((double)scaledZ*4) % dist) / 4); + for (int y = 15; y > height + 2; y--) { + double noise = this.mainNoiseGenerator.noise(x, y, z); + double heightOffset = y - height; + buffer[y] = noise + heightOffset; + } + } + +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/boxed/generators/BasicWorldGenerator.java b/src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java similarity index 93% rename from src/main/java/world/bentobox/boxed/generators/BasicWorldGenerator.java rename to src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java index ef87206..687fa55 100644 --- a/src/main/java/world/bentobox/boxed/generators/BasicWorldGenerator.java +++ b/src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java @@ -14,14 +14,14 @@ import world.bentobox.boxed.Boxed; * @author tastybento * */ -public class BasicWorldGenerator implements BaseNoiseGenerator { +public class OverWorldGenerator implements BaseNoiseGenerator { private final SimplexNoiseGenerator mainNoiseGenerator; private final Boxed addon; private final YamlConfiguration config; - public BasicWorldGenerator(Boxed addon, long seed) { + public OverWorldGenerator(Boxed addon, long seed) { this.addon = addon; // Initialize the noise generator based on the world seed this.mainNoiseGenerator = new SimplexNoiseGenerator(seed); diff --git a/src/main/resources/biomes.yml b/src/main/resources/biomes.yml index b06edb0..96e5868 100644 --- a/src/main/resources/biomes.yml +++ b/src/main/resources/biomes.yml @@ -1,3 +1,20 @@ +nether: + biomes: + NETHER_WASTES: + height: 8 + scale: 5 + BASALT_DELTAS: + height: 8 + scale: 1 + CRIMSON_FOREST: + height: 9 + scale: 10 + SOUL_SAND_VALLEY: + height: 9 + scale: 16 + WARPED_FOREST: + height: 10 + scale: 10 biomes: BADLANDS_PLATEAU: height: 9 diff --git a/src/main/resources/blueprints/default.json b/src/main/resources/blueprints/default.json index cf4caab..8a087cc 100644 --- a/src/main/resources/blueprints/default.json +++ b/src/main/resources/blueprints/default.json @@ -3,12 +3,12 @@ "icon": "PAPER", "displayName": "Default bundle", "description": [ - "§bDefault bundle of blueprints" + "Boxed Starter Blocks" ], "requirePermission": false, "blueprints": { "NORMAL": "island", - "NETHER": "bedrock", + "NETHER": "nether", "THE_END": "bedrock" }, "slot": 0 diff --git a/src/main/resources/blueprints/island.blu b/src/main/resources/blueprints/island.blu index fa8b9a1..56f1eae 100644 Binary files a/src/main/resources/blueprints/island.blu and b/src/main/resources/blueprints/island.blu differ diff --git a/src/main/resources/blueprints/nether.blu b/src/main/resources/blueprints/nether.blu new file mode 100644 index 0000000..a4a4619 Binary files /dev/null and b/src/main/resources/blueprints/nether.blu differ diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7b3ad37..e71fd33 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -68,12 +68,6 @@ world: # The default game mode for this world. Players will be set to this mode when they create # a new area for example. Options are SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR default-game-mode: SURVIVAL - # The default biome for the overworld - default-biome: PLAINS - # The default biome for the nether world (this may affect what mobs can spawn) - default-nether-biome: NETHER_WASTES - # The default biome for the end world (this may affect what mobs can spawn) - default-end-biome: THE_END # The maximum number of players a player can ban at any one time in this game mode. # The permission boxed.ban.maxlimit.X where X is a number can also be used per player # -1 = unlimited @@ -94,7 +88,7 @@ world: # Option will simulate vanilla portal mechanics that links portals together or creates a new portal, # if there is not a portal in other dimension. # Added since 1.0.3 - create-and-link-portals: false + create-and-link-portals: true end: # End Nether - if this is false, the end world will not be made and access to # the end will not occur. Other plugins may still enable portal usage.