diff --git a/pom.xml b/pom.xml index 7f7501e..77f934b 100644 --- a/pom.xml +++ b/pom.xml @@ -59,13 +59,13 @@ 2.0.9 1.20.4-R0.1-SNAPSHOT - 2.0.0-SNAPSHOT + 2.5.0-SNAPSHOT ${build.version}-SNAPSHOT -LOCAL - 1.18.2 + 1.19.0 BentoBoxWorld_AcidIsland bentobox-world diff --git a/src/main/java/world/bentobox/acidisland/AISettings.java b/src/main/java/world/bentobox/acidisland/AISettings.java index b3ac824..2dc9988 100644 --- a/src/main/java/world/bentobox/acidisland/AISettings.java +++ b/src/main/java/world/bentobox/acidisland/AISettings.java @@ -11,6 +11,7 @@ import com.google.common.base.Enums; +import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.configuration.ConfigComment; import world.bentobox.bentobox.api.configuration.ConfigEntry; import world.bentobox.bentobox.api.configuration.StoreAt; @@ -201,6 +202,15 @@ public class AISettings implements WorldSettings { @ConfigEntry(path = "world.island-height") private int islandHeight = 50; + @ConfigComment("The number of concurrent islands a player can have in the world") + @ConfigComment("A value of 0 will use the BentoBox config.yml default") + @ConfigEntry(path = "world.concurrent-islands") + private int concurrentIslands = 0; + + @ConfigComment("Disallow players to have other islands if they are in a team.") + @ConfigEntry(path = "world.disallow-team-member-islands") + boolean disallowTeamMemberIslands = true; + @ConfigComment("Use your own world generator for this world.") @ConfigComment("In this case, the plugin will not generate anything.") @ConfigEntry(path = "world.use-own-generator", experimental = true) @@ -220,6 +230,21 @@ public class AISettings implements WorldSettings { @ConfigEntry(path = "world.ocean-floor", needsReset = true) private boolean oceanFloor = false; + @ConfigComment("Structures") + @ConfigComment("This creates an vanilla structures in the worlds.") + @ConfigEntry(path = "world.make-structures", needsReset = true) + private boolean makeStructures = false; + + @ConfigComment("Caves") + @ConfigComment("This creates an vanilla caves in the worlds.") + @ConfigEntry(path = "world.make-caves", needsReset = true) + private boolean makeCaves = false; + + @ConfigComment("Decorations") + @ConfigComment("This creates an vanilla decorations in the worlds.") + @ConfigEntry(path = "world.make-decorations", needsReset = true) + private boolean makeDecorations = true; + @ConfigComment("Maximum number of islands in the world. Set to -1 or 0 for unlimited. ") @ConfigComment("If the number of islands is greater than this number, no new island will be created.") @ConfigEntry(path = "world.max-islands") @@ -2024,4 +2049,79 @@ public boolean isOceanFloor() { public void setOceanFloor(boolean oceanFloor) { this.oceanFloor = oceanFloor; } + + /** + * @return the makeStructures + */ + public boolean isMakeStructures() { + return makeStructures; + } + + /** + * @param makeStructures the makeStructures to set + */ + public void setMakeStructures(boolean makeStructures) { + this.makeStructures = makeStructures; + } + + /** + * @return the makeCaves + */ + public boolean isMakeCaves() { + return makeCaves; + } + + /** + * @param makeCaves the makeCaves to set + */ + public void setMakeCaves(boolean makeCaves) { + this.makeCaves = makeCaves; + } + + /** + * @return the makeDecorations + */ + public boolean isMakeDecorations() { + return makeDecorations; + } + + /** + * @param makeDecorations the makeDecorations to set + */ + public void setMakeDecorations(boolean makeDecorations) { + this.makeDecorations = makeDecorations; + } + + /** + * @return the disallowTeamMemberIslands + */ + @Override + public boolean isDisallowTeamMemberIslands() { + return disallowTeamMemberIslands; + } + + /** + * @param disallowTeamMemberIslands the disallowTeamMemberIslands to set + */ + public void setDisallowTeamMemberIslands(boolean disallowTeamMemberIslands) { + this.disallowTeamMemberIslands = disallowTeamMemberIslands; + } + + /** + * @return the concurrentIslands + */ + @Override + public int getConcurrentIslands() { + if (concurrentIslands <= 0) { + return BentoBox.getInstance().getSettings().getIslandNumber(); + } + return concurrentIslands; + } + + /** + * @param concurrentIslands the concurrentIslands to set + */ + public void setConcurrentIslands(int concurrentIslands) { + this.concurrentIslands = concurrentIslands; + } } diff --git a/src/main/java/world/bentobox/acidisland/AcidIslandPladdon.java b/src/main/java/world/bentobox/acidisland/AcidIslandPladdon.java index a54acd5..f345450 100644 --- a/src/main/java/world/bentobox/acidisland/AcidIslandPladdon.java +++ b/src/main/java/world/bentobox/acidisland/AcidIslandPladdon.java @@ -2,12 +2,18 @@ import world.bentobox.bentobox.api.addons.Addon; +import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.addons.Pladdon; public class AcidIslandPladdon extends Pladdon { + private GameModeAddon addon; + @Override public Addon getAddon() { - return new AcidIsland(); + if (addon == null) { + addon = new AcidIsland(); + } + return addon; } } diff --git a/src/main/java/world/bentobox/acidisland/events/EntityDamageByAcidEvent.java b/src/main/java/world/bentobox/acidisland/events/EntityDamageByAcidEvent.java index cdeb4f6..e041c02 100644 --- a/src/main/java/world/bentobox/acidisland/events/EntityDamageByAcidEvent.java +++ b/src/main/java/world/bentobox/acidisland/events/EntityDamageByAcidEvent.java @@ -1,21 +1,23 @@ package world.bentobox.acidisland.events; import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * Fired when an entity (items excluded) receives damage from acid - * @author Poslovitch + * @author Poslovitch, tastybento * @since 1.0 */ -public class EntityDamageByAcidEvent extends Event { +public class EntityDamageByAcidEvent extends Event implements Cancellable { private final Entity entity; private double damage; public enum Acid { RAIN, WATER } private final Acid cause; + private boolean cancelled; private static final HandlerList handlers = new HandlerList(); @Override @@ -64,4 +66,15 @@ public void setDamage(double damage) { public Acid getCause() { return cause; } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + + } } diff --git a/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java b/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java index 887454a..c0f0806 100644 --- a/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java +++ b/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java @@ -178,7 +178,14 @@ protected boolean checkForRain(Player player) { // Check they are still in this world } else if (wetPlayers.containsKey(player) && wetPlayers.get(player) < System.currentTimeMillis()) { double protection = addon.getSettings().getAcidRainDamage() * getDamageReduced(player); - double totalDamage = Math.max(0, addon.getSettings().getAcidRainDamage() - protection); + + User user = User.getInstance(player); + // Get the percentage reduction and ensure the value is between 0 and 100 + double percent = (100 + - Math.max(0, Math.min(100, user.getPermissionValue("acidisland.protection.rain", 0)))) / 100D; + + double totalDamage = Math.max(0, addon.getSettings().getAcidRainDamage() - protection) * percent; + AcidRainEvent event = new AcidRainEvent(player, totalDamage, protection, addon.getSettings().getAcidRainEffects()); Bukkit.getPluginManager().callEvent(event); @@ -187,11 +194,13 @@ protected boolean checkForRain(Player player) { .addPotionEffect(new PotionEffect(t, addon.getSettings().getRainEffectDuation() * 20, 1))); // Apply damage if there is any if (event.getRainDamage() > 0D) { - player.damage(event.getRainDamage()); - player.getWorld().playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); EntityDamageByAcidEvent e = new EntityDamageByAcidEvent(player, event.getRainDamage(), Acid.RAIN); // Fire event Bukkit.getPluginManager().callEvent(e); + if (!e.isCancelled()) { + player.damage(event.getRainDamage()); + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); + } } } } @@ -204,19 +213,28 @@ protected boolean continuouslyHurtPlayer(Player player) { return true; } else if (burningPlayers.containsKey(player) && burningPlayers.get(player) < System.currentTimeMillis()) { double protection = addon.getSettings().getAcidDamage() * getDamageReduced(player); - double totalDamage = Math.max(0, addon.getSettings().getAcidDamage() - protection); + + User user = User.getInstance(player); + // Get the percentage reduction and ensure the value is between 0 and 100 + double percent = (100 + - Math.max(0, Math.min(100, user.getPermissionValue("acidisland.protection.acid", 0)))) / 100D; + + double totalDamage = Math.max(0, addon.getSettings().getAcidDamage() - protection) * percent; + AcidEvent event = new AcidEvent(player, totalDamage, protection, addon.getSettings().getAcidEffects()); addon.getServer().getPluginManager().callEvent(event); if (!event.isCancelled()) { event.getPotionEffects().stream().filter(EFFECTS::contains).forEach(t -> player .addPotionEffect(new PotionEffect(t, addon.getSettings().getAcidEffectDuation() * 20, 1))); // Apply damage if there is any - if (event.getTotalDamage() > 0D) { - player.damage(event.getTotalDamage()); - player.getWorld().playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); + if (event.getTotalDamage() > 0D) { EntityDamageByAcidEvent e = new EntityDamageByAcidEvent(player, event.getTotalDamage(), Acid.WATER); // Fire event Bukkit.getPluginManager().callEvent(e); + if (!e.isCancelled()) { + player.damage(event.getTotalDamage()); + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); + } } } } @@ -230,9 +248,10 @@ protected boolean continuouslyHurtPlayer(Player player) { */ private boolean isSafeFromRain(Player player) { if (isEssentialsGodMode(player) || player.getWorld().getEnvironment().equals(Environment.NETHER) + || player.getGameMode() != GameMode.SURVIVAL || player.getWorld().getEnvironment().equals(Environment.THE_END) || (addon.getSettings().isHelmetProtection() && (player.getInventory().getHelmet() != null - && player.getInventory().getHelmet().getType().name().contains("HELMET"))) + && player.getInventory().getHelmet().getType().name().contains("HELMET"))) || (!addon.getSettings().isAcidDamageSnow() && player.getLocation().getBlock().getTemperature() < 0.1) // snow falls || player.getLocation().getBlock().getHumidity() == 0 // dry || (player.getActivePotionEffects().stream().map(PotionEffect::getType) @@ -260,7 +279,7 @@ private boolean isSafeFromRain(Player player) { */ boolean isSafeFromAcid(Player player) { // Check for GodMode - if (isEssentialsGodMode(player) + if (isEssentialsGodMode(player) || player.getGameMode() != GameMode.SURVIVAL // Protect visitors || (addon.getPlugin().getIWM().getIvSettings(player.getWorld()).contains(DamageCause.CUSTOM.name()) && !addon.getIslands().userIsOnIsland(player.getWorld(), User.getInstance(player)))) { diff --git a/src/main/java/world/bentobox/acidisland/world/AcidTask.java b/src/main/java/world/bentobox/acidisland/world/AcidTask.java index 1e9dab2..fd2a416 100644 --- a/src/main/java/world/bentobox/acidisland/world/AcidTask.java +++ b/src/main/java/world/bentobox/acidisland/world/AcidTask.java @@ -37,6 +37,8 @@ public class AcidTask { i.add(EntityType.POLAR_BEAR); i.add(EntityType.TURTLE); i.add(EntityType.DROWNED); + i.add(EntityType.GUARDIAN); + i.add(EntityType.ELDER_GUARDIAN); Enums.getIfPresent(EntityType.class, "AXOLOTL").toJavaUtil().ifPresent(i::add); IMMUNE = Collections.unmodifiableList(i); } @@ -86,10 +88,12 @@ void findEntities() { void applyDamage(Entity e, long damage) { if (e instanceof LivingEntity) { double actualDamage = Math.max(0, damage - damage * AcidEffect.getDamageReduced((LivingEntity)e)); - ((LivingEntity)e).damage(actualDamage); EntityDamageByAcidEvent event = new EntityDamageByAcidEvent(e, actualDamage, Acid.WATER); // Fire event Bukkit.getPluginManager().callEvent(event); + if (!event.isCancelled()) { + ((LivingEntity)e).damage(actualDamage); + } } else if (addon.getSettings().getAcidDestroyItemTime() > 0 && e instanceof Item){ // Item if (e.getLocation().getBlock().getType().equals(Material.WATER)) { diff --git a/src/main/java/world/bentobox/acidisland/world/ChunkGeneratorWorld.java b/src/main/java/world/bentobox/acidisland/world/ChunkGeneratorWorld.java index fbbbe56..748c0c0 100644 --- a/src/main/java/world/bentobox/acidisland/world/ChunkGeneratorWorld.java +++ b/src/main/java/world/bentobox/acidisland/world/ChunkGeneratorWorld.java @@ -27,10 +27,17 @@ */ public class ChunkGeneratorWorld extends ChunkGenerator { + private record FloorMats(Material base, Material top) { + } + private final AcidIsland addon; private final Random rand = new Random(); private final Map seaHeight = new EnumMap<>(Environment.class); private final Map roofChunk = new HashMap<>(); + private static final Map floorMats = Map.of(Environment.NETHER, + new FloorMats(Material.NETHERRACK, Material.SOUL_SAND), Environment.NORMAL, + new FloorMats(Material.SANDSTONE, Material.SAND), Environment.THE_END, + new FloorMats(Material.END_STONE, Material.END_STONE)); private PerlinOctaveGenerator gen; private record WorldConfig(int seaHeight, Material waterBlock) {} @@ -72,7 +79,8 @@ private void addNoise(@NonNull WorldInfo worldInfo, int chunkX, int chunkZ, @Non for (int z = 0; z < 16; z++) { int n = (int)(25 * gen.noise((chunkX << 4) + (double)x, (chunkZ << 4) + (double)z, 0.5, 0.5, true)); for (int y = worldInfo.getMinHeight(); y < 25 + n; y++) { - chunkData.setBlock(x, y, z, rand.nextBoolean() ? Material.SAND : Material.SANDSTONE); + chunkData.setBlock(x, y, z, rand.nextBoolean() ? floorMats.get(worldInfo.getEnvironment()).top() + : floorMats.get(worldInfo.getEnvironment()).base()); } } } @@ -90,11 +98,11 @@ public boolean shouldGenerateSurface() { } @Override public boolean shouldGenerateCaves() { - return addon.getSettings().isOceanFloor(); + return addon.getSettings().isMakeCaves(); } @Override public boolean shouldGenerateDecorations() { - return addon.getSettings().isOceanFloor(); + return addon.getSettings().isMakeDecorations(); } @Override public boolean shouldGenerateMobs() { @@ -102,7 +110,7 @@ public boolean shouldGenerateMobs() { } @Override public boolean shouldGenerateStructures() { - return addon.getSettings().isOceanFloor(); + return addon.getSettings().isMakeStructures(); } @Override diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index ffff1f8..ec1e131 100755 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -1,7 +1,7 @@ name: AcidIsland main: world.bentobox.acidisland.AcidIsland version: ${version}${build.number} -api-version: 1.22.1 +api-version: 2.4.0 metrics: true repository: "BentoBoxWorld/AcidIsland" icon: "OAK_BOAT" diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ce2df30..984485e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -125,6 +125,11 @@ world: # Island height - Lowest is 5. # It is the y coordinate of the bedrock block in the schem. island-height: 60 + # The number of concurrent islands a player can have in the world + # A value of 0 will use the BentoBox config.yml default + concurrent-islands: 1 + # Disallow players to have other islands if they are in a team. + disallow-team-member-islands: true # Use your own world generator for this world. # In this case, the plugin will not generate anything. # /!\ This feature is experimental and might not work as expected or might not work at all. @@ -139,6 +144,18 @@ world: # This creates an ocean floor environment, with vanilla elements. # /!\ 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. ocean-floor: true + # Structures + # This creates an vanilla structures in the worlds. + # /!\ 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. + make-structures: false + # Caves + # This creates an vanilla caves in the worlds. + # /!\ 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. + make-caves: false + # Decorations + # This creates an vanilla decorations in the worlds. + # /!\ 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. + make-decorations: true # Maximum number of islands in the world. Set to -1 or 0 for unlimited. # If the number of islands is greater than this number, no new island will be created. max-islands: 0 @@ -211,10 +228,10 @@ world: # This setting is toggled in world flags and set by the settings GUI. # Mob white list - these mobs will NOT be removed when logging in or doing /island remove-mobs-whitelist: - - ZOMBIE_VILLAGER - ENDERMAN - - ZOMBIFIED_PIGLIN + - ZOMBIE_VILLAGER - WITHER + - ZOMBIFIED_PIGLIN # World flags. These are boolean settings for various flags for this world flags: CREEPER_DAMAGE: true @@ -228,27 +245,33 @@ world: PREVENT_TELEPORT_WHEN_FALLING: false NATURAL_SPAWNING_OUTSIDE_RANGE: true ENTER_EXIT_MESSAGES: true + ALLOW_MOVE_BOX: true ENDERMAN_DEATH_DROP: true + LIQUIDS_FLOWING_OUT: false OFFLINE_REDSTONE: true REMOVE_END_EXIT_ISLAND: true OFFLINE_GROWTH: true REMOVE_MOBS: true ENDER_CHEST: false ITEM_FRAME_DAMAGE: false + TREES_GROWING_OUTSIDE_RANGE: false BOAT: true # These are the default protection settings for new islands. # The value is the minimum island rank required allowed to do the action # Ranks are: Visitor = 0, Member = 900, Owner = 1000 default-island-flags: HURT_ANIMALS: 500 + LOOM: 500 DRAGON_EGG: 500 REDSTONE: 500 BUCKET: 500 LOCK: 0 ENDER_PEARL: 500 + BELL_RINGING: 500 DOOR: 500 BREAK_HOPPERS: 500 FURNACE: 500 + HURT_TAMED_ANIMALS: 500 ANVIL: 500 MINECART: 500 FISH_SCOOPING: 500 @@ -256,6 +279,8 @@ world: END_PORTAL: 500 BREEDING: 500 HURT_VILLAGERS: 500 + BOOKSHELF: 500 + HARVEST: 500 TURTLE_EGGS: 500 FROST_WALKER: 500 COLLECT_LAVA: 500 @@ -268,6 +293,7 @@ world: NAME_TAG: 500 ARMOR_STAND: 500 CHANGE_SETTINGS: 1000 + SIGN_EDITING: 500 TRADING: 0 EGGS: 500 ITEM_DROP: 0 @@ -278,15 +304,19 @@ world: SCULK_SENSOR: 500 LECTERN: 500 SHULKER_BOX: 500 + GRINDSTONE: 500 ITEM_PICKUP: 0 CROP_TRAMPLE: 500 DROPPER: 500 BREWING: 500 + MOVE_BOX: 1000 TNT_PRIMING: 500 + PARKOUR_CREATIVE: 500 COLLECT_WATER: 500 AXOLOTL_SCOOPING: 500 BUTTON: 500 COMPOSTER: 500 + STONECUTTING: 500 FIRE_EXTINGUISH: 500 COMMAND_RANKS: 500 BEACON: 500 @@ -298,6 +328,7 @@ world: HIVE: 500 ITEM_FRAME: 500 PLACE_BLOCKS: 500 + CROP_PLANTING: 500 CRAFTING: 0 SHEARING: 500 ENCHANTING: 0 @@ -309,8 +340,10 @@ world: DISPENSER: 500 SCULK_SHRIEKER: 500 GATE: 0 + SMITHING: 500 EXPERIENCE_PICKUP: 500 HOPPER: 500 + CANDLES: 500 LEASH: 500 MOUNT_INVENTORY: 500 BREAK_BLOCKS: 500 @@ -320,13 +353,16 @@ world: POTION_THROWING: 500 BARREL: 500 COLLECT_POWDERED_SNOW: 500 + CARTOGRAPHY: 500 # These are the default settings for new islands default-island-settings: PVP_END: false PVP_NETHER: false LEAF_DECAY: true + ENDERMAN_TELEPORT: true ANIMAL_NATURAL_SPAWN: true MONSTER_NATURAL_SPAWN: true + SHULKER_TELEPORT: true FIRE_SPREAD: true FIRE_BURNING: true PVP_OVERWORLD: false @@ -551,4 +587,3 @@ protection: do-not-edit-these-settings: # These settings should not be edited reset-epoch: 0 - diff --git a/src/main/resources/locales/hr.yml b/src/main/resources/locales/hr.yml new file mode 100644 index 0000000..5332d57 --- /dev/null +++ b/src/main/resources/locales/hr.yml @@ -0,0 +1,7 @@ +--- +acidisland: + sign: + line0: "&1Otok kiseline" + line1: "[Ime]" + line2: Voda je kiselina! + line3: Budi oprezan! &c<3