Merge pull request #2514 from BentoBoxWorld/develop

Release 2.5.4
This commit is contained in:
tastybento 2024-09-22 15:30:38 -07:00 committed by GitHub
commit 234fa63a4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 401 additions and 57 deletions

View File

@ -88,7 +88,7 @@
<!-- Do not change unless you want different name for local builds. --> <!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<!-- This allows to change between versions. --> <!-- This allows to change between versions. -->
<build.version>2.5.3</build.version> <build.version>2.5.4</build.version>
<sonar.organization>bentobox-world</sonar.organization> <sonar.organization>bentobox-world</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url> <sonar.host.url>https://sonarcloud.io</sonar.host.url>
<server.jars>${project.basedir}/lib</server.jars> <server.jars>${project.basedir}/lib</server.jars>
@ -157,10 +157,6 @@
<id>codemc-repo</id> <id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public</url> <url>https://repo.codemc.org/repository/maven-public</url>
</repository> </repository>
<repository>
<id>placeholderapi-repo</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
<repository> <repository>
<id>dynmap-repo</id> <id>dynmap-repo</id>
<url>https://repo.mikeprimm.com/</url> <url>https://repo.mikeprimm.com/</url>

View File

@ -141,7 +141,6 @@ public class Settings implements ConfigObject {
private Set<String> fakePlayers = new HashSet<>(); private Set<String> fakePlayers = new HashSet<>();
/* PANELS */ /* PANELS */
@ConfigComment("Toggle whether panels should be closed or not when the player clicks anywhere outside of the inventory view.") @ConfigComment("Toggle whether panels should be closed or not when the player clicks anywhere outside of the inventory view.")
@ConfigEntry(path = "panel.close-on-click-outside") @ConfigEntry(path = "panel.close-on-click-outside")
private boolean closePanelOnClickOutside = true; private boolean closePanelOnClickOutside = true;
@ -189,6 +188,13 @@ public class Settings implements ConfigObject {
/* /*
* Island * Island
*/ */
@ConfigComment("Override island distance mismatch checking. BentoBox normally refuses to run if")
@ConfigComment("the island distance in the gamemode config is different to the one stored in the database")
@ConfigComment("for safety. This overrides that check. You should never need this, and if you do not understand it")
@ConfigComment("keep it as false")
@ConfigEntry(path = "island.override-safety-check")
private boolean overrideSafetyCheck = false;
// Number of islands // Number of islands
@ConfigComment("The default number of concurrent islands a player may have.") @ConfigComment("The default number of concurrent islands a player may have.")
@ConfigComment("This may be overridden by individual game mode config settings.") @ConfigComment("This may be overridden by individual game mode config settings.")
@ -1034,4 +1040,18 @@ public class Settings implements ConfigObject {
this.hideUsedBlueprints = hideUsedBlueprints; this.hideUsedBlueprints = hideUsedBlueprints;
} }
/**
* @return the overrideSafetyCheck
*/
public boolean isOverrideSafetyCheck() {
return overrideSafetyCheck;
}
/**
* @param overrideSafetyCheck the overrideSafetyCheck to set
*/
public void setOverrideSafetyCheck(boolean overrideSafetyCheck) {
this.overrideSafetyCheck = overrideSafetyCheck;
}
} }

View File

@ -133,6 +133,7 @@ public class AdminPurgeCommand extends CompositeCommand implements Listener {
// Process islands in one pass, logging and adding to the set if applicable // Process islands in one pass, logging and adding to the set if applicable
getPlugin().getIslands().getIslands().stream() getPlugin().getIslands().getIslands().stream()
.filter(i -> !i.isSpawn()).filter(i -> !i.getPurgeProtected()) .filter(i -> !i.isSpawn()).filter(i -> !i.getPurgeProtected())
.filter(i -> i.getWorld() != null) // to handle currently unloaded world islands
.filter(i -> i.getWorld().equals(this.getWorld())).filter(Island::isOwned).filter( .filter(i -> i.getWorld().equals(this.getWorld())).filter(Island::isOwned).filter(
i -> i.getMemberSet().stream() i -> i.getMemberSet().stream()
.allMatch(member -> (currentTimeMillis .allMatch(member -> (currentTimeMillis

View File

@ -104,7 +104,9 @@ public class PanelItemBuilder {
* @return PanelItemBuilder * @return PanelItemBuilder
*/ */
public PanelItemBuilder description(String description) { public PanelItemBuilder description(String description) {
Collections.addAll(this.description, description.split("\n")); if (description != null) {
Collections.addAll(this.description, description.split("\n"));
}
return this; return this;
} }
@ -168,7 +170,7 @@ public class PanelItemBuilder {
public boolean isPlayerHead() { public boolean isPlayerHead() {
return playerHeadName != null && !playerHeadName.isEmpty(); return playerHeadName != null && !playerHeadName.isEmpty();
} }
/** /**
* @return the playerHead * @return the playerHead
* @since 1.9.0 * @since 1.9.0

View File

@ -12,8 +12,12 @@ import com.google.gson.stream.JsonWriter;
public class ProfessionTypeAdapter extends TypeAdapter<Profession> { public class ProfessionTypeAdapter extends TypeAdapter<Profession> {
@Override @Override
public void write(JsonWriter out, Profession profession) throws IOException { public void write(JsonWriter out, Profession profession) throws IOException {
out.value(profession.name()); if (profession != null) {
out.value(profession.name());
return;
}
out.nullValue();
} }
@Override @Override

View File

@ -12,7 +12,11 @@ import com.google.gson.stream.JsonWriter;
public class VillagerTypeAdapter extends TypeAdapter<Villager.Type> { public class VillagerTypeAdapter extends TypeAdapter<Villager.Type> {
@Override @Override
public void write(JsonWriter out, Villager.Type type) throws IOException { public void write(JsonWriter out, Villager.Type type) throws IOException {
if (type == null) {
out.nullValue();
return;
}
out.value(type.name()); out.value(type.name());
} }

View File

@ -253,10 +253,32 @@ public class Players implements DataObject, MetaDataAble {
public Optional<Map<String, MetaDataValue>> getMetaData() { public Optional<Map<String, MetaDataValue>> getMetaData() {
if (metaData == null) { if (metaData == null) {
metaData = new HashMap<>(); metaData = new HashMap<>();
} else if (isImmutable(metaData)) {
metaData = new HashMap<>(metaData); // Convert immutable map to mutable
} }
return Optional.of(metaData); return Optional.of(metaData);
} }
private boolean isImmutable(Map<String, MetaDataValue> map) {
try {
String testKey = "testKey";
MetaDataValue testValue = new MetaDataValue("test");
// If the map already contains keys, use one of them
if (!map.isEmpty()) {
String existingKey = map.keySet().iterator().next();
map.put(existingKey, map.get(existingKey)); // Attempt to replace value
} else {
// Use a unique key-value pair
map.put(testKey, testValue);
map.remove(testKey);
}
return false; // No exception means the map is mutable
} catch (UnsupportedOperationException e) {
return true; // Exception means the map is immutable
}
}
/** /**
* @param metaData the metaData to set * @param metaData the metaData to set
* @since 1.15.4 * @since 1.15.4
@ -264,6 +286,9 @@ public class Players implements DataObject, MetaDataAble {
*/ */
@Override @Override
public void setMetaData(Map<String, MetaDataValue> metaData) { public void setMetaData(Map<String, MetaDataValue> metaData) {
if (isImmutable(metaData)) {
throw new IllegalArgumentException("Provided map is immutable and cannot be set.");
}
this.metaData = metaData; this.metaData = metaData;
} }

View File

@ -2,6 +2,7 @@ package world.bentobox.bentobox.listeners.flags.clicklisteners;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import org.bukkit.Material; import org.bukkit.Material;
@ -26,6 +27,7 @@ import world.bentobox.bentobox.panels.settings.SettingsTab;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
/** /**
*
* @author tastybento * @author tastybento
* *
*/ */
@ -108,11 +110,19 @@ public class CommandRankClickListener implements ClickHandler {
*/ */
public PanelItem getPanelItem(String c, User user, World world) { public PanelItem getPanelItem(String c, User user, World world) {
PanelItemBuilder pib = new PanelItemBuilder(); PanelItemBuilder pib = new PanelItemBuilder();
pib.name(c); pib.name(user.getTranslation("protection.panel.flag-item.name-layout", TextVariables.NAME, c));
pib.clickHandler(new CommandCycleClick(this, c)); pib.clickHandler(new CommandCycleClick(this, c));
pib.icon(Material.MAP); pib.icon(Material.MAP);
// TODO: use specific layout String result = "";
String d = user.getTranslation("protection.panel.flag-item.description-layout", TextVariables.DESCRIPTION, ""); // Remove the first word (everything before the first space)
String[] words = c.split(" ", 2); // Split into two parts, the first word and the rest
if (words.length > 1) {
result = words[1].replace(" ", "-"); // Replace spaces with hyphens
}
String ref = "protection.panel.flag-item.command-instructions." + result.toLowerCase(Locale.ENGLISH);
String commandDescription = user.getTranslationOrNothing(ref);
String d = user.getTranslation("protection.panel.flag-item.description-layout", TextVariables.DESCRIPTION,
commandDescription);
pib.description(d); pib.description(d);
RanksManager.getInstance().getRanks().forEach((reference, score) -> { RanksManager.getInstance().getRanks().forEach((reference, score) -> {
if (score >= RanksManager.MEMBER_RANK && score < island.getRankCommand(c)) { if (score >= RanksManager.MEMBER_RANK && score < island.getRankCommand(c)) {
@ -133,7 +143,7 @@ public class CommandRankClickListener implements ClickHandler {
.filter(c -> c.getWorld() != null && c.getWorld().equals(world)) // Only allow commands in this world .filter(c -> c.getWorld() != null && c.getWorld().equals(world)) // Only allow commands in this world
.filter(c -> c.testPermission(user.getSender())) // Only allow them to see commands they have permission to see .filter(c -> c.testPermission(user.getSender())) // Only allow them to see commands they have permission to see
.flatMap(c -> getCmdRecursively("/", c).stream()) .flatMap(c -> getCmdRecursively("/", c).stream())
.filter(label -> user.isOp() || !hiddenItems.contains(CommandCycleClick.COMMAND_RANK_PREFIX + label)) .filter(label -> user.isOp() || !hiddenItems.contains(CommandCycleClick.COMMAND_RANK_PREFIX + label)) // Hide any hidden commands
.limit(49) // Silently limit to 49 .limit(49) // Silently limit to 49
.toList(); .toList();
return result; return result;

View File

@ -84,6 +84,9 @@ public class BreakBlocksListener extends FlagListener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) public void onPlayerInteract(final PlayerInteractEvent e)
{ {
if (e.getClickedBlock() == null) {
return;
}
Player p = e.getPlayer(); Player p = e.getPlayer();
Location l = e.getClickedBlock().getLocation(); Location l = e.getClickedBlock().getLocation();
Material m = e.getClickedBlock().getType(); Material m = e.getClickedBlock().getType();
@ -95,7 +98,7 @@ public class BreakBlocksListener extends FlagListener {
if (((CaveVinesPlant) e.getClickedBlock().getBlockData()).isBerries()) { if (((CaveVinesPlant) e.getClickedBlock().getBlockData()).isBerries()) {
this.checkIsland(e, p, l, Flags.HARVEST); this.checkIsland(e, p, l, Flags.HARVEST);
} }
} }
case SWEET_BERRY_BUSH -> this.checkIsland(e, p, l, Flags.HARVEST); case SWEET_BERRY_BUSH -> this.checkIsland(e, p, l, Flags.HARVEST);
case ROOTED_DIRT -> this.checkIsland(e, p, l, Flags.BREAK_BLOCKS); case ROOTED_DIRT -> this.checkIsland(e, p, l, Flags.BREAK_BLOCKS);
default -> { // Do nothing default -> { // Do nothing

View File

@ -8,8 +8,6 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
@ -40,9 +38,10 @@ public class CreeperListener extends FlagListener {
if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getLocation().getWorld())) { if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getLocation().getWorld())) {
// If any were removed, then prevent damage too // If any were removed, then prevent damage too
e.blockList().clear(); e.blockList().clear();
e.setCancelled(true); // Still allow player and mob damage
return; e.setCancelled(false);
} }
// Check for griefing // Check for griefing
Creeper creeper = (Creeper)e.getEntity(); Creeper creeper = (Creeper)e.getEntity();
if (!Flags.CREEPER_GRIEFING.isSetForWorld(e.getLocation().getWorld()) if (!Flags.CREEPER_GRIEFING.isSetForWorld(e.getLocation().getWorld())
@ -55,25 +54,6 @@ public class CreeperListener extends FlagListener {
} }
} }
/**
* Prevent entities being damaged by explosion
* @param e - event
* @since 1.10.0
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final EntityDamageByEntityEvent e) {
if (!e.getCause().equals(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) || !getIWM().inWorld(e.getEntity().getLocation())
|| !e.getDamager().getType().equals(EntityType.CREEPER)) {
return;
}
// If creeper damage is not allowed in world cancel the damage
if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getEntity().getWorld())) {
e.setCancelled(true);
}
}
/** /**
* Prevent creepers from igniting if they are not allowed to grief * Prevent creepers from igniting if they are not allowed to grief
* @param e - event * @param e - event

View File

@ -9,6 +9,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.api.flags.FlagListener;
@ -36,15 +37,16 @@ public class EnterExitListener extends FlagListener {
handleEnterExit(User.getInstance(e.getPlayer()), e.getFrom(), e.getTo(), e); handleEnterExit(User.getInstance(e.getPlayer()), e.getFrom(), e.getTo(), e);
} }
private void handleEnterExit(@NonNull User user, @NonNull Location from, @NonNull Location to, @NonNull PlayerMoveEvent e) { private void handleEnterExit(@NonNull User user, @NonNull Location from, @Nullable Location to,
@NonNull PlayerMoveEvent e) {
// Only process if there is a change in X or Z coords // Only process if there is a change in X or Z coords
if (from.getWorld() != null && from.getWorld().equals(to.getWorld()) if (from.getWorld() != null && to != null && from.getWorld().equals(to.getWorld())
&& from.toVector().multiply(XZ).equals(to.toVector().multiply(XZ))) { && from.toVector().multiply(XZ).equals(to.toVector().multiply(XZ))) {
return; return;
} }
Optional<Island> islandFrom = getIslands().getProtectedIslandAt(from); Optional<Island> islandFrom = getIslands().getProtectedIslandAt(from);
Optional<Island> islandTo = getIslands().getProtectedIslandAt(to); Optional<Island> islandTo = to == null ? Optional.empty() : getIslands().getProtectedIslandAt(to);
/* /*
* Options: * Options:

View File

@ -72,6 +72,7 @@ public class CommandsManager {
} }
/** /**
* Get a map of every command registered in BentoBox
* @return the commands * @return the commands
*/ */
@NonNull @NonNull

View File

@ -1267,15 +1267,18 @@ public class IslandsManager {
// These will be deleted later // These will be deleted later
deletedIslands.add(island.getUniqueId()); deletedIslands.add(island.getUniqueId());
} // Check island distance and if incorrect stop BentoBox } // Check island distance and if incorrect stop BentoBox
else if (island.getWorld() != null && plugin.getIWM().inWorld(island.getWorld()) else if (!plugin.getSettings().isOverrideSafetyCheck() && island.getWorld() != null
&& plugin.getIWM().inWorld(island.getWorld())
&& island.getRange() != plugin.getIWM().getIslandDistance(island.getWorld())) { && island.getRange() != plugin.getIWM().getIslandDistance(island.getWorld())) {
throw new IOException("Island distance mismatch!\n" + "World '" + island.getWorld().getName() throw new IOException("Island distance mismatch!\n" + "World '" + island.getWorld().getName()
+ "' distance " + plugin.getIWM().getIslandDistance(island.getWorld()) + " != island range " + "' distance " + plugin.getIWM().getIslandDistance(island.getWorld()) + " != island range "
+ island.getRange() + "!\n" + "Island ID in database is " + island.getUniqueId() + ".\n" + island.getRange() + "!\n" + "Island ID in database is " + island.getUniqueId() + ".\n"
+ "Island distance in config.yml cannot be changed mid-game! Fix config.yml or clean database."); + "Island distance in config.yml cannot be changed mid-game! Fix config.yml or clean database.");
} else { } else {
// Fix island center if it is off if (!plugin.getSettings().isOverrideSafetyCheck()) {
fixIslandCenter(island); // Fix island center if it is off
fixIslandCenter(island);
}
islandCache.addIsland(island, true); islandCache.addIsland(island, true);
if (island.isSpawn()) { if (island.isSpawn()) {
@ -1650,6 +1653,10 @@ public class IslandsManager {
* @param uniqueId - UUID of player * @param uniqueId - UUID of player
*/ */
public void clearRank(int rank, UUID uniqueId) { public void clearRank(int rank, UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> clearRankSync(rank, uniqueId));
}
void clearRankSync(int rank, UUID uniqueId) {
islandCache.getCachedIslands().forEach( islandCache.getCachedIslands().forEach(
i -> i.getMembers().entrySet().removeIf(e -> e.getKey().equals(uniqueId) && e.getValue() == rank)); i -> i.getMembers().entrySet().removeIf(e -> e.getKey().equals(uniqueId) && e.getValue() == rank));
} }

View File

@ -1652,6 +1652,59 @@ protection:
&a player is outside their island &a player is outside their island
flag-item: flag-item:
name-layout: '&a [name]' name-layout: '&a [name]'
# Add commands to this list as required
command-instructions:
setname: |
&a Select the rank that can
&a set the name
ban: |
&a Select the rank that can
ban players
unban: |
&a Select the rank that can
&a unban players
expel: |
&a Select the rank who can
&a expel visitors
team-invite: |
&a Select the rank that can
&a invite
team-kick: |
&a Select the rank that can
&a kick
team-coop: |
&a Select the rank that can
&a coop
team-trust: |
&a Select the rank that can
&a trust
team-uncoop: |
&a Select the rank that can
&a uncoop
team-untrust: |
&a Select the rank that can
&a untrust
team-promote: |
&a Select the rank that can
&a promote player's rank
team-demote: |
&a Select the rank that can
&a demote player's rank
sethome: |
&a Select the rank that can
&a set homes
deletehome: |
&a Select the rank that can
&a delete homes
renamehome: |
&a Select the rank that can
&a rename homes
setcount: |
&a Select the rank that can
&a change the phase
border: |
&a Select the rank that can
&a use the border command
description-layout: | description-layout: |
&a [description] &a [description]
@ -1854,6 +1907,7 @@ panels:
# The section of translations used in Language Panel # The section of translations used in Language Panel
language: language:
title: "&2&l Select your language" title: "&2&l Select your language"
edited: "&c Changed to [lang]"
buttons: buttons:
# This button is used for displaying different locales that are available in language selection panel. # This button is used for displaying different locales that are available in language selection panel.
language: language:

View File

@ -12,6 +12,7 @@ import static org.mockito.Mockito.when;
import java.util.Collections; import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -364,4 +365,15 @@ public class AdminPurgeCommandTest {
verify(user, Mockito.times(1)).sendMessage(any()); verify(user, Mockito.times(1)).sendMessage(any());
} }
/**
* Test method for {@link world.bentobox.bentobox.api.commands.admin.purge.AdminPurgeCommand#getOldIslands(int)}
*/
@Test
public void testGetOldIslands() {
assertTrue(apc.getOldIslands(10).isEmpty());
Island island2 = mock(Island.class);
when(im.getIslands()).thenReturn(Set.of(island, island2));
assertTrue(apc.getOldIslands(10).isEmpty());
}
} }

View File

@ -122,6 +122,10 @@ public class CommandRankClickListenerTest extends RanksManagerBeforeClassTest {
when(user.getPlayer()).thenReturn(player); when(user.getPlayer()).thenReturn(player);
when(user.inWorld()).thenReturn(true); when(user.inWorld()).thenReturn(true);
when(user.getWorld()).thenReturn(world); when(user.getWorld()).thenReturn(world);
when(user.getTranslationOrNothing(anyString(), anyString()))
.thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
when(user.getTranslationOrNothing(anyString()))
.thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
when(user.getTranslation(anyString())) when(user.getTranslation(anyString()))
.thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class)); .thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
when(user.getTranslation(anyString(), anyString(), anyString())) when(user.getTranslation(anyString(), anyString(), anyString()))
@ -215,7 +219,8 @@ public class CommandRankClickListenerTest extends RanksManagerBeforeClassTest {
when(cm.getCommands()).thenReturn(map); when(cm.getCommands()).thenReturn(map);
assertTrue(crcl.onClick(panel, user, ClickType.LEFT, 0)); assertTrue(crcl.onClick(panel, user, ClickType.LEFT, 0));
verify(user).getTranslation("protection.panel.flag-item.description-layout", TextVariables.DESCRIPTION, ""); verify(user).getTranslation("protection.panel.flag-item.description-layout", TextVariables.DESCRIPTION,
"protection.panel.flag-item.command-instructions.");
} }
/** /**
@ -226,12 +231,12 @@ public class CommandRankClickListenerTest extends RanksManagerBeforeClassTest {
assertTrue(crcl.onClick(panel, user, ClickType.LEFT, 0)); assertTrue(crcl.onClick(panel, user, ClickType.LEFT, 0));
PanelItem pi = crcl.getPanelItem("test", user, world); PanelItem pi = crcl.getPanelItem("test", user, world);
assertEquals(Material.MAP, pi.getItem().getType()); assertEquals(Material.MAP, pi.getItem().getType());
assertEquals("protection.panel.flag-item.description-layout", pi.getDescription().get(0)); //assertEquals("protection.panel.flag-item.description-layout", pi.getDescription().get(0));
//assertEquals("protection.panel.flag-item.minimal-rankranks.member", pi.getDescription().get(1)); //assertEquals("protection.panel.flag-item.minimal-rankranks.member", pi.getDescription().get(1));
//assertEquals("protection.panel.flag-item.allowed-rankranks.sub-owner", pi.getDescription().get(2)); //assertEquals("protection.panel.flag-item.allowed-rankranks.sub-owner", pi.getDescription().get(2));
//assertEquals("protection.panel.flag-item.allowed-rankranks.owner", pi.getDescription().get(3)); //assertEquals("protection.panel.flag-item.allowed-rankranks.owner", pi.getDescription().get(0));
assertTrue(pi.getClickHandler().isPresent()); assertTrue(pi.getClickHandler().isPresent());
assertEquals("test", pi.getName()); assertEquals("protection.panel.flag-item.name-layout", pi.getName());
} }
} }

View File

@ -621,4 +621,15 @@ public class BreakBlocksListenerTest extends AbstractCommonSetup {
assertTrue(e.useInteractedBlock() == Result.ALLOW); assertTrue(e.useInteractedBlock() == Result.ALLOW);
} }
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BreakBlocksListener#onPlayerInteract(PlayerInteractEvent)}
*/
@Test
public void testNoClick() {
PlayerInteractEvent e = mock(PlayerInteractEvent.class);
when(e.getClickedBlock()).thenReturn(null);
bbl.onPlayerInteract(e);
verify(e).getClickedBlock();
}
} }

View File

@ -0,0 +1,136 @@
package world.bentobox.bentobox.listeners.flags.worldsettings;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.EntityExplodeEvent;
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.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.listeners.flags.AbstractCommonSetup;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
/**
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Bukkit.class, BentoBox.class, Flags.class, Util.class })
public class CreeperListenerTest extends AbstractCommonSetup {
private CreeperListener cl;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
super.setUp();
cl = new CreeperListener();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
User.clearUsers();
Mockito.framework().clearInlineMocks();
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
*/
@Test
public void testOnExplosionNotCreeper() {
List<Block> list = new ArrayList<>();
Entity entity = mock(Entity.class);
when(entity.getType()).thenReturn(EntityType.TNT);
when(iwm.inWorld(location)).thenReturn(true);
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
cl.onExplosion(event);
assertFalse(event.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
*/
@Test
public void testOnExplosionNotInWorld() {
List<Block> list = new ArrayList<>();
Entity entity = mock(Entity.class);
when(entity.getLocation()).thenReturn(location);
when(entity.getType()).thenReturn(EntityType.CREEPER);
when(iwm.inWorld(location)).thenReturn(false);
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
cl.onExplosion(event);
assertFalse(event.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
*/
@Test
public void testOnExplosionCreeperInWorldDamageOK() {
List<Block> list = new ArrayList<>();
list.add(mock(Block.class));
list.add(mock(Block.class));
list.add(mock(Block.class));
Creeper entity = mock(Creeper.class);
when(entity.getLocation()).thenReturn(location);
when(entity.getType()).thenReturn(EntityType.CREEPER);
when(iwm.inWorld(location)).thenReturn(true);
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
cl.onExplosion(event);
assertFalse(event.isCancelled());
assertFalse(event.blockList().isEmpty()); // No clearing of block list
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
*/
@Test
public void testOnExplosionCreeperInWorldDamageNOK() {
Flags.CREEPER_DAMAGE.setSetting(world, false);
List<Block> list = new ArrayList<>();
list.add(mock(Block.class));
list.add(mock(Block.class));
list.add(mock(Block.class));
Creeper entity = mock(Creeper.class);
when(location.getWorld()).thenReturn(world);
when(entity.getLocation()).thenReturn(location);
when(entity.getType()).thenReturn(EntityType.CREEPER);
when(iwm.inWorld(location)).thenReturn(true);
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
cl.onExplosion(event);
assertFalse(event.isCancelled());
assertTrue(event.blockList().isEmpty()); // No clearing of block list
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractEntityEvent)}.
*/
@Test
public void testOnPlayerInteractEntity() {
//TODO
}
}

View File

@ -242,6 +242,19 @@ public class EnterExitListenerTest {
verify(pim, never()).callEvent(any(IslandExitEvent.class)); verify(pim, never()).callEvent(any(IslandExitEvent.class));
} }
/**
* Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}.
*/
@Test
public void testOnMoveOutsideIslandToNull() {
PlayerMoveEvent e = new PlayerMoveEvent(user.getPlayer(), outside, null);
listener.onMove(e);
// Moving outside the island should result in no messages to the user
verify(notifier, never()).notify(any(), any());
verify(pim, never()).callEvent(any(IslandEnterEvent.class));
verify(pim, never()).callEvent(any(IslandExitEvent.class));
}
/** /**
* Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}. * Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}.
*/ */
@ -294,6 +307,23 @@ public class EnterExitListenerTest {
verify(notifier).notify(any(User.class), eq("protection.flags.ENTER_EXIT_MESSAGES.now-leaving")); verify(notifier).notify(any(User.class), eq("protection.flags.ENTER_EXIT_MESSAGES.now-leaving"));
} }
/**
* Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}.
*/
@Test
public void testExitingIslandEmptyIslandNameToNull() {
when(island.getName()).thenReturn("");
PlayerMoveEvent e = new PlayerMoveEvent(user.getPlayer(), inside, null);
listener.onMove(e);
// Moving into the island should show a message
verify(lm).get(any(), eq("protection.flags.ENTER_EXIT_MESSAGES.now-leaving"));
// The island owner needs to be checked
verify(island).isOwned();
verify(pim).callEvent(any(IslandExitEvent.class));
verify(pim, never()).callEvent(any(IslandEnterEvent.class));
verify(notifier).notify(any(User.class), eq("protection.flags.ENTER_EXIT_MESSAGES.now-leaving"));
}
/** /**
* Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}. * Test method for {@link EnterExitListener#onMove(org.bukkit.event.player.PlayerMoveEvent)}.
*/ */
@ -354,6 +384,18 @@ public class EnterExitListenerTest {
verify(pim).callEvent(any(IslandExitEvent.class)); verify(pim).callEvent(any(IslandExitEvent.class));
} }
/**
* Test method for {@link EnterExitListener#onTeleport(org.bukkit.event.player.PlayerTeleportEvent)}.
*/
@Test
public void testExitIslandTeleportToNull() {
PlayerTeleportEvent e = new PlayerTeleportEvent(user.getPlayer(), inside, null, TeleportCause.PLUGIN);
listener.onTeleport(e);
verify(notifier).notify(any(User.class), eq("protection.flags.ENTER_EXIT_MESSAGES.now-leaving"));
verify(pim, never()).callEvent(any(IslandEnterEvent.class));
verify(pim).callEvent(any(IslandExitEvent.class));
}
/** /**
* Test method for {@link EnterExitListener#onTeleport(org.bukkit.event.player.PlayerTeleportEvent)}. * Test method for {@link EnterExitListener#onTeleport(org.bukkit.event.player.PlayerTeleportEvent)}.

View File

@ -153,6 +153,8 @@ public class IslandsManagerTest extends AbstractCommonSetup {
// Class under test // Class under test
IslandsManager im; IslandsManager im;
private Settings settings;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@BeforeClass @BeforeClass
public static void beforeClass() throws IllegalAccessException, InvocationTargetException, IntrospectionException { public static void beforeClass() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
@ -187,12 +189,12 @@ public class IslandsManagerTest extends AbstractCommonSetup {
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL); when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
when(iwm.inWorld(any(World.class))).thenReturn(true); when(iwm.inWorld(any(World.class))).thenReturn(true);
when(iwm.inWorld(any(Location.class))).thenReturn(true); when(iwm.inWorld(any(Location.class))).thenReturn(true);
when(iwm.getIslandDistance(any())).thenReturn(25);
when(plugin.getIWM()).thenReturn(iwm); when(plugin.getIWM()).thenReturn(iwm);
// Settings // Settings
Settings s = mock(Settings.class); settings = new Settings();
when(plugin.getSettings()).thenReturn(s); when(plugin.getSettings()).thenReturn(settings);
when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
// World // World
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL); when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
@ -827,14 +829,41 @@ public class IslandsManagerTest extends AbstractCommonSetup {
/** /**
* Test method for * Test method for
* {@link world.bentobox.bentobox.managers.IslandsManager#load()}. * {@link world.bentobox.bentobox.managers.IslandsManager#load()}.
* @throws IOException
* @throws IntrospectionException
* @throws NoSuchMethodException
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
*/ */
@Test @Test
public void testLoad() { public void testLoad() throws IOException, InstantiationException, IllegalAccessException,
// InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException {
// im.load(); when(island.getRange()).thenReturn(100);
when(h.loadObjects()).thenReturn(List.of(island));
try {
im.load();
} catch (IOException e) {
assertEquals("Island distance mismatch!\n" + "World 'world' distance 25 != island range 100!\n"
+ "Island ID in database is null.\n"
+ "Island distance in config.yml cannot be changed mid-game! Fix config.yml or clean database.",
e.getMessage());
}
} }
@Test
public void testLoadNoDistanceCheck() throws IOException, InstantiationException, IllegalAccessException,
InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException {
settings.setOverrideSafetyCheck(true);
when(island.getUniqueId()).thenReturn(UUID.randomUUID().toString());
when(island.getRange()).thenReturn(100);
when(h.loadObjects()).thenReturn(List.of(island));
im.load();
// No exception should be thrown
}
/** /**
* Test method for * Test method for
* {@link world.bentobox.bentobox.managers.IslandsManager#locationIsOnIsland(org.bukkit.entity.Player, org.bukkit.Location)}. * {@link world.bentobox.bentobox.managers.IslandsManager#locationIsOnIsland(org.bukkit.entity.Player, org.bukkit.Location)}.
@ -1111,9 +1140,9 @@ public class IslandsManagerTest extends AbstractCommonSetup {
UUID coopUUID = UUID.randomUUID(); UUID coopUUID = UUID.randomUUID();
members.put(coopUUID, RanksManager.COOP_RANK); members.put(coopUUID, RanksManager.COOP_RANK);
// Clear a random user // Clear a random user
im.clearRank(RanksManager.COOP_RANK, UUID.randomUUID()); im.clearRankSync(RanksManager.COOP_RANK, UUID.randomUUID());
assertEquals(14, members.size()); assertEquals(14, members.size());
im.clearRank(RanksManager.COOP_RANK, coopUUID); im.clearRankSync(RanksManager.COOP_RANK, coopUUID);
assertEquals(13, members.size()); assertEquals(13, members.size());
} }