From 29121d6fdbba4bee7a1ee9517af3129c639d4625 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 26 Nov 2022 23:53:32 -0800 Subject: [PATCH] Update to 1.19.2 with new custom world generator (#44) * Baseline world gen. Random. * Work in progress - noise gen needs fixing. * WIP * WIP - redesign to use new world gen API Work still to do - handle island deletion (may not be supported) and test with multiple players. Clean up config. * Bug fixes Added better handling of aquatic elements. Avoid informing players of revoked achievements if the score is zero. Added the mangrove boat recipe to be ignored. * Add default score of unknown recipes * Fixed some biomes * Now with correct math for repeating islands * Java 17 workflow for Github * Put back what was accidentally removed. * Code cleanup. Remove debug. * Double for int calcs * More code cleanup and using new switch syntax --- .github/workflows/build.yml | 4 +- .gitignore | 1 + pom.xml | 17 +- .../bentobox/boxed/AdvancementsManager.java | 21 +- src/main/java/world/bentobox/boxed/Boxed.java | 132 ++++---- .../world/bentobox/boxed/BoxedPladdon.java | 1 + .../java/world/bentobox/boxed/Settings.java | 101 +++++-- ...r.java => AbstractBoxedBiomeProvider.java} | 128 +++++--- .../boxed/generators/BoxedBiomeGenerator.java | 4 +- .../boxed/generators/BoxedChunkGenerator.java | 225 +++++++++++--- .../generators/BoxedSeedChunkGenerator.java | 40 +++ .../bentobox/boxed/generators/DeleteGen.java | 49 --- .../generators/NetherBiomeGenerator.java | 18 -- .../boxed/generators/NetherGenerator.java | 105 ------- .../boxed/generators/OverWorldGenerator.java | 63 ---- .../boxed/listeners/AdvancementListener.java | 12 +- src/main/resources/advancements.yml | 2 + src/main/resources/biomes.yml | 284 ++---------------- src/main/resources/config.yml | 79 +++-- src/main/resources/locales/en-US.yml | 2 +- 20 files changed, 581 insertions(+), 707 deletions(-) rename src/main/java/world/bentobox/boxed/generators/{AbstractBoxedBiomeGenerator.java => AbstractBoxedBiomeProvider.java} (70%) create mode 100644 src/main/java/world/bentobox/boxed/generators/BoxedSeedChunkGenerator.java delete mode 100644 src/main/java/world/bentobox/boxed/generators/DeleteGen.java delete mode 100644 src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java delete mode 100644 src/main/java/world/bentobox/boxed/generators/NetherGenerator.java delete mode 100644 src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9cf60c..c771fd5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,10 +14,10 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Set up JDK 16 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 16 + java-version: 17 - name: Cache SonarCloud packages uses: actions/cache@v1 with: diff --git a/.gitignore b/.gitignore index a96c143..132f5b6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /pom.xml.versionsBackup /bin/ /boxed.iml +/.idea/ diff --git a/pom.xml b/pom.xml index bc555c7..df25295 100644 --- a/pom.xml +++ b/pom.xml @@ -54,18 +54,18 @@ UTF-8 UTF-8 - 16 + 17 2.0.9 - 1.17-R0.1-SNAPSHOT - 1.18.0-SNAPSHOT + 1.19.2-R0.1-SNAPSHOT + 1.22.0-SNAPSHOT ${build.version}-SNAPSHOT -LOCAL - 1.2.2 + 2.0.2 BentoBoxWorld_Boxed bentobox-world @@ -141,7 +141,7 @@ org.mockito mockito-core - 3.11.1 + 4.8.0 test @@ -162,13 +162,6 @@ ${bentobox.version} provided - - nl.rutgerkok - worldgeneratorapi - 1.2.0 - provided - diff --git a/src/main/java/world/bentobox/boxed/AdvancementsManager.java b/src/main/java/world/bentobox/boxed/AdvancementsManager.java index eff74c6..b4da618 100644 --- a/src/main/java/world/bentobox/boxed/AdvancementsManager.java +++ b/src/main/java/world/bentobox/boxed/AdvancementsManager.java @@ -35,6 +35,7 @@ public class AdvancementsManager { private final Map cache; private final YamlConfiguration advConfig; private int unknownAdvChange; + private int unknownRecipeChange; /** * @param addon addon @@ -57,6 +58,7 @@ public class AdvancementsManager { try { advConfig.load(advFile); unknownAdvChange = advConfig.getInt("settings.unknown-advancement-increase", 0); + unknownRecipeChange = advConfig.getInt("settings.unknown-recipe-increase", 0); } catch (IOException | InvalidConfigurationException e) { addon.logError("advancements.yml cannot be found! " + e.getLocalizedMessage()); } @@ -212,10 +214,25 @@ public class AdvancementsManager { } - private int getScore(String string) { + /** + * Get the score for this advancement + * @param string - advancement key as stored in the config file + * @return score of advancement, or default values if the key is not in the file + */ + public int getScore(String string) { String adv = "advancements." + string; // Check score of advancement - return !advConfig.contains(adv) && adv.endsWith("/root") ? advConfig.getInt("settings.default-root-increase") : advConfig.getInt(adv, this.unknownAdvChange); + if (advConfig.contains(adv)) { + return advConfig.getInt(adv, this.unknownAdvChange); + } + // Unknowns + if (adv.endsWith("/root")) { + return advConfig.getInt("settings.default-root-increase"); + } + if (adv.contains("minecraft:recipes")) { + return this.unknownRecipeChange; + } + return this.unknownAdvChange; } } diff --git a/src/main/java/world/bentobox/boxed/Boxed.java b/src/main/java/world/bentobox/boxed/Boxed.java index 4846824..af78414 100644 --- a/src/main/java/world/bentobox/boxed/Boxed.java +++ b/src/main/java/world/bentobox/boxed/Boxed.java @@ -2,13 +2,14 @@ package world.bentobox.boxed; import java.util.Collections; -import org.bukkit.Bukkit; +import org.bukkit.ChunkSnapshot; import org.bukkit.Difficulty; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.World.Environment; import org.bukkit.WorldCreator; -import org.bukkit.WorldType; +import org.bukkit.entity.SpawnCategory; +import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.eclipse.jdt.annotation.Nullable; @@ -21,13 +22,14 @@ import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.flags.Flag.Mode; import world.bentobox.bentobox.api.flags.Flag.Type; import world.bentobox.bentobox.managers.RanksManager; +import world.bentobox.boxed.generators.BoxedBiomeGenerator; import world.bentobox.boxed.generators.BoxedChunkGenerator; -import world.bentobox.boxed.generators.DeleteGen; +import world.bentobox.boxed.generators.BoxedSeedChunkGenerator; import world.bentobox.boxed.listeners.AdvancementListener; import world.bentobox.boxed.listeners.EnderPearlListener; /** - * Main Boxed class - provides an survival game inside a box + * Main Boxed class - provides a survival game inside a box * @author tastybento */ public class Boxed extends GameModeAddon { @@ -48,11 +50,12 @@ public class Boxed extends GameModeAddon { // Settings private Settings settings; - private ChunkGenerator chunkGenerator; + private BoxedChunkGenerator chunkGenerator; private final Config configObject = new Config<>(this, Settings.class); private AdvancementsManager advManager; - private DeleteGen delChunks; private ChunkGenerator netherChunkGenerator; + private World seedWorld; + private BiomeProvider boxedBiomeProvider; @Override public void onLoad() { @@ -60,18 +63,7 @@ public class Boxed extends GameModeAddon { saveDefaultConfig(); // Load settings from config.yml. This will check if there are any issues with it too. loadSettings(); - // Save biomes - this.saveResource("biomes.yml", false); - // Check for WGAPI - if (isNoWGAPI()) { - logError("WorldGeneratorAPI plugin is required."); - logError("Download the correct one for your server from https://github.com/rutgerkok/WorldGeneratorApi/releases"); - this.setState(State.DISABLED); - return; - } - // Chunk generator - chunkGenerator = new BoxedChunkGenerator(this).getGenerator(); - netherChunkGenerator = new BoxedChunkGenerator(this).getNetherGenerator(); + // Register commands playerCommand = new DefaultPlayerCommand(this) {}; @@ -79,10 +71,6 @@ public class Boxed extends GameModeAddon { } - private boolean isNoWGAPI() { - return Bukkit.getPluginManager().getPlugin("WorldGeneratorApi") == null; - } - private boolean loadSettings() { // Load settings again to get worlds settings = configObject.loadConfigObject(); @@ -92,16 +80,13 @@ public class Boxed extends GameModeAddon { setState(State.DISABLED); return false; } + // Initialize the Generator because createWorlds will be run after onLoad + this.chunkGenerator = new BoxedChunkGenerator(this); return true; } @Override - public void onEnable(){ - // Disable in onEnable - if (isNoWGAPI()) { - this.setState(State.DISABLED); - return; - } + public void onEnable() { // Check for recommended addons if (this.getPlugin().getAddonsManager().getAddonByName("Border").isEmpty()) { this.logWarning("Boxed normally requires the Border addon."); @@ -111,8 +96,6 @@ public class Boxed extends GameModeAddon { } // Advancements manager advManager = new AdvancementsManager(this); - // Get delete chunk generator - delChunks = new DeleteGen(this); // Make flags only applicable to this game mode MOVE_BOX.setGameModes(Collections.singleton(this)); ALLOW_MOVE_BOX.setGameModes(Collections.singleton(this)); @@ -127,6 +110,7 @@ public class Boxed extends GameModeAddon { // Register listeners this.registerListener(new AdvancementListener(this)); this.registerListener(new EnderPearlListener(this)); + //this.registerListener(new DebugListener(this)); // Register placeholders PlaceholdersManager phManager = new PlaceholdersManager(this); @@ -157,47 +141,89 @@ public class Boxed extends GameModeAddon { @Override public void createWorlds() { - if (isNoWGAPI()) { - return; - } + // Create seed world + log("Creating Boxed Seed world ..."); + seedWorld = WorldCreator + .name("seed") + .generator(new BoxedSeedChunkGenerator()) + .environment(Environment.NORMAL) + .generateStructures(false) + .seed(getSettings().getSeed()) + .createWorld(); + seedWorld.setDifficulty(Difficulty.PEACEFUL); // No damage wanted in this world. + saveChunks(seedWorld); + String worldName = settings.getWorldName().toLowerCase(); + if (getServer().getWorld(worldName) == null) { log("Creating Boxed world ..."); } // Create the world if it does not exist - islandWorld = getWorld(worldName, World.Environment.NORMAL, chunkGenerator); + islandWorld = getWorld(worldName, World.Environment.NORMAL); + /* // Make the nether if it does not exist if (settings.isNetherGenerate()) { if (getServer().getWorld(worldName + NETHER) == null) { log("Creating Boxed's Nether..."); } - netherWorld = settings.isNetherIslands() ? getWorld(worldName, World.Environment.NETHER, netherChunkGenerator) : getWorld(worldName, World.Environment.NETHER, null); + netherWorld = settings.isNetherIslands() ? getWorld(worldName, World.Environment.NETHER) : getWorld(worldName, World.Environment.NETHER); } // Make the end if it does not exist if (settings.isEndGenerate()) { if (getServer().getWorld(worldName + THE_END) == null) { log("Creating Boxed's End World..."); } - endWorld = settings.isEndIslands() ? getWorld(worldName, World.Environment.THE_END, chunkGenerator) : getWorld(worldName, World.Environment.THE_END, null); + endWorld = settings.isEndIslands() ? getWorld(worldName, World.Environment.THE_END) : getWorld(worldName, World.Environment.THE_END); } + */ + } + + private void saveChunks(World seedWorld) { + // Convert to chunks + int size = (int)(this.getSettings().getIslandDistance() / 16D); + double percent = size * 4D * size; + int count = 0; + int last = 0; + for (int x = -size; x < size; x ++) { + for (int z = -size; z < size; z++) { + ChunkSnapshot chunk = seedWorld.getChunkAt(x, z).getChunkSnapshot(true, true, false); + this.chunkGenerator.setChunk(chunk); + count++; + int p = (int) (count / percent * 100); + if (p % 10 == 0 && p != last) { + last = p; + this.log("Storing seed chunks. " + p + "% done"); + } + + } + } + } + + /** + * @return the chunkGenerator + */ + public BoxedChunkGenerator getChunkGenerator() { + return chunkGenerator; } /** * Gets a world or generates a new world if it does not exist * @param worldName2 - the overworld name * @param env - the environment - * @param chunkGenerator2 - the chunk generator. If null then the generator will not be specified * @return world loaded or generated */ - private World getWorld(String worldName2, Environment env, ChunkGenerator chunkGenerator2) { + private World getWorld(String worldName2, Environment env) { // Set world name worldName2 = env.equals(World.Environment.NETHER) ? worldName2 + NETHER : worldName2; worldName2 = env.equals(World.Environment.THE_END) ? worldName2 + THE_END : worldName2; - World w = WorldCreator.name(worldName2).type(WorldType.FLAT).environment(env).generator(chunkGenerator2).seed(settings.getSeed()).createWorld(); - // Backup world - World b = WorldCreator.name(worldName2 + "_bak").type(WorldType.FLAT).environment(env).generator(chunkGenerator2).seed(settings.getSeed()).createWorld(); - b.setDifficulty(Difficulty.PEACEFUL); // No damage wanted in this world. + boxedBiomeProvider = new BoxedBiomeGenerator(this); + World w = WorldCreator + .name(worldName2) + .generator(chunkGenerator) + .environment(env) + .seed(seedWorld.getSeed()) // For development + .createWorld(); // Set spawn rates if (w != null) { setSpawnRates(w); @@ -206,24 +232,31 @@ public class Boxed extends GameModeAddon { } + /** + * @return the boxedBiomeProvider + */ + public BiomeProvider getBoxedBiomeProvider() { + return boxedBiomeProvider; + } + private void setSpawnRates(World w) { if (getSettings().getSpawnLimitMonsters() > 0) { - w.setMonsterSpawnLimit(getSettings().getSpawnLimitMonsters()); + w.setSpawnLimit(SpawnCategory.MONSTER, getSettings().getSpawnLimitMonsters()); } if (getSettings().getSpawnLimitAmbient() > 0) { - w.setAmbientSpawnLimit(getSettings().getSpawnLimitAmbient()); + w.setSpawnLimit(SpawnCategory.AMBIENT, getSettings().getSpawnLimitAmbient()); } if (getSettings().getSpawnLimitAnimals() > 0) { - w.setAnimalSpawnLimit(getSettings().getSpawnLimitAnimals()); + w.setSpawnLimit(SpawnCategory.ANIMAL, getSettings().getSpawnLimitAnimals()); } if (getSettings().getSpawnLimitWaterAnimals() > 0) { - w.setWaterAnimalSpawnLimit(getSettings().getSpawnLimitWaterAnimals()); + w.setSpawnLimit(SpawnCategory.WATER_ANIMAL, getSettings().getSpawnLimitWaterAnimals()); } if (getSettings().getTicksPerAnimalSpawns() > 0) { - w.setTicksPerAnimalSpawns(getSettings().getTicksPerAnimalSpawns()); + w.setTicksPerSpawns(SpawnCategory.ANIMAL, getSettings().getTicksPerAnimalSpawns()); } if (getSettings().getTicksPerMonsterSpawns() > 0) { - w.setTicksPerMonsterSpawns(getSettings().getTicksPerMonsterSpawns()); + w.setTicksPerSpawns(SpawnCategory.MONSTER, getSettings().getTicksPerMonsterSpawns()); } } @@ -234,9 +267,6 @@ public class Boxed extends GameModeAddon { @Override public @Nullable ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - if (id != null && id.equals("delete")) { - return delChunks; - } return worldName.endsWith(NETHER) ? netherChunkGenerator : chunkGenerator; } diff --git a/src/main/java/world/bentobox/boxed/BoxedPladdon.java b/src/main/java/world/bentobox/boxed/BoxedPladdon.java index 8a5efe6..95455df 100644 --- a/src/main/java/world/bentobox/boxed/BoxedPladdon.java +++ b/src/main/java/world/bentobox/boxed/BoxedPladdon.java @@ -9,4 +9,5 @@ public class BoxedPladdon extends Pladdon { public Addon getAddon() { return new Boxed(); } + } diff --git a/src/main/java/world/bentobox/boxed/Settings.java b/src/main/java/world/bentobox/boxed/Settings.java index 3848f12..6c1d81b 100644 --- a/src/main/java/world/bentobox/boxed/Settings.java +++ b/src/main/java/world/bentobox/boxed/Settings.java @@ -74,23 +74,35 @@ public class Settings implements WorldSettings { @ConfigComment("World seed.") @ConfigComment("If you change this, stop the server and delete the worlds made.") - @ConfigEntry(path = "world.seed", needsReset = true) - private long seed = 978573758696L; + @ConfigEntry(path = "world.generator.seed", needsReset = true) + private long seed = 602103456450L; @ConfigComment("World difficulty setting - PEACEFUL, EASY, NORMAL, HARD") @ConfigComment("Other plugins may override this setting") @ConfigEntry(path = "world.difficulty") private Difficulty difficulty = Difficulty.NORMAL; + @ConfigComment("Generate surface") + @ConfigEntry(path = "world.generator.generate-surface", needsRestart = true) + private boolean generateSurface = true; + + @ConfigComment("Generate caves") + @ConfigEntry(path = "world.generator.generate-caves", needsRestart = true) + private boolean generateCaves = true; + + @ConfigComment("Generate Decorations") + @ConfigEntry(path = "world.generator.generate-decorations", needsRestart = true) + private boolean generateDecorations = true; + + @ConfigComment("Generate mobs") + @ConfigEntry(path = "world.generator.generate-mobs", needsRestart = true) + private boolean generateMobs = true; + @ConfigComment("Allow surface structures - villages, shipwrecks, broken portals, etc.") @ConfigComment("These will be randomly placed, so may not be available for every player.") - @ConfigEntry(path = "world.allow-structures", needsRestart = true) + @ConfigEntry(path = "world.generator.allow-structures", needsRestart = true) private boolean allowStructures = true; - @ConfigComment("Allow strongholds.") - @ConfigComment("These will be randomly placed, so may not be available for every player.") - @ConfigEntry(path = "world.allow-strongholds", experimental = true, needsRestart = true) - private boolean allowStrongholds = true; @ConfigComment("Spawn limits. These override the limits set in bukkit.yml") @ConfigComment("If set to a negative number, the server defaults will be used") @@ -111,11 +123,10 @@ public class Settings implements WorldSettings { @ConfigEntry(path = "world.spawn-limits.ticks-per-monster-spawns") private int ticksPerMonsterSpawns = -1; - @ConfigComment("Radius of player areas. (So distance between player starting spots is twice this)") + @ConfigComment("Radius of player area. (So distance between player starting spots is twice this)") @ConfigComment("It is the same for every dimension : Overworld, Nether and End.") - @ConfigComment("This value cannot be changed mid-game and the plugin will not start if it is different.") @ConfigEntry(path = "world.area-radius", needsReset = true) - private int islandDistance = 400; + private int islandDistance = 320; @ConfigComment("Starting size of boxed spaces. This is a radius so 1 = a 2x2 area.") @ConfigComment("Admins can adjust via the /boxadmin range set command") @@ -1659,20 +1670,6 @@ public class Settings implements WorldSettings { this.allowStructures = allowStructures; } - /** - * @return the allowStrongholds - */ - public boolean isAllowStrongholds() { - return allowStrongholds; - } - - /** - * @param allowStrongholds the allowStrongholds to set - */ - public void setAllowStrongholds(boolean allowStrongholds) { - this.allowStrongholds = allowStrongholds; - } - /** * @return the onJoinResetAdvancements */ @@ -1759,6 +1756,62 @@ public class Settings implements WorldSettings { this.broadcastAdvancements = broadcastAdvancements; } + /** + * @return the generateSurface + */ + public boolean isGenerateSurface() { + return generateSurface; + } + + /** + * @param generateSurface the generateSurface to set + */ + public void setGenerateSurface(boolean generateSurface) { + this.generateSurface = generateSurface; + } + + /** + * @return the generateCaves + */ + public boolean isGenerateCaves() { + return generateCaves; + } + + /** + * @param generateCaves the generateCaves to set + */ + public void setGenerateCaves(boolean generateCaves) { + this.generateCaves = generateCaves; + } + + /** + * @return the generateDecorations + */ + public boolean isGenerateDecorations() { + return generateDecorations; + } + + /** + * @param generateDecorations the generateDecorations to set + */ + public void setGenerateDecorations(boolean generateDecorations) { + this.generateDecorations = generateDecorations; + } + + /** + * @return the generateMobs + */ + public boolean isGenerateMobs() { + return generateMobs; + } + + /** + * @param generateMobs the generateMobs to set + */ + public void setGenerateMobs(boolean generateMobs) { + this.generateMobs = generateMobs; + } + /** * @return the denyVisitorAdvancements */ diff --git a/src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeGenerator.java b/src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeProvider.java similarity index 70% rename from src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeGenerator.java rename to src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeProvider.java index b635f0b..0a166ec 100644 --- a/src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeGenerator.java +++ b/src/main/java/world/bentobox/boxed/generators/AbstractBoxedBiomeProvider.java @@ -1,33 +1,37 @@ package world.bentobox.boxed.generators; import java.io.File; +import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; -import org.apache.commons.lang.math.NumberUtils; +import org.bukkit.ChunkSnapshot; import org.bukkit.World.Environment; import org.bukkit.block.Biome; import org.bukkit.block.BlockFace; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.WorldInfo; import org.bukkit.util.Vector; import com.google.common.base.Enums; -import nl.rutgerkok.worldgeneratorapi.BiomeGenerator; import world.bentobox.boxed.Boxed; /** * @author tastybento * */ -abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { +public abstract class AbstractBoxedBiomeProvider extends BiomeProvider { private static final Map ENV_MAP; + static { Map e = new EnumMap<>(Environment.class); e.put(Environment.NORMAL, "distribution.overworld"); @@ -36,16 +40,17 @@ abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { ENV_MAP = Collections.unmodifiableMap(e); } - protected final Map> quadrants; - private final Boxed addon; - protected final int dist; - private final int offsetX; - private final int offsetZ; private final Biome defaultBiome; + protected final int dist; - protected AbstractBoxedBiomeGenerator(Boxed boxed, Environment env, Biome defaultBiome) { + private final int offsetX; + private final int offsetZ; + protected final Map> quadrants; + + + protected AbstractBoxedBiomeProvider(Boxed boxed, Environment env, Biome defaultBiome) { this.addon = boxed; this.defaultBiome = defaultBiome; dist = addon.getSettings().getIslandDistance(); @@ -53,6 +58,7 @@ abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { offsetZ = addon.getSettings().getIslandZOffset(); // Load the config File biomeFile = new File(addon.getDataFolder(), "biomes.yml"); + // Check if it exists and if not, save it from the jar if (!biomeFile.exists()) { addon.saveResource("biomes.yml", true); } @@ -69,6 +75,71 @@ abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { quadrants.put(BlockFace.SOUTH_WEST, southWest); } + private Biome getBiome(BlockFace dir, double d) { + Entry en = ((TreeMap) quadrants.get(dir)).ceilingEntry(d); + return en == null ? defaultBiome : en.getValue(); + } + + @Override + public Biome getBiome(WorldInfo worldInfo, int x, int y, int z) { + int chunkX = (int)((double)x/16); + int chunkZ = (int)((double)z/16); + int size = (int)(dist / 16D); // Convert to chunk + chunkX = BoxedChunkGenerator.repeatCalc(chunkX, size); + chunkZ = BoxedChunkGenerator.repeatCalc(chunkZ, size); + ChunkSnapshot c = addon.getChunkGenerator().getChunk(chunkX, chunkZ); + + if (c != null) { + 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 + + Biome b = c.getBiome(xx, yy, zz); + // Some biomes should stay from the seed world. These are mostly underground biomes. + if (!b.equals(Biome.CUSTOM) && (b.equals(Biome.DRIPSTONE_CAVES) || b.equals(Biome.LUSH_CAVES) + || b.equals(Biome.RIVER) || b.equals(Biome.DEEP_DARK))) { + return b; + } else { + // Return the mapped biome + return getMappedBiome(x,z); + } + } else { + return Biome.WARM_OCEAN; + } + } + + private Biome getMappedBiome(int x, int z) { + /* + * Biomes go around the island centers + * + */ + Vector s = new Vector(x, 0, z); + 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); + } + + @Override + public List getBiomes(WorldInfo worldInfo) { + // Return all of them for now! + return Arrays.stream(Biome.values()).filter(b -> !b.equals(Biome.CUSTOM)).toList(); + } + + 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 loadQuad(YamlConfiguration config, String string) { SortedMap result = new TreeMap<>(); @@ -77,7 +148,7 @@ abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { } for (String ring : config.getStringList(string)) { String[] split = ring.split(":"); - if (split.length == 2 && NumberUtils.isNumber(split[0])) { + if (split.length == 2) { try { double d = Double.parseDouble(split[0]); Biome biome = Enums.getIfPresent(Biome.class, split[1].toUpperCase(Locale.ENGLISH)).orNull(); @@ -96,41 +167,4 @@ abstract class AbstractBoxedBiomeGenerator implements BiomeGenerator { return result; } - @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 ? defaultBiome : en.getValue(); - } - - 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); - } - } diff --git a/src/main/java/world/bentobox/boxed/generators/BoxedBiomeGenerator.java b/src/main/java/world/bentobox/boxed/generators/BoxedBiomeGenerator.java index fe6c045..c69ca57 100644 --- a/src/main/java/world/bentobox/boxed/generators/BoxedBiomeGenerator.java +++ b/src/main/java/world/bentobox/boxed/generators/BoxedBiomeGenerator.java @@ -9,10 +9,10 @@ import world.bentobox.boxed.Boxed; * @author tastybento * */ -public class BoxedBiomeGenerator extends AbstractBoxedBiomeGenerator { +public class BoxedBiomeGenerator extends AbstractBoxedBiomeProvider { public BoxedBiomeGenerator(Boxed boxed) { super(boxed, Environment.NORMAL, Biome.OCEAN); } -} +} \ No newline at end of file diff --git a/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java b/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java index abe6509..d41c3a1 100644 --- a/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java +++ b/src/main/java/world/bentobox/boxed/generators/BoxedChunkGenerator.java @@ -1,58 +1,211 @@ package world.bentobox.boxed.generators; -import org.bukkit.generator.ChunkGenerator; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; -import nl.rutgerkok.worldgeneratorapi.WorldGeneratorApi; -import nl.rutgerkok.worldgeneratorapi.WorldRef; -import nl.rutgerkok.worldgeneratorapi.decoration.DecorationType; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.generator.WorldInfo; + +import world.bentobox.bentobox.util.Pair; import world.bentobox.boxed.Boxed; /** * @author tastybento * */ -public class BoxedChunkGenerator { +public class BoxedChunkGenerator extends ChunkGenerator { - private final WorldRef wordRef; private final Boxed addon; - private final WorldRef wordRefNether; + private final int size; + private Map, ChunkSnapshot> chunks = new HashMap<>(); + + //private final WorldRef wordRefNether; public BoxedChunkGenerator(Boxed addon) { this.addon = addon; - wordRef = WorldRef.ofName(addon.getSettings().getWorldName()); - wordRefNether = WorldRef.ofName(addon.getSettings().getWorldName() + "_nether"); + this.size = (int)(addon.getSettings().getIslandDistance() / 16D); // Size is chunks } - public ChunkGenerator getGenerator() { - return WorldGeneratorApi - .getInstance(addon.getPlugin(), 0, 5) - .createCustomGenerator(wordRef, generator -> { - // Set the noise generator - generator.setBaseNoiseGenerator(new OverWorldGenerator(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 BoxedBiomeGenerator(addon)); - }); + @Override + public BiomeProvider getDefaultBiomeProvider(WorldInfo worldInfo) { + return addon.getBoxedBiomeProvider(); } - 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); + /** + * @param chunk the chunk to set + */ + public void setChunk(ChunkSnapshot chunk) { + // Make the coords always positive + chunks.putIfAbsent(new Pair<>(chunk.getX(), chunk.getZ()), chunk); + } + + /** + * @param x chunk x + * @param z chunk z + * @return chunk snapshot or null if there is none + */ + public ChunkSnapshot getChunk(int x, int z) { + return chunks.get(new Pair<>(x, z)); + } + + /** + * @param chunks the chunks to set + */ + public void setChunks(Map, ChunkSnapshot> chunks) { + this.chunks = chunks; + } + + @Override + public boolean canSpawn(World world, int x, int z) + { + return true; + } + + @Override + public void generateNoise(WorldInfo worldInfo, Random r, int chunkX, int chunkZ, ChunkData cd) { + + int height = worldInfo.getMaxHeight(); + int minY = worldInfo.getMinHeight(); + int xx = repeatCalc(chunkX, size); + int zz = repeatCalc(chunkZ, size); + Pair coords = new Pair<>(xx, zz); + if (!chunks.containsKey(coords)) { + // This should never be needed because islands should abut each other + cd.setRegion(0, minY, 0, 16, 0, 16, Material.WATER); + return; + } + // Copy the chunk + ChunkSnapshot chunk = chunks.get(coords); + for (int x = 0; x < 16; x ++) { + for (int z = 0; z < 16; z++) { + for (int y = minY; y < height; y++) { + Material m = chunk.getBlockType(x, y, z); + // Handle blocks that occur naturally in water + if (isInWater(m)) { + cd.setBlock(x, y, z, Material.WATER); + } else { + // Handle liquids and default blocks + switch (m) { + case WATER, LAVA, NETHERRACK, STONE, END_STONE -> cd.setBlock(x, y, z, m); + default -> + // Most other blocks + cd.setBlock(x, y, z, isGround(m) ? Material.STONE : Material.AIR); + } } - if (!addon.getSettings().isAllowStrongholds()) { - generator.getWorldDecorator().withoutDefaultDecorations(DecorationType.STRONGHOLDS); - } - generator.setBiomeGenerator(new NetherBiomeGenerator(addon)); - }); + } + } + } + } + + /** + * Calculates the repeating value for a given size + * @param chunkCoord chunk coord + * @param s size + * @return mapped chunk coord + */ + public static int repeatCalc(int chunkCoord, int s) { + int xx; + if (chunkCoord > 0) { + xx = Math.floorMod(chunkCoord + s, s*2) - s; + } else { + xx = Math.floorMod(chunkCoord - s, -s*2) + s; + } + return xx; + } + + /** + * @return the chunks + */ + public Map, ChunkSnapshot> getChunks() { + return chunks; + } + + private static boolean isInWater(Material m) { + return switch (m) { + // Underwater plants + case KELP, KELP_PLANT, SEAGRASS, BUBBLE_COLUMN, BUBBLE_CORAL, BUBBLE_CORAL_BLOCK, BUBBLE_CORAL_FAN, + BUBBLE_CORAL_WALL_FAN, DEAD_BRAIN_CORAL, DEAD_BRAIN_CORAL_BLOCK, DEAD_BRAIN_CORAL_FAN, + DEAD_BRAIN_CORAL_WALL_FAN, DEAD_BUBBLE_CORAL, DEAD_BUBBLE_CORAL_BLOCK, DEAD_BUBBLE_CORAL_FAN, + DEAD_BUBBLE_CORAL_WALL_FAN, DEAD_BUSH, DEAD_FIRE_CORAL, DEAD_FIRE_CORAL_BLOCK, DEAD_FIRE_CORAL_FAN, + DEAD_FIRE_CORAL_WALL_FAN, DEAD_HORN_CORAL, DEAD_HORN_CORAL_BLOCK, DEAD_HORN_CORAL_FAN, + DEAD_HORN_CORAL_WALL_FAN, DEAD_TUBE_CORAL, DEAD_TUBE_CORAL_BLOCK, DEAD_TUBE_CORAL_FAN, + DEAD_TUBE_CORAL_WALL_FAN, FIRE_CORAL, FIRE_CORAL_BLOCK, FIRE_CORAL_FAN, FIRE_CORAL_WALL_FAN, + HORN_CORAL, HORN_CORAL_BLOCK, HORN_CORAL_FAN, HORN_CORAL_WALL_FAN, TUBE_CORAL, TUBE_CORAL_BLOCK, + TUBE_CORAL_FAN, TUBE_CORAL_WALL_FAN, TALL_SEAGRASS -> true; + default -> false; + }; + } + + + private static boolean isGround(Material m) { + if (m.isAir() || m.isBurnable() || !m.isSolid()) return false; + return switch (m) { + case ANDESITE, BEDROCK, CALCITE, CLAY, COAL_ORE, COARSE_DIRT, COBBLESTONE, COPPER_ORE, DEEPSLATE, + DEEPSLATE_COAL_ORE, DEEPSLATE_COPPER_ORE, DEEPSLATE_DIAMOND_ORE, DEEPSLATE_EMERALD_ORE, + DEEPSLATE_GOLD_ORE, DEEPSLATE_IRON_ORE, DEEPSLATE_LAPIS_ORE, DEEPSLATE_REDSTONE_ORE, DIAMOND_ORE, + DIORITE, DIRT, DIRT_PATH, DRIPSTONE_BLOCK, EMERALD_ORE, END_STONE, FARMLAND, GLOWSTONE, GOLD_ORE, + GRANITE, GRASS_BLOCK, IRON_ORE, MAGMA_BLOCK, MYCELIUM, NETHERITE_BLOCK, NETHERRACK, RED_SAND, + RED_SANDSTONE, ROOTED_DIRT, SAND, SANDSTONE, SOUL_SAND, SOUL_SOIL, STONE, TERRACOTTA, AMETHYST_BLOCK, + AMETHYST_CLUSTER, AMETHYST_SHARD, BASALT, BLACKSTONE, BLACK_CONCRETE, BLACK_GLAZED_TERRACOTTA, + BLACK_TERRACOTTA, BLUE_CONCRETE, BLUE_GLAZED_TERRACOTTA, BLUE_TERRACOTTA, BONE_BLOCK, BROWN_CONCRETE, + BROWN_GLAZED_TERRACOTTA, BROWN_TERRACOTTA, BUDDING_AMETHYST, CHISELED_DEEPSLATE, + CHISELED_NETHER_BRICKS, CHISELED_POLISHED_BLACKSTONE, CHISELED_QUARTZ_BLOCK, CHISELED_RED_SANDSTONE, + CHISELED_SANDSTONE, CHISELED_STONE_BRICKS, COAL_BLOCK, COBBLED_DEEPSLATE, CRYING_OBSIDIAN, + CUT_RED_SANDSTONE, CUT_RED_SANDSTONE_SLAB, CUT_SANDSTONE, CUT_SANDSTONE_SLAB, CYAN_CONCRETE, + CYAN_GLAZED_TERRACOTTA, CYAN_TERRACOTTA, DEEPSLATE_BRICKS, DIAMOND_BLOCK, ECHO_SHARD, EMERALD_BLOCK, + GOLD_BLOCK, GRAVEL, GRAY_CONCRETE, GRAY_GLAZED_TERRACOTTA, GRAY_TERRACOTTA, GREEN_CONCRETE, + GREEN_GLAZED_TERRACOTTA, GREEN_TERRACOTTA, INFESTED_CHISELED_STONE_BRICKS, INFESTED_COBBLESTONE, + INFESTED_CRACKED_STONE_BRICKS, INFESTED_DEEPSLATE, INFESTED_MOSSY_STONE_BRICKS, INFESTED_STONE, + INFESTED_STONE_BRICKS, LAPIS_ORE, LARGE_AMETHYST_BUD, LIGHT_BLUE_CONCRETE, + LIGHT_BLUE_GLAZED_TERRACOTTA, LIGHT_BLUE_TERRACOTTA, LIGHT_GRAY_CONCRETE, + LIGHT_GRAY_GLAZED_TERRACOTTA, LIGHT_GRAY_TERRACOTTA, LIME_CONCRETE, LIME_GLAZED_TERRACOTTA, + LIME_TERRACOTTA, MAGENTA_CONCRETE, MAGENTA_GLAZED_TERRACOTTA, MAGENTA_TERRACOTTA, MOSSY_COBBLESTONE, + MUD, NETHERITE_SCRAP, NETHER_GOLD_ORE, NETHER_QUARTZ_ORE, OBSIDIAN, ORANGE_CONCRETE, + ORANGE_GLAZED_TERRACOTTA, ORANGE_TERRACOTTA, PACKED_MUD, PINK_CONCRETE, PINK_GLAZED_TERRACOTTA, + PINK_TERRACOTTA, PODZOL, POLISHED_ANDESITE, POLISHED_BASALT, POLISHED_BLACKSTONE, + POLISHED_DEEPSLATE, POLISHED_DIORITE, POLISHED_GRANITE, PURPLE_CONCRETE, PURPLE_GLAZED_TERRACOTTA, + PURPLE_TERRACOTTA, PURPUR_BLOCK, QUARTZ_BLOCK, RAW_COPPER_BLOCK, RAW_GOLD_BLOCK, RAW_IRON_BLOCK, + REDSTONE_BLOCK, REDSTONE_ORE, RED_CONCRETE, RED_GLAZED_TERRACOTTA, RED_TERRACOTTA, SMOOTH_BASALT, + SMOOTH_QUARTZ, SMOOTH_RED_SANDSTONE, SMOOTH_SANDSTONE, SMOOTH_STONE, TUFF, WARPED_HYPHAE, + WARPED_NYLIUM, WHITE_CONCRETE, WHITE_GLAZED_TERRACOTTA, WHITE_TERRACOTTA, YELLOW_CONCRETE, + YELLOW_GLAZED_TERRACOTTA, YELLOW_TERRACOTTA -> true; + default -> false; + }; + } + + @Override + public boolean shouldGenerateNoise() { + return false; + } + + @Override + public boolean shouldGenerateSurface() { + return this.addon.getSettings().isGenerateSurface(); + } + + @Override + public boolean shouldGenerateCaves() { + return this.addon.getSettings().isGenerateCaves(); + } + + @Override + public boolean shouldGenerateDecorations() { + return this.addon.getSettings().isGenerateDecorations(); + } + + @Override + public boolean shouldGenerateMobs() { + return this.addon.getSettings().isGenerateMobs(); + } + + @Override + public boolean shouldGenerateStructures() { + return this.addon.getSettings().isAllowStructures(); } } diff --git a/src/main/java/world/bentobox/boxed/generators/BoxedSeedChunkGenerator.java b/src/main/java/world/bentobox/boxed/generators/BoxedSeedChunkGenerator.java new file mode 100644 index 0000000..8f44450 --- /dev/null +++ b/src/main/java/world/bentobox/boxed/generators/BoxedSeedChunkGenerator.java @@ -0,0 +1,40 @@ +package world.bentobox.boxed.generators; + +import org.bukkit.generator.ChunkGenerator; + +/** + * @author tastybento + * + */ +public class BoxedSeedChunkGenerator extends ChunkGenerator { + + @Override + public boolean shouldGenerateNoise() { + return true; + } + + @Override + public boolean shouldGenerateSurface() { + return true; + } + + @Override + public boolean shouldGenerateCaves() { + return true; + } + + @Override + public boolean shouldGenerateDecorations() { + return true; + } + + @Override + public boolean shouldGenerateMobs() { + return false; + } + + @Override + public boolean shouldGenerateStructures() { + return false; + } +} diff --git a/src/main/java/world/bentobox/boxed/generators/DeleteGen.java b/src/main/java/world/bentobox/boxed/generators/DeleteGen.java deleted file mode 100644 index bc60d68..0000000 --- a/src/main/java/world/bentobox/boxed/generators/DeleteGen.java +++ /dev/null @@ -1,49 +0,0 @@ -package world.bentobox.boxed.generators; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.generator.ChunkGenerator; - -import world.bentobox.boxed.Boxed; - -/** - * @author tastybento - * - */ -public class DeleteGen extends ChunkGenerator { - - private final Map backMap; - /** - * @param addon addon - */ - public DeleteGen(Boxed addon) { - backMap = new HashMap<>(); - backMap.put(addon.getOverWorld(), Bukkit.getWorld(addon.getOverWorld().getName() + "_bak")); - if (addon.getNetherWorld() != null) { - backMap.put(addon.getNetherWorld(), Bukkit.getWorld(addon.getNetherWorld().getName() + "_bak")); - } - } - - @Override - public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { - ChunkData result = createChunkData(world); - if (backMap.containsKey(world)) { - // Load the chunk from the back world - Chunk chunk = backMap.get(world).getChunkAt(chunkX, chunkZ); - for (int x = 0; x < 16; x++) { - for (int y = 0; y < world.getMaxHeight(); y++) { - for (int z = 0; z < 16; z++) { - result.setBlock(x, y, z, chunk.getBlock(x, y, z).getBlockData()); - } - } - } - } - return result; - } - -} diff --git a/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java b/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java deleted file mode 100644 index 53f038a..0000000 --- a/src/main/java/world/bentobox/boxed/generators/NetherBiomeGenerator.java +++ /dev/null @@ -1,18 +0,0 @@ -package world.bentobox.boxed.generators; - -import org.bukkit.World.Environment; -import org.bukkit.block.Biome; - -import world.bentobox.boxed.Boxed; - -/** - * @author tastybento - * - */ -public class NetherBiomeGenerator extends AbstractBoxedBiomeGenerator { - - public NetherBiomeGenerator(Boxed boxed) { - super(boxed, Environment.NETHER, Biome.NETHER_WASTES); - } - -} diff --git a/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java b/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java deleted file mode 100644 index a0c8e8a..0000000 --- a/src/main/java/world/bentobox/boxed/generators/NetherGenerator.java +++ /dev/null @@ -1,105 +0,0 @@ -package world.bentobox.boxed.generators; - -import java.io.File; -import java.util.EnumMap; -import java.util.Map; - -import org.bukkit.Material; -import org.bukkit.block.Biome; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.util.noise.NoiseGenerator; -import org.bukkit.util.noise.SimplexNoiseGenerator; - -import com.google.common.base.Enums; - -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 static final String NETHER_BIOMES = "nether.biomes"; - private final BiomeNoise defaultNoise = new BiomeNoise(10D, 0D, 2D); - private final NoiseGenerator mainNoiseGenerator; - private final Boxed addon; - private final Map biomeNoiseMap; - - - public NetherGenerator(Boxed addon, long seed) { - this.addon = addon; - // Initialize the noise generator based on the world seed - this.mainNoiseGenerator = new SimplexNoiseGenerator(seed); - // Load the config - File biomeFile = new File(addon.getDataFolder(), "biomes.yml"); - if (!biomeFile.exists()) { - addon.saveResource("biomes.yml", true); - } - YamlConfiguration config = YamlConfiguration.loadConfiguration(biomeFile); - biomeNoiseMap = new EnumMap<>(Biome.class); - if (config.isConfigurationSection(NETHER_BIOMES)) { - for (String key : config.getConfigurationSection(NETHER_BIOMES).getKeys(false)) { - double noiseScaleHorizontal = config.getDouble(NETHER_BIOMES + "." + key + ".scale", 10D); - double height = config.getDouble(NETHER_BIOMES + "." + key + ".height", 0D); - double noiseScaleVertical = config.getDouble(NETHER_BIOMES + "." + key + ".vscale", 2D); - Enums.getIfPresent(Biome.class, key).toJavaUtil() - .ifPresent(biome -> biomeNoiseMap.put(biome, new BiomeNoise(noiseScaleHorizontal, height, noiseScaleVertical))); - } - } - } - - static class BiomeNoise { - double noiseScaleHorizontal = 10D; - double height = 0D; - double noiseScaleVertical = 2D; - /** - * @param noiseScaleHorizontal horizontal noise scale - * @param height height - * @param noiseScaleVertical vertical noise scale - */ - public BiomeNoise(double noiseScaleHorizontal, double height, double noiseScaleVertical) { - this.noiseScaleHorizontal = noiseScaleHorizontal; - this.height = height; - this.noiseScaleVertical = noiseScaleVertical; - } - @Override - public String toString() { - return "BiomeNoise [noiseScaleHorizontal=" + noiseScaleHorizontal + ", height=" + height - + ", noiseScaleVertical=" + noiseScaleVertical + "]"; - } - - } - @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(); - - Biome biome = biomeGenerator.getZoomedOutBiome(scaledX, scaledZ); - - if (biome == null) { - // edge of island - biome = Biome.NETHER_WASTES; - } - BiomeNoise bm = this.biomeNoiseMap.getOrDefault(biome, defaultNoise); - double x = ((((double)scaledX*4) % dist) / 4) / bm.noiseScaleHorizontal; - double z = ((((double)scaledZ*4) % dist) / 4) / bm.noiseScaleHorizontal; - for (int y = 0; y < 16; y++) { - double noise = this.mainNoiseGenerator.noise(x, y / Math.max(0.5, bm.noiseScaleVertical), z); - double heightOffset = y < 12 && bm.height != 0 ? bm.height - y : 0; - buffer[y] = noise + heightOffset; - } - } - -} \ No newline at end of file diff --git a/src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java b/src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java deleted file mode 100644 index f3c8796..0000000 --- a/src/main/java/world/bentobox/boxed/generators/OverWorldGenerator.java +++ /dev/null @@ -1,63 +0,0 @@ -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.SimplexNoiseGenerator; - -import nl.rutgerkok.worldgeneratorapi.BaseNoiseGenerator; -import nl.rutgerkok.worldgeneratorapi.BiomeGenerator; -import world.bentobox.boxed.Boxed; - -/** - * @author tastybento - * - */ -public class OverWorldGenerator implements BaseNoiseGenerator { - - private final SimplexNoiseGenerator mainNoiseGenerator; - private final Boxed addon; - private final YamlConfiguration config; - - - public OverWorldGenerator(Boxed addon, long seed) { - this.addon = addon; - // Initialize the noise generator based on the world seed - this.mainNoiseGenerator = new SimplexNoiseGenerator(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.STONE.createBlockData(); - ts.waterBlock = Material.WATER.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(); - Biome biome = biomeGenerator.getZoomedOutBiome(scaledX, scaledZ); - double noiseScaleHorizontal = config.getDouble("biomes." + biome.name() + ".scale", 10D); - double height = config.getDouble("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; - } - } - -} \ No newline at end of file diff --git a/src/main/java/world/bentobox/boxed/listeners/AdvancementListener.java b/src/main/java/world/bentobox/boxed/listeners/AdvancementListener.java index 3737fab..b1f2487 100644 --- a/src/main/java/world/bentobox/boxed/listeners/AdvancementListener.java +++ b/src/main/java/world/bentobox/boxed/listeners/AdvancementListener.java @@ -9,6 +9,7 @@ import java.util.Spliterators; import java.util.stream.StreamSupport; import org.bukkit.Bukkit; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Server; @@ -71,14 +72,19 @@ public class AdvancementListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onAdvancement(PlayerAdvancementDoneEvent e) { + // Ignore if player is not in survival + if (!e.getPlayer().getGameMode().equals(GameMode.SURVIVAL)) { + return; + } if (Util.sameWorld(e.getPlayer().getWorld(), addon.getOverWorld())) { + // Only allow members or higher to get advancements in a box if (addon.getSettings().isDenyVisitorAdvancements() && !addon.getIslands().getIslandAt(e.getPlayer().getLocation()).map(i -> i.getMemberSet().contains(e.getPlayer().getUniqueId())).orElse(false)) { // Remove advancement from player e.getAdvancement().getCriteria().forEach(c -> e.getPlayer().getAdvancementProgress(e.getAdvancement()).revokeCriteria(c)); User u = User.getInstance(e.getPlayer()); - if (u != null) { + if (u != null && addon.getAdvManager().getScore(e.getAdvancement().getKey().getKey()) > 0) { u.notify("boxed.adv-disallowed", TextVariables.NAME, e.getPlayer().getName(), TextVariables.DESCRIPTION, this.keyToString(u, e.getAdvancement().getKey())); } return; @@ -117,7 +123,7 @@ public class AdvancementListener implements Listener { /** * Synchronize the player's advancements to that of the island. - * Player's advancements should be cleared before calling this othewise they will get add the island ones as well. + * Player's advancements should be cleared before calling this otherwise they will get add the island ones as well. * @param user - user */ public void syncAdvancements(User user) { @@ -153,7 +159,7 @@ public class AdvancementListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPortal(PlayerPortalEvent e) { - if (!Util.sameWorld(e.getPlayer().getWorld(), addon.getOverWorld())) { + if (!Util.sameWorld(e.getPlayer().getWorld(), addon.getOverWorld()) || !e.getPlayer().getGameMode().equals(GameMode.SURVIVAL)) { return; } if (e.getCause().equals(TeleportCause.NETHER_PORTAL)) { diff --git a/src/main/resources/advancements.yml b/src/main/resources/advancements.yml index 4db81e8..65d5fef 100644 --- a/src/main/resources/advancements.yml +++ b/src/main/resources/advancements.yml @@ -2,6 +2,7 @@ settings: default-root-increase: 0 unknown-advancement-increase: 1 + unknown-recipe-increase: 0 advancements: 'minecraft:adventure/adventuring_time': 1 'minecraft:adventure/arbalistic': 1 @@ -907,6 +908,7 @@ advancements: 'minecraft:recipes/transportation/furnace_minecart': 0 'minecraft:recipes/transportation/hopper_minecart': 0 'minecraft:recipes/transportation/jungle_boat': 0 + 'minecraft:recipes/transportation/mangrove_boat': 0 'minecraft:recipes/transportation/minecart': 0 'minecraft:recipes/transportation/oak_boat': 0 'minecraft:recipes/transportation/powered_rail': 0 diff --git a/src/main/resources/biomes.yml b/src/main/resources/biomes.yml index eca7278..5ffeab7 100644 --- a/src/main/resources/biomes.yml +++ b/src/main/resources/biomes.yml @@ -5,50 +5,35 @@ distribution: - 0.05:PLAINS - 0.1:DESERT - 0.2:SAVANNA - - 0.4:JUNGLE_EDGE - - 0.5:JUNGLE - - 0.6:JUNGLE_HILLS - - 0.75:BAMBOO_JUNGLE_HILLS + - 0.5:SPARSE_JUNGLE + - 0.65:JUNGLE - 0.8:BAMBOO_JUNGLE - - 0.9:BADLANDS_PLATEAU - - 1.0:BADLANDS - - 1.1:LUKEWARM_OCEAN - - 20.0:WARM_OCEAN + - 1.0:MANGROVE_SWAMP south-east: - 0.05:PLAINS - - 0.1:SUNFLOWER_PLAINS + - 0.8:SUNFLOWER_PLAINS - 0.2:FLOWER_FOREST - 0.3:SAVANNA - - 0.4:DESERT - - 0.5:SHATTERED_SAVANNA - - 0.65:DESERT_HILLS - - 0.7:GRAVELLY_MOUNTAINS - - 0.9:BADLANDS_PLATEAU - - 1.0:ERODED_BADLANDS - - 1.1:MUSHROOM_FIELD_SHORE - - 20.0:WARM_OCEAN + - 0.4:BEACH + - 0.5:COLD_OCEAN north-west: - 0.05:PLAINS - - 0.25:FOREST - - 0.3:FLOWER_FOREST - - 0.4:DARK_FOREST - - 0.5:SNOWY_TAIGA - - 0.65:SNOWY_TAIGA_HILLS - - 0.7:SNOWY_MOUNTAINS - - 0.9:MOUNTAIN_EDGE - - 1.1:BEACH - - 20.0:COLD_OCEAN + - 0.8:WARM_OCEAN + - 1.5:COLD_OCEAN + - 2.0:OCEAN south-west: - - 0.05:PLAINS - - 0.25:SWAMP - - 0.3:FOREST - - 0.4:DARK_FOREST - - 0.5:SNOWY_TAIGA - - 0.65:SNOWY_TAIGA_HILLS - - 0.7:SNOWY_MOUNTAINS - - 0.9:MOUNTAIN_EDGE - - 1.1:ICE_SPIKES - - 20.0:COLD_OCEAN + - 0.04:PLAINS + - 0.05:DARK_FOREST + - 0.06:BIRCH_FOREST + - 0.07:FOREST + - 0.09:OLD_GROWTH_PINE_TAIGA + - 0.12:TAIGA + - 0.25:SNOWY_BEACH + - 0.3:FROZEN_OCEAN + - 0.5:ICE_SPIKES + - 0.7:TAIGA + - 1.1:SNOWY_PLAINS + - 2.1:SNOWY_TAIGA nether: north-east: - 0.03:NETHER_WASTES @@ -90,230 +75,3 @@ distribution: - 1.26:SOUL_SAND_VALLEY - 1.54:BASALT_DELTAS - 2.1:NETHER_WASTES -nether: - biomes: - NETHER_WASTES: - height: 0 - vscale: 2 - scale: 8 - BASALT_DELTAS: - height: 0 - vscale: 1 - scale: 1 - CRIMSON_FOREST: - height: 10 - vscale: 10 - scale: 10 - SOUL_SAND_VALLEY: - height: 8 - vscale: 16 - scale: 16 - WARPED_FOREST: - height: 9 - vscale: 10 - scale: 10 -biomes: - BADLANDS_PLATEAU: - height: 9 - scale: 16 - BADLANDS: - height: 8 - scale: 10 - BAMBOO_JUNGLE_HILLS: - height: 9 - scale: 2.5 - BAMBOO_JUNGLE: - height: 8 - scale: 10 - BEACH: - height: 7 - scale: 16 - BIRCH_FOREST_HILLS: - height: 9 - scale: 2.5 - BIRCH_FOREST: - height: 8 - scale: 10 - COLD_OCEAN: - height: 5 - scale: 3.33 - DARK_FOREST_HILLS: - height: 9 - scale: 2.5 - DARK_FOREST: - height: 8 - scale: 10 - DEEP_COLD_OCEAN: - height: 5 - scale: 3.33 - DEEP_FROZEN_OCEAN: - height: 5 - scale: 3.33 - DEEP_LUKEWARM_OCEAN: - height: 5 - scale: 3.33 - DEEP_OCEAN: - height: 5 - scale: 3.33 - DEEP_WARM_OCEAN: - height: 5 - scale: 3.33 - DESERT_HILLS: - height: 9 - scale: 2.5 - DESERT_LAKES: - height: 8 - scale: 10 - DESERT: - height: 8 - scale: 15 - ERODED_BADLANDS: - height: 8 - scale: 17 - FLOWER_FOREST: - height: 8 - scale: 10 - FOREST: - height: 8 - scale: 10 - FROZEN_OCEAN: - height: 5 - scale: 3.33 - FROZEN_RIVER: - height: 5 - scale: 10 - GIANT_SPRUCE_TAIGA_HILLS: - height: 9 - scale: 2.5 - GIANT_SPRUCE_TAIGA: - height: 8 - scale: 10 - GIANT_TREE_TAIGA_HILLS: - height: 9 - scale: 2.5 - GIANT_TREE_TAIGA: - height: 8 - scale: 10 - GRAVELLY_MOUNTAINS: - height: 10 - scale: 2.5 - ICE_SPIKES: - height: 8 - scale: 20 - JUNGLE_EDGE: - height: 8 - scale: 10 - JUNGLE_HILLS: - height: 9 - scale: 2.5 - JUNGLE: - height: 8 - scale: 10 - LUKEWARM_OCEAN: - height: 5 - scale: 3.33 - MODIFIED_BADLANDS_PLATEAU: - height: 9 - scale: 16 - MODIFIED_GRAVELLY_MOUNTAINS: - height: 10 - scale: 2.5 - MODIFIED_JUNGLE_EDGE: - height: 8 - scale: 10 - MODIFIED_JUNGLE: - height: 8 - scale: 10 - MODIFIED_WOODED_BADLANDS_PLATEAU: - height: 9 - scale: 16 - MOUNTAIN_EDGE: - height: 10 - scale: 2.5 - MOUNTAINS: - height: 10 - scale: 2.5 - MUSHROOM_FIELD_SHORE: - height: 5 - scale: 10 - MUSHROOM_FIELDS: - height: 8 - scale: 10 - OCEAN: - height: 5 - scale: 3.33 - PLAINS: - height: 8 - scale: 10 - RIVER: - height: 5 - scale: 10 - SAVANNA_PLATEAU: - height: 9 - scale: 16 - SAVANNA: - height: 8 - scale: 10 - SHATTERED_SAVANNA_PLATEAU: - height: 9 - scale: 16 - SHATTERED_SAVANNA: - height: 8 - scale: 10 - SNOWY_BEACH: - height: 7 - scale: 16 - SNOWY_MOUNTAINS: - height: 10 - scale: 2.5 - SNOWY_TAIGA_HILLS: - height: 9 - scale: 2.5 - SNOWY_TAIGA_MOUNTAINS: - height: 10 - scale: 2.5 - SNOWY_TAIGA: - height: 8 - scale: 10 - SNOWY_TUNDRA: - height: 8 - scale: 10 - STONE_SHORE: - height: 8 - scale: 10 - SUNFLOWER_PLAINS: - height: 8 - scale: 10 - SWAMP_HILLS: - height: 9 - scale: 2.5 - SWAMP: - height: 8 - scale: 10 - TAIGA_HILLS: - height: 9 - scale: 2.5 - TAIGA_MOUNTAINS: - height: 10 - scale: 2.5 - TAIGA: - height: 8 - scale: 10 - TALL_BIRCH_FOREST: - height: 8 - scale: 10 - TALL_BIRCH_HILLS: - height: 9 - scale: 2.5 - WARM_OCEAN: - height: 5 - scale: 3.33 - WOODED_BADLANDS_PLATEAU: - height: 9 - scale: 16 - WOODED_HILLS: - height: 9 - scale: 2.5 - WOODED_MOUNTAINS: - height: 10 - scale: 2.5 diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index f002d77..2972590 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,4 @@ -# Boxed Configuration {$version} +# Boxed Configuration 2.0.2-SNAPSHOT-LOCAL boxed: command: # Player Command. What command users will run to access their area. @@ -27,10 +27,30 @@ world: # Name of the world - if it does not exist then it will be generated. # It acts like a prefix for nether and end (e.g. boxed_world, boxed_world_nether, boxed_world_end) world-name: boxed_world - # World seed. - # If you change this, stop the server and delete the worlds made. - # /!\ BentoBox currently does not support changing this value mid-game. If you do need to change it, do a full reset of your databases and worlds. - seed: 978573758696 + generator: + # World seed. + # If you change this, stop the server and delete the worlds made. + # /!\ BentoBox currently does not support changing this value mid-game. If you do need to change it, do a full reset of your databases and worlds. + seed: 602103456450 + # Generate surface + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + generate-surface: true + # Generate bedrock + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + generate-bedrock: true + # Generate caves + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + generate-caves: true + # Generate Decorations + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + generate-decorations: true + # Generate mobs + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + generate-mobs: true + # Allow surface structures - villages, shipwrecks, broken portals, etc. + # These will be randomly placed, so may not be available for every player. + # /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work. + allow-structures: true # World difficulty setting - PEACEFUL, EASY, NORMAL, HARD # Other plugins may override this setting difficulty: NORMAL @@ -47,11 +67,10 @@ world: # Setting to 0 will disable monster spawns, but this is not recommended. Minecraft default is 400. # A negative value uses the server default ticks-per-monster-spawns: -1 - # Radius of player areas. (So distance between player starting spots is twice this) + # Radius of player area. (So distance between player starting spots is twice this) # It is the same for every dimension : Overworld, Nether and End. - # This value cannot be changed mid-game and the plugin will not start if it is different. # /!\ BentoBox currently does not support changing this value mid-game. If you do need to change it, do a full reset of your databases and worlds. - area-radius: 1000 + area-radius: 320 # Starting size of boxed spaces. This is a radius so 1 = a 2x2 area. # Admins can adjust via the /boxadmin range set command starting-protection-range: 1 @@ -64,7 +83,7 @@ world: start-z: 0 # Area height - Lowest is 5. # It is the y coordinate of the bedrock block in the blueprint. - area-height: 5 + area-height: 8 # Maximum number of player areas in the world. Set to -1 or 0 for unlimited. # If the number of areas is greater than this number, it will stop players from joining the world. max-areas: -1 @@ -81,21 +100,21 @@ world: # Note: Some default challenges will not be possible if there is no nether. # Note that with a standard nether all players arrive at the same portal and entering a # portal will return them back to their areas. - generate: true + generate: false # Nether spawn protection radius - this is the distance around the nether spawn - # that will be protected from player interaction (breaking blocks, pouring lava etc.) + # that will be public from player interaction (breaking blocks, pouring lava etc.) # Minimum is 0 (not recommended), maximum is 100. Default is 25. # Only applies to vanilla nether spawn-radius: 32 # This option indicates if nether portals should be linked via dimensions. - # 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 + # Option will simulate vanilla portal mechanics that links portals together + # or creates a new portal, if there is not a portal in that dimension. + # Added since 1.0.3. 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. - generate: true + generate: false # Mob white list - these mobs will NOT be removed when logging in or doing /boxed remove-mobs-whitelist: [] # World flags. These are boolean settings for various flags for this world @@ -105,6 +124,7 @@ world: ISLAND_RESPAWN: true REDSTONE: true CREEPER_GRIEFING: true + VISITOR_KEEP_INVENTORY: false BUCKET: false ENDER_PEARL: false DOOR: true @@ -182,6 +202,7 @@ world: WORLD_TNT_DAMAGE: true HOPPER: false LEASH: false + ALLOW_MOVE_BOX: true BREAK_BLOCKS: false MOUNT_INVENTORY: false OFFLINE_REDSTONE: true @@ -211,15 +232,15 @@ world: BREAK_HOPPERS: 500 FURNACE: 500 MONSTER_SPAWNERS_SPAWN: 500 - ANVIL: 500 MINECART: 500 + ANVIL: 500 FISH_SCOOPING: 500 FIRE_IGNITE: 500 END_PORTAL: 500 BREEDING: 500 HURT_VILLAGERS: 500 - FROST_WALKER: 500 TURTLE_EGGS: 500 + FROST_WALKER: 500 COLLECT_LAVA: 500 BREAK_SPAWNERS: 500 LEVER: 0 @@ -236,10 +257,10 @@ world: FLINT_AND_STEEL: 500 NETHER_PORTAL: 0 LECTERN: 500 - CROP_TRAMPLE: 500 ITEM_PICKUP: 0 - DROPPER: 500 + CROP_TRAMPLE: 500 BREWING: 500 + DROPPER: 500 TNT_PRIMING: 500 COLLECT_WATER: 500 BUTTON: 0 @@ -254,8 +275,8 @@ world: ITEM_FRAME: 500 CRAFTING: 0 SHEARING: 500 - ENCHANTING: 500 ANIMAL_SPAWNERS_SPAWN: 500 + ENCHANTING: 500 BOAT: 0 BED: 500 SPAWN_EGGS: 500 @@ -276,14 +297,14 @@ world: PVP_END: false PVP_NETHER: false LEAF_DECAY: true - TNT_DAMAGE: true MONSTER_SPAWNERS_SPAWN: true + TNT_DAMAGE: true ANIMAL_NATURAL_SPAWN: true MONSTER_NATURAL_SPAWN: true FIRE_IGNITE: true FIRE_SPREAD: true - FIRE_BURNING: true ANIMAL_SPAWNERS_SPAWN: true + FIRE_BURNING: true PVP_OVERWORLD: false # These settings/flags are hidden from users # Ops can toggle hiding in-game using SHIFT-LEFT-CLICK on flags in settings @@ -353,11 +374,11 @@ area: exp: true # Reset Ender Chest - if true, the player's Ender Chest will be cleared. ender-chest: false - # Reset advancements + # Reset advancements. reset-advancements: true # Grant these advancements grant-advancements: - - minecraft:story/root + - minecraft:story/root on-leave: # What the plugin should reset when the player leaves or is kicked from an area # Reset Money - if this is true, will reset the player's money to the starting money @@ -376,7 +397,7 @@ area: exp: false # Reset Ender Chest - if true, the player's Ender Chest will be cleared. ender-chest: false - # Reset advancements + # Reset advancements. reset-advancements: false # Grant these advancements grant-advancements: [] @@ -445,17 +466,17 @@ area: # # Note that player-executed commands might not work, as these commands can be run with said player being offline. on-leave: [] - # Returns a list of commands that should be executed when the player respawns after death if Flags.ISLAND_RESPAWN is true. + # List of commands that should be executed when the player respawns after death if Flags.ISLAND_RESPAWN is true. # These commands are run by the console, unless otherwise stated using the [SUDO] prefix, # in which case they are executed by the player. - # + # # Available placeholders for the commands are the following: # * [name]: name of the player - # + # # Here are some examples of valid commands to execute: # * '[SUDO] bbox version' # * 'bsbadmin deaths set [player] 0' - # + # # Note that player-executed commands might not work, as these commands can be run with said player being offline. # Added since 1.14.0. on-respawn: [] diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 3fb8606..104a5c9 100755 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -321,7 +321,7 @@ boxed: LOCK: name: Lock player box OFFLINE_REDSTONE: - description: "&a When disabled, redstone\n&a will not operate in boxs\n&a\ + description: "&a When disabled, redstone\n&a will not operate in boxes\n&a\ \ where all members are offline.\n&a May help reduce lag. " PISTON_PUSH: description: |-