diff --git a/pom.xml b/pom.xml index c53805163..90bf01ed9 100644 --- a/pom.xml +++ b/pom.xml @@ -50,13 +50,9 @@ - - codemc-snapshots - https://repo.codemc.org/repository/maven-snapshots - - codemc-releases - https://repo.codemc.org/repository/maven-releases + bentoboxworld + https://repo.codemc.org/repository/bentoboxworld/ @@ -88,7 +84,7 @@ -LOCAL - 2.7.0 + 3.0.1 bentobox-world https://sonarcloud.io ${project.basedir}/lib diff --git a/src/main/java/world/bentobox/bentobox/BentoBox.java b/src/main/java/world/bentobox/bentobox/BentoBox.java index b46ab2b69..daa0b91dd 100644 --- a/src/main/java/world/bentobox/bentobox/BentoBox.java +++ b/src/main/java/world/bentobox/bentobox/BentoBox.java @@ -1,5 +1,7 @@ package world.bentobox.bentobox; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; @@ -464,6 +466,32 @@ public class BentoBox extends JavaPlugin implements Listener { getPluginLoader().disablePlugin(this); return false; } + log("Saving default panels..."); + + if (!Files.exists(Path.of(this.getDataFolder().getPath(), "panels", "island_creation_panel.yml"))) { + log("Saving default island_creation_panel..."); + this.saveResource("panels/island_creation_panel.yml", false); + } + + if (!Files.exists(Path.of(this.getDataFolder().getPath(), "panels", "language_panel.yml"))) { + log("Saving default language_panel..."); + this.saveResource("panels/language_panel.yml", false); + } + + if (!Files.exists(Path.of(this.getDataFolder().getPath(), "panels", "island_homes_panel.yml"))) { + log("Saving default island_homes_panel..."); + this.saveResource("panels/island_homes_panel.yml", false); + } + + if (!Files.exists(Path.of(this.getDataFolder().getPath(), "panels", "team_invite_panel.yml"))) { + log("Saving default team_invite_panel..."); + this.saveResource("panels/team_invite_panel.yml", false); + } + + if (!Files.exists(Path.of(this.getDataFolder().getPath(), "panels", "team_panel.yml"))) { + log("Saving default team_panel..."); + this.saveResource("panels/team_panel.yml", false); + } return true; } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminUnregisterCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminUnregisterCommand.java index 06cb6a578..f9f631df3 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminUnregisterCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminUnregisterCommand.java @@ -15,6 +15,7 @@ import world.bentobox.bentobox.api.commands.ConfirmableCommand; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.RanksManager; @@ -115,10 +116,10 @@ public class AdminUnregisterCommand extends ConfirmableCommand { // Remove all island players that reference this island targetIsland.getMembers().clear(); if (user.isPlayer()) { - targetIsland.log(new LogEntry.Builder("UNREGISTER").data("player", targetUUID.toString()) + targetIsland.log(new LogEntry.Builder(LogType.UNREGISTER).data("player", targetUUID.toString()) .data("admin", user.getUniqueId().toString()).build()); } else { - targetIsland.log(new LogEntry.Builder("UNREGISTER").data("player", targetUUID.toString()) + targetIsland.log(new LogEntry.Builder(LogType.UNREGISTER).data("player", targetUUID.toString()) .data("admin", "console").build()); } user.sendMessage("commands.admin.unregister.unregistered-island", TextVariables.XYZ, Util.xyz(targetIsland.getCenter().toVector()), diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommand.java index 3b069c3f6..592445062 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommand.java @@ -13,7 +13,6 @@ import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.RanksManager; -import world.bentobox.bentobox.util.IslandInfo; import world.bentobox.bentobox.util.Util; /** @@ -59,35 +58,28 @@ public class AdminTeamKickCommand extends CompositeCommand { @Override public boolean execute(User user, String label, @NonNull List args) { - Island island = getIslands().getIsland(getWorld(), targetUUID); - if (island == null) { + List islands = getIslands().getIslands(getWorld(), targetUUID); + if (islands.isEmpty()) { return false; } - if (targetUUID.equals(island.getOwner())) { - user.sendMessage("commands.admin.team.kick.cannot-kick-owner"); - new IslandInfo(island).showMembers(user); - return false; - } - User target = User.getInstance(targetUUID); - target.sendMessage("commands.admin.team.kick.admin-kicked"); + islands.forEach(island -> { + if (!user.getUniqueId().equals(island.getOwner())) { + User target = User.getInstance(targetUUID); + target.sendMessage("commands.admin.team.kick.admin-kicked"); - getIslands().removePlayer(island, targetUUID); - user.sendMessage("commands.admin.team.kick.success", TextVariables.NAME, target.getName(), "[owner]", getPlayers().getName(island.getOwner())); + getIslands().removePlayer(island, targetUUID); + user.sendMessage("commands.admin.team.kick.success", TextVariables.NAME, target.getName(), "[owner]", + getPlayers().getName(island.getOwner())); + // Fire event so add-ons know + TeamEvent.builder().island(island).reason(TeamEvent.Reason.KICK).involvedPlayer(targetUUID).admin(true) + .build(); + IslandEvent.builder().island(island).involvedPlayer(targetUUID).admin(true) + .reason(IslandEvent.Reason.RANK_CHANGE) + .rankChange(island.getRank(target), RanksManager.VISITOR_RANK).build(); + } + }); + user.sendMessage("commands.admin.team.kick.success-all"); - // Fire event so add-ons know - TeamEvent.builder() - .island(island) - .reason(TeamEvent.Reason.KICK) - .involvedPlayer(targetUUID) - .admin(true) - .build(); - IslandEvent.builder() - .island(island) - .involvedPlayer(targetUUID) - .admin(true) - .reason(IslandEvent.Reason.RANK_CHANGE) - .rankChange(island.getRank(target), RanksManager.VISITOR_RANK) - .build(); return true; } } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommand.java index 0db39b132..4b1d1c4ec 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommand.java @@ -54,7 +54,8 @@ public class IslandSethomeCommand extends ConfirmableCommand { // Check number of homes int maxHomes = getIslands().getMaxHomes(island); - if (getIslands().getNumberOfHomesIfAdded(island, String.join(" ", args)) > maxHomes) { + // The + 1 is for the default home + if (getIslands().getNumberOfHomesIfAdded(island, String.join(" ", args)) > maxHomes + 1) { user.sendMessage("commands.island.sethome.too-many-homes", TextVariables.NUMBER, String.valueOf(maxHomes)); user.sendMessage("commands.island.sethome.homes-are"); getIslands().getIslands(getWorld(), user).forEach(is -> diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java index 9244508c7..f0e3523bd 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamInviteAcceptCommand.java @@ -9,6 +9,8 @@ import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.TeamInvite; @@ -120,6 +122,9 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand { user.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, inviter.getName(), TextVariables.DISPLAY_NAME, inviter.getDisplayName()); } + // Add historu record + island.log(new LogEntry.Builder(LogType.TRUSTED).data(user.getUniqueId().toString(), "trusted") + .data(invite.getInviter().toString(), "trusted by").build()); } } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java index 16e23ee5c..0533f65ea 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java @@ -12,6 +12,8 @@ import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.team.TeamEvent; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.RanksManager; @@ -91,6 +93,9 @@ public class IslandTeamSetownerCommand extends CompositeCommand { IslandEvent.builder().island(island).involvedPlayer(user.getUniqueId()).admin(false) .reason(IslandEvent.Reason.RANK_CHANGE).rankChange(RanksManager.OWNER_RANK, RanksManager.SUB_OWNER_RANK) .build(); + // Add historu record + island.log(new LogEntry.Builder(LogType.NEWOWNER).data(targetUUID2.toString(), "new owner") + .data(user.getUniqueId().toString(), "old owner").build()); return true; } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java index 38c0349f7..435bbdee5 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamTrustCommand.java @@ -9,6 +9,8 @@ import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.TeamInvite.Type; @@ -110,6 +112,10 @@ public class IslandTeamTrustCommand extends CompositeCommand { island.setRank(target, RanksManager.TRUSTED_RANK); user.sendMessage("commands.island.team.trust.success", TextVariables.NAME, target.getName(), TextVariables.DISPLAY_NAME, target.getDisplayName()); target.sendMessage("commands.island.team.trust.you-are-trusted", TextVariables.NAME, user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName()); + // Add historu record + island.log(new LogEntry.Builder(LogType.TRUSTED).data(targetUUID.toString(), "trusted") + .data(user.getUniqueId().toString(), "trusted by").build()); + } return true; } else { diff --git a/src/main/java/world/bentobox/bentobox/api/configuration/Config.java b/src/main/java/world/bentobox/bentobox/api/configuration/Config.java index 420dd4174..8acafe596 100644 --- a/src/main/java/world/bentobox/bentobox/api/configuration/Config.java +++ b/src/main/java/world/bentobox/bentobox/api/configuration/Config.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; -import org.apache.commons.lang.exception.ExceptionUtils; import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.BentoBox; @@ -64,9 +63,9 @@ public class Config { return handler.loadObject(uniqueId); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException | IntrospectionException | NoSuchMethodException | SecurityException e) { - logger.severe(() -> "Could not load config object! " + e.getMessage()); + BentoBox.getInstance().logError("Could not load config object! " + e.getMessage()); // Required for debugging - logger.severe(ExceptionUtils.getStackTrace(e)); + e.printStackTrace(); } return null; diff --git a/src/main/java/world/bentobox/bentobox/api/logs/LogEntry.java b/src/main/java/world/bentobox/bentobox/api/logs/LogEntry.java index 583bd24a9..173c572d1 100644 --- a/src/main/java/world/bentobox/bentobox/api/logs/LogEntry.java +++ b/src/main/java/world/bentobox/bentobox/api/logs/LogEntry.java @@ -1,7 +1,6 @@ package world.bentobox.bentobox.api.logs; import java.util.LinkedHashMap; -import java.util.Locale; import java.util.Map; import org.eclipse.jdt.annotation.NonNull; @@ -15,20 +14,102 @@ import com.google.gson.annotations.Expose; * An {@link world.bentobox.bentobox.database.objects.adapters.AdapterInterface AdapterInterface} is provided to be able to save/retrieve * a list of instances of this object to/from the database: {@link world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter LogEntryListAdapter}. * - * @author Poslovitch + * @author Poslovitch, tastybento + * */ public class LogEntry { @Expose private final long timestamp; @Expose - private final String type; + private final LogType type; + @Expose + private final String customType; @Expose private final Map data; + /** + * This is a log enum. If you are a developer and need more make a PR. Or use the string one. + */ + public enum LogType { + /** + * Something removed + */ + REMOVE, + /** + * Something added + */ + ADD, + /** + * Island unregistered + */ + UNREGISTER, + /** + * Player banned + */ + BAN, + /** + * Something was completed + */ + COMPELTE, + /** + * Island became unowned + */ + UNOWNED, + /** + * Island became spawn + */ + SPAWN, + /** + * Player unbanned + */ + UNBAN, + /** + * Player joined + */ + JOINED, + /** + * New owner made + */ + NEWOWNER, + /** + * Player trusted + */ + TRUSTED, + /** + * Player cooped + */ + COOP, + /** + * Unknown reason + */ + UNKNOWN, + /** + * Island reset or a reset of some kind + */ + RESET, + /** + * Everything was reset + */ + RESET_ALL, + /** + * New thing + */ + NEW, + /** + * Something duplicated + */ + DUPLICATE, + /** + * General info + */ + INFO, + } + private LogEntry(@NonNull Builder builder) { this.timestamp = builder.timestamp; this.type = builder.type; this.data = builder.data; + this.customType = builder.customType; } public long getTimestamp() { @@ -36,7 +117,7 @@ public class LogEntry { } @NonNull - public String getType() { + public LogType getType() { return type; } @@ -47,13 +128,25 @@ public class LogEntry { public static class Builder { private long timestamp; - private final String type; + private final LogType type; private Map data; + private final String customType; - public Builder(@NonNull String type) { + public Builder(LogType type) { this.timestamp = System.currentTimeMillis(); - this.type = type.toUpperCase(Locale.ENGLISH); + this.type = type; this.data = new LinkedHashMap<>(); + this.customType = null; + } + + /** + * @param customType log type + */ + public Builder(String customType) { + this.timestamp = System.currentTimeMillis(); + this.type = LogType.UNKNOWN; + this.data = new LinkedHashMap<>(); + this.customType = customType; } public Builder timestamp(long timestamp) { diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/BiomeTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/BiomeTypeAdapter.java index b30b52b95..c7a239387 100644 --- a/src/main/java/world/bentobox/bentobox/database/json/adapters/BiomeTypeAdapter.java +++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/BiomeTypeAdapter.java @@ -8,10 +8,10 @@ package world.bentobox.bentobox.database.json.adapters; import java.io.IOException; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.bukkit.Registry; import org.bukkit.block.Biome; import com.google.gson.TypeAdapter; @@ -32,11 +32,12 @@ public final class BiomeTypeAdapter extends TypeAdapter */ final Map biomeMap; + @SuppressWarnings("deprecation") public BiomeTypeAdapter() { this.biomeMap = new HashMap<>(); // Put in current values. - Arrays.stream(Biome.values()).forEach(biome -> this.biomeMap.put(biome.name(), biome)); + Registry.BIOME.forEach(biome -> this.biomeMap.put(biome.name(), biome)); // Put in renamed biomes values. this.biomeMap.put("TALL_BIRCH_FOREST", Biome.OLD_GROWTH_BIRCH_FOREST); diff --git a/src/main/java/world/bentobox/bentobox/database/objects/Island.java b/src/main/java/world/bentobox/bentobox/database/objects/Island.java index e55c6a0ea..663c31cf0 100644 --- a/src/main/java/world/bentobox/bentobox/database/objects/Island.java +++ b/src/main/java/world/bentobox/bentobox/database/objects/Island.java @@ -37,6 +37,7 @@ import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.configuration.WorldSettings; import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.metadata.MetaDataAble; import world.bentobox.bentobox.api.metadata.MetaDataValue; import world.bentobox.bentobox.api.user.User; @@ -327,7 +328,7 @@ public class Island implements DataObject, MetaDataAble { public boolean ban(@NonNull UUID issuer, @NonNull UUID target) { if (getRank(target) != RanksManager.BANNED_RANK) { setRank(target, RanksManager.BANNED_RANK); - log(new LogEntry.Builder("BAN").data("player", target.toString()).data("issuer", issuer.toString()) + log(new LogEntry.Builder(LogType.BAN).data("player", target.toString()).data("issuer", issuer.toString()) .build()); setChanged(); } @@ -360,7 +361,7 @@ public class Island implements DataObject, MetaDataAble { */ public boolean unban(@NonNull UUID issuer, @NonNull UUID target) { if (members.remove(target) != null) { - log(new LogEntry.Builder("UNBAN").data("player", target.toString()).data("issuer", issuer.toString()) + log(new LogEntry.Builder(LogType.UNBAN).data("player", target.toString()).data("issuer", issuer.toString()) .build()); return true; } @@ -1132,7 +1133,7 @@ public class Island implements DataObject, MetaDataAble { this.owner = owner; if (owner == null) { - log(new LogEntry.Builder("UNOWNED").build()); + log(new LogEntry.Builder(LogType.UNOWNED).build()); return; } // Defensive code: demote any previous owner @@ -1281,7 +1282,7 @@ public class Island implements DataObject, MetaDataAble { setFlagsDefaults(); setFlag(Flags.LOCK, RanksManager.VISITOR_RANK); } - log(new LogEntry.Builder("SPAWN").data("value", String.valueOf(isSpawn)).build()); + log(new LogEntry.Builder(LogType.SPAWN).data("value", String.valueOf(isSpawn)).build()); setChanged(); } diff --git a/src/main/java/world/bentobox/bentobox/database/objects/adapters/AdapterInterface.java b/src/main/java/world/bentobox/bentobox/database/objects/adapters/AdapterInterface.java index 096e59b07..7c688b9d1 100644 --- a/src/main/java/world/bentobox/bentobox/database/objects/adapters/AdapterInterface.java +++ b/src/main/java/world/bentobox/bentobox/database/objects/adapters/AdapterInterface.java @@ -10,17 +10,17 @@ package world.bentobox.bentobox.database.objects.adapters; */ public interface AdapterInterface { - /** - * Serialize object - * @param object - object to serialize - * @return serialized object - */ - S deserialize(Object object); - /** * Deserialize object * @param object - object to deserialize * @return deserialized object */ + S deserialize(Object object); + + /** + * Serialize object + * @param object - object to serialize + * @return serialized object + */ V serialize(Object object); } diff --git a/src/main/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapter.java b/src/main/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapter.java index a4f8b5954..d3b38f358 100644 --- a/src/main/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapter.java +++ b/src/main/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapter.java @@ -5,7 +5,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import com.google.common.base.Enums; + import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; /** * @author Poslovitch @@ -41,7 +44,7 @@ public class LogEntryListAdapter implements AdapterInterface, Lis List> serialized = (List>) object; for (Map entry : serialized) { long timestamp = (long) entry.get(TIMESTAMP); - String type = (String) entry.get(TYPE); + LogType type = Enums.getIfPresent(LogType.class, (String) entry.get(TYPE)).or(LogType.UNKNOWN); Map data = (Map) entry.get(DATA); result.add(new LogEntry.Builder(type).timestamp(timestamp).data(data).build()); @@ -62,7 +65,7 @@ public class LogEntryListAdapter implements AdapterInterface, Lis history.forEach(logEntry -> { Map value = new LinkedHashMap<>(); value.put(TIMESTAMP, logEntry.getTimestamp()); - value.put(TYPE, logEntry.getType()); + value.put(TYPE, logEntry.getType().name()); if (logEntry.getData() != null) { value.put(DATA, logEntry.getData()); diff --git a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java index 5cfe753f5..d3c6ed29b 100644 --- a/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java +++ b/src/main/java/world/bentobox/bentobox/database/yaml/YamlDatabaseHandler.java @@ -26,8 +26,13 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import org.bukkit.Bukkit; +import org.bukkit.Keyed; import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.Sound; import org.bukkit.World; +import org.bukkit.block.Biome; import org.bukkit.configuration.MemorySection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.EntityType; @@ -220,6 +225,14 @@ public class YamlDatabaseHandler extends AbstractDatabaseHandler { double d = (double) setTo; float f = (float)d; method.invoke(instance, f); + } else if (setType.getTypeName().equals("org.bukkit.Sound")) { + Sound s = Registry.SOUNDS + .get(NamespacedKey.fromString(((String) setTo).toLowerCase(Locale.ENGLISH))); + method.invoke(instance, s); + } else if (setType.getTypeName().equals("org.bukkit.block.Biome")) { + Biome b = Registry.BIOME + .get(NamespacedKey.fromString(((String) setTo).toLowerCase(Locale.ENGLISH))); + method.invoke(instance, b); } else { method.invoke(instance, setTo); } @@ -369,7 +382,6 @@ public class YamlDatabaseHandler extends AbstractDatabaseHandler { Method method = propertyDescriptor.getReadMethod(); // Invoke the read method to get the value. We have no idea what type of value it is. Object value = method.invoke(instance); - String storageLocation = field.getName(); // Check if there is an annotation on the field @@ -575,6 +587,10 @@ public class YamlDatabaseHandler extends AbstractDatabaseHandler { if (object instanceof Location l) { return Util.getStringLocation(l); } + // Keyed interfaces that are replacing enums + if (object instanceof Keyed k) { + return k.getKey().getKey(); + } // Enums if (object instanceof Enum e) { //Custom enums are a child of the Enum class. Just get the names of each one. diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EggListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EggListener.java index 001192553..409c28d59 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EggListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/EggListener.java @@ -1,7 +1,10 @@ package world.bentobox.bentobox.listeners.flags.protection; +import org.bukkit.entity.Egg; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.player.PlayerEggThrowEvent; import world.bentobox.bentobox.api.flags.FlagListener; @@ -24,4 +27,19 @@ public class EggListener extends FlagListener { e.setHatching(false); } } + + /** + * Handle visitor chicken egg hitting + * @param e - event + */ + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onEggHit(ProjectileHitEvent e) { + if (e.getEntity() instanceof Egg egg) { + if (egg.getShooter() instanceof Player player) { + if (!checkIsland(e, player, egg.getLocation(), Flags.EGGS)) { + e.setCancelled(true); + } + } + } + } } diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java index 3553d61f8..10b05a7dd 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/HurtingListener.java @@ -114,13 +114,14 @@ public class HurtingListener extends FlagListener { */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerFeedParrots(PlayerInteractEntityEvent e) { - if (e.getRightClicked() instanceof Parrot - && (e.getHand().equals(EquipmentSlot.HAND) && e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.COOKIE)) - || (e.getHand().equals(EquipmentSlot.OFF_HAND) && e.getPlayer().getInventory().getItemInOffHand().getType().equals(Material.COOKIE))) { - if (((Parrot) e.getRightClicked()).isTamed()) { - checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.HURT_TAMED_ANIMALS); - } else { - checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.HURT_ANIMALS); + if (e.getRightClicked() instanceof Parrot parrot) { + if ((e.getHand().equals(EquipmentSlot.HAND) && e.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.COOKIE)) + || (e.getHand().equals(EquipmentSlot.OFF_HAND) && e.getPlayer().getInventory().getItemInOffHand().getType().equals(Material.COOKIE))) { + if (parrot.isTamed()) { + checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.HURT_TAMED_ANIMALS); + } else { + checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.HURT_ANIMALS); + } } } } diff --git a/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java b/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java index 5ec8784e2..591f74818 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java @@ -389,4 +389,25 @@ public abstract class AbstractTeleportListener * Set of entities that currently is in teleportation. */ protected final Set inTeleport; + + /** + * @return the inTeleport + */ + public Set getInTeleport() { + return inTeleport; + } + + /** + * @return the inPortal + */ + public Set getInPortal() { + return inPortal; + } + + /** + * @return the teleportOrigin + */ + public Map getTeleportOrigin() { + return teleportOrigin; + } } diff --git a/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java b/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java index b461e942e..58a91ded1 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java @@ -59,30 +59,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements // Section: Listeners // --------------------------------------------------------------------- - - /** - * This listener checks player portal events and triggers appropriate methods to transfer - * players to the correct location in other dimension. - *

- * This event is triggered when player is about to being teleported because of contact with the - * nether portal or end gateway portal (exit portal triggers respawn). - *

- * This event is not called if nether/end is disabled in server settings. - * - * @param event the player portal event. - */ - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onPlayerPortalEvent(PlayerPortalEvent event) - { - switch (event.getCause()) - { - case NETHER_PORTAL -> this.portalProcess(event, World.Environment.NETHER); - case END_PORTAL, END_GATEWAY -> this.portalProcess(event, World.Environment.THE_END); - default -> throw new IllegalArgumentException("Unexpected value: " + event.getCause()); - } - } - - /** * Fires the event if nether or end is disabled at the system level * @@ -96,7 +72,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements // This handles only players. return; } - Entity entity = event.getEntity(); Material type = event.getLocation().getBlock().getType(); UUID uuid = entity.getUniqueId(); @@ -106,7 +81,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements { return; } - this.inPortal.add(uuid); // Add original world for respawning. this.teleportOrigin.put(uuid, event.getLocation().getWorld()); @@ -133,7 +107,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements }, 40); return; } - // End portals are instant transfer if (!Bukkit.getAllowEnd() && (type.equals(Material.END_PORTAL) || type.equals(Material.END_GATEWAY))) { @@ -226,6 +199,31 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements }); } + /** + * This listener checks player portal events and triggers appropriate methods to transfer + * players to the correct location in other dimension. + *

+ * This event is triggered when player is about to being teleported because of contact with the + * nether portal or end gateway portal (exit portal triggers respawn). + *

+ * This event is not called if nether/end is disabled in server settings. + * + * @param event the player portal event. + */ + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerPortalEvent(PlayerPortalEvent event) { + switch (event.getCause()) { + case NETHER_PORTAL -> this.portalProcess(event, World.Environment.NETHER); + case END_PORTAL, END_GATEWAY -> this.portalProcess(event, World.Environment.THE_END); + default -> { // Do nothing, ignore + + } + /* + * Other potential reasons: CHORUS_FRUIT , COMMAND, DISMOUNT, + * ENDER_PEARL, EXIT_BED, PLUGIN, SPECTATE , UNKNOWN + */ + } + } // --------------------------------------------------------------------- @@ -248,26 +246,22 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements // Not teleporting from/to bentobox worlds. return; } - if (!this.isAllowedInConfig(overWorld, environment)) { // World is disabled in config. Do not teleport player. event.setCancelled(true); return; } - if (!this.isAllowedOnServer(environment)) { // World is disabled in bukkit. Event is not triggered, but cancel by chance. event.setCancelled(true); } - if (this.inTeleport.contains(event.getPlayer().getUniqueId())) { // Player is already in teleportation. return; } - this.inTeleport.add(event.getPlayer().getUniqueId()); if (fromWorld.equals(overWorld) && !this.isIslandWorld(overWorld, environment)) @@ -276,7 +270,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements this.handleToStandardNetherOrEnd(event, overWorld, environment); return; } - if (!fromWorld.equals(overWorld) && !this.isIslandWorld(overWorld, environment)) { // If entering a portal in the other world, teleport to a portal in overworld if @@ -284,7 +277,6 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements this.handleFromStandardNetherOrEnd(event, overWorld, environment); return; } - // To the nether/end or overworld. World toWorld = !fromWorld.getEnvironment().equals(environment) ? this.getNetherEndWorld(overWorld, environment) : overWorld; @@ -320,13 +312,11 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements // If there is no island, then processor already created island. Nothing to do more. return; } - if (!event.isCancelled() && event.getCanCreatePortal()) { // Let the server teleport return; } - if (World.Environment.THE_END.equals(environment)) { // Prevent death from hitting the ground while calculating location. @@ -366,7 +356,7 @@ public class PlayerTeleportListener extends AbstractTeleportListener implements * @param overWorld - over world * @param environment - environment involved */ - private void handleToStandardNetherOrEnd(PlayerPortalEvent event, + void handleToStandardNetherOrEnd(PlayerPortalEvent event, World overWorld, World.Environment environment) { diff --git a/src/main/java/world/bentobox/bentobox/lists/GameModePlaceholder.java b/src/main/java/world/bentobox/bentobox/lists/GameModePlaceholder.java index 03b67d59b..f79a69bf2 100644 --- a/src/main/java/world/bentobox/bentobox/lists/GameModePlaceholder.java +++ b/src/main/java/world/bentobox/bentobox/lists/GameModePlaceholder.java @@ -3,7 +3,10 @@ package world.bentobox.bentobox.lists; import java.text.DateFormat; import java.time.Instant; import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; @@ -11,6 +14,8 @@ import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.placeholders.GameModePlaceholderReplacer; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -120,6 +125,14 @@ public enum GameModePlaceholder { * @since 1.5.0 */ ISLAND_MEMBERS_COUNT("island_members_count", (addon, user, island) -> island == null ? "" : String.valueOf(island.getMemberSet().size())), + + /** + * Returns the number of players that are or have ever been a MEMBER on this island. + * @since 3.0.0 + */ + ISLAND_HISTORICAL_MEMBERS_COUNT("island_historical_members_count", + (addon, user, island) -> island == null ? "" : getHistoricalMembers(island)), + /** * Returns a comma separated list of player names that are at least MEMBER on this island. * @since 1.13.0 @@ -395,6 +408,24 @@ public enum GameModePlaceholder { this.replacer = replacer; } + /** + * Provides a count of how many players have ever joined the island as a member including the owner + * @param island island + * @return String count of the number of members + */ + private static String getHistoricalMembers(@Nullable Island island) { + Set uniqueMembers = new HashSet<>(); + for (LogEntry le : island.getHistory()) { + if (le.getType() == LogType.JOINED) { + Iterator it = le.getData().keySet().iterator(); + while (it.hasNext()) { + uniqueMembers.add(it.next()); + } + } + } + return String.valueOf(uniqueMembers.size()); + } + /** * Get the visited island * @param addon - game mode addon diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java index 9aceb1595..681fd69e7 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java @@ -47,6 +47,8 @@ import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.Reason; import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.Database; import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory; @@ -938,6 +940,7 @@ public class IslandsManager { */ @NonNull public Map getHomeLocations(@NonNull Island island) { + island.getHomes().forEach((n, l) -> BentoBox.getInstance().logDebug(n)); return island.getHomes(); } @@ -954,6 +957,7 @@ public class IslandsManager { /** * Get the number of homes on this island if this home were added + * This includes the default home, which has no name * * @param island - island * @param name - name @@ -1189,6 +1193,7 @@ public class IslandsManager { * * @param player player */ + @SuppressWarnings("deprecation") private void readyPlayer(@NonNull Player player) { // Stop any gliding player.setGliding(false); @@ -1537,6 +1542,8 @@ public class IslandsManager { // Add player to new island teamIsland.addMember(playerUUID); islandCache.addPlayer(playerUUID, teamIsland); + // Add historu record + teamIsland.log(new LogEntry.Builder(LogType.JOINED).data(playerUUID.toString(), "player").build()); // Save the island updateIsland(teamIsland); } diff --git a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java index a1c0c6859..d4b04400c 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java @@ -23,6 +23,8 @@ import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.flags.Flag; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.database.Database; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.RanksManager; @@ -431,6 +433,8 @@ public class IslandCache { } island.removeMember(uuid); island.removePrimary(uuid); + // Add historu record + island.log(new LogEntry.Builder(LogType.REMOVE).data(uuid.toString(), "player").build()); } /** diff --git a/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java b/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java index bb4f2cb22..198e8950c 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java @@ -15,6 +15,8 @@ import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.island.IslandCreateEvent; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.Reason; +import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; import world.bentobox.bentobox.api.events.island.IslandResetEvent; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -217,6 +219,8 @@ public class NewIsland { island.setFlagsDefaults(); // Register metrics plugin.getMetrics().ifPresent(BStats::increaseIslandsCreatedCount); + // Add historu record + island.log(new LogEntry.Builder(LogType.JOINED).data(user.getUniqueId().toString(), "owner").build()); // Save island IslandsManager.updateIsland(island); } diff --git a/src/main/java/world/bentobox/bentobox/util/IslandInfo.java b/src/main/java/world/bentobox/bentobox/util/IslandInfo.java index 909262f44..43af66e9b 100644 --- a/src/main/java/world/bentobox/bentobox/util/IslandInfo.java +++ b/src/main/java/world/bentobox/bentobox/util/IslandInfo.java @@ -150,8 +150,9 @@ public class IslandInfo { user.sendMessage("commands.admin.info.island-center", TextVariables.XYZ, Util.xyz(location)); user.sendMessage("commands.admin.info.protection-range", RANGE, String.valueOf(island.getProtectionRange())); user.sendMessage("commands.admin.info.protection-coords", XZ1, - Util.xyz(new Vector(island.getMinProtectedX(), 0, island.getMinProtectedZ())), "[xz2]", - Util.xyz(new Vector(island.getMaxProtectedX() - 1, 0, island.getMaxProtectedZ() - 1))); + Util.xyz(new Vector(island.getMinProtectedX(), world.getMinHeight(), island.getMinProtectedZ())), + "[xz2]", Util.xyz(new Vector(island.getMaxProtectedX() - 1, world.getMaxHeight(), + island.getMaxProtectedZ() - 1))); if (island.isSpawn()) { user.sendMessage("commands.admin.info.is-spawn"); } diff --git a/src/main/java/world/bentobox/bentobox/util/Util.java b/src/main/java/world/bentobox/bentobox/util/Util.java index 02674d784..00434d260 100644 --- a/src/main/java/world/bentobox/bentobox/util/Util.java +++ b/src/main/java/world/bentobox/bentobox/util/Util.java @@ -712,7 +712,7 @@ public class Util { * @param player - player */ public static void resetHealth(Player player) { - double maxHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue(); + double maxHealth = player.getAttribute(Attribute.MAX_HEALTH).getBaseValue(); player.setHealth(maxHealth); } @@ -743,7 +743,6 @@ public class Util { throw new IllegalStateException("Class " + clazz.getName() + " does not implement WorldRegenerator"); } } catch (Exception e) { - e.printStackTrace(); plugin.logWarning("No Regenerator found for " + bukkitVersion + ", falling back to Bukkit API."); handler = new world.bentobox.bentobox.nms.fallback.WorldRegeneratorImpl(); } @@ -773,7 +772,6 @@ public class Util { throw new IllegalStateException("Class " + clazz.getName() + " does not implement PasteHandler"); } } catch (Exception e) { - e.printStackTrace(); plugin.logWarning("No PasteHandler found for " + bukkitVersion + ", falling back to Bukkit API."); handler = new world.bentobox.bentobox.nms.fallback.PasteHandlerImpl(); } diff --git a/src/main/resources/locales/de.yml b/src/main/resources/locales/de.yml index 09f8e3d17..be8bb01b8 100644 --- a/src/main/resources/locales/de.yml +++ b/src/main/resources/locales/de.yml @@ -3,6 +3,7 @@ meta: authors: - xXjojojXx - Poslovitch + - Archerymaister banner: RED_BANNER:1:STRIPE_RIGHT:BLACK:STRIPE_LEFT:YELLOW prefixes: bentobox: "&6 BentoBox &7 &l > &r " @@ -13,16 +14,16 @@ general: command-cancelled: "&c Befehl abgebrochen." no-permission: "&c Du hast nicht die Berechtigung, diesen Befehl auszuführen (&7 [permission]&c )." - insufficient-rank: "&c Ihr Rang ist dafür nicht hoch genug! (&7 [rank]&c )" + insufficient-rank: "&c Dein Rang ist dafür nicht hoch genug! (&7 [rank]&c )" use-in-game: "&c Dieser Befehl ist nur im Spiel verfügbar." use-in-console: "&c Dieser Befehl ist nur in der Konsole verfügbar." no-team: "&c Du hast kein Team!" no-island: "&c Du hast keine Insel!" - player-has-island: "&c Der Spieler hat bereits eine Insel!" + player-has-island: "&c Dieser Spieler hat bereits eine Insel!" player-has-no-island: "&c Dieser Spieler hat keine Insel!" already-have-island: "&c Du hast bereits eine Insel!" no-safe-location-found: "&c Es konnte kein sicherer Ort auf der Insel gefunden - werden, an den du dich teleportieren konntest." + werden, an den du dich teleportieren kannst." not-owner: "&c Du bist nicht der Besitzer der Insel!" player-is-not-owner: "&b [name] &c ist nicht Besitzer einer Insel!" not-in-team: "&c Dieser Spieler gehört nicht zu deinem Team!" @@ -36,9 +37,9 @@ general: must-be-positive-number: "&c [number] ist keine gültige positive Zahl." not-on-island: "&c Du bist nicht auf der Insel!" worlds: - overworld: Überwelt + overworld: Oberwelt nether: Nether - the-end: Das Ende + the-end: Das End commands: help: header: "&7 =========== &c [label] Hilfe &7 ===========" @@ -52,7 +53,7 @@ commands: help: description: Admin Befehl resets: - description: die Resets der Spieler bearbeiten + description: Resets der Spieler bearbeiten set: description: Legt die Resets dieses Players fest parameters: " " @@ -60,31 +61,31 @@ commands: reset: description: Setzt die Resets dieses Spielers auf 0 zurück parameters: "" - success-everyone: "&a Erfolgreiches Zurücksetzen &b jedermann&a 's resets + success-everyone: "&a Erfolgreiches Zurücksetzen &bvon allen&a Resets auf &b 0&a ." - success: "&a Erfolgreiches Zurücksetzen von &b [name]&a 's resets auf &b 0&a + success: "&a Erfolgreiches Zurücksetzen von &b [name]&a 's Resets auf &b 0&a ." add: - description: fügt dem Spieler Resets hinzu + description: Fügt dem Spieler Resets hinzu parameters: " " - success: "&a Erfolgreiches Hinzufügen von &b [number] &a resets zu &b [name], - wodurch die Summe auf &b [total] &a resets erhöht wurde." + success: "&a Erfolgreiches Hinzufügen von&b [number]&a Resets zu&b [name], + wodurch die Summe auf &b [total] &a Resets erhöht wurde." remove: - description: entfernt Resets von dem Spieler + description: Entfernt Resets von dem Spieler parameters: " " - success: "&a Erfolgreiches Entfernen von &b [number] &a resets zu &b [name], - wodurch die Summe auf &b [total]&a resets reduziert wurde." + success: "&a Erfolgreiches Entfernen von&b [number] &a Resets für&b [name], + wodurch die Summe auf&b [total]&a Resets reduziert wurde." purge: parameters: "[days]" - description: löschen von Inseln, die seit mehr als [days] verlassen sind + description: Löschen von Inseln, die seit mehr als [days] verlassen sind days-one-or-more: Muss mindestens 1 Tag oder mehr betragen purgable-islands: Es wurden [number] löschbare Inseln gefunden. - purge-in-progress: "&c Löschung läuft. Benutze Löschstop zum Abbrechen" - number-error: "&c Angabe muss eine Anzahl von Tagen sein" - confirm: "&d Tippe [label] purge confirm zum Starten des Löschvorgangs ein" + purge-in-progress: "&c Löschung läuft. Benutze /[label] purge stop zum Abbrechen" + number-error: "&c Eingabe muss eine Anzahl von Tagen sein" + confirm: "&d Tippe /[label] purge confirm zum Starten des Löschvorgangs ein" completed: "&a Lösung gestoppt" see-console-for-status: Löschung gestartet. Für den Status siehe Konsole - no-purge-in-progress: "&c Derzeit wird keine Bereinigung durchgeführt." + no-purge-in-progress: "&c Derzeit wird keine Löschung durchgeführt." protect: description: Umschalten des Insellöschschutzes move-to-island: "&c Erst auf eine Insel gehen!" @@ -97,8 +98,8 @@ commands: description: Löschen freier Inseln - Bestätigung erforderlich unowned-islands: "&d [number] Inseln gefunden" status: - description: zeigt den Status der Bereinigung an - status: "&b [purged] &a islands purged out of &b [purgeable] &7(&b[percentage] + description: Zeigt den Status der Bereinigung an + status: "&b [purged] &a von&b [purgeable] &b Inseln wurden gelöscht &7(&b[percentage] %&7)&a." team: description: Teams verwalten @@ -110,12 +111,12 @@ commands: success: "&b [name]&a wurde der Insel von &b [owner]&a hinzugefügt." disband: parameters: "" - description: das Team des Eigentümers auflösen - use-disband-owner: "&c Nicht der Besitzer! Benutze auflösen [owner]." + description: Das Team des Eigentümers auflösen + use-disband-owner: "&c Nicht der Besitzer! Benutze disband [owner]." disbanded: "&c Der Admin hat dein Team aufgelöst!" - success: "&b Das Team von [name] &a wurde aufgelöst." + success: "&b Das Team von [name]&a wurde aufgelöst." fix: - description: scannt und behebt die inselübergreifende Mitgliedschaft in der + description: Scannt und behebt die inselübergreifende Mitgliedschaft in der Datenbank scanning: Datenbank wird durchsucht... duplicate-owner: "&c Spieler besitzt mehr als eine Insel in der Datenbank: @@ -128,27 +129,27 @@ commands: done: "&a Scan" kick: parameters: "" - description: einen Spieler aus einem Team kicken + description: Einen Spieler aus einem Team kicken cannot-kick-owner: "&c Du kannst den Besitzer nicht kicken. Kick erst die Mitglieder." not-in-team: "&c Dieser Spieler ist nicht in einem Team." admin-kicked: "&c Der Admin hat dich aus dem Team gekickt." - success: "&b [name] &a wurde von der Insel von &b [owner] &a gekickt." + success: "&b [name]&a wurde von der Insel von &b [owner] &a gekickt." setowner: parameters: "" description: überträgt das Insel-Eigentum auf den Spieler already-owner: "&c [name] ist bereits der Besitzer dieser Insel!" - must-be-on-island: "&c Sie müssen auf der Insel sein, um den Besitzer festzulegen" - confirmation: "&a Möchten Sie [name] wirklich als Eigentümer der Insel in + must-be-on-island: "&c Du musst auf der Insel sein, um den Besitzer festzulegen" + confirmation: "&a Möchtest du [name] wirklich als Eigentümer der Insel in [xyz] festlegen?" - success: "&b [name]&a ist jetzt der Besitzer dieser Insel." + success: "&b [name]&a ist jetzt der Besitzer dieser Insel." extra-islands: "&c Warnung: Dieser Spieler besitzt jetzt [number] Inseln. Das sind mehr als durch die Einstellungen oder Berechtigungen erlaubt ist: [max]." range: description: Admin Insel Bereichsbefehl invalid-value: - too-low: "&c Der Schutzbereich muss größer sein als &b 1&c !" + too-low: "&c Der Schutzbereich muss größer sein als&b 1&c !" too-high: "&c Der Schutzbereich sollte gleich groß oder kleiner sein als &b [number]&c !" same-as-before: "&c Der Schutzbereich ist bereits eingestellt auf &b [number]&c @@ -157,30 +158,30 @@ commands: already-off: "&c Die Indikatoren sind bereits aus" already-on: "&c Die Indikatoren sind bereits an" description: Anzeige des Inselbereichs ein/ausblenden - hiding: "&2 Versteckte Reichweite Indikatoren" + hiding: "&2 Inselbegrenzungen ausgeblendet" hint: |- - &c Rote Barriere-Icons &f zeigen die aktuelle Inselschutzbereichsgrenze an. - &7 Graue Partikel &f zeigen die maximale Inselgrenze an. - Grüne Partikel &f zeigen den voreingestellten Schutzbereich an, wenn der Inselschutzbereich davon abweicht. - showing: "&2 Anzeigen von Reichweite Indikatoren" + &c Rote Barriere-Icons&f zeigen die aktuelle Inselschutzbereichsgrenze an. + &7 Graue Partikel&f zeigen die maximale Inselgrenze an. + Grüne Partikel&f zeigen den voreingestellten Schutzbereich an, wenn der Inselschutzbereich davon abweicht. + showing: "&2 Inselbegrenzungen eingeblendet" set: parameters: " [Inselstandort]" - description: legt den geschützten Inselbereich fest + description: Legt den geschützten Inselbereich fest success: "&a Inselschutzbereich einstellen auf &b [number]&a ." reset: parameters: "" description: Setzt den inselgeschützten Bereich auf den Weltstandard zurück - success: "& a Setzen Sie den Inselschutzbereich auf & b [number] & a zurück." + success: "& a Setzt den Inselschutzbereich auf & b [number] & a zurück." add: description: Erhöht den Schutzbereich der Insel parameters: " [Inselstandort]" - success: "&a Erfolgreiche Erhöhung von &b [name]&a 's geschützten Bereich + success: "&a Erfolgreiche Erhöhung von &b [name]&a's geschützten Bereich der Insel auf &b [total] &7 (&b +[number]&7 )&a ." remove: description: Verringert den Schutzbereich der Insel parameters: " [Inselstandort]" success: "&a Erfolgreich reduziert &b [name]&a 's geschützten Bereich der - Insel auf&b [total] &7 (&b -[number]&7 )&a ." + Insel um&b [total] &7 (&b -[number]&7 )&a ." register: parameters: "" description: Spieler auf freier Insel registrieren, auf der du dich befindest @@ -201,7 +202,7 @@ commands: unknown-island-location: "&c Unbekannter Inselstandort" specify-island-location: "&c Gib denn Inselstandort in x,y,z Format an" player-has-more-than-one-island: "&c Spieler hat mehr als eine Insel. Gib - an welche" + an welche." info: parameters: "" description: Informationen über deinen Standort oder die Spielerinsel erhalten @@ -209,14 +210,14 @@ commands: title: "========== Insel Info ============" island-uuid: 'UUID: [uuid]' owner: 'Besitzer: [owner] ([uuid])' - last-login: 'Letzter login: [date]' + last-login: 'Letzter Login: [date]' last-login-date-time-format: EEE MMM dd HH:mm:ss zzz yyyy deaths: 'Tode: [number]' resets-left: 'Resets: [number] (Max: [total])' team-members-title: 'Teammitglieder:' team-owner-format: "&a [name] [rank]" team-member-format: "&b [name] [rank]" - island-protection-center: 'Schutzbereich Mitte: [xyz]' + island-protection-center: 'Mittelpunkt des Schutzbereiches: [xyz]' island-center: 'Inselmitte: [xyz]' island-coords: 'Koordinaten der Insel: [xz1] bis [xz2]' islands-in-trash: "&d Der Spieler hat Inseln im Papierkorb." @@ -233,12 +234,12 @@ commands: bundle: "&a Blaupausenpaket zum Erstellen der Insel: &b [name]" switch: description: Schutzumgehung ein-/ausschalten - op: "&c Ops können den Schutz immer umgehen. Deop um den Befehl zu benutzen." + op: "&c OPs können den Schutz immer umgehen. Deop um den Befehl zu benutzen." removing: Entfernen der Schutzumgehung... adding: Schutzumgehung hinzufügen... switchto: parameters: " " - description: die Spielerinsel durch die nummerierte Insel im Papierkorb ersetzen + description: Die Spielerinsel durch die nummerierte Insel im Papierkorb ersetzen out-of-range: "&c Die Zahl muss zwischen 1 und [number] liegen. Verwende &l [label] trash [player] &r &c um die Inselnummern zu sehen" cannot-switch: "&c Wechsel fehlgeschlagen. Siehe Konsolenprotokoll für Fehler." @@ -250,35 +251,35 @@ commands: parameters: "[player]" description: Zeige freie Inseln oder Spielerinseln im Papierkorb title: "&d =========== Inseln im Papierkorb ===========" - count: "&l &d Insel [number]:" - use-switch: "&a Nutze &l [label] switchto &r &a um den Spieler + count: "&l&d Insel [number]:" + use-switch: "&a Nutze&l /[label] switchto &r&a um den Spieler auf die Insel im Papierkorb zu wechseln" - use-emptytrash: "&a Nutze &l [label] emptytrash [player]&r &a, um den Papierkorb + use-emptytrash: "&a Nutze&l /[label] emptytrash [player]&r&a, um den Papierkorb dauerhaft zu leeren" emptytrash: parameters: "[player]" description: Den Papierkorb für Spieler oder aller freien Inseln im Papierkorb leeren - success: "&a Papierkorb erfolgreich entleert." + success: "&a Papierkorb erfolgreich geleert." version: description: BentoBox und Addon-Versionen anzeigen setrange: parameters: " " - description: die Reichweite der Spielerinsel festlegen - range-updated: "&a Inselbereich aktualisiert auf &b [number]&a ." + description: Die Reichweite der Spielerinsel festlegen + range-updated: "&a Inselbereich aktualisiert auf &b [number]&a." reload: - description: neu laden + description: Neu laden tp: parameters: " [Insel des Spielers]" - description: zu einer Spielerinsel teleportieren - manual: "&c Kein sicherer Warp gefunden! Manuell in die Nähe von &b [location] + description: Zu einer Spielerinsel teleportieren + manual: "&c Kein sicherer Warp gefunden! Manuell in die Nähe von&b [location] &c teleportieren und nachsehen" tpuser: parameters: " [Insel des Spielers]" - description: einen Spieler zur Insel eines anderen Spielers teleportieren + description: Einen Spieler zur Insel eines anderen Spielers teleportieren getrank: parameters: "" - description: den Rang eines Spielers auf seiner Insel erhalten + description: Den Rang eines Spielers auf seiner Insel erhalten rank-is: "&a Der Rang ist [rank] auf ihrer Insel." setrank: parameters: " [Insels Besitzer]" @@ -286,14 +287,14 @@ commands: festlegen unknown-rank: "&c Unbekannter Rang!" not-possible: "&c Der Rang muss höher sein als Besucher." - rank-set: "&a Rang gesetzt von &b [from] &a auf &b [to] &a auf &b [name]&a 's + rank-set: "&a Rang von&b [from]&a auf&b [to]&a gesetzt für&b [name]&a's Insel." setprotectionlocation: parameters: "[x y z Koordinaten]" - description: aktuellen Standort oder [x y z] als Zentrum des Schutzbereichs + description: Aktuellen Standort oder [x y z] als Zentrum des Schutzbereichs der Insel einstellen island: "&c Dies betrifft die Insel in [xyz], die '[name]' gehört." - confirmation: "&c Möchten Sie [xyz] wirklich als Schutzzentrum festlegen?" + confirmation: "&c Möchtest du [xyz] wirklich als Schutzzentrum festlegen?" success: "&a [xyz] erfolgreich als Schutzzentrum festgelegt." fail: "&a Fehler beim Festlegen von [xyz] als Schutzzentrum." island-location-changed: "&a [user] hat das Schutzzentrum der Insel in [xyz] @@ -305,13 +306,13 @@ commands: no-island-here: "&c Es gibt hier keine Insel." confirmation: "&c Bist du sicher, dass du diese Insel als Spawn für diese Welt setzen willst?" - success: "&a Diese Insel erfolgreich als Spawn für diese Welt gesetzt." + success: "&a Diese Insel wurde erfolgreich als Spawn für diese Welt gesetzt." setspawnpoint: - description: aktuellen Standort als Spawnpunkt für diese Insel festlegen + description: Aktuellen Standort als Spawnpunkt für diese Insel festlegen no-island-here: "&c Hier gibt es keine Insel." - confirmation: "&c Möchten Sie diesen Ort wirklich als Spawnpunkt für diese Insel + confirmation: "&c Möchtest du diesen Ort wirklich als Spawnpunkt für diese Insel festlegen?" - success: "&a Setzen Sie diesen Ort erfolgreich als Spawnpunkt für diese Insel." + success: "&a Spawnpunkt für diese Insel erfolgreich gesetzt." island-spawnpoint-changed: "&a [user] hat diesen Insel-Spawnpunkt geändert." settings: parameters: "[player]" @@ -328,14 +329,14 @@ commands: could-not-load: "&c Diese Datei konnte nicht geladen werden!" could-not-save: "&c Hmm, etwas ist beim Speichern der Datei schiefgegangen: [message]" - set-pos1: "&a Position 1 set auf [vector]" - set-pos2: "&a Position 2 set auf [vector]" - set-different-pos: "&c Setze eine andere Position - diese Pos ist bereits gesetzt!" + set-pos1: "&a Position 1 auf [vector] gesetzt" + set-pos2: "&a Position 2 auf [vector] gesetzt" + set-different-pos: "&c Setze eine andere Position - diese Position ist bereits gesetzt!" need-pos1-pos2: "&c Zuerst Pos1 und Pos2 setzen!" copying: "&b Kopiere Blöcke..." copied-blocks: "&b [number] Blöcke in die Zwischenablage kopiert" - look-at-a-block: "&c Blick auf den zu setzenden Block innerhalb von 20 Blöcken" - mid-copy: "&c Du bist mitten in der Kopie. Warte bis die Kopie fertig ist." + look-at-a-block: "&c Schaue auf den zu setzenden Block innerhalb von 20 Blöcken" + mid-copy: "&c Du stehst mitten in der Kopie. Warte bis die Kopie fertig ist." copied-percent: "&6 Kopiert [number]%" copy: parameters: "[air]" @@ -359,7 +360,7 @@ commands: origin: description: Setze den Ursprung der Blaupause auf deine Position paste: - description: die Zwischenablage an Ihrem Standort einfügen + description: Die Zwischenablage an Ihrem Standort einfügen pasting: "&a Einfügen..." pos1: description: 1. Ecke der quaderförmigen Zwischenablage setzen @@ -371,11 +372,11 @@ commands: rename: parameters: " " description: Eine Blaupause umbenennen - success: "&a Blaupause &b [old] &a wurde erfolgreich in &b [name]&a umbenannt." + success: "&a Blaupause&b [old]&a wurde erfolgreich in&b [name]&a umbenannt." pick-different-name: "&c Bitte gib einen Namen an, der sich vom aktuellen Namen der Blaupause unterscheidet." management: - back: zurück + back: Zurück instruction: Klick auf die Blaupause und dann klick hier title: Blaupausen-Bundle-Manager edit: Klicken zum Bearbeiten @@ -384,15 +385,15 @@ commands: world-name-syntax: "[name] Welt" world-instructions: "Blaupause zum Setzen \nnach rechts legen" trash: Papierkorb - no-trash: Papierkorb nicht möglich - trash-instructions: Rechtsklick hier zum Löschen + no-trash: Kann nicht weggeworfen werden + trash-instructions: Rechtsklicke hier zum Löschen no-trash-instructions: Standardpaket kann nicht gelöscht werden permission: Berechtigung - no-permission: Keine Erlaubnis + no-permission: Keine Permission perm-required: Erforderlich no-perm-required: Perm für Standardpaket kann nicht festgelegt werden perm-not-required: Nicht erforderlich - perm-format: "&e" + perm-format: "&e " remove: Rechtsklick zum Entfernen blueprint-instruction: |- Zum Auswählen anklicken, @@ -402,19 +403,19 @@ commands: new-bundle: Neues Bundle new-bundle-instructions: Zum Erstellen eines neuen Bundles anklicken name: - quit: beenden + quit: Beenden prompt: Gib einen Namen ein, oder 'quit' zum Beenden too-long: "&c Zu lang" - pick-a-unique-name: Wähle bitte einen eindeutigeren Namen + pick-a-unique-name: Wähle bitte einen einzigartigen Namen stripped-char-in-unique-name: "&c Einige Zeichen wurden entfernt, da sie nicht zulässig sind. &a Die neue ID lautet &b [name]&a." success: Erfolg! conversation-prefix: ">" description: - quit: beenden + quit: Beenden instructions: |- Gib eine mehrzeilige Beschreibung für [name] ein. - und 'quit' in einer eigenen Zeile um zu beenden. + Schreibe 'quit' in einer eigenen Zeile um zu beenden. success: Erfolg! cancelling: Abbrechen slot: "&f Bevorzugter Slot [number]" @@ -437,13 +438,13 @@ commands: description: Welteinstellungen verwalten delete: parameters: "" - description: löscht die Insel eines Spielers + description: Löscht die Insel eines Spielers cannot-delete-owner: "&c Alle Inselmitglieder müssen vor dem Löschen von der Insel gekickt werden." deleted-island: "&a Insel bei &e [xyz] &a wurde erfolgreich gelöscht." deletehomes: parameters: "" - description: löscht alle benannten Häuser von einer Insel + description: Löscht alle benannten Häuser von einer Insel warning: "&c Alle benannten Häuser werden von der Insel gelöscht!" why: parameters: "" @@ -453,73 +454,73 @@ commands: deaths: description: Tode von Spielern bearbeiten reset: - description: setzt die Tode des Spielers zurück + description: Setzt die Tode des Spielers zurück parameters: "" - success: "&a Erfolgreiches Zurücksetzen von &b [name]&a 's Toden auf &b 0&a + success: "&a Erfolgreiches Zurücksetzen von &b [name]&a's Toden auf &b 0&a ." set: description: Legt die Tode des Spielers fest parameters: " " success: "&a Erfolgreiche Einstellung von &b [name]&a's Toden auf &b [number]&a." add: - description: fügt dem Spieler Tode hinzu + description: Fügt dem Spieler Tode hinzu parameters: " " - success: "&a Es wurde erfolgreich &b [number] &a Tode zu &b [name] hinzugefügt, - wodurch sich die Gesamtzahl auf &b [total] &a Tode erhöht." + success: "&a Es wurde&b [number]&a Tode zu &b [name] hinzugefügt, + wodurch sich die Gesamtzahl auf&b [total]&a Tode erhöht." remove: - description: entfernt Tode von dem Spieler + description: Entfernt Tode von dem Spieler parameters: " " - success: "&a Es wurden erfolgreich &b [number] &a Tode von &b [name] entfernt, - wodurch sich die Gesamtzahl auf &b [total]&a Tode verringert hat." + success: "&a Es wurden&b [number]&a Tode von &b[name] entfernt, + wodurch sich die Gesamtzahl auf&b [total]&a Tode verringert hat." resetname: description: Spielerinselnamen zurücksetzen success: "&a Der Inselname von [name] wurde erfolgreich zurückgesetzt." bentobox: description: BentoBox Admin-Befehl perms: - description: Zeigt die effektiven Dauerwellen für BentoBox und Add-ons in einem + description: Zeigt die aktiven Permissions für BentoBox und Add-ons in einem YAML-Format an about: - description: zeigt Copyright- und Lizenzinformationen an + description: Zeigt Copyright- und Lizenzinformationen an reload: - description: lädt BentoBox und alle Addons, Einstellungen und Locales neu + description: Lädt BentoBox, alle Addons, Einstellungen und Locales neu locales-reloaded: "&2 Sprachen neu geladen." addons-reloaded: "&2 Addons neu geladen." settings-reloaded: "&2 Einstellungen neu geladen." - addon: "&6 Neu laden von &b [name]&2 ." - addon-reloaded: "&b [name] &2 neu geladen." - warning: "&c Warnung: Das Neuladen kann zu Instabilität führen, wenn du also + addon: "&6 Neu laden von &b [name]&2." + addon-reloaded: "&b[name] &2 neu geladen." + warning: "&c Warnung: Das Neuladen kann zu Instabilität führen, wenn du danach Fehler siehst, starte den Server neu." unknown-addon: "&c Unbekanntes Addon!" locales: - description: lädt Gebietsschemas neu + description: Lädt Locales neu version: - plugin-version: "&2 BentoBox version: &3 [version]" - description: zeigt die Versionen von BentoBox und Addons an + plugin-version: "&2 BentoBox version:&3 [version]" + description: Zeigt die Versionen von BentoBox und Addons an loaded-addons: 'Geladene Addons:' loaded-game-worlds: 'Geladene Spielewelten:' - addon-syntax: "&2 [name] &3 [version] &7 (&3 [state]&7 )" - game-world: "&2 [name] &7 (&3 [addon]&7 ): &a Oberwelt&7 , &r Nether&7 , &r + addon-syntax: "&2 [name]&3 [version]&7 (&3 [state]&7 )" + game-world: "&2 [name]&7 (&3 [addon]&7 ): &a Oberwelt&7,&r Nether&7,&r End" - server: "&2 Ausführen von &3 [name] [version]&2 ." - database: "&2 Datenbank: &3 [database]" + server: "&2 Ausführen von&3 [name] [version]&2." + database: "&2 Datenbank:&3 [database]" manage: - description: zeigt das Verwaltungs-Panel an + description: Zeigt das Verwaltungs-Panel an catalog: - description: zeigt den Katalog an + description: Zeigt den Katalog an locale: - description: führt eine Analyse der Lokalisierungsdateien durch + description: Führt eine Analyse der Lokalisierungsdateien durch see-console: |- - &a Überprüfe die Konsole, um die Rückmeldung zu sehen. - &a Dieser Befehl ist so spammy, dass das Feedback nicht aus dem Chat gelesen werden kann... + [prefix_bentobox]&a Überprüfe die Konsole, um die Rückmeldung zu sehen. + [prefix_bentobox]&a Dieser Befehl ist so spammy, dass das Feedback nicht aus dem Chat gelesen werden kann... migrate: - description: migriert Daten von einer Datenbank in eine andere + description: Migriert Daten von einer Datenbank in eine andere players: "&6 Spieler migrieren" names: "&6 Namen migrieren" addons: "&6 Migrieren von Addons" class: "&6 Migration [description]" - migrated: "&A migriert" - completed: "[prefix_bentobox]&a Abgeschlossen" + migrated: "&a Migriert" + completed: "&a Abgeschlossen" rank: description: Ränge auflisten, hinzufügen oder entfernen parameters: "&a [list | add | remove] [Rangreferenz] [Rangwert]" @@ -532,7 +533,7 @@ commands: failure: "&c [rank] konnte nicht entfernt werden. Unbekannter Rang." list: "&a Die registrierten Ränge sind wie folgt:" confirmation: - confirm: "&c Befehl innerhalb von &b [seconds]s&c zur Bestätigung erneut eingeben." + confirm: "&c Befehl innerhalb von&b [seconds]s&c zur Bestätigung erneut eingeben." previous-request-cancelled: "&6 Vorherige Bestätigungsanforderung abgebrochen." request-cancelled: "&c Bestätigungs-Timeout - &b-Anforderung abgebrochen." delay: @@ -544,19 +545,19 @@ commands: description: Über dieses Addon go: parameters: "[home number]" - description: teleportiert dich auf deine Insel + description: Teleportiert dich auf deine Insel teleport: "&a Teleportiert dich auf deine Insel." - teleported: "&a Teleportierte dich zu Home &e #[number]." - unknown-home: "&c Unbekannter Heimatname!" + teleported: "&a Zu Home&e #[number] teleportiert." + unknown-home: "&c Unbekannter Home-Name!" help: description: Der wichtigste Inselbefehl spawn: - description: teleportiert dich zum Spawn + description: Teleportiert dich zum Spawn teleporting: "&a Teleportiert dich zum Spawn." no-spawn: "&c Es gibt keinen Spawn auf dieser Welt." create: - description: erstellt eine Insel, mit Hilfe einer optionalen Blaupause (erfordert - Genehmigung) + description: Erstellt eine Insel, mit Hilfe einer optionalen Blaupause (erfordert + Permission) parameters: "" too-many-islands: "&c Es gibt zu viele Inseln auf dieser Welt: es gibt nicht genug Platz, um deine zu erstellen." @@ -570,10 +571,10 @@ commands: you-cannot-make-team: "&c Teammitglieder können keine Inseln in derselben Welt wie ihre Teaminsel erstellen." pasting: - estimated-time: "&a Geschätzte Zeit: &b [number] &a Sekunden." - blocks: "&a Block für Block aufbauen: &b [number] &a Blöcke insgesamt..." - entities: "&a Füllen mit Entitäten: &b [number] &a Entitäten in insgesamt..." - dimension-done: "&eine Insel in [world] wird gebaut." + estimated-time: "&a Geschätzte Zeit:&b [number]&a Sekunden." + blocks: "&a Block für Block aufbauen:&b [number]&a Blöcke insgesamt..." + entities: "&a Füllen mit Entitäten:&b [number]&a Entitäten insgesamt..." + dimension-done: "&a Insel in [world] wird gebaut." done: "&a Erledigt! Deine Insel ist bereit und wartet auf dich!" pick: "&2 Eine Insel auswählen" unknown-blueprint: "&c Diese Blaupause wurde noch nicht geladen." @@ -582,40 +583,40 @@ commands: you-can-teleport-to-your-island: "&a Du kannst dich auf deine Insel teleportieren, wann immer du willst." deletehome: - description: einen Heimatort löschen - parameters: "[Heimatname]" + description: Homepunkt löschen + parameters: "[Home name]" homes: - description: listet eure Häuser auf + description: Listet deine Homes auf info: description: Informationen über deine Insel oder die Insel des Spielers anzeigen parameters: "" near: - description: zeigt die Namen der benachbarten Inseln um Sie herum an + description: Zeigt die Namen der benachbarten Inseln um dich herum an the-following-islands: "&a Die folgenden Inseln sind in der Nähe:" - syntax: "&6 [direction]: &a [name]" - north: Nord - south: Süd - east: Ost - west: West + syntax: "&6 [direction]:&a [name]" + north: Norden + south: Süden + east: Osten + west: Westen no-neighbors: "&c Du hast keine unmittelbaren Nachbarinseln!" reset: description: Startet deine Insel neu und entfernt die alte parameters: "" none-left: "&c Du hast keine Resets mehr übrig!" - resets-left: "&c Du hast &b [number] &c Resets übrig" + resets-left: "&c Du hast&b [number]&c Resets übrig" confirmation: |- &c Bist du sicher, dass du das tun willst? &c Alle Inselmitglieder werden von der Insel gekickt, du musst sie danach neu einladen. - &c Es gibt kein Zurück: wenn deine aktuelle Insel gelöscht ist, gibt es &l keine &r &c Möglichkeit, sie später wiederherzustellen. + &c Es gibt kein Zurück: wenn deine aktuelle Insel gelöscht ist, gibt es&l keine&r&c Möglichkeit, sie später wiederherzustellen. kicked-from-island: "&c Du wirst im [gamemode] von deiner Insel gekickt, weil der Besitzer sie zurücksetzt." sethome: description: Setze deinen Home Teleport Punkt must-be-on-your-island: "&c Du musst auf deiner Insel sein, um ein Home zu setzen!" - too-many-homes: "&c Kann nicht eingestellt werden - Ihre Insel hat maximal [number] - Häuser." + too-many-homes: "&c Kann nicht eingestellt werden - Deine Insel hat maximal [number] + Homes." home-set: "&6 Dein Insel-Home wurde auf deine aktuelle Position gesetzt." - homes-are: "&6 Inselhäuser sind:" + homes-are: "&6 Inselhomes sind:" home-list-syntax: "&6 [name]" nether: not-allowed: "&c Du darfst dein Home nicht im Nether setzen." @@ -627,19 +628,19 @@ commands: setname: description: Gib deiner Insel einen Namen name-too-short: "&c Zu kurz. Die Mindestgröße ist [number] Zeichen." - name-too-long: "&c Zu lang. Die maximale Größe ist [number] Zeichen." + name-too-long: "&c Zu lang. Die Maximalgröße ist [number] Zeichen." name-already-exists: "&c Es gibt bereits eine Insel mit diesem Namen in diesem Spielmodus." parameters: "" - success: "&a Der Name Ihrer Insel wurde erfolgreich auf &b [name]&a gesetzt." + success: "&a Der Name Ihrer Insel wurde erfolgreich auf&b [name]&a gesetzt." renamehome: - description: einen Heimatort umbenennen + description: Ein Home umbenennen parameters: "[Heimatname]" - enter-new-name: "&6 Geben Sie den neuen Namen ein" - already-exists: "&c Dieser Name existiert bereits, versuchen Sie es mit einem + enter-new-name: "&6 Gib den neuen Namen ein" + already-exists: "&c Dieser Name existiert bereits, versuche es mit einem anderen Namen." resetname: - description: setze deinen Inselnamen zurück + description: Setze deinen Inselnamen zurück success: "&a Setzen Sie Ihren Inselnamen erfolgreich zurück." team: description: Dein Team verwalten @@ -652,13 +653,13 @@ commands: description: Der Status des Teams rank-filter: name: Rangfilter - description: "&a Klicken Sie hier, um die Ränge zu wechseln" + description: "&a Klicke hier, um die Ränge zu wechseln" invitation: Einladung invite: name: Spieler einladen description: | - &a Spieler müssen sich in der - &a selben Welt wie Sie befinden, um + &a Spieler müssen sich in + &a deiner Welt befinden, um &a in der Liste angezeigt zu werden. tips: LEFT: @@ -667,12 +668,12 @@ commands: RIGHT: name: "&b Rechtsklick" SHIFT_RIGHT: - name: "&b Umschalttaste Rechtsklick" + name: "&b Umschalttaste + Rechtsklick" reject: "&a zum Ablehnen" kick: "&a um Spieler rauszuwerfen" leave: "&a verlässt das Team" SHIFT_LEFT: - name: "&b Umschalttaste Linksklick" + name: "&b Umschalttaste + Linksklick" accept: "&a zum Akzeptieren" setowner: | &a, um den Besitzer @@ -680,11 +681,11 @@ commands: info: description: zeigt detaillierte Informationen über dein Team an member-layout: - online: "&a &l o &r &f [name]" - offline: "&c &l o &r &f [name] &7 ([last_seen])" - offline-not-last-seen: "&c &l o &r &f [name]" + online: "&a&l o&r&f [name]" + offline: "&c&l o&r&f [name] &7 ([last_seen])" + offline-not-last-seen: "&c&l o&r&f [name]" last-seen: - layout: "&b [number] &7 [unit] vorher" + layout: "&b [number]&7 [unit] vorher" days: Tage hours: Stunden minutes: Minuten @@ -694,20 +695,20 @@ commands: &a Online-Mitglieder: &b [online] rank-layout: owner: "&6 [rank]:" - generic: "&6 [rank] &7 (&b [number]&7 )&6 :" + generic: "&6 [rank]&7 (&b [number]&7 )&6:" coop: - description: einen Spieler Coop-Rang auf deiner Insel machen + description: Einen Spieler den Coop-Rang auf deiner Insel geben parameters: "" cannot-coop-yourself: "&c Du kannst dich nicht selbst coopen!" already-has-rank: "&c Der Spieler hat bereits einen Rang!" you-are-a-coop-member: "&2 Du wurdest von [name] gecooped" - success: "&a Du hast &b [name] gecooped." + success: "&a Du hast&b [name] gecooped." name-has-invited-you: | &a [name] hat Sie eingeladen, - &a als Genossenschaftsmitglied + &a als Coop-Mitglied &a ihrer Insel beizutreten. uncoop: - description: einen Coop-Rang von einem Spieler entfernen + description: Einen Coop-Rang von einem Spieler entfernen parameters: "" cannot-uncoop-yourself: "&c Du kannst dich nicht selbst entcoopen!" cannot-uncoop-member: "&c Du kannst kein Teammitglied entcoopen!" @@ -716,12 +717,12 @@ commands: von [name]'s Insel" all-members-logged-off: "&c Alle Inselmitglieder haben sich ausgeloggt, so dass du kein Coop-Mitglied mehr auf der Insel von [name] bist" - success: "&b [name] &a ist nicht länger ein Coop-Mitglied deiner Insel." + success: "&b [name]&a ist nicht länger ein Coop-Mitglied deiner Insel." is-full: "&c Sie können niemanden einbinden." trust: description: Gib einem Spieler einen vertrauenswürdigen Rang auf deiner Insel parameters: "" - trust-in-yourself: "&c Vertraue auf dich selbst!" + trust-in-yourself: "&c Vertraue dir selbst!" name-has-invited-you: | &a [name] hat Sie eingeladen, &a als vertrauenswürdiges Mitglied @@ -731,16 +732,16 @@ commands: success: "&a Du vertraust &b [name]&a ." is-full: "&c Sie können keinem anderen vertrauen." untrust: - description: den Rang eines vertrauenswürdigen Spielers vom Spieler entfernen + description: Den Rang eines vertrauenswürdigen Spielers vom Spieler entfernen parameters: "" cannot-untrust-yourself: "&c Du kannst dir nicht selbst misstrauen!" cannot-untrust-member: "&c Du kannst einem Teammitglied nicht misstrauen!" player-not-trusted: "&c Der Spieler ist nicht vertrauenswürdig!" - you-are-no-longer-trusted: "&c Du bist nicht mehr vertrauenswürdig für &b + you-are-no-longer-trusted: "&c Du bist nicht mehr vertrauenswürdig für&b [name]&a !" - success: "&b [name] &a wird auf deiner Insel nicht mehr vertraut." + success: "&b [name]&a wird auf deiner Insel nicht mehr vertraut." invite: - description: einen Spieler auf deine Insel einladen + description: Einen Spieler auf deine Insel einladen invitation-sent: "&a Einladung gesendet an [name]" removing-invite: "&c Einladung entfernen" name-has-invited-you: | @@ -749,8 +750,8 @@ commands: to-accept-or-reject: "&a Gib /[label] team accept um zu akzeptieren, oder /[label] team reject um abzulehnen" you-will-lose-your-island: | - &c WARNUNG! Sie verlieren alle - &c Ihre Inseln, wenn Sie akzeptieren! + &c WARNUNG! Du verlierst alle + &c Inseln, wenn Sie akzeptieren! gui: titles: team-invite-panel: Spieler einladen @@ -780,7 +781,7 @@ commands: cooldown: "&c Du kannst diese Person für weitere [number] Sekunden nicht einladen." island-is-full: "&c Deine Insel ist voll, du kannst niemanden mehr einladen." - none-invited-you: "&c Niemand hat dich eingeladen :c." + none-invited-you: "&c Niemand hat dich eingeladen. :c" you-already-are-in-team: "&c Du bist bereits in einem Team!" already-on-team: "&c Dieser Spieler ist bereits in einem Team!" invalid-invite: "&c Diese Einladung ist nicht mehr gültig, sorry." @@ -788,7 +789,7 @@ commands: parameters: "" you-can-invite: "&a Du kannst [number] weitere Spieler einladen." accept: - description: eine Einladung annehmen + description: Eine Einladung annehmen you-joined-island: "&a Du bist einer Insel beigetreten! Benutze /[label] team info um die anderen Mitglieder zu sehen." name-joined-your-island: "&a [name] hat sich deiner Insel angeschlossen!" @@ -797,12 +798,12 @@ commands: &c diese &c Einladung annehmen möchten? reject: - description: eine Einladung ablehnen + description: Eine Einladung ablehnen you-rejected-invite: "&a Du hast die Einladung, einer Insel beizutreten, abgelehnt." name-rejected-your-invite: "&c [name] hat deine Insel-Einladung abgelehnt!" cancel: - description: die ausstehende Einladung zu deiner Insel zurücknehmen + description: Die ausstehende Einladung zu deiner Insel zurücknehmen leave: cannot-leave: "&c Besitzer können nicht gehen! Werde zuerst Mitglied, oder kicke alle Mitglieder." @@ -810,14 +811,14 @@ commands: left-your-island: "&c [name] &c hat deine Insel verlassen" success: "&a Du hast diese Insel verlassen." kick: - description: entferne ein Mitglied von deiner Insel + description: Entferne ein Mitglied von deiner Insel parameters: "" player-kicked: "&c Der [name] hat dich im [gamemode] von der Insel geworfen!" cannot-kick: "&c Du kannst dich nicht selbst kicken!" - cannot-kick-rank: "&c Dein Rang erlaubt es nicht, [name] zu treten!" - success: "&b [name] &a wurde von deiner Insel gekickt." + cannot-kick-rank: "&c Dein Rang erlaubt es nicht, [name] zu kicken!" + success: "&b [name]&a wurde von deiner Insel gekickt." demote: - description: einen Spieler auf deiner Insel um einen Rang zurückstufen + description: Einen Spieler auf deiner Insel um einen Rang zurückstufen parameters: "" errors: cant-demote-yourself: "&c Du kannst dich nicht selbst zurückstufen!" @@ -826,10 +827,10 @@ commands: failure: "&c Der Spieler kann nicht weiter zurückgestuft werden!" success: "&a Rückstufung von [name] auf [rank]." promote: - description: einen Spieler auf deiner Insel um einen Rang befördern + description: Einen Spieler auf deiner Insel um einen Rang befördern parameters: "" errors: - cant-promote-yourself: "&c Du kannst dich nicht bewerben!" + cant-promote-yourself: "&c Du kannst dich nicht befördern!" cant-promote: "&c Sie können nicht über Ihren Rang hinaus aufsteigen!" must-be-member: "&c Der Spieler muss ein Inselmitglied sein!" failure: "&c Der Spieler kann nicht weiter befördert werden!" @@ -838,38 +839,38 @@ commands: description: Deinen Inselbesitz auf ein Mitglied übertragen errors: cant-transfer-to-yourself: "&c Du kannst dir das Eigentum nicht selbst übertragen! - &7 (&o Tja, eigentlich könntest du... Aber wir wollen nicht, dass du es - tust. Weil es sinnlos ist. &r &7 )" + &7(&o Tja, eigentlich könntest du... Aber wir wollen nicht, dass du es + tust. Weil es sinnlos ist.&r& )" target-is-not-member: "&c Dieser Spieler gehört nicht zu deinem Inselteam!" at-max: "&c Dieser Spieler hat bereits die maximal zulässige Anzahl an Inseln!" name-is-the-owner: "&a [name] ist jetzt der Inselbesitzer!" parameters: "" you-are-the-owner: "&a Du bist jetzt der Inselbesitzer!" ban: - description: einen Spieler von deiner Insel verbannen + description: Einen Spieler von deiner Insel verbannen parameters: "" cannot-ban-yourself: "&c Du kannst dich nicht bannen!" cannot-ban: "&c Dieser Spieler kann nicht gebannt werden." - cannot-ban-member: "&c Kick das Teammitglied zuerst, dann bannen." + cannot-ban-member: "&c Kick das Teammitglied zuerst, dann kannst bannen." cannot-ban-more-players: "&c Du hast das Ban-Limit erreicht, du kannst keine - Spieler mehr von deiner Insel verbannen." + Spieler mehr von deiner Insel bannen." player-already-banned: "&c Der Spieler ist bereits gebannt." - player-banned: "&b [name]&c ist jetzt von deiner Insel verbannt." - owner-banned-you: "&b [name]&c hat dich von seiner Insel verbannt!" + player-banned: "&b [name]&c ist jetzt von deiner Insel verbannt." + owner-banned-you: "&b [name]&c hat dich von seiner Insel verbannt!" you-are-banned: "&b Du bist von dieser Insel verbannt!" unban: - description: entbanne einen Spieler von deiner Insel + description: Entbanne einen Spieler von deiner Insel parameters: "" cannot-unban-yourself: "&c Du kannst dich nicht selbst entbannen!" player-not-banned: "&c Der Spieler ist nicht gebannt." - player-unbanned: "&b [name]&a ist jetzt nicht mehr von deiner Insel verbannt." - you-are-unbanned: "&b [name]&a hat dich von seiner Insel entbannt!" + player-unbanned: "&b [name]&a ist jetzt nicht mehr von deiner Insel verbannt." + you-are-unbanned: "&b [name]&a hat dich von seiner Insel entbannt!" banlist: - description: gebannte Spieler auflisten + description: Gebannte Spieler auflisten noone: "&a Niemand ist auf dieser Insel verbannt." the-following: "&b Die folgenden Spieler sind gebannt:" names: "&c [line]" - you-can-ban: "&b Du kannst bis zu &e [number] &b weitere Spieler verbannen." + you-can-ban: "&b Du kannst bis zu&e [number]&b weitere Spieler verbannen." settings: description: Einstellungen der Insel anzeigen language: @@ -878,14 +879,14 @@ commands: not-available: "&c Diese Sprache ist nicht verfügbar." already-selected: "&c Sie verwenden diese Sprache bereits." expel: - description: einen Spieler von deiner Insel vertreiben + description: Einen Spieler von deiner Insel vertreiben parameters: "" cannot-expel-yourself: "&c Du kannst dich nicht selbst vertreiben!" cannot-expel: "&c Dieser Spieler kann nicht vertrieben werden." cannot-expel-member: "&c Du kannst kein Teammitglied vertreiben!" not-on-island: "&c Dieser Spieler ist nicht auf deiner Insel!" - player-expelled-you: "&b [name]&c hat dich von der Insel vertrieben!" - success: "&a Du hast &b [name] &a von der Insel vertrieben." + player-expelled-you: "&b [name]&c hat dich von der Insel vertrieben!" + success: "&a Du hast&b [name]&a von der Insel vertrieben." ranks: owner: Besitzer sub-owner: Mitbesitzer @@ -901,15 +902,15 @@ protection: flags: ALLAY: name: Interaktion beruhigen - description: Erlauben Sie das Geben und Mitnehmen von Gegenständen nach/von + description: Geben und Nehmen von Gegenständen an/von einem Allay hint: Allay-Interaktion deaktiviert ANIMAL_NATURAL_SPAWN: - description: Natürliches Laichen von Tieren umschalten - name: Tier natürlicher Laich + description: Natürliches Spawnen von Tieren umschalten + name: Tier ANIMAL_SPAWNERS_SPAWN: - description: Schalten Sie das Laichen von Tieren mit Spawnern um - name: Tierlaicher + description: Schaltet das Spawnen von Tieren mit Spawnern um + name: Tierspawner ANVIL: description: Interaktion umschalten name: Ambosse @@ -917,11 +918,11 @@ protection: ARMOR_STAND: description: Interaktion umschalten name: Rüstungsständer - hint: Rüstungsstandnutzung deaktiviert + hint: Rüstungsständnutzung deaktiviert AXOLOTL_SCOOPING: name: Axolotl beim Schöpfen description: Lassen Sie Axolotl mit einem Eimer schöpfen - hint: Axolotl-Schaufeln deaktiviert + hint: Axolotl-Schöpfen deaktiviert BEACON: description: Interaktion umschalten name: Leuchtfeuer @@ -950,23 +951,23 @@ protection: hint: Blockabbau deaktiviert BREAK_SPAWNERS: description: |- - Toggle Spawner brechen. + Spawner abbauen umschalten Überschreibt das Flag Break Blocks. name: Spawner brechen hint: Spawner brechen deaktiviert BREAK_HOPPERS: description: |- - Kipptrichter brechen. + Trichter abbauen. Überschreibt das Flag Break Blocks. - name: Hopper brechen - hint: Hopper Brechen deaktiviert + name: Hopper abbauen + hint: Hopper abbauen deaktiviert BREEDING: description: Umschalten der Zucht name: Tiere züchten hint: Tierzucht geschützt BREWING: description: Interaktion umschalten - name: Brauereistände + name: Braustände hint: Brauen deaktiviert BUCKET: description: Interaktion umschalten @@ -983,24 +984,24 @@ protection: CAKE: description: Kuchen Interaktion umschalten name: Kuchen - hint: Kuchen essen deaktiviert + hint: Kuchenessen deaktiviert CARTOGRAPHY: - name: Kartographietabellen + name: Kartographietisch description: Verwendung umschalten hint: Zugriff auf die Kartografietabelle deaktiviert CONTAINER: name: Behälter - description: "&a Umschalten der Interaktion mit Truhen, \n&a Shulker-Boxen und + description: "&a Umschalten der Interaktion mit Truhen, \n&a Shulker-Boxen, Blumentöpfen, \n&a Kompostern und Fässern.\n\n&7 Andere Behälter werden \n&7 durch spezielle Flags gehandhabt." hint: Zugriff auf Behälter deaktiviert CHEST: - name: Truhen und Minenkarrenkisten + name: Truhen- und Truhenminecarts description: |- &a Schalte die Interaktion mit Truhen - &a und Truhen-Minecarts um. - &a (Enthält keine eingeschlossenen Truhen) - hint: Brustzugang deaktiviert + &a und Truhenminecarts um. + &a (Enthält keine Redstonetruhen) + hint: Kistenzugang deaktiviert BARREL: name: Fässer description: Fass-Interaktion umschalten @@ -1014,7 +1015,7 @@ protection: COMPOSTER: name: Komposter description: Komposter-Interaktion umschalten - hint: Composer-Interaktion deaktiviert + hint: Komposter-Interaktion deaktiviert LOOM: name: Webstuhl description: Verwendung umschalten @@ -1026,7 +1027,7 @@ protection: GRINDSTONE: name: Schleifstein description: Verwendung umschalten - hint: Grindstone-Zugriff deaktiviert + hint: Schleifstein-Zugriff deaktiviert SHULKER_BOX: name: Shulker-Boxen description: Shulker-Box-Interaktion umschalten @@ -1045,9 +1046,9 @@ protection: description: Verwendung umschalten hint: Der Zugang zum Steinmetz ist deaktiviert TRAPPED_CHEST: - name: Gefangene Truhen - description: Wechseln Sie zwischen der Interaktion mit eingeschlossener Brust - hint: Zugang zur eingeschlossenen Brust deaktiviert + name: Redstonetruhen + description: Interaktion mit Redstonetruhen umschalten + hint: Zugang zu Redstonetruhe deaktiviert DISPENSER: name: Werfer description: Umschalten der Werfer-Interaktion @@ -1072,28 +1073,28 @@ protection: name: Chorusfrüchte hint: Chorusfrucht Teleportation deaktiviert CLEAN_SUPER_FLAT: - description: "&a Ermöglicht die Bereinigung beliebiger \n&a superflacher Chunks + description: "&a Ermöglicht die Bereinigung beliebiger\n&a superflacher Chunks in \n&a Inselwelten" name: Bereinigung Super Flat COARSE_DIRT_TILLING: description: "&a Umschalten der Bearbeitung von grober \n&a Erde und Abbauen von Podzol \n&a zur Gewinnung von Erde" - name: grobe Erde bearbeiten + name: Grobe Erde bearbeiten hint: Keine Bearbeitung grober Erde COLLECT_LAVA: - description: "&a Umschalten des Lavasammelns \n&a (Überbrückung der Eimer)" + description: "&a Umschalten des Lavasammelns \n&a (Überschreibt Eimer)" name: Lava sammeln hint: Kein Sammeln von Lava COLLECT_WATER: - description: "&a Umschalten des Wassersammelns \n&a (Überbrückung der Eimer)" + description: "&a Umschalten des Wassersammelns \n&a (Überschreibt Eimer)" name: Wasser sammeln hint: Wassereimer deaktiviert COLLECT_POWDERED_SNOW: description: |- &a Toggle Sammeln von Pulverschnee - &a (Buckets überschreiben) - name: Sammeln Sie Pulverschnee - hint: Pulverschneeschaufeln deaktiviert + &a (Eimer überschreiben) + name: Pulverschnee sammeln + hint: Pulverschneesammeln deaktiviert COMMAND_RANKS: name: "&e Befehlsreihenfolge" description: "&a Befehlsreihenfolge konfigurieren" @@ -1113,7 +1114,7 @@ protection: name: Pflanzenanbau hint: Pflanzenanbau deaktiviert CROP_TRAMPLE: - description: Umschalten des Felder zertrampelns + description: Felder zertrampeln umschalten name: Felder zertrampeln hint: Felder zertrampeln deaktiviert DOOR: @@ -1130,21 +1131,21 @@ protection: name: Verwendung von Farbstoffen hint: Färben deaktiviert EGGS: - description: Umschalten des Eierwerfens + description: Eierwerfen umschalten name: Eier werfen hint: Eier werfen deaktiviert ENCHANTING: - description: Umschalten der Nutzung + description: Nutzung umschalten name: Verzauberungstisch hint: Verzauberungstische deaktiviert ENDER_CHEST: - description: Umschalten Nutzung/Crafting + description: Nutzung/Herstellung umschalten name: Ender Truhen hint: Ender Truhen sind in dieser Welt deaktiviert ENDERMAN_DEATH_DROP: description: "&a Endermen werden \n&a jeden Block, den sie \n&a halten, fallen lassen, wenn sie getötet werden." - name: Enderman Death Drop + name: Endermen lassen Blöcke fallen ENDERMAN_GRIEFING: description: "&a Endermen können \n&a Blöcke von Inseln entfernen" name: Enderman Beschädigung @@ -1154,17 +1155,17 @@ protection: &a wenn aktiv. name: Enderman-Teleport ENDER_PEARL: - description: Umschalten der Nutzung + description: Nutzung umschalten name: Enderperlen hint: Nutzung von Enderperlen deaktiviert ENTER_EXIT_MESSAGES: - description: Eintritt- und Austrittsmeldungen anzeigen + description: Kommens- und Gehensmeldungen anzeigen island: "[name]'s Insel" - name: Ein- und Ausgangsmeldungen - now-entering: "&b Du betrittst jetzt [name]" - now-entering-your-island: "&a Geben Sie jetzt Ihre Insel ein: &b [name]" + name: Kommens- und Gehensmeldungen + now-entering: "&b Du betrittst jetzt [name]s Insel" + now-entering-your-island: "&a Du betrittst jetzt deine Insel" now-leaving: "&b Du verlässt jetzt [name]" - now-leaving-your-island: "&a Verlasse jetzt deine Insel: &b [name]" + now-leaving-your-island: "&a Du verlässt jetzt deine Insel" EXPERIENCE_BOTTLE_THROWING: name: Erfahrungsflasche werfen description: Umschalten des Werfens von Erfahrungsflaschen. @@ -1186,7 +1187,7 @@ protection: kann oder nicht." FISH_SCOOPING: name: Fische fangen - description: Erlaubt das Keschern von Fischen mit einem Eimer + description: Erlaubt das Fangen von Fischen mit einem Eimer hint: Fische fangen deaktiviert FLINT_AND_STEEL: name: Feuerzeug @@ -1208,19 +1209,19 @@ protection: HARVEST: description: |- &a Legt fest, wer Getreide ernten kann. - &a Vergessen Sie nicht, das Element zuzulassen - &eine Abholung auch! + &a Vergiss nicht, das Item aufsammeln auch zuzulassen + &a zuzulassen! name: Ernte - hint: Ernteernte deaktiviert + hint: Ernte deaktiviert HIVE: description: "&a Bienenstockernte umschalten." name: Bienenstockernte - hint: Ernte behindert + hint: Ernte deaktiviert HURT_TAMED_ANIMALS: description: Verletzen ein-/ausschalten. Aktiviert bedeutet, dass gezähmte Tiere - Schaden nehmen können. Deaktiviert bedeutet, dass sie unbesiegbar sind. - name: Verletzte gezähmte Tiere - hint: Gezähmtes Tier, das Behinderte verletzt + Schaden nehmen können. Deaktiviert bedeutet, dass sie nicht verletzt werden können. + name: Verletze gezähmte Tiere + hint: Gezähmtes Tier verletzen deaktivert HURT_ANIMALS: description: Umschalten des Verletzens name: Tiere verletzen @@ -1240,9 +1241,9 @@ protection: hint: Item Rahmen Nutzung deaktiviert ITEM_FRAME_DAMAGE: description: "&a Mobs können \n&a Item-Rahmen beschädigen" - name: Item Rahmenschäden + name: Itemrahmenschäden INVINCIBLE_VISITORS: - description: "&a Konfigurieren Sie unbesiegbare Besucher \n&a Einstellungen." + description: "&a Unbesiegbare Besucher" name: "&e Unbesiegbare Besucher" hint: "&c Besucher geschützt" ISLAND_RESPAWN: @@ -1272,18 +1273,17 @@ protection: description: "&a Erlaubt es, Bücher auf ein Lesepult zu legen \n&a oder Bücher daraus zu nehmen.\n\n&c Es hindert die Spieler nicht daran, \n&c die Bücher zu lesen." - hint: Kann kein Buch auf ein Lesepult legen oder ein Buch daraus nehmen. + hint: Interaktion mit Lesepulten deaktiviert LEVER: description: Umschalten der Nutzung - name: Hebel benutzen + name: Hebeln benutzen hint: Nutzung von Hebeln deaktiviert LIMIT_MOBS: description: |- - &a Limitgesellschaften von - &a spawnen in diesem Spiel - &a Modus. - name: "&e Beschränken Sie das Spawnen des Entitätstyps" - can: "&a Kann laichen" + &a Limitiert das Erscheinen von + &a Mobs in diesem Spielmodus + name: "&e Beschränkt das Spawnen des Entitätstyps" + can: "&a Kann spawnen" cannot: "&c Kann nicht spawnen" LIQUIDS_FLOWING_OUT: name: Flüssigkeiten, die aus den Inseln herausfließen @@ -1299,8 +1299,8 @@ protection: CHANGE_SETTINGS: name: Einstellungen ändern description: |- - &a Ermöglicht den Wechsel des Mitglieds - &eine Rolle kann Inseleinstellungen ändern. + &a Ermöglicht Mitgliedern das Ändern + &a von Inseleinstellungen. MILKING: description: Umschalten des Melkens von Kühen name: Melken @@ -1310,21 +1310,21 @@ protection: description: Umschalten von Minecart-Interaktionen hint: Minecart-Interaktion deaktiviert MONSTER_NATURAL_SPAWN: - description: Toggle Natürliches Monsterspawnen - name: Monster natürlicher Spawn + description: Schaltet natürliches Monsterspawnen um + name: Natürlicher Monsterspawn MONSTER_SPAWNERS_SPAWN: - description: Schalten Sie das Spawnen von Monstern mit Spawnern um + description: Schaltet das Spawnen von Monstern mit Spawnern um name: Monsterspawner MOUNT_INVENTORY: - description: "&a Umschalten des Zugriffs \n&a zum Montieren des Inventars" - name: Inventar montieren - hint: Montage des Inventars deaktiviert + description: "&a Umschalten des Zugriffs \n&a auf Reittierinventare" + name: Reittierinventare + hint: Reittierinventare deaktiviert NAME_TAG: name: Namensschilder description: Umschalten der Nutzung hint: Namensschild-Interaktion deaktiviert NATURAL_SPAWNING_OUTSIDE_RANGE: - name: Natürliches Kreatur spawning ausser Reichweite + name: Natürliche Spawns außerhalb des Schutzbereiches description: "&a Umschalten, ob Kreaturen (Tiere und \n&a Monster) außerhalb \n&a des Schutzbereichs einer Insel natürlich spawnen können.\n\n&c Beachte, dass es Kreaturen \n&c nicht daran hindert, über einen Mob-Spawner oder ein @@ -1332,33 +1332,33 @@ protection: NOTE_BLOCK: description: Umschalten der Nutzung name: Notenblock - hint: Notenblock Interaktion deaktiviert + hint: Notenblockinteraktion deaktiviert OBSIDIAN_SCOOPING: - name: Obsidian-Schaufeln - description: "&a Umschalten der Schaufel \n&a Erlaubt es, Obsidian mit einem - leeren Eimer zurück in die Lava umzuwandeln \n&a Schützt Neulinge. Reduziert + name: Schöpfen von Obsidian + description: "&a Umschalten des Schöpfens \n&a Erlaubt es, Obsidian mit einem + leeren Eimer zurück in die Lava umzuwandeln \n&a Hilft Neulingen und reduziert Resets." scooping: "&a Obsidian wieder in Lava verwandelt. Sei nächstes Mal vorsichtig!" obsidian-nearby: "&c Es gibt Obsidianblöcke in der Nähe, du kannst diesen Block - nicht in Lava schaufeln." + nicht in Lava umwandeln." OFFLINE_GROWTH: description: "&a Wenn deaktiviert, wachsen Pflanzen \n&a nicht auf Inseln \n&a, - auf welchen alle Mitglieder offline sind. \n&a Kann helfen, Lags zu reduzieren." + auf denen alle Mitglieder offline sind. \n&a Kann helfen, Lags zu reduzieren." name: Offline-Wachstum OFFLINE_REDSTONE: - description: "&a Wenn deaktiviert, wird redstone \n&a nicht auf Inseln \n&a + description: "&a Wenn deaktiviert, wird Redstone \n&a nicht auf Inseln \n&a funktionieren, auf denen alle Mitglieder offline sind. \n&a Kann helfen, Lags zu reduzieren. \n&a Hat keinen Einfluss auf die Spawn-Insel." name: Offline Redstone PETS_STAY_AT_HOME: description: |- - &a Wenn sie aktiv sind, können + &a Wenn aktiv, können &a gezähmte Haustiere nur auf die &a Heimatinsel des Besitzers gehen &a und sie nicht verlassen. name: Haustiere bleiben zu Hause PISTON_PUSH: - description: "&a Aktivieren Sie diese Option, um zu \n&a verhindern, dass Kolben + description: "&a Aktiviere diese Option, um zu \n&a verhindern, dass Kolben Blöcke außerhalb\n&a der Insel drücken." name: Kolben schieben PLACE_BLOCKS: @@ -1372,11 +1372,11 @@ protection: NETHER_PORTAL: description: Umschalten der Nutzung name: Nether Portal - hint: Portalnutzung deaktiviert + hint: Netherportalnutzung deaktiviert END_PORTAL: description: Umschalten der Nutzung name: End Portal - hint: Portalnutzung deaktiviert + hint: Endportalnutzung deaktiviert PRESSURE_PLATE: description: Umschalten der Nutzung name: Druckplatten @@ -1385,18 +1385,18 @@ protection: description: |- &c PVP aktivieren/deaktivieren &c im End. - name: End PVP + name: PVP im End hint: PVP im End deaktiviert - enabled: "&c Der PVP am Ende wurde aktiviert." - disabled: "&a Der PVP am Ende wurde deaktiviert." + enabled: "&c Das PVP im End wurde aktiviert." + disabled: "&a Das PVP im End wurde deaktiviert." PVP_NETHER: description: |- &c PVP aktivieren/deaktivieren &c im Nether. name: Nether PVP hint: PVP im Nether deaktiviert - enabled: "&c Der PVP im Nether wurde aktiviert." - disabled: "&a Der PVP im Nether wurde deaktiviert." + enabled: "&c Das PVP im Nether wurde aktiviert." + disabled: "&a Das PVP im Nether wurde deaktiviert." PVP_OVERWORLD: description: |- &c PVP aktivieren/deaktivieren @@ -1410,9 +1410,9 @@ protection: name: Redstone Items hint: Redstone-Interaktion deaktiviert REMOVE_END_EXIT_ISLAND: - description: "&a Verhindert, dass die \n&a Endausgangsinsel bei den Koordinaten + description: "&a Verhindert, dass die \n&a Ausgangsinsel vom End bei den Koordinaten 0,0 \n&a erzeugt wird" - name: Entfernen der Endausgangsinsel + name: Entfernen der Ausgangsinsel vom End REMOVE_MOBS: description: "&a Entferne Monster, wenn \n&a sie sich auf die Insel teleportieren" name: Monster entfernen @@ -1431,8 +1431,8 @@ protection: SPAWNER_SPAWN_EGGS: description: "&a Erlaubt die Änderung des Entitätstyps \n&a eines Spawners unter Verwendung von Spawn-Eiern." - name: Spawneier auf spawnern - hint: changing a spawner's entity type using spawn eggs is not allowed + name: Spawner ändern + hint: Das Ändern von Spawnern ist nicht gestattet SCULK_SENSOR: description: |- &a Schaltet den Sculk-Sensor um @@ -1441,16 +1441,16 @@ protection: hint: Die Aktivierung des Sculk-Sensors ist deaktiviert SCULK_SHRIEKER: description: |- - &a Schaltet den Sculk-Schreier um - &a Aktivierung. - name: Sculk-Schreier - hint: Die Aktivierung von Sculk Shrieker ist deaktiviert + &a Schaltet die Aktivierung von + &a Sculk-Kreischern um. + name: Sculk-Kreischer + hint: Die Aktivierung von Sculk-Kreischern ist deaktiviert SIGN_EDITING: description: |- &a Ermöglicht Textbearbeitung - &a von Zeichen - name: Zeichenbearbeitung - hint: Die Zeichenbearbeitung ist deaktiviert + &a von Schildern + name: Schildbearbeitung + hint: Die Schildbearbeitung ist deaktiviert TNT_DAMAGE: description: "&a Erlaubt es TNT und TNT-Minecarts \n&a Blöcke zu zerstören und Objekte \n&a zu beschädigen." @@ -1462,38 +1462,38 @@ protection: hint: TNT Zündung deaktiviert TRADING: description: Handel umschalten - name: Villager Handel - hint: Handel mit Villagern deaktiviert + name: Dorfbewohnerhandel + hint: Handel mit Dorfbewohnern deaktiviert TRAPDOOR: description: Zugriff umschalten name: Falltüren hint: Nutzung von Falltüren deaktiviert TREES_GROWING_OUTSIDE_RANGE: - name: Bäume, die ausserhalb der Reichweite wachsen + name: Bäume, die ausserhalb des Inselbereichs wachsen description: "&a Umschalten, ob Bäume außerhalb des Schutzbereichs einer \n&a Insel wachsen können oder nicht. \n&a Es verhindert nicht nur, dass die Setzlinge \n&a außerhalb des Schutzbereichs einer Insel \n&a wachsen, sondern blockiert - auch die Erzeugung \n&a von Blättern/Stämmen außerhalb der Insel, also \n&a - das Fällen des Baumes." + auch die Erzeugung \n&a von Blättern/Stämmen außerhalb der Insel, was wichtig für \n&a + das Fällen des Baumes ist." TURTLE_EGGS: - description: Zerkleinerung umschalten + description: Zertreten umschalten name: Schildkröteneier - hint: Schildkrötenei Zerdrücken deaktiviert + hint: Zertreten von Schildkröteneiern deaktiviert FROST_WALKER: description: Verzauberung Eisläufer umschalten name: Eisläufer hint: Eisläufer deaktiviert EXPERIENCE_PICKUP: name: Erfahrung aufnehmen - description: Erfahrungskugel-Aufnahme umschalten + description: Aufsammeln von Erfahrung umschalten hint: Erfahrung aufnehmen deaktiviert PREVENT_TELEPORT_WHEN_FALLING: - name: Verhindert den Teleport bei einem Sturz + name: Verhindert den Teleport beim Fallen description: "&a Verhindert, dass Spieler sich mit einem Befehl \n&a zurück auf ihre Insel teleportieren, \n&a wenn sie fallen." hint: "&c Das kannst du nicht machen, wenn du fällst." VISITOR_KEEP_INVENTORY: - name: Besucher führen eine Bestandsaufnahme des Todes + name: Besucher behalten ihr Inventar beim Tod description: |- &a Verhindern Sie, dass Spieler ihre &a Gegenstände und Erfahrungen @@ -1509,33 +1509,32 @@ protection: &a Heimatinsel des Besitzers gehen &a und sie nicht verlassen. VISITOR_TRIGGER_RAID: - name: Besucher lösen Razzien aus + name: Besucher können Raids auslösen description: |- - &a Schaltet um, ob Besucher starten können - &a ein Überfall auf eine Insel, die sie sind - &ein Besuch. - &A - &ein Bad Omen-Effekt wird entfernt! + &a Schaltet um, ob Besucher Rais auf + &a Inseln starten können, die sie Besuchen. + &a + &a Der Bad Omen-Effekt wird entfernt! ENTITY_PORTAL_TELEPORT: - name: Nutzung des Entitätsportals + name: Portalnutzung durch Entitäten description: |- - &a Schaltet um, ob Entitäten (Nicht-Spieler) dies können - &a nutzen Portale, um zwischen ihnen zu teleportieren - &a Dimensionen + &a Schaltet um, ob Entitäten (Nicht-Spieler) + &a Portale nutzen können, um zwischen + &a Dimensionen zu teleportieren WITHER_DAMAGE: name: Umschalten von Wither-Schäden description: "&a Wenn aktiv, kann der Wither \n&a Blöcke und Spieler schädigen" WORLD_BLOCK_EXPLODE_DAMAGE: description: |- - &a Bett- und Respawn-Anker zulassen - &a, um Blöcke zu zerstören und zu beschädigen - &a Entitäten außerhalb der Inselgrenzen. + &a Bett- und Respawn-Anker können Blöcke und + &a Entitäten außerhalb der Inselgrenzen verletzen. name: Weltblock-Explosionsschaden WORLD_TNT_DAMAGE: description: |- - &a TNT- und TNT-Minecarts zulassen - &a um Blöcke zu brechen und zu beschädigen - &a Entitäten außerhalb der Inselgrenzen. + &a TNT- und TNT-Minecarts können + &a außerhalb der Inselgrenzen + &a Blöcke zerstören und Entitäten + &a verletzen. name: Welt-TNT-Schaden locked: "&c Diese Insel ist gesperrt!" protected: "&c Insel geschützt: [description]" @@ -1552,12 +1551,12 @@ protection: name: "&a Grundeinstellungen" description: "&a Zeigt die nützlichsten Einstellungen an." expert: - name: "&c Experten Einstellungen" + name: "&c Experteneinstellungen" description: "&a Zeigt alle verfügbaren Einstellungen an." - click-to-switch: "&e Klick &a, zum wechseln zum &r [next]&r &a ." + click-to-switch: "&e Klicken&a, zum wechseln zu&r [next]&r&a." reset-to-default: name: "&c Zurücksetzen auf Standard" - description: "&a Setzt &c &l ALLE &r &a Einstellungen auf ihren \n&a Standardwert + description: "&a Setzt&c&l ALLE&r&a Einstellungen auf ihren \n&a Standardwert zurück." PROTECTION: title: "&6 Schutz" @@ -1587,7 +1586,7 @@ protection: &a [description] &7 Aktuelle Einstellung: [setting] - setting-active: "&a Aktiv" + setting-active: "&a Aktiviert" setting-disabled: "&c Deaktiviert" management: panel: @@ -1595,7 +1594,7 @@ management: views: gamemodes: name: "&6 Gamemodes" - description: "&e Klick &a um die aktuell geladenen Spielmodi anzuzeigen" + description: "&e Klicke&a, um die aktuell geladenen Spielmodi anzuzeigen" blueprints: name: "&6 Blaupausen" description: "&a Öffnet das Admin-Blaupausenmenü." @@ -1604,14 +1603,14 @@ management: description: "&a Inseln: &b [islands]" addons: name: "&6 Addons" - description: "&e Klick &a um die aktuell geladenen Addons anzuzeigen" + description: "&e Klicke&a, um die aktuell geladenen Addons anzuzeigen" hooks: name: "&6 Haken" - description: "&e klicken &a um die aktuell geladenen Haken anzuzeigen" + description: "&e Klicke,&a um die aktuell geladenen Haken anzuzeigen" actions: reload: name: "&c Neu laden" - description: "&e Klick &c &l zweimal &r &a um BentoBox neu zu laden" + description: "&e Klicke&c&l zweimal&r&a um BentoBox neu zu laden" buttons: catalog: name: "&6 Addon Katalog" @@ -1626,21 +1625,21 @@ management: state: name: "&6 Kompatibilität" description: - COMPATIBLE: "&a Ausführung &e [name] [Version]&a .\n\n&a BentoBox läuft - derzeit auf einer \n&a &l KOMPATIBELEN &r &a Server Software und \n&a + COMPATIBLE: "&a Ausführung &e [name] [Version]&a.\n\n&a BentoBox läuft + derzeit auf einer \n&a&l KOMPATIBLEN&r&a Server-Software und \n&a Version.\n\n&a Seine Funktionen sind vollständig darauf ausgelegt, \n&a in dieser Umgebung zu laufen." - SUPPORTED: "&a Ausführung &e [name] [Version]&a .\n\n&a BentoBox läuft derzeit - auf einer \n&a &l UNTERSTÜTZTEN &r &a Server-Software und einer \n&a Version.\n\n&a + SUPPORTED: "&a Ausführung &e [name] [Version]&a.\n\n&a BentoBox läuft derzeit + auf einer \n&a&l UNTERSTÜTZTEN&r&a Server-Software und einer \n&a Version.\n\n&a Die meisten seiner Funktionen werden \n&a in dieser Umgebung problemlos laufen." - NOT_SUPPORTED: "&a Ausführung &e [name] [Version]&a .\n\n&a BentoBox läuft - derzeit auf einer \n&6 &l NICHT UNTERSTÜTZTEN &r &a Server-Software oder + NOT_SUPPORTED: "&a Ausführung &e [name] [Version]&a.\n\n&a BentoBox läuft + derzeit auf einer \n&6&l NICHT UNTERSTÜTZTEN &r&aServer-Software oder \n&a Version.\n\n&a Während die meisten seiner Funktionen \n&a korrekt - ausgeführt werden, ist mit &6 plattformspezifischen Fehlern oder \n&6 - Problemen zu rechnen&a ." - INCOMPATIBLE: "&a Ausführung &e [name] [Version]&a .\n\n&a BentoBox läuft - derzeit auf einer \n&c &l INKOMPATIBELEN &r &a Server-Software oder \n&a + ausgeführt werden, ist mit&6 plattformspezifischen Fehlern oder \n&6 + Problemen zu rechnen&a." + INCOMPATIBLE: "&a Ausführung &e [name] [Version]&a.\n\n&a BentoBox läuft + derzeit auf einer \n&c &l INKOMPATIBLEN&r&a Server-Software oder \n&a Version.\n\n&c Seltsames Verhalten und Fehler können auftreten \n&c und die meisten Funktionen können instabil sein." catalog: @@ -1660,12 +1659,12 @@ catalog: zu blättern." icon: description-template: "&8 [topic]\n&a [install]\n\n&7 &o [description]\n\n&e - Klick &a, um den Link zur neuesten Version \n&a zu erhalten." + Klicke&a, um den Link zur neuesten Version \n&a zu erhalten." already-installed: Bereits installiert! install-now: Jetzt installieren! empty-here: name: "&b Hier sieht es leer aus..." - description: "&c BentoBox konnte keine Verbindung zu GitHub herstellen.\n\nErlaubt + description: "&c BentoBox konnte keine Verbindung zu GitHub herstellen.\n\nErlaube BentoBox die Verbindung zu GitHub in \n&a der Konfiguration oder versuche es später noch einmal." enums: @@ -1681,7 +1680,7 @@ enums: MELTING: Schmelzen LAVA: Lava DROWNING: Ertrinken - BLOCK_EXPLOSION: Explosion blockieren + BLOCK_EXPLOSION: Blockexplosion ENTITY_EXPLOSION: Entitätsexplosion VOID: Leere LIGHTNING: Blitz @@ -1693,25 +1692,25 @@ enums: FALLING_BLOCK: Fallender Block THORNS: Dornen DRAGON_BREATH: Drachenatem - CUSTOM: Brauch + CUSTOM: Benutzerdefiniert FLY_INTO_WALL: In die Wand fliegen HOT_FLOOR: Heißer Boden - CRAMMING: Pauken + CRAMMING: Cramming DRYOUT: Austrocknen - FREEZE: Einfrieren + FREEZE: Erfrieren KILL: Töten SONIC_BOOM: Überschallknall WORLD_BORDER: Weltgrenze panel: credits: - title: "&8 [name] &2 Credits" + title: "&8 [name]&2 Credits" contributor: name: "&a [name]" - description: "&a Verpflichtungen: &b [commits]" + description: "&a Beiträge:&b [commits]" empty-here: name: "&c Hier sieht es leer aus..." description: "&c BentoBox konnte die Mitwirkenden \n&c für dieses Addon nicht - erfassen.\n\n&a BentoBox erlauben, sich mit GitHub in \n&a der Konfiguration + erfassen.\n\n&a BentoBox in der Konfiguration erlauben, sich mit GitHub \n&a zu verbinden oder es später erneut versuchen." panels: island_creation: @@ -1720,10 +1719,10 @@ panels: bundle: name: "&l [name]" description: "[description]" - uses: "&a Verwendet [number]/[max]" + uses: "&a Verwendung [number]/[max]" unlimited: "&a Unbegrenzte Nutzung erlaubt" language: - title: "&2&l Wählen Sie Ihre Sprache" + title: "&2&l Sprache wählen" buttons: language: name: "&f&l [name]" @@ -1741,13 +1740,13 @@ panels: name: "&f&l Nächste Seite" description: "&7 Zur Seite [number] wechseln" tips: - click-to-next: "&e Klicken Sie auf &7, um weiterzugehen." - click-to-previous: "&e Klicken Sie auf &7, um zum vorherigen zu gelangen." - click-to-choose: "&e Klicken Sie zum Auswählen auf &7." - click-to-toggle: "&e Klicken Sie zum Umschalten auf &7." - left-click-to-cycle-down: "&e Klicken Sie mit der linken Maustaste auf &7, um + click-to-next: "&e Klicken&7, um weiterzugehen." + click-to-previous: "&e Klicken&7, um zum zurückgehen." + click-to-choose: "&e Klicken&7 zum Auswählen." + click-to-toggle: "&e Klicken&7 zum Umschalten." + left-click-to-cycle-down: "&e Linksklicken &7, um nach unten zu blättern." - right-click-to-cycle-up: "&e Klicken Sie mit der rechten Maustaste auf &7, um + right-click-to-cycle-up: "&e Rechtsklicken &7, um nach oben zu blättern." successfully-loaded: |- &6 ____ _ ____ diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index c3a201ecd..43e180e4e 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -159,6 +159,7 @@ commands: not-in-team: '&c This player is not in a team.' admin-kicked: '&c The admin kicked you from the team.' success: '&b [name] &a has been kicked from &b [owner]&a ''s island.' + success-all: '&b Player removed from all teams in this world' setowner: parameters: description: transfers island ownership to the player diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0ca09ce7d..fcb054854 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: BentoBox main: world.bentobox.bentobox.BentoBox version: ${project.version}${build.number} -api-version: "1.20" +api-version: "1.21" authors: [tastybento, Poslovitch] contributors: ["The BentoBoxWorld Community"] diff --git a/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java b/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java index 3d4128bcb..6164ff1b9 100644 --- a/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java +++ b/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java @@ -17,10 +17,12 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Server; import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.entity.Player.Spigot; import org.bukkit.event.entity.EntityExplodeEvent; @@ -34,6 +36,7 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.util.Vector; import org.eclipse.jdt.annotation.Nullable; import org.junit.After; +import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -58,6 +61,7 @@ import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlayersManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; /** @@ -103,9 +107,13 @@ public abstract class AbstractCommonSetup { protected FlagsManager fm; @Mock protected Spigot spigot; + protected Server server; + @Before public void setUp() throws Exception { + + server = ServerMocks.newServer(); // Bukkit PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); // Set up plugin @@ -136,6 +144,7 @@ public abstract class AbstractCommonSetup { when(mockPlayer.getName()).thenReturn("tastybento"); when(mockPlayer.getInventory()).thenReturn(inv); when(mockPlayer.spigot()).thenReturn(spigot); + when(mockPlayer.getType()).thenReturn(EntityType.PLAYER); User.setPlugin(plugin); User.clearUsers(); @@ -221,6 +230,7 @@ public abstract class AbstractCommonSetup { */ @After public void tearDown() throws Exception { + ServerMocks.unsetBukkitServer(); User.clearUsers(); Mockito.framework().clearInlineMocks(); } @@ -233,42 +243,6 @@ public abstract class AbstractCommonSetup { checkSpigotMessage(expectedMessage, 1); } - /* - public void checkSpigotMessage(String expectedMessage, boolean shouldBePresent) { - // Capture the argument passed to spigot().sendMessage(...) if messages are sent - ArgumentCaptor captor = ArgumentCaptor.forClass(TextComponent.class); - - if (shouldBePresent) { - // If we expect a message to be present, verify that sendMessage() was called at least once - verify(spigot, atLeastOnce()).sendMessage(captor.capture()); - - // Get all captured TextComponents - List capturedMessages = captor.getAllValues(); - - // Check if any captured message contains the expected text - boolean messageFound = capturedMessages.stream() - .map(component -> component.toPlainText()) // Convert each TextComponent to plain text - .anyMatch(messageText -> messageText.contains(expectedMessage)); // Check if the expected message is present - - // Assert that the message was found - assertTrue("Expected message not found: " + expectedMessage, messageFound); - - } else { - // If we expect no messages with this text, capture any sent messages to ensure none match the given message - verify(spigot, atLeast(0)).sendMessage(captor.capture()); - - // Get all captured TextComponents - List capturedMessages = captor.getAllValues(); - - // Check that none of the captured messages contain the forbidden text - boolean messageFound = capturedMessages.stream().map(component -> component.toPlainText()) // Convert each TextComponent to plain text - .anyMatch(messageText -> messageText.contains(expectedMessage)); // Check if the message is present - - // Assert that the message was NOT found - assertFalse("Unexpected message found: " + expectedMessage, messageFound); - } - }*/ - public void checkSpigotMessage(String expectedMessage, int expectedOccurrences) { // Capture the argument passed to spigot().sendMessage(...) if messages are sent ArgumentCaptor captor = ArgumentCaptor.forClass(TextComponent.class); diff --git a/src/test/java/world/bentobox/bentobox/RanksManagerBeforeClassTest.java b/src/test/java/world/bentobox/bentobox/RanksManagerBeforeClassTest.java index 4f6f589b8..193bc531b 100644 --- a/src/test/java/world/bentobox/bentobox/RanksManagerBeforeClassTest.java +++ b/src/test/java/world/bentobox/bentobox/RanksManagerBeforeClassTest.java @@ -29,7 +29,6 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; -import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.AbstractDatabaseHandler; import world.bentobox.bentobox.database.DatabaseSetup; import world.bentobox.bentobox.managers.RanksManager; @@ -126,9 +125,8 @@ public abstract class RanksManagerBeforeClassTest extends AbstractCommonSetup { } @After - public void tearDown() throws IOException { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); deleteAll(new File("database")); deleteAll(new File("database_backup")); } diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java index 3e2be1e67..858bb9a33 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java @@ -26,7 +26,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -128,12 +127,9 @@ public class AdminResetFlagsCommandTest extends AbstractCommonSetup { } - /** - */ @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java index 97e7f2d53..284028a36 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java @@ -24,6 +24,7 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -42,6 +43,7 @@ import world.bentobox.bentobox.managers.BlueprintsManager; import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.HooksManager; import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.mocks.ServerMocks; /** * @author tastybento @@ -67,8 +69,11 @@ public class AdminBlueprintLoadCommandTest { private Map map; private File blueprintsFolder; - /** - */ + @BeforeClass + public static void beforeClass() { + ServerMocks.newServer(); + } + @Before public void setUp() throws Exception { // Set up plugin @@ -124,8 +129,6 @@ public class AdminBlueprintLoadCommandTest { abcc = new AdminBlueprintLoadCommand(ac); } - /** - */ @After public void tearDown() throws Exception { User.clearUsers(); diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java index 1ab109bc5..ac5386a6c 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java @@ -25,6 +25,7 @@ import org.bukkit.Bukkit; import org.bukkit.util.Vector; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -44,6 +45,7 @@ import world.bentobox.bentobox.managers.BlueprintsManager; import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.HooksManager; import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.mocks.ServerMocks; /** * @author tastybento @@ -67,8 +69,11 @@ public class AdminBlueprintSaveCommandTest { private BlueprintsManager bm; private Blueprint bp = new Blueprint(); - /** - */ + @BeforeClass + public static void beforeClass() { + ServerMocks.newServer(); + } + @Before public void setUp() throws Exception { // Set up plugin diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeCommandTest.java index 0d87b0d1e..c6384b23e 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeCommandTest.java @@ -94,9 +94,8 @@ public class AdminRangeCommandTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } @Test diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeResetCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeResetCommandTest.java index 49fd2c3ac..a9c0952e0 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeResetCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeResetCommandTest.java @@ -117,9 +117,8 @@ public class AdminRangeResetCommandTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeSetCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeSetCommandTest.java index 01ed546c7..819aecce5 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeSetCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeSetCommandTest.java @@ -119,9 +119,8 @@ public class AdminRangeSetCommandTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamDisbandCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamDisbandCommandTest.java index 70aa816f9..e9a245be7 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamDisbandCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamDisbandCommandTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.framework; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -152,9 +151,8 @@ public class AdminTeamDisbandCommandTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommandTest.java index d860d0e18..5c57bc793 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/team/AdminTeamKickCommandTest.java @@ -68,6 +68,10 @@ public class AdminTeamKickCommandTest { private World world; @Mock private PluginManager pim; + @Mock + private Island island; + @Mock + private Island island2; /** */ @@ -106,9 +110,14 @@ public class AdminTeamKickCommandTest { IslandWorldManager iwm = mock(IslandWorldManager.class); when(plugin.getIWM()).thenReturn(iwm); + // Island + when(island.getOwner()).thenReturn(uuid); + when(island2.getOwner()).thenReturn(notUUID); + // Player has island to begin with when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); when(im.hasIsland(any(), any(User.class))).thenReturn(true); + when(im.getIslands(world, uuid)).thenReturn(List.of(island, island2)); // when(im.isOwner(any(),any())).thenReturn(true); // when(im.getOwner(any(),any())).thenReturn(uuid); when(plugin.getIslands()).thenReturn(im); @@ -172,46 +181,21 @@ public class AdminTeamKickCommandTest { verify(user).sendMessage(eq("commands.admin.team.kick.not-in-team")); } - /** - * Test method for {@link AdminTeamKickCommand#execute(User, String, List)} . - */ - @Test - public void testExecuteKickOwner() { - when(im.inTeam(any(), any())).thenReturn(true); - Island is = mock(Island.class); - when(im.getIsland(any(), any(UUID.class))).thenReturn(is); - when(pm.getUUID(any())).thenReturn(notUUID); - - when(is.getOwner()).thenReturn(notUUID); - - AdminTeamKickCommand itl = new AdminTeamKickCommand(ac); - assertTrue(itl.canExecute(user, itl.getLabel(), Collections.singletonList("tastybento"))); - assertFalse(itl.execute(user, itl.getLabel(), Collections.singletonList("tastybento"))); - verify(user).sendMessage(eq("commands.admin.team.kick.cannot-kick-owner")); - verify(user).sendMessage("commands.admin.info.team-members-title"); - verify(im, never()).removePlayer(eq(world), eq(notUUID)); - verify(user, never()).sendMessage(eq("commands.admin.team.kick.success"), anyString(), anyString(), anyString(), anyString()); - verify(pim, never()).callEvent(any()); - } - /** * Test method for {@link world.bentobox.bentobox.api.commands.admin.team.AdminTeamKickCommand#execute(User, String, List)}. */ @Test public void testExecute() { when(im.inTeam(any(), any())).thenReturn(true); - Island is = mock(Island.class); - when(im.getIsland(any(), any(UUID.class))).thenReturn(is); String name = "tastybento"; - when(pm.getUUID(any())).thenReturn(notUUID); + when(pm.getUUID(any())).thenReturn(uuid); when(pm.getName(any())).thenReturn(name); - when(is.getOwner()).thenReturn(uuid); - AdminTeamKickCommand itl = new AdminTeamKickCommand(ac); assertTrue(itl.canExecute(user, itl.getLabel(), Collections.singletonList(name))); assertTrue(itl.execute(user, itl.getLabel(), Collections.singletonList(name))); - verify(im).removePlayer(is, notUUID); + verify(im, never()).removePlayer(island, uuid); + verify(im).removePlayer(island2, uuid); verify(user).sendMessage(eq("commands.admin.team.kick.success"), eq(TextVariables.NAME), eq(name), eq("[owner]"), anyString()); // Offline so event will be called 4 times verify(pim, times(4)).callEvent(any()); diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommandTest.java index fed4c3d5a..f99ae73de 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandExpelCommandTest.java @@ -21,11 +21,11 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.Server; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginManager; import org.bukkit.scheduler.BukkitScheduler; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -74,12 +74,11 @@ public class IslandExpelCommandTest extends RanksManagerBeforeClassTest { private Addon addon; private IslandExpelCommand iec; - @Mock - private Server server; - + @Before public void setUp() throws Exception { super.setUp(); + User.setPlugin(plugin); // Command manager @@ -96,7 +95,6 @@ public class IslandExpelCommandTest extends RanksManagerBeforeClassTest { when(user.isOp()).thenReturn(false); uuid = UUID.randomUUID(); when(user.getUniqueId()).thenReturn(uuid); - when(server.getOnlinePlayers()).thenReturn(Collections.emptySet()); when(mockPlayer.getServer()).thenReturn(server); when(user.getPlayer()).thenReturn(mockPlayer); when(user.getName()).thenReturn("tastybento"); @@ -154,6 +152,11 @@ public class IslandExpelCommandTest extends RanksManagerBeforeClassTest { iec = new IslandExpelCommand(ic); } + @After + public void tearDown() throws Exception { + super.tearDown(); + } + /** * Test method for * {@link world.bentobox.bentobox.api.commands.island.IslandExpelCommand#IslandExpelCommand(world.bentobox.bentobox.api.commands.CompositeCommand)}. diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java index 5d3af68ef..c278f45b8 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java @@ -176,9 +176,8 @@ public class IslandGoCommandTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandResetCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandResetCommandTest.java index ca5c6a65f..7f2cc43ab 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandResetCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandResetCommandTest.java @@ -187,6 +187,10 @@ public class IslandResetCommandTest extends AbstractCommonSetup { irc = new IslandResetCommand(ic); } + @After + public void tearDown() throws Exception { + super.tearDown(); + } /** * Test method for * {@link IslandResetCommand#canExecute(User, String, java.util.List)} @@ -254,12 +258,6 @@ public class IslandResetCommandTest extends AbstractCommonSetup { checkSpigotMessage("commands.island.reset.kicked-from-island", 11); } - @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); - } - /** * Test method for {@link IslandResetCommand#canExecute(User, String, java.util.List)} */ diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommandTest.java index 9dd2e46ab..5e2e21460 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSethomeCommandTest.java @@ -201,11 +201,11 @@ public class IslandSethomeCommandTest { */ @Test public void testCanExecuteTooManyHomes() { - when(im.getMaxHomes(island)).thenReturn(10); + when(im.getMaxHomes(island)).thenReturn(9); when(im.getNumberOfHomesIfAdded(eq(island), anyString())).thenReturn(11); IslandSethomeCommand isc = new IslandSethomeCommand(ic); assertFalse(isc.canExecute(user, "island", Collections.emptyList())); - verify(user).sendMessage("commands.island.sethome.too-many-homes", TextVariables.NUMBER, "10"); + verify(user).sendMessage("commands.island.sethome.too-many-homes", TextVariables.NUMBER, "9"); verify(user).sendMessage("commands.island.sethome.homes-are"); } @@ -251,7 +251,7 @@ public class IslandSethomeCommandTest { @Test public void testExecuteUserStringListOfStringMultiHomeTooMany() { when(im.getMaxHomes(island)).thenReturn(3); - when(im.getNumberOfHomesIfAdded(eq(island), anyString())).thenReturn(4); + when(im.getNumberOfHomesIfAdded(eq(island), anyString())).thenReturn(5); IslandSethomeCommand isc = new IslandSethomeCommand(ic); assertFalse(isc.canExecute(user, "island", Collections.singletonList("13"))); verify(user).sendMessage(eq("commands.island.sethome.too-many-homes"), eq("[number]"), eq("3")); diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSpawnCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSpawnCommandTest.java index 47c87a3a1..931adb747 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSpawnCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandSpawnCommandTest.java @@ -130,12 +130,9 @@ public class IslandSpawnCommandTest extends AbstractCommonSetup { isc = new IslandSpawnCommand(ic); } - /** - */ @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClickTest.java b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClickTest.java index 4f6f2c877..40d8dac64 100644 --- a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClickTest.java +++ b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/CycleClickTest.java @@ -55,6 +55,7 @@ import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.RanksManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.panels.settings.SettingsTab; import world.bentobox.bentobox.util.Util; @@ -95,12 +96,13 @@ public class CycleClickTest { @Mock private @NonNull Player p; + /** * @throws java.lang.Exception - exception */ @Before public void setUp() throws Exception { - + ServerMocks.newServer(); // Set up plugin Whitebox.setInternalState(BentoBox.class, "instance", plugin); @@ -233,6 +235,7 @@ public class CycleClickTest { @After public void tearDown() { + ServerMocks.unsetBukkitServer(); Mockito.framework().clearInlineMocks(); } @@ -376,7 +379,6 @@ public class CycleClickTest { assertTrue(udc.onClick(panel, user, ClickType.SHIFT_LEFT, SLOT)); assertTrue(hiddenFlags.isEmpty()); // Verify sounds - verify(p).playSound(user.getLocation(), Sound.BLOCK_GLASS_BREAK, 1F, 1F); - verify(p).playSound(user.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1F, 1F); + verify(p, times(2)).playSound((Location) null, (Sound) null, 1F, 1F); } } diff --git a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClickTest.java b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClickTest.java index d45ef701a..bd697a8ca 100644 --- a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClickTest.java +++ b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClickTest.java @@ -37,6 +37,7 @@ import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.FlagsManager; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.panels.settings.SettingsTab; import world.bentobox.bentobox.util.Util; @@ -67,6 +68,7 @@ public class IslandToggleClickTest { */ @Before public void setUp() throws Exception { + ServerMocks.newServer(); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); // Set up plugin @@ -119,6 +121,7 @@ public class IslandToggleClickTest { @After public void tearDown() { + ServerMocks.unsetBukkitServer(); Mockito.framework().clearInlineMocks(); } diff --git a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/WorldToggleClickTest.java b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/WorldToggleClickTest.java index a2ff9470d..688876a78 100644 --- a/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/WorldToggleClickTest.java +++ b/src/test/java/world/bentobox/bentobox/api/flags/clicklisteners/WorldToggleClickTest.java @@ -36,6 +36,7 @@ import world.bentobox.bentobox.api.panels.Panel; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.managers.FlagsManager; import world.bentobox.bentobox.managers.IslandWorldManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; @RunWith(PowerMockRunner.class) @@ -57,10 +58,9 @@ public class WorldToggleClickTest { @Mock private World world; - /** - */ @Before public void setUp() throws Exception { + ServerMocks.newServer(); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); // Set up plugin BentoBox plugin = mock(BentoBox.class); @@ -104,6 +104,7 @@ public class WorldToggleClickTest { @After public void tearDown() { + ServerMocks.unsetBukkitServer(); Mockito.framework().clearInlineMocks(); } diff --git a/src/test/java/world/bentobox/bentobox/api/user/UserTest.java b/src/test/java/world/bentobox/bentobox/api/user/UserTest.java index 2cc6fe8c3..852e03fca 100644 --- a/src/test/java/world/bentobox/bentobox/api/user/UserTest.java +++ b/src/test/java/world/bentobox/bentobox/api/user/UserTest.java @@ -45,7 +45,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -136,9 +135,8 @@ public class UserTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } diff --git a/src/test/java/world/bentobox/bentobox/blueprints/BlueprintPasterTest.java b/src/test/java/world/bentobox/bentobox/blueprints/BlueprintPasterTest.java index d869cfdc2..bde76d559 100644 --- a/src/test/java/world/bentobox/bentobox/blueprints/BlueprintPasterTest.java +++ b/src/test/java/world/bentobox/bentobox/blueprints/BlueprintPasterTest.java @@ -14,6 +14,7 @@ import org.bukkit.World; import org.bukkit.util.Vector; import org.eclipse.jdt.annotation.NonNull; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -34,6 +35,7 @@ import world.bentobox.bentobox.database.objects.Island; */ @RunWith(PowerMockRunner.class) @PrepareForTest({BentoBox.class, User.class, Bukkit.class}) +@Ignore("Enums") public class BlueprintPasterTest { private BlueprintPaster bp; diff --git a/src/test/java/world/bentobox/bentobox/commands/BentoBoxPermsCommandTest.java b/src/test/java/world/bentobox/bentobox/commands/BentoBoxPermsCommandTest.java index 338a6ea5d..a0943f280 100644 --- a/src/test/java/world/bentobox/bentobox/commands/BentoBoxPermsCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/commands/BentoBoxPermsCommandTest.java @@ -106,12 +106,9 @@ public class BentoBoxPermsCommandTest extends AbstractCommonSetup { cmd = new BentoBoxPermsCommand(ac); } - /** - * @throws java.lang.Exception - */ @After public void tearDown() throws Exception { - Mockito.framework().clearInlineMocks(); + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapterTest.java b/src/test/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapterTest.java index ce91f6469..d6620aec9 100644 --- a/src/test/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapterTest.java +++ b/src/test/java/world/bentobox/bentobox/database/objects/adapters/LogEntryListAdapterTest.java @@ -7,6 +7,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.After; import org.junit.Before; @@ -14,6 +15,7 @@ import org.junit.Test; import org.mockito.Mockito; import world.bentobox.bentobox.api.logs.LogEntry; +import world.bentobox.bentobox.api.logs.LogEntry.LogType; /** * @author tastybento @@ -28,8 +30,6 @@ public class LogEntryListAdapterTest { private UUID issuer; private List toLog; - /** - */ @Before public void setUp() throws Exception { config = new YamlConfiguration(); @@ -38,9 +38,11 @@ public class LogEntryListAdapterTest { issuer = UUID.randomUUID(); toLog = new ArrayList<>(); - toLog.add(new LogEntry.Builder("BAN").data("player", target.toString()).data("issuer", issuer.toString()).build()); - toLog.add(new LogEntry.Builder("UNBAN").data("player", target.toString()).data("issuer", issuer.toString()).build()); - toLog.add(new LogEntry.Builder("UNOWNED").build()); + toLog.add(new LogEntry.Builder(LogType.BAN).data("player", target.toString()).data("issuer", issuer.toString()) + .build()); + toLog.add(new LogEntry.Builder(LogType.UNBAN).data("player", target.toString()) + .data("issuer", issuer.toString()).build()); + toLog.add(new LogEntry.Builder(LogType.UNOWNED).build()); history.addAll(toLog); } @@ -67,4 +69,28 @@ public class LogEntryListAdapterTest { } } + /** + * Test method for {@link world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter#serialize(java.lang.Object)} + * and {@link world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter#deserialize(java.lang.Object)}. + * @throws InvalidConfigurationException + */ + @Test + public void testSerializeDeserializeUnknownHistory() throws InvalidConfigurationException { + // Make entries using unknown types + String bad = "test:\n" + " history:\n" + " - timestamp: 1731359067207\n" + " type: WEIRD\n" + " data:\n" + + " player: 3f9d5634-331e-4598-9445-7449d56f7f74\n" + + " issuer: b366ba84-adec-42fe-b9dc-2c6a7b26f067\n" + " - timestamp: 1731359067207\n" + + " type: ENTRY\n" + " data:\n" + " player: 3f9d5634-331e-4598-9445-7449d56f7f74\n" + + " issuer: b366ba84-adec-42fe-b9dc-2c6a7b26f067\n" + " - timestamp: 1731359067207\n" + + " type: SUPER\n" + " data: {}"; + config.loadFromString(bad); + + // Verify + List historyCheck = a.deserialize(config.get("test.history")); + assertEquals(3, historyCheck.size()); + for (int i = 0; i < historyCheck.size(); i++) { + assertEquals(LogType.UNKNOWN, historyCheck.get(i).getType()); + } + } + } diff --git a/src/test/java/world/bentobox/bentobox/listeners/JoinLeaveListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/JoinLeaveListenerTest.java index 6ac0e9044..12f9d211d 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/JoinLeaveListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/JoinLeaveListenerTest.java @@ -35,7 +35,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.stubbing.Answer; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -206,9 +205,8 @@ public class JoinLeaveListenerTest extends RanksManagerBeforeClassTest { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/listeners/StandardSpawnProtectionListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/StandardSpawnProtectionListenerTest.java index 2aad266a2..a654b311a 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/StandardSpawnProtectionListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/StandardSpawnProtectionListenerTest.java @@ -119,12 +119,9 @@ public class StandardSpawnProtectionListenerTest extends AbstractCommonSetup { ssp = new StandardSpawnProtectionListener(plugin); } - /** - */ @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/clicklisteners/CommandRankClickListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/clicklisteners/CommandRankClickListenerTest.java index 7a8feddb4..2e59a1051 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/clicklisteners/CommandRankClickListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/clicklisteners/CommandRankClickListenerTest.java @@ -25,6 +25,7 @@ import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.Inventory; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -148,6 +149,11 @@ public class CommandRankClickListenerTest extends RanksManagerBeforeClassTest { crcl = new CommandRankClickListener(); } + @After + public void tearDown() throws Exception { + super.tearDown(); + } + /** * Test method for {@link world.bentobox.bentobox.listeners.flags.clicklisteners.CommandRankClickListener#onClick(world.bentobox.bentobox.api.panels.Panel, world.bentobox.bentobox.api.user.User, org.bukkit.event.inventory.ClickType, int)}. */ diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListenerTest.java index 564ded34b..303697ec4 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListenerTest.java @@ -51,6 +51,7 @@ import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlayersManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; @RunWith(PowerMockRunner.class) @@ -87,6 +88,7 @@ public class LockAndBanListenerTest { @Before public void setUp() throws Exception { + ServerMocks.newServer(); // Server & Scheduler PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); when(Bukkit.getScheduler()).thenReturn(sch); @@ -189,6 +191,7 @@ public class LockAndBanListenerTest { @After public void tearDown() { + ServerMocks.unsetBukkitServer(); User.clearUsers(); framework().clearInlineMocks(); } diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ChestDamageListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ChestDamageListenerTest.java index d44ec3ab0..3c2042d23 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ChestDamageListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ChestDamageListenerTest.java @@ -173,9 +173,8 @@ public class ChestDamageListenerTest extends AbstractCommonSetup } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java index a135bfa6a..0067bf715 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java @@ -18,13 +18,11 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import world.bentobox.bentobox.AbstractCommonSetup; import world.bentobox.bentobox.BentoBox; -import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.lists.Flags; import world.bentobox.bentobox.util.Util; @@ -47,13 +45,9 @@ public class CreeperListenerTest extends AbstractCommonSetup { cl = new CreeperListener(); } - /** - * @throws java.lang.Exception - */ @After public void tearDown() throws Exception { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java index 7a3ca7228..fc7181d3f 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java @@ -62,6 +62,7 @@ import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.FlagsManager; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; @RunWith(PowerMockRunner.class) @@ -90,10 +91,9 @@ public class InvincibleVisitorsListenerTest { @Mock private PluginManager pim; - /** - */ @Before public void setUp() throws Exception { + ServerMocks.newServer(); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); // Set up plugin @@ -186,6 +186,7 @@ public class InvincibleVisitorsListenerTest { @After public void tearDown() { + ServerMocks.unsetBukkitServer(); User.clearUsers(); framework().clearInlineMocks(); } diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ObsidianScoopingListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ObsidianScoopingListenerTest.java index 7700c446f..09b76e75a 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ObsidianScoopingListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/ObsidianScoopingListenerTest.java @@ -140,9 +140,8 @@ public class ObsidianScoopingListenerTest extends AbstractCommonSetup { } @After - public void tearDown() { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + public void tearDown() throws Exception { + super.tearDown(); } @Test diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/VisitorKeepInventoryListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/VisitorKeepInventoryListenerTest.java index c58c77417..c21847e76 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/VisitorKeepInventoryListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/VisitorKeepInventoryListenerTest.java @@ -111,12 +111,9 @@ public class VisitorKeepInventoryListenerTest extends AbstractCommonSetup { l = new VisitorKeepInventoryListener(); } - /** - */ @After public void tearDown() throws Exception { - User.clearUsers(); - Mockito.framework().clearInlineMocks(); + super.tearDown(); } /** diff --git a/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java new file mode 100644 index 000000000..fd4594861 --- /dev/null +++ b/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java @@ -0,0 +1,546 @@ +package world.bentobox.bentobox.listeners.teleports; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.util.UUID; + +import org.bukkit.Bukkit; +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.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityPortalEnterEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerPortalEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.util.Vector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import world.bentobox.bentobox.AbstractCommonSetup; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.util.Util; + +/** + * @author tastybento + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ BentoBox.class, Util.class, Bukkit.class }) +public class PlayerTeleportListenerTest extends AbstractCommonSetup { + + private PlayerTeleportListener ptl; + @Mock + private Block block; + @Mock + private BukkitScheduler scheduler; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + super.setUp(); + + // Bukkit + when(Bukkit.getAllowNether()).thenReturn(true); + when(Bukkit.getAllowEnd()).thenReturn(true); + when(Bukkit.getScheduler()).thenReturn(scheduler); + + // World + when(world.getEnvironment()).thenReturn(Environment.NORMAL); + when(world.getSpawnLocation()).thenReturn(location); + // Location + Vector vector = mock(Vector.class); + when(vector.toLocation(world)).thenReturn(location); + when(location.toVector()).thenReturn(vector); + // IWM + when(iwm.getNetherWorld(world)).thenReturn(world); + when(iwm.getEndWorld(world)).thenReturn(world); + when(iwm.isNetherGenerate(world)).thenReturn(true); + when(iwm.isEndGenerate(world)).thenReturn(true); + when(iwm.isNetherIslands(world)).thenReturn(true); + when(iwm.isEndIslands(world)).thenReturn(true); + + // Util + when(Util.getWorld(world)).thenReturn(world); + + // IM + when(plugin.getIslandsManager()).thenReturn(im); + + // Block + when(location.getBlock()).thenReturn(block); + + ptl = new PlayerTeleportListener(plugin); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#PlayerTeleportListener(world.bentobox.bentobox.BentoBox)}. + */ + @Test + public void testPlayerTeleportListener() { + assertNotNull(ptl); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventNether() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventEnd() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.END_PORTAL, 0, false, + 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventUnknown() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.UNKNOWN, 0, false, 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessNotBentoboxWorld() { + when(Util.getWorld(location.getWorld())).thenReturn(null); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that no further processing occurs + assertFalse(e.isCancelled()); + verifyNoMoreInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessWorldDisabledInConfig() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(false); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the event was cancelled + assertTrue(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessWorldDisabledOnServer() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(false); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the event was cancelled + assertTrue(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessAlreadyInTeleport() { + ptl.getInTeleport().add(uuid); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify no further processing occurs + assertFalse(e.isCancelled()); + } + + @Test + public void testPortalProcessStandardNetherOrEnd() { + // Mocking required dependencies + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(true); + when(ptl.isIslandWorld(world, World.Environment.NETHER)).thenReturn(false); + + // Creating the event + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + + // Running the method + ptl.onPlayerPortalEvent(e); + + // Validating that the event destination is unchanged (indicating standard processing occurred) + assertFalse(e.isCancelled()); + assertNotNull(e.getTo()); + assertEquals(location.getWorld(), e.getTo().getWorld()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessIslandTeleport() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(true); + when(ptl.isIslandWorld(world, World.Environment.NETHER)).thenReturn(true); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the portal creation settings were adjusted + assertEquals(2, e.getCreationRadius()); + assertNotNull(e.getTo()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessEndVelocityReset() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.END_PORTAL, 0, false, + 0); + ptl.onPlayerPortalEvent(e); + // Verify player velocity and fall distance were reset + verify(mockPlayer, times(1)).setVelocity(new Vector(0, 0, 0)); + verify(mockPlayer, times(1)).setFallDistance(0); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalNonPlayerEntity() { + // Mock a non-player entity + Entity mockEntity = mock(Entity.class); + when(mockEntity.getType()).thenReturn(EntityType.ZOMBIE); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockEntity, location); + ptl.onPlayerPortal(e); + + // Verify no further processing for non-player entities + verifyNoInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalAlreadyInPortal() { + // Simulate player already in portal + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + ptl.onPlayerPortal(e); + + // Verify no further processing occurs + verifyNoInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalNetherPortalDisabled() { + // Mock configuration for Nether disabled + when(Bukkit.getAllowNether()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.NETHER_PORTAL); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + ptl.onPlayerPortal(e); + + // Verify PlayerPortalEvent is scheduled + verify(Bukkit.getScheduler(), times(1)).runTaskLater(eq(plugin), any(Runnable.class), eq(40L)); + } + + @Test + public void testOnPlayerPortalEndPortalDisabled() { + // Mock configuration for End disabled + when(Bukkit.getAllowEnd()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.END_PORTAL); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Check if the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify the event behavior indirectly by confirming the origin world was stored + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + @Test + public void testOnPlayerPortalEndGatewayDisabled() { + // Mock configuration for End disabled + when(Bukkit.getAllowEnd()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.END_GATEWAY); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Check if the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify the event behavior indirectly by confirming the origin world was stored + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + @Test + public void testOnPlayerPortalValidBentoBoxWorld() { + // Mock configuration for a valid BentoBox world + when(Bukkit.getAllowNether()).thenReturn(true); + when(Bukkit.getAllowEnd()).thenReturn(true); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.NETHER_PORTAL); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Verify the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify teleportOrigin was updated with the correct world + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onExitPortal(org.bukkit.event.player.PlayerMoveEvent)}. + */ + @Test + public void testOnExitPortalPlayerNotInPortal() { + // Mock a player who is not in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, location); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that no changes occurred to inPortal or other collections + assertFalse(ptl.getInPortal().contains(playerId)); + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + @Test + public void testOnExitPortalPlayerStillInPortal() { + // Mock a player in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + + // Mock the destination block type as a Nether portal + when(location.getBlock().getType()).thenReturn(Material.NETHER_PORTAL); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, location); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that the player is still in the inPortal list + assertTrue(ptl.getInPortal().contains(playerId)); + + // Verify that no changes occurred to inTeleport or teleportOrigin + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + @Test + public void testOnExitPortalPlayerExitsPortal() { + // Mock a player in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + ptl.getInTeleport().add(playerId); + ptl.getTeleportOrigin().put(playerId, location.getWorld()); + + // Mock the destination block type as something other than a Nether portal + Location toLocation = mock(Location.class); + when(toLocation.getBlock()).thenReturn(block); + when(toLocation.getBlock().getType()).thenReturn(Material.AIR); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, toLocation); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that the player was removed from inPortal, inTeleport, and teleportOrigin + assertFalse(ptl.getInPortal().contains(playerId)); + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerExitPortal(org.bukkit.event.player.PlayerRespawnEvent)}. + */ + @Test + public void testOnPlayerExitPortalPlayerAlreadyProcessed() { + // Mock a player who is not in teleportOrigin + UUID playerId = mockPlayer.getUniqueId(); + + // Create the event + @SuppressWarnings("deprecation") + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that no changes occurred to the event + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalNotBentoBoxWorld() { + // Mock teleportOrigin with a world not in BentoBox + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Mock the world not being a BentoBox world + when(Util.getWorld(world)).thenReturn(null); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that no changes occurred to the event + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsRespawnInsideProtection() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location remains unchanged + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsRespawnOutsideProtection() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the island spawn point + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsNoSpawnPoint() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the island's protection center + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalNoIsland() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the world spawn location + assertEquals(location, event.getRespawnLocation()); + } + + +} diff --git a/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java index ed338ad83..d6e4fc354 100644 --- a/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java @@ -41,6 +41,7 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.blueprints.Blueprint; import world.bentobox.bentobox.blueprints.BlueprintClipboard; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; @@ -103,7 +104,7 @@ public class BlueprintClipboardManagerTest { " \"ySize\": 10,\n" + " \"zSize\": 10\n" + "}"; - @Mock + private Server server; private void zip(File targetFile) throws IOException { @@ -128,6 +129,7 @@ public class BlueprintClipboardManagerTest { */ @Before public void setUp() throws Exception { + server = ServerMocks.newServer(); PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); blueprintFolder = new File("blueprints"); @@ -152,7 +154,7 @@ public class BlueprintClipboardManagerTest { */ @After public void tearDown() throws Exception { - + ServerMocks.unsetBukkitServer(); if (blueprintFolder.exists()) { // Clean up file system Files.walk(blueprintFolder.toPath()) diff --git a/src/test/java/world/bentobox/bentobox/managers/BlueprintsManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/BlueprintsManagerTest.java index da730c1cd..9cd41f9f9 100644 --- a/src/test/java/world/bentobox/bentobox/managers/BlueprintsManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/BlueprintsManagerTest.java @@ -60,6 +60,7 @@ import world.bentobox.bentobox.blueprints.BlueprintPaster; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; /** @@ -98,11 +99,12 @@ public class BlueprintsManagerTest { private BukkitTask task; private int times; - @Mock + private Server server; @Before public void setUp() throws Exception { + server = ServerMocks.newServer(); // Set up plugin BentoBox plugin = mock(BentoBox.class); Whitebox.setInternalState(BentoBox.class, "instance", plugin); @@ -187,6 +189,7 @@ public class BlueprintsManagerTest { */ @After public void tearDown() throws Exception { + ServerMocks.unsetBukkitServer(); // Clean up file system deleteDir(dataFolder.toPath()); // Delete addon.jar diff --git a/src/test/java/world/bentobox/bentobox/managers/IslandChunkDeletionManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/IslandChunkDeletionManagerTest.java index 252857ea1..6896e72a0 100644 --- a/src/test/java/world/bentobox/bentobox/managers/IslandChunkDeletionManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/IslandChunkDeletionManagerTest.java @@ -6,6 +6,7 @@ import static org.mockito.Mockito.when; import org.bukkit.Bukkit; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -26,6 +27,7 @@ import world.bentobox.bentobox.util.DeleteIslandChunks; */ @RunWith(PowerMockRunner.class) @PrepareForTest({BentoBox.class, Bukkit.class, DeleteIslandChunks.class}) +@Ignore("NMS") public class IslandChunkDeletionManagerTest { @Mock diff --git a/src/test/java/world/bentobox/bentobox/managers/IslandDeletionManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/IslandDeletionManagerTest.java index c19a9e0d3..f92ea2fbe 100644 --- a/src/test/java/world/bentobox/bentobox/managers/IslandDeletionManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/IslandDeletionManagerTest.java @@ -49,6 +49,7 @@ import world.bentobox.bentobox.util.Util; */ @RunWith(PowerMockRunner.class) @PrepareForTest( { Bukkit.class, BentoBox.class, Util.class, Location.class }) +@Ignore("NMS") public class IslandDeletionManagerTest { @Mock diff --git a/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java index 00d19a6c5..d550ca413 100644 --- a/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/PlayersManagerTest.java @@ -65,6 +65,7 @@ import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Names; import world.bentobox.bentobox.database.objects.Players; import world.bentobox.bentobox.hooks.VaultHook; +import world.bentobox.bentobox.mocks.ServerMocks; import world.bentobox.bentobox.util.Util; /** @@ -134,6 +135,8 @@ public class PlayersManagerTest { public void setUp() throws Exception { // Clear any lingering database tearDown(); + + ServerMocks.newServer(); // Set up plugin Whitebox.setInternalState(BentoBox.class, "instance", plugin); when(plugin.getVault()).thenReturn(Optional.of(vault)); @@ -178,7 +181,7 @@ public class PlayersManagerTest { when(p.getUniqueId()).thenReturn(uuid); AttributeInstance at = mock(AttributeInstance.class); when(at.getValue()).thenReturn(20D); - when(p.getAttribute(Attribute.GENERIC_MAX_HEALTH)).thenReturn(at); + when(p.getAttribute(Attribute.MAX_HEALTH)).thenReturn(at); when(p.getName()).thenReturn("tastybento"); User.getInstance(p); @@ -271,6 +274,7 @@ public class PlayersManagerTest { @After public void tearDown() throws Exception { + ServerMocks.unsetBukkitServer(); User.clearUsers(); Mockito.framework().clearInlineMocks(); deleteAll(new File("database")); diff --git a/src/test/java/world/bentobox/bentobox/mocks/ServerMocks.java b/src/test/java/world/bentobox/bentobox/mocks/ServerMocks.java new file mode 100644 index 000000000..8fd039318 --- /dev/null +++ b/src/test/java/world/bentobox/bentobox/mocks/ServerMocks.java @@ -0,0 +1,118 @@ +package world.bentobox.bentobox.mocks; + +import static org.mockito.ArgumentMatchers.notNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.Server; +import org.bukkit.Tag; +import org.bukkit.UnsafeValues; +import org.eclipse.jdt.annotation.NonNull; + +public final class ServerMocks { + + public static @NonNull Server newServer() { + Server mock = mock(Server.class); + + Logger noOp = mock(Logger.class); + when(mock.getLogger()).thenReturn(noOp); + when(mock.isPrimaryThread()).thenReturn(true); + + // Unsafe + UnsafeValues unsafe = mock(UnsafeValues.class); + when(mock.getUnsafe()).thenReturn(unsafe); + + // Server must be available before tags can be mocked. + Bukkit.setServer(mock); + + // Bukkit has a lot of static constants referencing registry values. To initialize those, the + // registries must be able to be fetched before the classes are touched. + Map, Object> registers = new HashMap<>(); + + doAnswer(invocationGetRegistry -> registers.computeIfAbsent(invocationGetRegistry.getArgument(0), clazz -> { + Registry registry = mock(Registry.class); + Map cache = new HashMap<>(); + doAnswer(invocationGetEntry -> { + NamespacedKey key = invocationGetEntry.getArgument(0); + // Some classes (like BlockType and ItemType) have extra generics that will be + // erased during runtime calls. To ensure accurate typing, grab the constant's field. + // This approach also allows us to return null for unsupported keys. + Class constantClazz; + try { + //noinspection unchecked + constantClazz = (Class) clazz + .getField(key.getKey().toUpperCase(Locale.ROOT).replace('.', '_')).getType(); + } catch (ClassCastException e) { + throw new RuntimeException(e); + } catch (NoSuchFieldException e) { + return null; + } + + return cache.computeIfAbsent(key, key1 -> { + Keyed keyed = mock(constantClazz); + doReturn(key).when(keyed).getKey(); + return keyed; + }); + }).when(registry).get(notNull()); + return registry; + })).when(mock).getRegistry(notNull()); + + // Tags are dependent on registries, but use a different method. + // This will set up blank tags for each constant; all that needs to be done to render them + // functional is to re-mock Tag#getValues. + doAnswer(invocationGetTag -> { + Tag tag = mock(Tag.class); + doReturn(invocationGetTag.getArgument(1)).when(tag).getKey(); + doReturn(Set.of()).when(tag).getValues(); + doAnswer(invocationIsTagged -> { + Keyed keyed = invocationIsTagged.getArgument(0); + Class type = invocationGetTag.getArgument(2); + if (!type.isAssignableFrom(keyed.getClass())) { + return null; + } + // Since these are mocks, the exact instance might not be equal. Consider equal keys equal. + return tag.getValues().contains(keyed) + || tag.getValues().stream().anyMatch(value -> value.getKey().equals(keyed.getKey())); + }).when(tag).isTagged(notNull()); + return tag; + }).when(mock).getTag(notNull(), notNull(), notNull()); + + // Once the server is all set up, touch BlockType and ItemType to initialize. + // This prevents issues when trying to access dependent methods from a Material constant. + try { + Class.forName("org.bukkit.inventory.ItemType"); + Class.forName("org.bukkit.block.BlockType"); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + return mock; + } + + public static void unsetBukkitServer() { + try { + Field server = Bukkit.class.getDeclaredField("server"); + server.setAccessible(true); + server.set(null, null); + } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private ServerMocks() { + } + +} \ No newline at end of file