diff --git a/src/main/java/world/bentobox/caveblock/Settings.java b/src/main/java/world/bentobox/caveblock/Settings.java index 2795e19..67b63e4 100644 --- a/src/main/java/world/bentobox/caveblock/Settings.java +++ b/src/main/java/world/bentobox/caveblock/Settings.java @@ -812,6 +812,15 @@ public class Settings implements WorldSettings return numberOfBlockGenerationTries; } + /** + * This method returns the newMaterialGenerator value. + * @return the value of newMaterialGenerator. + */ + public boolean isNewMaterialGenerator() + { + return newMaterialGenerator; + } + /** * {@inheritDoc} @@ -1647,6 +1656,17 @@ public class Settings implements WorldSettings } + /** + * This method sets the newMaterialGenerator value. + * @param newMaterialGenerator the numberOfBlockGenerationTries new value. + * + */ + public void setNewMaterialGenerator(boolean newMaterialGenerator) + { + this.newMaterialGenerator = newMaterialGenerator; + } + + /** * @return the debug */ @@ -2198,6 +2218,12 @@ public class Settings implements WorldSettings @ConfigEntry(path = "world.generation-tries", needsReset = true) private int numberOfBlockGenerationTries = 1; + @ConfigComment("Should we use the new material generator ?") + @ConfigComment("This will generate ores and blocks similar to how vanilla does,") + @ConfigComment("but it will override the blocks settings of each world.") + @ConfigEntry(path = "world.use-new-material-generator", needsReset = true) + private boolean newMaterialGenerator = false; + @ConfigComment("") @ConfigComment("Make over world roof of bedrock, if false, it will be made from stone") @ConfigEntry(path = "world.normal.roof", needsReset = true) diff --git a/src/main/java/world/bentobox/caveblock/Utils.java b/src/main/java/world/bentobox/caveblock/Utils.java new file mode 100644 index 0000000..934bfd3 --- /dev/null +++ b/src/main/java/world/bentobox/caveblock/Utils.java @@ -0,0 +1,20 @@ +package world.bentobox.caveblock; + +import org.bukkit.Location; + +public class Utils { + + /** + * Convert chunk location to world location + * + * @param x the x coordinate of the chunk location + * @param y the y coordinate + * @param z the z coordinate of the chunk location + * @param chunkX the x coordinate of the chunk + * @param chunkZ the z coordinate of the chunk + * @return the world location + */ + public static Location getLocationFromChunkLocation(int x, int y, int z, int chunkX, int chunkZ) { + return new Location(null, x + (chunkX * 16D), y, z + (chunkZ * 16D)); + } +} diff --git a/src/main/java/world/bentobox/caveblock/generators/ChunkGeneratorWorld.java b/src/main/java/world/bentobox/caveblock/generators/ChunkGeneratorWorld.java index 52a65da..bac828f 100644 --- a/src/main/java/world/bentobox/caveblock/generators/ChunkGeneratorWorld.java +++ b/src/main/java/world/bentobox/caveblock/generators/ChunkGeneratorWorld.java @@ -1,6 +1,5 @@ package world.bentobox.caveblock.generators; - import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; @@ -14,15 +13,17 @@ import org.bukkit.block.data.BlockData; import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.WorldInfo; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; /** * Class ChunkGeneratorWorld ... * - * @author BONNe - * Created on 27.01.2019 + * @author tastybento */ public class ChunkGeneratorWorld extends ChunkGenerator { - + private static final int BLOB_SIZE = 1; private static final Map> ORES; static { diff --git a/src/main/java/world/bentobox/caveblock/generators/populators/EntitiesPopulator.java b/src/main/java/world/bentobox/caveblock/generators/populators/EntitiesPopulator.java index 4c95ec2..0b71ce3 100644 --- a/src/main/java/world/bentobox/caveblock/generators/populators/EntitiesPopulator.java +++ b/src/main/java/world/bentobox/caveblock/generators/populators/EntitiesPopulator.java @@ -1,52 +1,80 @@ package world.bentobox.caveblock.generators.populators; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.stream.Collectors; - -import org.bukkit.Chunk; +import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.World.Environment; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.LimitedRegion; +import org.bukkit.generator.WorldInfo; import org.bukkit.util.BoundingBox; - import world.bentobox.bentobox.util.Pair; import world.bentobox.caveblock.CaveBlock; +import world.bentobox.caveblock.Utils; +import java.util.*; +import java.util.stream.Collectors; /** - * This class populates generated chunk with entites by random chance. + * This class populates generated chunk with entities by random chance. */ -public class EntitiesPopulator extends BlockPopulator -{ +public class EntitiesPopulator extends BlockPopulator { + + // --------------------------------------------------------------------- + // Section: Variables + // --------------------------------------------------------------------- + + /** + * Water entities + */ + private static final List WATER_ENTITIES = Arrays.asList(EntityType.GUARDIAN, + EntityType.SQUID, + EntityType.COD, + EntityType.SALMON, + EntityType.PUFFERFISH, + EntityType.TROPICAL_FISH, + EntityType.DROWNED, + EntityType.DOLPHIN); + /** + * CaveBlock addon. + */ + private final CaveBlock addon; + /** + * Map that contains chances for spawning per environment. + */ + private Map chances; + /** + * World height + */ + private int worldHeight; + + // --------------------------------------------------------------------- + // Section: Constructor + // --------------------------------------------------------------------- /** * This is default constructor + * * @param addon CaveBlock addon. */ - public EntitiesPopulator(CaveBlock addon) - { + public EntitiesPopulator(CaveBlock addon) { this.addon = addon; this.loadSettings(); } + // --------------------------------------------------------------------- + // Section: Methods + // --------------------------------------------------------------------- /** * This method load chances per environment. */ private void loadSettings() { // Set up chances - chances = new HashMap<>(); + chances = new EnumMap<>(Environment.class); // Normal chances.put(Environment.NORMAL, new Chances(this.getEntityMap(addon.getSettings().getNormalBlocks()), addon.getSettings().getNormalMainBlock())); // Nether @@ -54,43 +82,49 @@ public class EntitiesPopulator extends BlockPopulator // End chances.put(Environment.THE_END, new Chances(this.getEntityMap(addon.getSettings().getEndBlocks()), addon.getSettings().getEndMainBlock())); // Other settings - worldHeight = addon.getSettings().getWorldDepth() - 1; + worldHeight = addon.getSettings().getWorldDepth(); } - /** * This method populates chunk with entities. - * @param world World where population must be. - * @param random Randomness - * @param chunk Chunk were populator operates. + * + * @param worldInfo World where population must be. + * @param random Randomness + * @param chunkX X coordinate of chunk + * @param chunkZ Z coordinate of chunk + * @param limitedRegion Region where population operates. */ @Override - public void populate(World world, Random random, Chunk chunk) - { - for (Map.Entry> entry : chances.get(world.getEnvironment()).entityChanceMap.entrySet()) - { - for (int subY = 0; subY < worldHeight; subY += 16) - { + public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) { + int minHeight = worldInfo.getMinHeight(); + int height = Math.min(worldInfo.getMaxHeight(), worldHeight) - 1; + + for (Map.Entry, Boolean>> entry : chances.get(worldInfo.getEnvironment()).entityChanceMap.entrySet()) { + Pair value = entry.getValue().x; + boolean hasAI = entry.getValue().z; + for (int subY = minHeight; subY < height; subY += 16) { // Use double so chance can be < 1 - if (random.nextDouble() * 100 < entry.getValue().x) - { - int y = Math.min(worldHeight - 2, subY + random.nextInt(15)); + if (random.nextDouble() * 100 < value.x) { + int y = Math.min(height - 2, subY + random.nextInt(15)); // Spawn only in middle of chunk because bounding box will grow out from here - this.tryToPlaceEntity(world, chunk.getBlock(7, y, 7), entry.getKey(), chances.get(world.getEnvironment()).mainMaterial); + this.tryToPlaceEntity( + worldInfo, Utils.getLocationFromChunkLocation(7, y, 7, chunkX, chunkZ), limitedRegion, + entry.getKey(), hasAI, + chances.get(worldInfo.getEnvironment()).mainMaterial + ); } } } } - /** * This method returns Entity frequently and pack size map. + * * @param objectList List with objects that contains data. * @return Map that contains entity, its rarity and pack size. */ - private Map> getEntityMap(List objectList) - { - Map> entityMap = new HashMap<>(objectList.size()); + private Map, Boolean>> getEntityMap(List objectList) { + Map, Boolean>> entityMap = new EnumMap<>(EntityType.class); Map entityTypeMap = Arrays.stream(EntityType.values()). collect(Collectors.toMap(Enum::name, @@ -100,128 +134,86 @@ public class EntitiesPopulator extends BlockPopulator // wrong material object. objectList.stream(). - filter(object -> object.startsWith("ENTITY")). - map(object -> object.split(":")). - filter(splitString -> splitString.length == 4). - forEach(splitString -> { - EntityType entity = entityTypeMap.getOrDefault(splitString[1], null); + filter(object -> object.startsWith("ENTITY")). + map(object -> object.split(":")). + filter(splitString -> splitString.length >= 4). + forEach(splitString -> { + EntityType entity = entityTypeMap.getOrDefault(splitString[1], null); + boolean hasAI = splitString.length <= 4 || Boolean.parseBoolean(splitString[4]); - if (entity != null) - { - entityMap.put(entity, - new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3]))); - } - }); + if (entity != null) { + entityMap.put(entity, + new Pair<>( + new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3])), + hasAI + ) + ); + } + }); return entityMap; } /** * Places entities if there is room for them. - * @param world - World were mob must be spawned. - * @param block - Block that was chosen by random. - * @param entity - Entity that must be spawned. + * + * @param worldInfo - World were mob must be spawned. + * @param location - Location that was chosen by random. + * @param limitedRegion - Region where entity must be spawned. + * @param entityType - Entity that must be spawned. + * @param hasAI - If entity has AI. * @param originalMaterial - replacement material. */ - private void tryToPlaceEntity(World world, Block block, EntityType entity, Material originalMaterial) - { - if (block.getType().equals(originalMaterial)) { - // Spawn entity - Entity e = world.spawnEntity(block.getLocation().add(0.5, 0, 0.5), entity); - if (e instanceof LivingEntity) { - // Do not despawn - ((LivingEntity)e).setRemoveWhenFarAway(false); - } - // Make space for entity based on the entity's size - BoundingBox bb = e.getBoundingBox(); + private void tryToPlaceEntity(WorldInfo worldInfo, Location location, LimitedRegion limitedRegion, EntityType entityType, boolean hasAI, Material originalMaterial) { + if (!limitedRegion.isInRegion(location)) return; + if (!limitedRegion.getType(location).equals(originalMaterial)) return; - for (int x = (int) Math.floor(bb.getMinX()); x < bb.getMaxX(); x++) { - for (int z = (int) Math.floor(bb.getMinZ()); z < bb.getMaxZ(); z++) { - int y = (int) Math.floor(bb.getMinY()); - Block b = world.getBlockAt(x, y, z); - for (; y < bb.getMaxY(); y++) { - if (addon.getSettings().isDebug()) { - addon.log("DEBUG: Entity spawn: " + world.getName() + " " + x + " " + y + " " + z + " " + e.getType()); - } - b = world.getBlockAt(x, y, z); - if (!b.getType().equals(originalMaterial)) { - // Cannot place entity - e.remove(); - return; - } - b.setType(WATER_ENTITIES.contains(entity) ? Material.WATER : Material.AIR); + Entity entity = limitedRegion.spawnEntity(location, entityType); + if (entity instanceof LivingEntity livingEntity) { + livingEntity.setAI(hasAI); + livingEntity.setRemoveWhenFarAway(false); + } + + BoundingBox bb = entity.getBoundingBox(); + for (int x = (int) Math.floor(bb.getMinX()); x < bb.getMaxX(); x++) { + for (int z = (int) Math.floor(bb.getMinZ()); z < bb.getMaxZ(); z++) { + int y = (int) Math.floor(bb.getMinY()); + if (!limitedRegion.isInRegion(x, y, z)) { + entity.remove(); + return; + } + + for (; y <= bb.getMaxY(); y++) { + if (addon.getSettings().isDebug()) { + addon.log("DEBUG: Entity spawn: " + worldInfo.getName() + " " + x + " " + y + " " + z + " " + entity.getType()); } - // Add air block on top for all water entities (required for dolphin, okay for others) - if (WATER_ENTITIES.contains(entity) && b.getRelative(BlockFace.UP).getType().equals(originalMaterial)) { - b.getRelative(BlockFace.UP).setType(Material.CAVE_AIR); + + if (!limitedRegion.isInRegion(x, y, z) || !limitedRegion.getType(x, y, z).equals(originalMaterial)) { + // Cannot place entity + entity.remove(); + return; } + limitedRegion.setType(x, y, z, WATER_ENTITIES.contains(entityType) ? Material.WATER : Material.AIR); + } + // Add air block on top for all water entities (required for dolphin, okay for others) + if (WATER_ENTITIES.contains(entityType) && limitedRegion.isInRegion(x, y, z) && limitedRegion.getType(x, y, z).equals(originalMaterial)) { + limitedRegion.setType(x, y, z, Material.CAVE_AIR); } } } } - // --------------------------------------------------------------------- // Section: Private Classes // --------------------------------------------------------------------- - /** * Chances class to store chances for environments and main material + * + * @param entityChanceMap - contains chances for each entity, and the boolean indicates that entity should have AI. + * @param mainMaterial - material on which entity can replace. */ - private class Chances - { - /** - * @param entityChanceMap - contains chances for each entity. - * @param mainMaterial - material on which entity can replace. - */ - Chances(Map> entityChanceMap, Material mainMaterial) - { - this.entityChanceMap = entityChanceMap; - this.mainMaterial = mainMaterial; - } - - - /** - * Map that contains chances for entity to spawn. - */ - final Map> entityChanceMap; - - /** - * Main material that can be replaced. - */ - final Material mainMaterial; + private record Chances(Map, Boolean>> entityChanceMap, + Material mainMaterial) { } - - - // --------------------------------------------------------------------- - // Section: Variables - // --------------------------------------------------------------------- - - /** - * CaveBlock addon. - */ - private CaveBlock addon; - - /** - * Map that contains chances for spawning per environment. - */ - private Map chances; - - /** - * World height - */ - private int worldHeight; - - /** - * Water entities - */ - private final static List WATER_ENTITIES = Arrays.asList(EntityType.GUARDIAN, - EntityType.SQUID, - EntityType.COD, - EntityType.SALMON, - EntityType.PUFFERFISH, - EntityType.TROPICAL_FISH, - EntityType.DROWNED, - EntityType.DOLPHIN); } diff --git a/src/main/java/world/bentobox/caveblock/generators/populators/FlatBiomeProvider.java b/src/main/java/world/bentobox/caveblock/generators/populators/FlatBiomeProvider.java new file mode 100644 index 0000000..a701cb5 --- /dev/null +++ b/src/main/java/world/bentobox/caveblock/generators/populators/FlatBiomeProvider.java @@ -0,0 +1,48 @@ +package world.bentobox.caveblock.generators.populators; + +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.WorldInfo; +import world.bentobox.caveblock.CaveBlock; +import world.bentobox.caveblock.Settings; + +import java.util.Collections; +import java.util.List; + +public class FlatBiomeProvider extends BiomeProvider { + private final Settings settings; + + // --------------------------------------------------------------------- + // Section: Constructor + // --------------------------------------------------------------------- + + /** + * @param addon - CaveBlock object + */ + public FlatBiomeProvider(CaveBlock addon) { + this.settings = addon.getSettings(); + } + + // --------------------------------------------------------------------- + // Section: Methods + // --------------------------------------------------------------------- + + private Biome getBiome(World.Environment environment) { + return switch (environment) { + case NETHER -> this.settings.getDefaultNetherBiome(); + case THE_END -> this.settings.getDefaultTheEndBiome(); + default -> this.settings.getDefaultBiome(); + }; + } + + @Override + public Biome getBiome(WorldInfo worldInfo, int x, int y, int z) { + return getBiome(worldInfo.getEnvironment()); + } + + @Override + public List getBiomes(WorldInfo worldInfo) { + return Collections.singletonList(getBiome(worldInfo.getEnvironment())); + } +} diff --git a/src/main/java/world/bentobox/caveblock/generators/populators/MaterialPopulator.java b/src/main/java/world/bentobox/caveblock/generators/populators/MaterialPopulator.java index 7b0233b..c2b42d9 100644 --- a/src/main/java/world/bentobox/caveblock/generators/populators/MaterialPopulator.java +++ b/src/main/java/world/bentobox/caveblock/generators/populators/MaterialPopulator.java @@ -1,47 +1,67 @@ - package world.bentobox.caveblock.generators.populators; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World.Environment; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.LimitedRegion; +import org.bukkit.generator.WorldInfo; +import world.bentobox.bentobox.util.Pair; +import world.bentobox.caveblock.CaveBlock; +import world.bentobox.caveblock.Utils; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Random; -import org.bukkit.Chunk; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.World.Environment; -import org.bukkit.block.Block; -import org.bukkit.generator.BlockPopulator; - -import world.bentobox.bentobox.util.Pair; -import world.bentobox.caveblock.CaveBlock; - - /** - * This class allows to fill given chunk with necessary blocks. + * This class allows filling given chunk with necessary blocks. */ -public class MaterialPopulator extends BlockPopulator -{ +public class MaterialPopulator extends BlockPopulator { + + // --------------------------------------------------------------------- + // Section: Variables + // --------------------------------------------------------------------- + + /** + * CaveBlock addon. + */ + private final CaveBlock addon; + /** + * Map that contains chances for spawning per environment. + */ + private Map chances; + /** + * World height + */ + private int worldHeight; + + // --------------------------------------------------------------------- + // Section: Constructor + // --------------------------------------------------------------------- /** * This is default constructor + * * @param addon CaveBlock addon. */ - public MaterialPopulator(CaveBlock addon) - { + public MaterialPopulator(CaveBlock addon) { this.addon = addon; // Load settings this.loadSettings(); } + // --------------------------------------------------------------------- + // Section: Methods + // --------------------------------------------------------------------- /** * Loads chances for Material Populator */ private void loadSettings() { // Set up chances - chances = new HashMap<>(); + chances = new EnumMap<>(Environment.class); // Normal chances.put(Environment.NORMAL, new Chances(this.getMaterialMap(addon.getSettings().getNormalBlocks()), addon.getSettings().getNormalMainBlock())); // Nether @@ -49,84 +69,71 @@ public class MaterialPopulator extends BlockPopulator // End chances.put(Environment.THE_END, new Chances(this.getMaterialMap(addon.getSettings().getEndBlocks()), addon.getSettings().getEndMainBlock())); // Other settings - worldHeight = addon.getSettings().getWorldDepth() - 1; + worldHeight = addon.getSettings().getWorldDepth(); } - /** * This method populates chunk with blocks. - * @param world World where population must be. - * @param random Randomness - * @param chunk Chunk were populator operates. + * + * @param worldInfo World where population must be. + * @param random Randomness + * @param chunkX X coordinate of chunk + * @param chunkZ Z coordinate of chunk + * @param limitedRegion Region were populator operates. */ @Override - public void populate(World world, Random random, Chunk chunk) - { - Chances chances = this.chances.get(world.getEnvironment()); + public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) { + int minHeight = worldInfo.getMinHeight(); + int height = Math.min(worldInfo.getMaxHeight(), worldHeight) - 1; + Chances envChances = this.chances.get(worldInfo.getEnvironment()); + for (Map.Entry> entry : envChances.materialChanceMap.entrySet()) { + for (int subY = minHeight + 1; subY < height; subY += 16) { + if (random.nextDouble() * 100 >= entry.getValue().x) { + continue; + } - for (Map.Entry> entry : chances.materialChanceMap.entrySet()) - { - for (int subY = 1; subY < worldHeight; subY += 16) - { - if (random.nextDouble() * 100 < entry.getValue().x) - { + // Blocks must be 1 away from edge to avoid adjacent chunk loading + Location location = Utils.getLocationFromChunkLocation( + random.nextInt(13) + 1, + Math.min(height - 2, subY + random.nextInt(15)), + random.nextInt(13) + 1, + chunkX, chunkZ); - // Blocks must be 1 away from edge to avoid adjacent chunk loading - int x = random.nextInt(13) + 1; - int z = random.nextInt(13) + 1; - int y = Math.min(worldHeight - 2, subY + random.nextInt(15)); - /* - * TODO: remove - if (addon.getSettings().isDebug()) { - addon.log("DEBUG: Material: " + world.getName() + " " + x + " " + y + " " + z + " " + entry.getKey()); + if (!limitedRegion.isInRegion(location)) { + continue; + } + + Material material = limitedRegion.getType(location); + if (!material.equals(envChances.mainMaterial)) { + continue; + } + + int packSize = random.nextInt(entry.getValue().z); + boolean continuePlacing = true; + while (continuePlacing) { + if (!material.equals(entry.getKey())) { + limitedRegion.setType(location, entry.getKey()); + packSize--; } - */ - Block block = chunk.getBlock(x, y, z); - if (block.getType().equals(chances.mainMaterial)) - { - int packSize = random.nextInt(entry.getValue().z); - - boolean continuePlacing = true; - - while (continuePlacing) - { - if (!block.getType().equals(entry.getKey())) - { - // Set type without physics is required otherwise server goes into an infinite loop - block.setType(entry.getKey(), false); - packSize--; - } - - // The direction chooser - switch (random.nextInt(5)) - { - case 0: - x = Math.min(15, x + 1); - break; - case 1: - y = Math.min(worldHeight - 2, y + 1); - break; - case 2: - z = Math.min(15, z + 1); - break; - case 3: - x = Math.max(0, x - 1); - break; - case 4: - y = Math.max(1, y - 1); - break; - case 5: - z = Math.max(0, z - 1); - break; - } - - block = chunk.getBlock(x, y, z); - - continuePlacing = packSize > 0 && (block.getType().equals(chances.mainMaterial) || - block.getType().equals(entry.getKey())); + switch (random.nextInt(6)) { + case 0 -> location.setX(location.getX() + 1); + case 1 -> location.setY(location.getY() + 1); + case 2 -> location.setZ(location.getZ() + 1); + case 3 -> location.setX(location.getX() - 1); + case 4 -> location.setY(location.getY() - 1); + case 5 -> location.setZ(location.getZ() - 1); + default -> { + continuePlacing = false; + continue; } } + + continuePlacing = packSize > 0 && limitedRegion.isInRegion(location) && location.getY() > minHeight; + if (continuePlacing) { + material = limitedRegion.getType(location); + continuePlacing = material.equals(envChances.mainMaterial) || material.equals(entry.getKey()); + } } } } @@ -134,84 +141,42 @@ public class MaterialPopulator extends BlockPopulator /** * This method returns material frequently and pack size map. + * * @param objectList List with objects that contains data. * @return Map that contains material, its rarity and pack size. */ - private Map> getMaterialMap(List objectList) - { - Map> materialMap = new HashMap<>(objectList.size()); + private Map> getMaterialMap(List objectList) { + Map> materialMap = new EnumMap<>(Material.class); // wrong material object. objectList.stream(). - filter(object -> object.startsWith("MATERIAL")). - map(object -> object.split(":")). - filter(splitString -> splitString.length == 4). - forEach(splitString -> { - Material material = Material.getMaterial(splitString[1]); - // Material must be a block otherwise the chunk cannot be populated - if (material != null && material.isBlock()) - { - materialMap.put(material, - new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3]))); - } else { - addon.logError("Could not parse MATERIAL in config.yml: " + splitString[1] + " is not a valid block."); - } - }); + filter(object -> object.startsWith("MATERIAL")). + map(object -> object.split(":")). + filter(splitString -> splitString.length == 4). + forEach(splitString -> { + Material material = Material.getMaterial(splitString[1]); + // Material must be a block otherwise the chunk cannot be populated + if (material != null && material.isBlock()) { + materialMap.put(material, + new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3]))); + } else { + addon.logError("Could not parse MATERIAL in config.yml: " + splitString[1] + " is not a valid block."); + } + }); return materialMap; } - // --------------------------------------------------------------------- // Section: Private Classes // --------------------------------------------------------------------- - /** * Chances class to store chances for environments and main material + * + * @param materialChanceMap - contains chances for each material. + * @param mainMaterial - material on which material can replace. */ - private class Chances - { - /** - * @param materialChanceMap - contains chances for each material. - * @param mainMaterial - material on which material can replace. - */ - Chances(Map> materialChanceMap, Material mainMaterial) - { - this.materialChanceMap = materialChanceMap; - this.mainMaterial = mainMaterial; - } - - - /** - * Map that contains chances for entity to spawn. - */ - final Map> materialChanceMap; - - /** - * Main material that can be replaced. - */ - final Material mainMaterial; + private record Chances(Map> materialChanceMap, Material mainMaterial) { } - - - // --------------------------------------------------------------------- - // Section: Variables - // --------------------------------------------------------------------- - - - /** - * CaveBlock addon. - */ - private CaveBlock addon; - - /** - * Map that contains chances for spawning per environment. - */ - private Map chances; - - /** - * World height - */ - private int worldHeight; } diff --git a/src/main/java/world/bentobox/caveblock/generators/populators/NewMaterialPopulator.java b/src/main/java/world/bentobox/caveblock/generators/populators/NewMaterialPopulator.java new file mode 100644 index 0000000..8838939 --- /dev/null +++ b/src/main/java/world/bentobox/caveblock/generators/populators/NewMaterialPopulator.java @@ -0,0 +1,96 @@ +package world.bentobox.caveblock.generators.populators; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.LimitedRegion; +import org.bukkit.generator.WorldInfo; +import world.bentobox.caveblock.Utils; +import world.bentobox.caveblock.generators.Ore; + +import java.util.*; + +public class NewMaterialPopulator extends BlockPopulator { + private final Map> ores = new EnumMap<>(World.Environment.class); + + public NewMaterialPopulator() { + // Source https://minecraft.fandom.com/wiki/Blob + List worldOres = new ArrayList<>(); + worldOres.add(new Ore(-64, 16, Material.DIAMOND_ORE, 1, 10, true)); + worldOres.add(new Ore(-64, 64, Material.LAPIS_ORE, 1, 7, true)); + worldOres.add(new Ore(-64, 30, Material.GOLD_ORE, 2, 9, true)); + worldOres.add(new Ore(0, 16, Material.TUFF, 2, 33, false)); + worldOres.add(new Ore(-64, 16, Material.REDSTONE_ORE, 8, 8, true)); + worldOres.add(new Ore(0, 16, Material.GRAVEL, 8, 33, false)); + worldOres.add(new Ore(0, 79, Material.GRANITE, 5, 33, false)); + worldOres.add(new Ore(0, 79, Material.ANDESITE, 5, 33, false)); + worldOres.add(new Ore(0, 79, Material.DIORITE, 5, 33, false)); + worldOres.add(new Ore(32, 320, Material.EMERALD_ORE, 11, 1, true)); + worldOres.add(new Ore(95, 136, Material.COAL_ORE, 20, 17, false)); + worldOres.add(new Ore(0, 96, Material.COPPER_ORE, 20, 9, true)); + worldOres.add(new Ore(-64, 320, Material.IRON_ORE, 20, 9, true)); + worldOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false)); + ores.put(World.Environment.NORMAL, worldOres); + List netherOres = new ArrayList<>(); + netherOres.add(new Ore(1, 22, Material.ANCIENT_DEBRIS, 1, 5, true)); + netherOres.add(new Ore(-64, 30, Material.NETHER_GOLD_ORE, 2, 9, true)); + netherOres.add(new Ore(0, 16, Material.GRAVEL, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.BASALT, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.BLACKSTONE, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.FIRE, 8, 33, false)); + netherOres.add(new Ore(200, 320, Material.GLOWSTONE, 8, 33, false)); + netherOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false)); + netherOres.add(new Ore(-64, 320, Material.LAVA, 8, 33, false)); + netherOres.add(new Ore(0, 16, Material.MAGMA_BLOCK, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.CRIMSON_FUNGUS, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.WARPED_FUNGUS, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.CRIMSON_NYLIUM, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.WARPED_NYLIUM, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.SHROOMLIGHT, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.CRIMSON_STEM, 8, 33, false)); + netherOres.add(new Ore(0, 320, Material.WARPED_STEM, 8, 33, false)); + netherOres.add(new Ore(-64, 34, Material.SOUL_SOIL, 20, 17, false)); + netherOres.add(new Ore(0, 96, Material.NETHER_QUARTZ_ORE, 20, 9, true)); + netherOres.add(new Ore(-64, 320, Material.BONE_BLOCK, 20, 9, true)); + ores.put(World.Environment.NETHER, netherOres); + List endOres = new ArrayList<>(); + endOres.add(new Ore(32, 320, Material.PURPUR_BLOCK, 11, 1, true)); + endOres.add(new Ore(95, 136, Material.OBSIDIAN, 20, 17, false)); + endOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false)); + ores.put(World.Environment.THE_END, endOres); + } + + @Override + public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) { + for (int y = worldInfo.getMinHeight(); y < worldInfo.getMaxHeight(); y++) { + for (Ore o : ores.get(worldInfo.getEnvironment())) { + if (y > o.minY() && y < o.maxY() && random.nextInt(100) <= o.chance()) { + pasteBlob(worldInfo, random, chunkX, chunkZ, limitedRegion, y, o); + if (o.cont()) { + break; + } + } + } + } + } + + private void pasteBlob(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion, int y, Ore o) { + //int blobSize = (int) (((double)random.nextInt(o.blob()) / 3) + 1); + int blobSize = 1; + int offset = random.nextInt(16); + for (int x = Math.max(0, offset - blobSize); x < Math.min(16, offset + blobSize); x++) { + for (int z = Math.max(0, offset - blobSize); z < Math.min(16, offset + blobSize); z++) { + for (int yy = Math.max(worldInfo.getMinHeight(), y - blobSize); yy < Math.min(worldInfo.getMaxHeight(), y + blobSize); yy++) { + Location location = Utils.getLocationFromChunkLocation(x, yy, z, chunkX, chunkZ); + if (!limitedRegion.isInRegion(location)) { + continue; + } + if (limitedRegion.getType(location).isSolid() && random.nextBoolean()) { + limitedRegion.setType(location, o.material()); + } + } + } + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1da2b6e..7e2cf37 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -93,6 +93,11 @@ world: # This indicate how many times block should be tried to generate. # /!\ 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. generation-tries: 2 + # Should we use the new material generator ? + # This will generate ores and blocks similar to how vanilla does, + # but it will override the blocks settings of each world. + # /!\ 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. + use-new-material-generator: false normal: # # Make over world roof of bedrock, if false, it will be made from stone diff --git a/src/main/resources/locales/pl.yml b/src/main/resources/locales/pl.yml new file mode 100644 index 0000000..87939ed --- /dev/null +++ b/src/main/resources/locales/pl.yml @@ -0,0 +1,301 @@ +--- +caveblock: + sign: + line0: "&cCaveBlock" + line1: Witaj! + line2: "[name]" + line3: Zacznij kopać! &c<3 + informational: + to-nether: Uuu... Pech, wpadłes do Netheru. + to-the-end: To już jest koniec. + to-normal: Powrót do jaskini. + general: + errors: + no-island: "&cNie masz jaskini!" + player-has-island: "&cGracz już posiada jaskinie!" + player-has-no-island: "&cTen gracz nie posiada jaskini!" + already-have-island: "&cJuż masz jaskinie!" + no-safe-location-found: "&cNie można znaleźć bezpiecznego miejsca dla teleportu + do jaskini." + not-owner: "&cTo nie twoja jaskinia!" + commands: + admin: + team: + add: + name-has-island: "&c[name] posiada jaskinie. Pierw wyrejestruj lub usuń!" + success: "&b[name]&a został dodany do jaskini gracza &b[owner]." + kick: + success: "&b[name] &azostał wyrzucony z jaskini gracza &b[owner]." + setowner: + description: przenosi własności jaskini do gracza + already-owner: "&c[name] jest już właścicielem tej jaskini!" + success: "&b name]&a jest teraz właścicielem tej jaskini." + range: + description: Zasięg komendy Jaskinii Admina + display: + description: pokaż/ukryj wskaźniki zasięgu jaskiń + hint: |- + &cCzerwone ikony bariery &fpokazują aktualny limit zasięgu chronionego jaskini. + &7Szare cząsteczki &fpokazują maksymalny limit jaskini. + &aZielone cząsteczki &fpokazują domyślny zasięg ochrony, jeśli zasięg ochrony jaskini różni się od niego. + set: + description: ustawia zasięg ochrony jaskini + success: "&aUstaw zasięg ochrony jaskini na &b[liczba]&a." + reset: + description: resetuje zasięg chroniony jaskini do wartości domyślnych świata + success: "&aZresetuj zasięg ochrony jaskini na &b[numer]&a." + register: + description: zarejestruj gracza w niezarejestrowanej jaskini, w której się + znajdujesz + registered-island: "&aZarejestrowano gracza do jaskini w [xyz]." + already-owned: "&cJaskinia jest już własnością innego gracza!" + no-island-here: "&cTutaj nie ma jaskini. Potwierdź, aby utworzyć." + in-deletion: "&cTo miejsce jaskini jest obecnie usuwane. Spróbuj później." + cannot-make-island: "&cPrzepraszamy, nie można tu umieścić jaskini. Zobacz + konsolę, aby poznać możliwe błędy." + unregister: + description: wyrejestruj właściciela z jaskini, ale zachowaj bloki jaskiniowe + unregistered-island: "&aNiezarejestrowany gracz z jaskini w [xyz]." + info: + description: uzyskaj informacje o tym, gdzie jesteś lub o jaskini gracza + no-island: "&cNie jesteś teraz w jaskini ..." + title: "======== Informacje o jaskini ========" + islands-in-trash: "&dGracz ma jaskinie w koszu." + is-spawn: Wyspa jest jaskinią spawnu + switchto: + description: zmień jaskinię gracza na ponumerowaną znajdującą się w koszu + out-of-range: "&cNumer musi mieścić się w przedziale od 1 do [number]. Użyj + &l[label] trash [player], &r&caby zobaczyć numery jaskiń" + trash: + no-unowned-in-trash: "&cŻadnych bezpańskich jaskiń w śmieciach" + no-islands-in-trash: "&cGracz nie ma jaskiń w koszu" + description: pokaż bezpańskie jaskinie lub jaskinie graczy w śmieciach + title: "&d=========== Jaskinie w koszu ===========" + count: "&l&dJaskinia [number]:" + use-switch: "&aUżyj &l[label] switchto &r&a aby przełączyć + gracza do jaskini w koszu" + emptytrash: + description: Usuń śmieci dla gracza lub wszystkie bezpańskie jaskinie w koszu + setrange: + description: ustaw zasięg jaskini gracza + range-updated: Zasięg jaskiń został zaktualizowany do [number] + tp: + description: teleportuj się do jaskini gracza + getrank: + description: zdobądź rangę gracza w swojej jaskini + rank-is: "&aRank to [range] w ich jaskini." + setrank: + description: ustaw rangę gracza w jego jaskini + setspawn: + description: ustaw jaskinię jako spawn dla tego świata + already-spawn: "&cTa jaskinia już się odradza!" + no-island-here: "&cNie ma tu jaskini." + confirmation: "&cCzy na pewno chcesz ustawić tę jaskinię jako miejsce odrodzenia + tego świata?" + resetflags: + description: Zresetuj wszystkie jaskinie do domyślnych ustawień flag w config.yml + delete: + description: usuwa jaskinię gracza + cannot-delete-owner: "&cWszyscy członkowie jaskini muszą zostać wyrzuceni + z jaskini przed jej usunięciem." + deleted-island: "&aWyspa w &e[xyz] &azostała pomyślnie usunięta." + island: + go: + description: teleportować cię do swojej jaskini + teleport: "&aTeleportuję Cię do Twojej jaskini." + help: + description: Główne dowództwo jaskini + create: + description: stwórz jaskinię, korzystając z opcjonalnego planu (wymaga pozwolenia) + too-many-islands: "&cNa tym świecie jest zbyt wiele jaskiń: nie ma wystarczająco + dużo miejsca, aby stworzyć twoją." + unable-create-island: "&cTwoja jaskinia nie może zostać wygenerowana, skontaktuj + się z administratorem." + creating-island: "&aTworzenie jaskini, proszę chwilę poczekać..." + pick: "&aWybierz jaskinię" + info: + description: wyświetlaj informacje o swojej jaskini lub jaskini gracza + near: + description: pokaż nazwy sąsiednich jaskiń wokół ciebie + the-following-islands: "&aW pobliżu znajdują się następujące jaskinie:" + no-neighbors: "&cNie masz bezpośrednio sąsiadujących jaskiń!" + reset: + description: uruchom ponownie jaskinię i usuń starą + must-remove-members: "&cMusisz usunąć wszystkich członków ze swojej jaskini, + zanim będziesz mógł ją ponownie uruchomić (/island team kick )." + sethome: + must-be-on-your-island: "&cMusisz być w swojej jaskini, aby wrócić do domu!" + home-set: "&6Twój dom w jaskini został ustawiony na bieżącą lokalizację." + setname: + description: ustaw nazwę dla swojej jaskini + resetname: + description: zresetuj nazwę jaskini + team: + coop: + description: zrób ranking kooperacyjny gracza w swojej jaskini + uncoop: + you-are-no-longer-a-coop-member: "&cNie jesteś już członkiem współpracy + w jaskini [name]" + all-members-logged-off: "&cWszyscy członkowie jaskini wylogowali się, więc + nie jesteś już członkiem kooperacji w jaskini [name]" + trust: + description: dać graczowi zaufaną rangę w swojej jaskini + invite: + description: zaproś gracza do swojej jaskini + name-has-invited-you: "&a[name] zaprasza Cię do swojej jaskini." + you-will-lose-your-island: "&cOSTRZEŻENIE! Stracisz swoją jaskinię, jeśli + się zgodzisz!" + errors: + island-is-full: "&cTwoja jaskinia jest pełna, nie możesz nikogo zaprosić." + accept: + you-joined-island: "&aDołączyłeś do jaskini! Użyj /[etykieta] informacji + o zespole, aby zobaczyć innych członków." + name-joined-your-island: "&a[name] dołączył do Twojej jaskini!" + confirmation: |- + &cCzy na pewno chcesz przyjąć to zaproszenie? + &c&lZgubisz&n&r &c&lyswoją obecną jaskinię! + reject: + you-rejected-invite: "&aOdrzuciłeś zaproszenie do jaskini." + name-rejected-your-invite: "&c[name] odrzucił Twoje zaproszenie do jaskini!" + cancel: + description: anuluj oczekujące zaproszenie do swojej jaskini + leave: + description: opuść swoją jaskinię + left-your-island: "&c[name] &rozszczep swoją jaskinię" + kick: + description: usuń członka ze swojej jaskini + owner-kicked: "&cWłaściciel wykopał cię z jaskini!" + success: "&b[name] &został wyrzucony z Twojej jaskini." + demote: + description: zdegraduj gracza w swojej jaskini w dół o rangę + promote: + description: awansować gracza w swojej jaskini na wyższą rangę + setowner: + description: przenieść własność jaskini na członka + errors: + target-is-not-member: "&cTen gracz nie jest częścią twojej drużyny jaskiniowej!" + name-is-the-owner: "&a[name] jest teraz właścicielem jaskini!" + you-are-the-owner: "&aJesteś teraz właścicielem jaskini!" + ban: + description: zbanuj gracza ze swojej jaskini + cannot-ban-more-players: "&c Osiągnąłeś limit banów, nie możesz zbanować więcej + graczy ze swojej jaskini." + player-banned: "&b[name]&c jest teraz zablokowany w Twojej jaskini." + owner-banned-you: "&b[name]&c zabronił Ci wstępu do swojej jaskini!" + you-are-banned: "&bNie masz dostępu do tej jaskini!" + unban: + description: odbanuj gracza z twojej jaskini + player-unbanned: "&b[name]&a jest teraz odblokowany w Twojej jaskini." + you-are-unbanned: "&b[name]&a odblokował cię w swojej jaskini!" + banlist: + noone: "&aNikt nie jest zabroniony w tej jaskini." + settings: + description: wyświetl ustawienia jaskini + expel: + description: wyrzuć gracza ze swojej jaskini + not-on-island: "&cTego gracza nie ma w twojej jaskini!" + player-expelled-you: "&b[name]&c wyrzucił cię z jaskini!" + ranks: + owner: Król krasnoludów + sub-owner: Krasnoludzki Rycerz + member: Krasnolud + trusted: Zaufane + coop: Kooperacja + visitor: Człowiek + banned: Ork + protection: + flags: + ENDERMAN_GRIEFING: + description: |- + &aEndermen może usunąć + &blokady z jaskiń + name: Rozpacz Endermana + ENTER_EXIT_MESSAGES: + island: Jaskinia [name] + GEO_LIMIT_MOBS: + description: |- + &aUsuń moby, które idą + &poza chronionym + &ostań w przestrzeni + name: "&eOgranicz moby do jaskini" + ISLAND_RESPAWN: + description: |- + &aGracze odradzają się + &w ich jaskini + name: Odrodzenie w jaskini + LIQUIDS_FLOWING_OUT: + name: Płyny wypływające poza jaskinie + description: |- + &aPrzełącz, czy płyny mogą wypływać na zewnątrz + &a zasięgu ochrony jaskini. + LOCK: + description: Przełącz blokadę + name: Zablokuj jaskinię + NATURAL_SPAWNING_OUTSIDE_RANGE: + name: Naturalne stworzenie odradzające się poza zasięgiem + description: |- + &aPrzełącz czy stworzenia (zwierzęta i + i potwory) mogą naturalnie odradzać się na zewnątrz + &aa zasięg ochrony jaskini. + + &cPamiętaj, że nie zapobiega to stworzeniom + &cby odradzać się za pomocą generatora mobów lub spawnu + &ceg. + OFFLINE_GROWTH: + description: |- + &aPo wyłączeniu rośliny + &nie będzie rosnąć w jaskiniach + &kiedy wszyscy członkowie są offline. + &aMoże pomóc zmniejszyć opóźnienia. + name: Rozwój offline + OFFLINE_REDSTONE: + description: |- + &aKiedy wyłączone, czerwony kamień + &nie będzie działać w jaskiniach + &gdzie wszyscy członkowie są offline. + &aMoże pomóc zmniejszyć opóźnienia. + name: Offline Redstone + PISTON_PUSH: + description: |- + &aZezwalaj tłokom na pchanie + &blokuje na zewnątrz jaskini + name: Popychanie tłoka + REMOVE_MOBS: + description: |- + &aUsuń potwory, gdy + &ateleport do jaskini + name: Usuń potwory + TREES_GROWING_OUTSIDE_RANGE: + name: Drzewa rosnące poza zasięgiem + description: |- + &aPrzełącz, czy drzewa mogą rosnąć na zewnątrz i + zakres ochrony &acave, czy nie. + PREVENT_TELEPORT_WHEN_FALLING: + name: Zapobiegaj teleportacji podczas upadku + description: |- + &aZapobiegaj teleportacji graczy + &z powrotem do swojej jaskini za pomocą poleceń + i jeśli spadają. + hint: "&cNie możesz teleportować się z powrotem do swojej jaskini, gdy spadasz." + locked: "&cTa jaskinia jest zamknięta!" + protected: "&cJaskinia chroniona: [description]" + spawn-protected: "&cSpawn chroniony: [description]" + panel: + PROTECTION: + description: |- + &aUstawienia ochrony + &dla tej jaskini + SETTING: + description: |- + &aUstawienia ogólne + &dla tej jaskini +protection: + flags: + SKY_WALKER_FLAG: + description: |- + &5&oPozwala to włączyć/wyłączyć + &5&możliwość chodzenia po + &5&otop świata jaskiń + &5&obez dodatkowych uprawnień. + name: Sky Walker + hint: Pozwala chodzić po suficie jaskini. diff --git a/src/main/resources/locales/vi.yml b/src/main/resources/locales/vi.yml new file mode 100644 index 0000000..08c34ad --- /dev/null +++ b/src/main/resources/locales/vi.yml @@ -0,0 +1,292 @@ +########################################################################################### +# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # +# the one at http://yaml-online-parser.appspot.com # +########################################################################################### + +caveblock: + sign: + line0: "&cCaveBlock" + line1: "Chào mừng!" + line2: "[name]" + line3: "Đào đi! &c<3" + + informational: + to-nether: "Rất tệ khi vào địa ngục." + to-the-end: "Kết thúc rồi." + to-normal: "Về hang của bạn." + # Override BentoBox default command strings + # General strings + general: + errors: + no-island: "&cBạn không có hang!" + player-has-island: "&cNgười chơi đã có hang!" + player-has-no-island: "&cNgười chơi không có hang!" + already-have-island: "&cBạn đã có hang!" + no-safe-location-found: "&cKhông thể tìm thấy vị trí an toàn trong hang." + not-owner: "&cBạn không phải chủ hang!" + commands: + # Parameters in <> are required, parameters in [] are optional + admin: + team: + add: + name-has-island: "&c[name] đã có hang. Huỷ hoặc xoá nó trước!" + success: "&b[name]&a đã được thêm vào hang của &b[owner]&a." + kick: + success: "&b[name] &ađã bị đuổi từ hang của &b[owner]&a." + setowner: + description: "chuyển quyền chủ hang cho người chơi" + already-owner: "&c[name] đã là chủ hang!" + success: "&b[name]&a giờ là chủ hang." + range: + description: "lệnh độ rộng hang của Admin" + display: + description: "hiện/ẩn đánh dấu độ rộng hang" + hint: |- + &cKí tự Rào chặn đỏ &fthể hiện độ rộng vùng bảo vệ của hang. + &7Hạt Xám &fthể hiện giới hạn của hang. + &aHạt Xanh &fthể hiện vùng bảo vệ mặc định nếu vùng bảo vệ của hang khác mặc định. + set: + description: "chỉnh vùng bảo vệ hang" + success: "&aĐã chỉnh vùng bảo vệ hang thành &b[number]&a." + reset: + description: "chỉnh vùng bảo vệ hang về mặc định" + success: "&aĐã chỉnh vùng bảo vệ hang thành &b[number]&a." + register: + description: "đăng kí người chơi vào hang không chủ ở vị trí của bạn" + registered-island: "&aĐã đăng kí người chơi ở hang [xyz]." + already-owned: "&cHang đã có chủ!" + no-island-here: "&cKhông có hang ở đây. Xác nhận để tạo." + in-deletion: "&cHang đang được xoá. Thử lại sau." + cannot-make-island: "&c Hang không thể đặt ở đây. Xem lỗi trên bảng điều khiển." + unregister: + description: "huỷ quyền chủ hang, nhưng giữ lại các khối trong hang" + unregistered-island: "&aĐã huỷ đăng kí người chơi ở hang [xyz]." + info: + description: "lấy thông về nơi bạn ở hoặc hang của người chơi" + no-island: "&cBạn không ở một hang..." + title: "========== Thông tin Hang ============" + islands-in-trash: "&dNgười chơi có hang trong thùng rác." + is-spawn: "Đảo là hang triệu hồi" + switchto: + description: "chuyển hang của người chơi thành một số trong thùng rác" + out-of-range: "&cSố phải từ 1 đến [number]. Dùng &l[label] trash [player] &r&cđể xem số hang" + trash: + no-unowned-in-trash: "&cKhông có hang không chủ trong thùng rác" + no-islands-in-trash: "&cNgười chơi không có hang trong thùng rác" + description: "xem hang không chủ hoặc của người chơi trong thùng rác" + title: "&d=========== Hang trong Thùng Rác ===========" + count: "&l&dHang [number]:" + use-switch: "&aDùng &l[label] switchto &r&a để chuyển người chơi vào hang trong thùng rác" + emptytrash: + description: "Dọn rác cho người chơi, hoặc toàn bộ hang không chủ trong thùng rác" + setrange: + description: "chỉnh độ rộng hang của người chơi" + range-updated: "Đã chỉnh độ rộng của hang thành [number]" + tp: + description: "dịch chuyển đến hang của người chơi" + getrank: + description: "xem cấp độ của người chơi trong hang" + rank-is: "&aCấp độ là [rank] ở hang của họ." + setrank: + description: "chỉnh cấp độ của người chơi ở hang của họ" + setspawn: + description: "chỉnh một hang thành nơi bắt đầu ở thế giới này" + already-spawn: "&cHang này đã là nơi bắt đầu!" + no-island-here: "&cKhông có hang ở đây." + confirmation: "&cBạn có chắc là chọn hang này làm nơi bắt đầu ở thế giới này?" + resetflags: + description: "Đặt lại cờ của các hang về mặc định trong config.yml" + delete: + description: "xoá hang của người chơi" + cannot-delete-owner: "&cThành viên của hang phải bị đuổi trước khi xoá." + deleted-island: "&aĐảo &e[xyz] &ađã được xoá thành công." + island: + go: + description: "dịch chuyển đến hang của bạn" + teleport: "&aĐang dịch chuyển đến hang của bạn." + help: + description: "Lệnh hang chính" + create: + description: "tạo hang, dùng bản vẽ nếu có (cần quyền)" + too-many-islands: "&cQuá nhiều hang ở thế giới này: không đủ khoảng trống cho khu của bạn." + unable-create-island: "&cHang của bạn không được tạo, hãy liên hệ quản trị viên." + creating-island: "&aĐang tạo hang, chờ một chút..." + pick: "&aChọn hang" + info: + description: "xem thông tin hang của bạn hoặc của người chơi" + near: + description: "xem tên của hang kế bên bạn" + the-following-islands: "&aHang kế bên bạn:" + no-neighbors: "&cKhông có hang kế bên bạn!" + reset: + description: "tạo lại hang và xoá hang cũ" + must-remove-members: "&cBạn phải xoá thành viên khỏi hang trước khi xoá (/[label] team kick )." + sethome: + must-be-on-your-island: "&cBạn phải ở hang của bạn để đặt nhà!" + home-set: "&6Nhà của hang đã đặt ở vị trí của bạn." + setname: + description: "đặt tên cho hang" + resetname: + description: "đặt lại tên của hang" + team: + coop: + description: "cho người chơi cấp chơi cùng với hang của bạn" + uncoop: + you-are-no-longer-a-coop-member: '&cBạn không còn chơi cùng với hang của [name].' + all-members-logged-off: '&c Người chơi ở hang đã thoát hết nên bạn không còn chơi cùng với hang của [name].' + trust: + description: "cho người chơi cấp tin tưởng với hang bạn" + invite: + description: "mời người chơi vào hang của bạn" + name-has-invited-you: "&a[name] đã mời bạn vào hang của họ." + you-will-lose-your-island: "&cCHÚ Ý! Bạn sẽ mất hang của bạn nếu chấp nhận lời mời" + errors: + island-is-full: "&cHang đã đầy, bạn không thể mời thêm." + accept: + you-joined-island: "&aBạn đã vào hang! Dùng /[label] team info để xem thành viên khác." + name-joined-your-island: "&a[name] đã vào hang của bạn!" + confirmation: |- + &cBạn có chắc muón chấp nhận lời mời này? + &c&lBạn sẽ &nMẤT&r &c&lhang hiện tại của bạn! + reject: + you-rejected-invite: "&aBạn đã từ chối lời mời vào hang." + name-rejected-your-invite: "&c[name] đã từ chối lời mời của bạn!" + cancel: + description: "huỷ lời mời đang chờ vào hang của bạn" + leave: + description: "rời hang của bạn" + left-your-island: "&c[name] &cđã rời hang của bạn" + kick: + description: "xoá thành viên khỏi hang của bạn" + owner-kicked: "&cChủ hang đã đuổi bạn!" + success: "&b[name] &ađã bị đuổi khỏi hang của bạn." + demote: + description: "hạ cấp của người chơi trong hang" + promote: + description: "nâng cấp của người chơi trong hang" + setowner: + description: "chuyển quyền chủ hang cho người chơi" + errors: + target-is-not-member: "&cNgười chơi đó không ở trong đội của bạn!" + name-is-the-owner: "&a[name] giờ là chủ hang!" + you-are-the-owner: "&aBạn giờ là chủ hang!" + ban: + description: "cấm người chơi khỏi hang của bạn" + cannot-ban-more-players: "&cĐã đạt giới hạn cấm, bạn không thể cấm thêm người." + player-banned: "&b[name]&c đã bị cấm khỏi hang của bạn." + owner-banned-you: "&b[name]&c đã cấm bạn khỏi hang của họ!" + you-are-banned: "&bBạn đã bị cấm ở hang này!" + unban: + description: "bỏ cấm người chơi khỏi hang của bạn" + player-unbanned: "&b[name]&a không còn bị cấm khỏi hang của bạn." + you-are-unbanned: "&b[name]&a huỷ cấm bạn khỏi hang của họ!" + banlist: + noone: "&aKhông ai bị cấm ở hang này." + settings: + description: "xem tuỳ chọn hang" + expel: + description: "trục xuất người chơi khỏi hang của bạn" + not-on-island: "&cNgười chơi đó không ở hang của bạn!" + player-expelled-you: "&b[name]&c đã trục xuất bạn khỏi hang của họ!" + + ranks: + owner: "Vua Người Lùn" + sub-owner: "Hiệp Sĩ Người Lùn" + member: "Người Lùn" + trusted: "Tin Tưởng" + coop: "Chơi Cùng" + visitor: "Con Người" + banned: "Orc" + + protection: + flags: + ENDERMAN_GRIEFING: + description: |- + &aNgười Ender có thể cướp + &akhối khỏi hang + name: "Trộm bởi Người Ender" + ENTER_EXIT_MESSAGES: + island: "hang của [name]" + GEO_LIMIT_MOBS: + description: |- + &a Xóa các quái đã rời khỏi + &a khu vực bảo vệ trong hang + name: "&eGiới hạn quái trong đảo" + ISLAND_RESPAWN: + description: |- + &aNgười chơi hồi sinh + &aở hang của họ + name: "Hồi sinh tại hang" + LIQUIDS_FLOWING_OUT: + name: "Chất lỏng tràn ra khỏi hang" + description: |- + &aBật/Tắt việc chất lỏng có thể + &atràn ra khỏi khu vực bảo vệ của hang. + LOCK: + description: "Bật/Tắt khóa" + name: "Khoá đảo" + NATURAL_SPAWNING_OUTSIDE_RANGE: + name: "Sinh quái tự nhiên ngoài hang" + description: |- + &aBật/Tắt cho phép con vật (động vật và + &aquái vật) có thể sinh tự nhiên ngoài + &akhu vực bảo vệ của hang. + + &cLưu ý là nó không chặn việc sinh quái + &cbằng lồng triệu hồi hoặc trứng. + OFFLINE_GROWTH: + description: |- + &aKhi tắt, cây trồng + &asẽ không mọc lớn trong hang + &anếu tất cả thành viên đều ngoại tuyến. + &aCó thể giúp giảm lag. + name: "Mọc cây khi ngoại tuyến" + OFFLINE_REDSTONE: + description: |- + &aKhi tắt, đá đỏ + &asẽ không hoạt động trong hang + &anếu tất cả thành viên đều ngoại tuyến. + &aCó thể giúp giảm lag. + &aKhông ảnh hưởng đảo triệu hồi. + name: "Đá đỏ khi ngoại tuyến" + PISTON_PUSH: + description: |- + &aCho phép pít tông đẩy + &akhối ra khỏi hang + name: "Pít tông đẩy khối" + REMOVE_MOBS: + description: |- + &aXoá quái khi dịch + &achuyển đến đảo + name: "Xoá quái" + TREES_GROWING_OUTSIDE_RANGE: + name: "Cây mọc ngoài đảo" + description: |- + &aBật/Tắt việc cây có thể mọc ngoài + &akhu vực bảo vệ trong hang. + PREVENT_TELEPORT_WHEN_FALLING: + name: "Chặn dịch chuyển khi đang rời" + description: |- + &aChặn người chơi khỏi việc dịch chuyển + &avề đảo của họ bằng lệnh khi đang rơi. + hint: '&cBạn không thể làm điều đó khi đang rơi.' + locked: "&cHang đã bị khoá!" + protected: "&cĐã bảo vệ hang: [description]" + spawn-protected: "&cĐã bảo vệ nơi bắt đầu: [description]" + + panel: + PROTECTION: + description: |- + &aTuỳ chỉnh bảo vệ + &acho hang này + SETTING: + description: |- + &aTuỳ chỉnh tổng quan + &acho hang này + +protection: + flags: + SKY_WALKER_FLAG: + description: "&5&oCho phép bật/tắt\n&5&oquyền để đi trên\n&5&ođỉnh của thế giới hang\n&5&omà không cần thêm quyền." + name: "Bước Trên Trời Cao" + hint: "Cho phép đi trên đỉnh hang." \ No newline at end of file diff --git a/src/main/resources/locales/zh-CN.yml b/src/main/resources/locales/zh-CN.yml index dabc0a1..14f858a 100644 --- a/src/main/resources/locales/zh-CN.yml +++ b/src/main/resources/locales/zh-CN.yml @@ -1,286 +1,282 @@ ---- caveblock: sign: - line0: "&c方块洞穴" - line1: 欢迎! - line3: 开始挖掘! &c <3 + line0: "&c洞穴生存" + line1: "欢迎!" line2: "[name]" + line3: "开始挖掘吧! &c<3" + informational: - to-nether: 真倒霉到地狱了。 - to-the-end: 您已经到了末地。 - to-normal: 回到你的洞穴。 + to-nether: "太不走运了! 掉进了下界." + to-the-end: "您到达了末地." + to-normal: "回到您的洞穴." general: errors: - no-island: "&c您没有洞穴!" - player-has-island: "&c玩家已经有一个山洞了!" - player-has-no-island: "&c该玩家没有洞穴!" - already-have-island: "&c您已经有一个山洞!" - no-safe-location-found: "&c在山洞找不到传送您的安全地点。" - not-owner: "&c您不是洞穴的所有者!" + no-island: "&c您还没有洞穴!" + player-has-island: "&c玩家已有洞穴!" + player-has-no-island: "&c玩家还没有洞穴!" + already-have-island: "&c您已经拥有洞穴!" + no-safe-location-found: "&c无法将您传送到洞穴中, 因为没有找到安全的位置." + not-owner: "&c您不是您洞穴的主人!" commands: admin: team: add: - name-has-island: "&c [name]有一个山洞。首先注销或删除它们!" - success: "&b [name]&a已添加到&b [owner]&a的洞穴中。" + name-has-island: "&c[name] 已有洞穴. 请先反注册或删除它们!" + success: "&b[name]&a 已被添加到 &b[owner]&a 的洞穴." kick: - success: "&b [name]&ahas被踢出了&b [owner]&a的山洞。" + success: "&b[name] &a已被 &b[owner]&a 的洞穴移出." setowner: - description: 将洞穴所有权转移给玩家 - already-owner: "&c [name]已经是该洞穴的所有者!" - success: "&b [name]&a现在是这个洞穴的所有者。" + description: "将洞穴的所有权转让给玩家" + already-owner: "&c[name] 玩家已经是此洞穴的主人了!" + success: "&b[name]&a 现在是此洞穴的主人." range: - description: 管理员洞穴范围命令 + description: "管理员洞穴边界命令" display: - description: 显示/隐藏洞穴范围指示器 + description: "显示/隐藏洞穴边界" hint: |- - &c红色屏障图标&f显示当前的洞穴保护范围限制。 - &7灰色粒子&f显示最大洞穴极限。 - &a绿色粒子&f如果洞穴保护范围不同于默认保护范围,则显示默认保护范围。 + &c 红色屏障图标 &f 显示洞穴现在被保护的范围. + &7 灰色粒子 &f 显示最大边界范围. + &a 绿色粒子 &f 显示默认被保护的边界, 如果现在的边界不与其重合的话. set: - description: 设置洞穴保护范围 - success: "&a将洞穴保护范围设置为&b [number]&a。" + description: "设置洞穴被保护的边界范围" + success: "&a洞穴被保护的范围更新至 &b[number]&a." reset: - description: 将洞穴保护范围重置为世界默认值 - success: "&a将洞穴保护范围重置为&b [number]&a。" + description: "重置洞穴被保护的范围到当前世界的默认值" + success: "&a重置洞穴被保护的范围至 &b[number]&a." register: - description: 注册玩家到您所在的无人洞 - registered-island: "&a注册玩家到[xyz]洞穴。" - already-owned: "&c洞穴已被另一位玩家拥有!" - no-island-here: "&c这里没有洞穴。确认做一个。" - in-deletion: "&c该洞穴空间当前正在被删除。等会再试。" - cannot-make-island: "&c抱歉,不能在此处放置洞穴。请参阅控制台以获取可能的错误。" + description: "将玩家注册到您所在的未被拥有的洞穴中" + registered-island: "&a在 [xyz] 将玩家注册到洞穴中." + already-owned: "&c此洞穴已被其他玩家所有!" + no-island-here: "&c这里还没有 box. 确认以创建一个." + in-deletion: "&c此区域正在重新生成. 请稍后重试." + cannot-make-island: "&c抱歉, 无法在此处生成洞穴. 从后台查看可能的错误." unregister: - description: 从山洞中注销所有者,但保留山洞块 - unregistered-island: "&a来自[xyz]洞穴的未注册玩家。" + description: "反注册洞穴的主人, 同时保留洞穴中的方块" + unregistered-island: "&a在 [xyz] 将玩家从洞穴中反注册." info: - description: 获取有关您所在位置或玩家洞穴的信息 - no-island: "&c您现在不在山洞里..." - title: "==========洞穴信息============" - islands-in-trash: "&d玩家在垃圾桶中有洞穴。" - is-spawn: 岛是出生点 + description: "获取您所在区域或相应玩家洞穴的信息" + no-island: "&c您未在一个洞穴中......" + title: "========== 洞穴信息 ============" + islands-in-trash: "&d玩家拥有废弃的洞穴." + is-spawn: "该区域是主城" switchto: - description: 将玩家的洞穴切换到垃圾桶中的第一洞 - out-of-range: "&c数字必须介于1到[number]之间。使用&l [label]垃圾[player]&r&c查看洞穴编号" + description: "将玩家的洞穴切换到废弃的洞穴中的第一位" + out-of-range: "&c数字必须从 1 到 [number]. 输入 &l[label] trash [player] &r&c来查看洞穴数量" trash: - no-unowned-in-trash: "&c垃圾桶中没有无人认领的洞穴" - no-islands-in-trash: "&c玩家没有洞穴在垃圾桶中" - description: 在垃圾桶中显示无人洞穴或玩家的洞穴 - title: "&d ============垃圾洞===========" + no-unowned-in-trash: "&c废弃的洞穴中没有无主人的洞穴" + no-islands-in-trash: "&c玩家没有废弃的洞穴" + description: "在废弃的洞穴中显示无主人的洞穴或玩家的洞穴" + title: "&d=========== 废弃的洞穴 ===========" count: "&l&d洞穴 [number]:" - use-switch: "&a使用&l [label]切换到 &r&a将玩家洞穴切换到垃圾桶" + use-switch: "&a输入 &l[label] switchto &r&a 将玩家切换到废弃的洞穴中" emptytrash: - description: 清除玩家的垃圾桶,或垃圾桶中所有未拥有的洞穴 + description: "给玩家清除废弃的洞穴, 或清除所有无主人的废弃的洞穴" setrange: - description: 设定玩家洞穴的范围 - range-updated: 洞穴范围更新为[数字] + description: "设置玩家洞穴的范围" + range-updated: "洞穴范围更新至 [number]" tp: - description: 传送到玩家的洞穴 + description: "传送到玩家的洞穴" getrank: - description: 在他们的洞穴中获得玩家的排名 - rank-is: "&aRank在他们的洞穴中[排名]。" + description: "查看玩家在其洞穴中的地位" + rank-is: "&a玩家在其洞穴中的地位是 [rank]." setrank: - description: 设定玩家在洞穴中的等级 + description: "设置玩家在其洞穴中的地位" setspawn: - description: 为这个世界设置一个洞穴 - already-spawn: "&c这个洞穴已经是产卵了!" - no-island-here: "&c这里没有洞穴。" - confirmation: "&c您确定要将此洞穴设置为这个世界的生成物吗?" + description: "将洞穴设置为当前世界的主城" + already-spawn: "&c此洞穴已经是主城了!" + no-island-here: "&c这里还没有洞穴." + confirmation: "&c确认要将将洞穴设置为当前世界的主城吗?" resetflags: - description: 将所有洞穴重置为config.yml中的默认标志设置 + description: "重置所有洞穴的 flag 值成 config.yml 中的默认值" delete: - description: 删除玩家的洞穴 - cannot-delete-owner: "&c删除所有洞穴成员之前,必须将其踢出洞穴。" - deleted-island: "&e [xyz]&ahas中的&aIsland已成功删除。" + description: "删除一名玩家的洞穴" + cannot-delete-owner: "&c在删除此洞穴之前, 必须移出此洞穴中的所有成员." + deleted-island: "&a成功删除位于 &e[xyz] &a处的洞穴." island: go: - description: 传送你到你的洞穴 - teleport: "&a将您传送到山洞。" + description: "传送到您的洞穴" + teleport: "&a正在传送到您的洞穴." help: - description: 主要洞穴命令 + description: "洞穴主命令" create: - description: 使用可选的蓝图创建一个洞穴(需要许可) - too-many-islands: "&c这个世界上有太多的洞穴:没有足够的空间来创建您的洞穴。" - unable-create-island: "&c您的洞穴无法生成,请与管理员联系。" - creating-island: "&a创建您的洞穴,请稍等..." - pick: "&a选择一个山洞" + description: "使用模板创建一个新的洞穴 (需要权限)" + too-many-islands: "&c世界中含有太多洞穴了: 没有空间创建您的洞穴." + unable-create-island: "&c生成洞穴失败, 请联系管理员." + creating-island: "&a生成洞穴中, 请稍后..." + pick: "&a选择一个洞穴" info: - description: 显示有关您的洞穴或玩家洞穴的信息 + description: "显示您或相应玩家的洞穴信息" near: - description: 显示您周围的洞穴名称 - the-following-islands: "&a附近有以下洞穴:" - no-neighbors: "&c您没有紧邻的洞穴!" + description: "显示周围洞穴的名称" + the-following-islands: "&a周围的洞穴有:" + no-neighbors: "&c您的周围没有其它洞穴!" reset: - description: 重新启动您的洞穴并删除旧的 - must-remove-members: "&c您必须先从洞穴中删除所有成员,然后才能重新启动洞穴(/岛国队踢<player>)。" + description: "删除现有的洞穴并重新开始" + must-remove-members: "&c在您重新开始之前, 您必须移出洞穴中的所有成员 (/island team kick )." sethome: - must-be-on-your-island: "&c您必须在洞穴里才能回家!" - home-set: "&6您的洞穴之家已设置为您当前的位置。" + must-be-on-your-island: "&c必须在洞穴中才能设置家的位置!" + home-set: "&6洞穴家的位置已设置到您当前位置." setname: - description: 为你的洞穴命名 + description: "设置您洞穴的名称" resetname: - description: 重设您的洞穴名称 + description: "重置您洞穴的名称" team: coop: - description: 让玩家在你的洞穴中进行排名 + description: "将玩家设置为您洞穴的副 OP" uncoop: - you-are-no-longer-a-coop-member: "&c您不再是[name]的洞穴的鸡舍成员" - all-members-logged-off: "&c所有洞穴成员都已注销,因此您不再是[name]洞穴的合作伙伴" + you-are-no-longer-a-coop-member: "&c您不再是 [name] 的洞穴的副 OP 了" + all-members-logged-off: "&c洞穴的所有玩家都离线了, 因此您不再是 [name] 的洞穴的副 OP 了" trust: - description: 给玩家一个值得信赖的等级 + description: "将玩家设置为您洞穴的信任者" invite: - description: 邀请玩家加入你的洞穴 - name-has-invited-you: "&a [name]邀请您加入他们的洞穴。" - you-will-lose-your-island: "&c警告!如果您接受,您将迷路!" + description: "邀请一名玩家到您的洞穴中" + name-has-invited-you: "&a[name] 邀请您加入他(她)的洞穴." + you-will-lose-your-island: "&c注意! 如果接受邀请, 您将失去现有的洞穴!" errors: - island-is-full: "&c您的洞穴已满,您不能邀请其他任何人。" + island-is-full: "&c您的洞穴已满, 无法再邀请更多的玩家." accept: - you-joined-island: "&a您加入了一个山洞!使用/ [标签]小组信息来查看其他成员。" - name-joined-your-island: "&a [name]加入了您的洞穴!" + you-joined-island: "&a您加入了一个洞穴! 输入 /[label] team info 来查看其他成员." + name-joined-your-island: "&a[name] 加入了您的洞穴!" confirmation: |- - &c确定要接受此邀请吗? - &c&l您会&nLOSE&r&c&ly您当前的洞穴! + &c确认要接收此邀请? + &c&l您将 &n失去&r &c&l现有的洞穴! reject: - you-rejected-invite: "&a您拒绝了加入洞穴的邀请。" - name-rejected-your-invite: "&c [name]拒绝了您的洞穴邀请!" + you-rejected-invite: "&a您拒绝了加入洞穴的邀请." + name-rejected-your-invite: "&c[name] 拒绝了您加入洞穴的邀请!" cancel: - description: 取消待处理的邀请,加入你的洞穴 + description: "取消待接受/拒绝的洞穴加入邀请" leave: - description: 离开你的洞穴 - left-your-island: "&c [name]&cleft your cave" + description: "退出您的洞穴" + left-your-island: "&c[name] &c退出了您的洞穴" kick: - description: 从您的洞穴中删除一个成员 - owner-kicked: "&c主人将您踢出山洞!" - success: "&b [name]&ahas被踢出您的山洞。" + description: "从您的洞穴中移出一名玩家" + owner-kicked: "&c洞穴的主人移出了您!" + success: "&b[name] &a从您的洞穴中被移出." demote: - description: 将您的玩家降级 + description: "降低洞穴中一名玩家的地位" promote: - description: 提升您的玩家排名 + description: "提升洞穴中一名玩家的地位" setowner: - description: 将您的洞穴所有权转让给成员 + description: "将洞穴转让给一名成员" errors: - target-is-not-member: 该球员不属于您的洞穴团队! - name-is-the-owner: "&a [name]现在是洞穴所有者!" - you-are-the-owner: "&a您现在是洞穴主人!" + target-is-not-member: "&c玩家不在您洞穴的队伍中!" + name-is-the-owner: "&a[name] 现在是洞穴的主人!" + you-are-the-owner: "&a您成为了洞穴的主人!" ban: - description: 禁止玩家进入您的洞穴 - cannot-ban-more-players: "&c您已达到禁令限制,您不能再从您的洞穴禁赛。" - player-banned: "&b [name]&c现在被禁止进入您的洞穴。" - owner-banned-you: "&b [name]&c禁止您进入他们的洞穴!" - you-are-banned: "&b您被禁止进入这个洞穴!" + description: "从洞穴中禁止一名玩家" + cannot-ban-more-players: "&c达到最大禁止玩家的数量, 无法再禁止更多的玩家." + player-banned: "&b[name]&c 被您的洞穴禁止." + owner-banned-you: "&b[name]&c 的洞穴禁止了您!" + you-are-banned: "&b您已被此洞穴禁止!" unban: - description: 禁止玩家进入您的洞穴 - player-unbanned: "&b [name]&a现在不受您的洞穴限制。" - you-are-unbanned: "&b [name]&a禁止您进入他们的洞穴!" + description: "从洞穴中解封一名玩家" + player-unbanned: "&b[name]&a 被您的洞穴解封." + you-are-unbanned: "&b[name]&a 的洞穴解封了您!" banlist: - noone: "&a没有人被禁止进入这个洞穴。" + noone: "&a没有玩家被此洞穴禁止." settings: - description: 显示洞穴设置 + description: "显示洞穴设置" expel: - description: 将玩家驱逐出您的洞穴 - not-on-island: "&c那个玩家不在你的洞穴里!" - player-expelled-you: "&b [name]&c将您赶出了山洞!" + description: "从洞穴中请出一名玩家" + not-on-island: "&c该玩家不在您洞穴中!" + player-expelled-you: "&c您被 &b[name]&c 的洞穴请出!" + ranks: - owner: 矮人王 - sub-owner: 矮人骑士 - member: 侏儒 - trusted: 值得信赖 - coop: 鸡舍 - visitor: 人的 - banned: 兽人 + owner: "矮人王" + sub-owner: "矮人骑士" + member: "小矮人" + trusted: "信任者" + coop: "副 OP" + visitor: "人类" + banned: "被禁止玩家" + protection: flags: ENDERMAN_GRIEFING: description: |- - &aEndermen可以删除 - &a洞穴 - name: 恩德曼悲痛 + &a末影人可以 + &a移动洞穴中的方块 + name: "末影人破坏" ENTER_EXIT_MESSAGES: - island: "[名字]的洞穴" + island: "[name] 的洞穴" GEO_LIMIT_MOBS: description: |- - &a删除小怪 - &外部保护 - &占用空间 - name: "&e限制小怪进入山洞" + &a移除在洞穴保护 + &a范围外的生物 + name: "&e将生物限制在洞穴内" ISLAND_RESPAWN: description: |- - &a玩家重生 - 和他们的洞穴 - name: 洞穴重生 + &a玩家在他们的 + &a洞穴中重生 + name: "洞穴中重生" LIQUIDS_FLOWING_OUT: - name: 液体在洞穴外流动 + name: "流体流出洞穴" description: |- - &a切换液体是否可以流出 - &a洞穴的保护范围。 + &a切换流体是否能 + &a流出洞穴保护范围. LOCK: - description: 拨动锁 - name: 锁洞 + description: "切换是否禁止访客访问" + name: "锁定洞穴" NATURAL_SPAWNING_OUTSIDE_RANGE: - name: 自然生物产生范围外 + name: "常规生物在保护范围外生成" description: |- - &a切换是否生物(动物和 - &amonsters)可以在外面自然产卵 - &aa洞穴的保护范围。 + &a切换常规生物 (动物和 + &a怪物) 是否能在洞穴保护 + &a范围外生成. - &c请注意,这不会阻止生物 - &cto通过暴民生成器或生成器生成 - &cegg。 + &c注意, 此操作不能防止 + &c洞穴保护范围外的 + &c刷怪笼或刷怪蛋生成生物. OFFLINE_GROWTH: description: |- - &a禁用时,植物 - &a不会在洞穴中生长 - &awhen所有成员均处于离线状态。 - &a可以帮助减少延迟。 - name: 离线增长 + &a如果禁用, 当洞穴中的所有成员 + &a都离线时, 植物将停止生长. + &a或许能减少服务器卡顿. + name: "离线生长" OFFLINE_REDSTONE: description: |- - &a禁用时,红石 - &a不会在山洞中运作 - &a所有成员均处于离线状态。 - &a可以帮助减少延迟。 - name: 离线红石 + &a如果禁用, 当洞穴中的所有成员 + &a都离线时, 红石将停止运作. + &a或许能减少服务器卡顿. + name: "离线红石" PISTON_PUSH: description: |- - &a允许活塞推动 - &在洞穴外面 - name: 活塞推 + &a允许活塞推动 + &a洞穴外的方块 + name: "活塞推动" REMOVE_MOBS: description: |- - &a移除怪物 - &前往洞穴 - name: 移除怪物 + &a传送到洞穴中时, + &a移除洞穴中的所有怪物 + name: "Remove monsters" TREES_GROWING_OUTSIDE_RANGE: - name: 树木生长范围外 + name: "树木在洞穴保护范围外生长" description: |- - &a切换树木是否可以在 - 是否使用&acave的保护范围。 + &a切换树木是否能长到 + &a洞穴保护范围之外. PREVENT_TELEPORT_WHEN_FALLING: - name: 跌倒时防止传送 + name: "掉落时禁止传送" description: |- - &a防止玩家被传送 - 使用命令返回他们的洞穴 - &aif他们跌倒了。 - hint: "&c跌倒时无法传送回洞穴。" - locked: "&c这个洞穴被锁了!" - protected: "&cCave保护:[说明]" - spawn-protected: "&cSpawn受保护:[描述]" + &a当玩家正在掉落时 + &a禁止他们通过指令进行传送. + hint: "&c在掉落时不能传送." + locked: "&c该洞穴已禁止访客访问!" + protected: "&c没有权限: [description]" + spawn-protected: "&c没有权限: [description]" + panel: PROTECTION: description: |- - &a保护设置 - &a这个洞 + &a洞穴的 + &a保护设置 SETTING: description: |- - &a常规设置 - &a这个洞 + &a洞穴的 + &a一般设置 + protection: flags: SKY_WALKER_FLAG: - hint: 允许在洞穴顶上行走。 - name: 天空行者 - description: |- - &5&o这允许启用/禁用 - &5&o能力继续前进 - &5&otop洞穴世界 - &5&o没有额外的权限。 + description: "&5&o这将允许/禁止\n&5&o没有额外权限的玩家\n&5&o在洞穴世界的顶部\n&5&o行走." + name: "天空行者" + hint: "允许在洞穴的天花板上行走."