Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 2.5.4 #2514

Merged
merged 23 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
86c9a8f
Version 2.5.4
tastybento Sep 1, 2024
dbf4bb7
Fix bug with saving mobs in blueprints #2497
tastybento Sep 7, 2024
80219f3
Add protection around meta data being written that is immutable
tastybento Sep 7, 2024
a716feb
Merge pull request #2498 from BentoBoxWorld/2497_Blueprint_and_mobs
tastybento Sep 7, 2024
a9b8613
Protect against null to locations. #2496
tastybento Sep 8, 2024
6896a45
Merge pull request #2499 from BentoBoxWorld/2496_null_to_location
tastybento Sep 8, 2024
8ba3f03
Prevent null island worlds from blocking purging. #2500
tastybento Sep 13, 2024
8240484
Added test case
tastybento Sep 13, 2024
ab8f3a7
Merge pull request #2501 from BentoBoxWorld/2500_Admin_purge_command_…
tastybento Sep 13, 2024
2b6c7f8
Improve command rank GUI with helpful text descriptions #2502
tastybento Sep 14, 2024
f5abdd4
Merge pull request #2503 from BentoBoxWorld/2502_Improved_command_ran…
tastybento Sep 14, 2024
0965e07
Make the rank clearing async to avoid lag. #2504
tastybento Sep 14, 2024
060e700
Merge pull request #2505 from BentoBoxWorld/2504_lag_on_logout
tastybento Sep 14, 2024
625bfa6
Change how creeper damage flag works. #2507
tastybento Sep 17, 2024
5a4cbcc
Add some tests
tastybento Sep 17, 2024
4876064
Remove unused import
tastybento Sep 17, 2024
e90755d
Merge pull request #2508 from BentoBoxWorld/2507_Allow_creepers_to_hu…
tastybento Sep 17, 2024
d2410a5
Do not fix island centers
tastybento Sep 18, 2024
37ba89a
Merge pull request #2510 from BentoBoxWorld/2506_Override_island_dist…
tastybento Sep 18, 2024
a15b437
NPE fix for #2512
tastybento Sep 22, 2024
a40e9ec
Add test
tastybento Sep 22, 2024
b5ff354
Merge pull request #2513 from BentoBoxWorld/2512_random_errors
tastybento Sep 22, 2024
a5fee6b
Merge branch 'master' into develop
tastybento Sep 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- 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.host.url>https://sonarcloud.io</sonar.host.url>
<server.jars>${project.basedir}/lib</server.jars>
Expand Down Expand Up @@ -157,10 +157,6 @@
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
<repository>
<id>placeholderapi-repo</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
<repository>
<id>dynmap-repo</id>
<url>https://repo.mikeprimm.com/</url>
Expand Down
22 changes: 21 additions & 1 deletion src/main/java/world/bentobox/bentobox/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ public class Settings implements ConfigObject {
private Set<String> fakePlayers = new HashSet<>();

/* PANELS */

@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")
private boolean closePanelOnClickOutside = true;
Expand Down Expand Up @@ -189,6 +188,13 @@ public class Settings implements ConfigObject {
/*
* 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
@ConfigComment("The default number of concurrent islands a player may have.")
@ConfigComment("This may be overridden by individual game mode config settings.")
Expand Down Expand Up @@ -1034,4 +1040,18 @@ public void setHideUsedBlueprints(boolean 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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Set<String> getOldIslands(int days) {
// Process islands in one pass, logging and adding to the set if applicable
getPlugin().getIslands().getIslands().stream()
.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(
i -> i.getMemberSet().stream()
.allMatch(member -> (currentTimeMillis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ public PanelItemBuilder description(String... description) {
* @return PanelItemBuilder
*/
public PanelItemBuilder description(String description) {
Collections.addAll(this.description, description.split("\n"));
if (description != null) {
Collections.addAll(this.description, description.split("\n"));
}
return this;
}

Expand Down Expand Up @@ -168,7 +170,7 @@ public PanelItem.ClickHandler getClickHandler() {
public boolean isPlayerHead() {
return playerHeadName != null && !playerHeadName.isEmpty();
}

/**
* @return the playerHead
* @since 1.9.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
public class ProfessionTypeAdapter extends TypeAdapter<Profession> {

@Override
public void write(JsonWriter out, Profession profession) throws IOException {
out.value(profession.name());
public void write(JsonWriter out, Profession profession) throws IOException {
if (profession != null) {
out.value(profession.name());
return;
}
out.nullValue();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
public class VillagerTypeAdapter extends TypeAdapter<Villager.Type> {

@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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,17 +253,42 @@ public void addToPendingKick(World world)
public Optional<Map<String, MetaDataValue>> getMetaData() {
if (metaData == null) {
metaData = new HashMap<>();
} else if (isImmutable(metaData)) {
metaData = new HashMap<>(metaData); // Convert immutable map to mutable
}
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
* @since 1.15.4
* @see User#setMetaData(Map)
*/
@Override
public void setMetaData(Map<String, MetaDataValue> metaData) {
if (isImmutable(metaData)) {
throw new IllegalArgumentException("Provided map is immutable and cannot be set.");
}
this.metaData = metaData;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import org.bukkit.Material;
Expand All @@ -26,6 +27,7 @@
import world.bentobox.bentobox.util.Util;

/**
*
* @author tastybento
*
*/
Expand Down Expand Up @@ -108,11 +110,19 @@ private void openPanel(User user, String panelName, World world) {
*/
public PanelItem getPanelItem(String c, User user, World world) {
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.icon(Material.MAP);
// TODO: use specific layout
String d = user.getTranslation("protection.panel.flag-item.description-layout", TextVariables.DESCRIPTION, "");
String result = "";
// 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);
RanksManager.getInstance().getRanks().forEach((reference, score) -> {
if (score >= RanksManager.MEMBER_RANK && score < island.getRankCommand(c)) {
Expand All @@ -133,7 +143,7 @@ private List<String> getCommands(World world, User user) {
.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
.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
.toList();
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ public void onBreakHanging(final HangingBreakByEntityEvent e) {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e)
{
if (e.getClickedBlock() == null) {
return;
}
Player p = e.getPlayer();
Location l = e.getClickedBlock().getLocation();
Material m = e.getClickedBlock().getType();
Expand All @@ -95,7 +98,7 @@ public void onPlayerInteract(final PlayerInteractEvent e)
if (((CaveVinesPlant) e.getClickedBlock().getBlockData()).isBerries()) {
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);
default -> { // Do nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
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.player.PlayerInteractEntityEvent;

Expand Down Expand Up @@ -40,9 +38,10 @@ public void onExplosion(final EntityExplodeEvent e) {
if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getLocation().getWorld())) {
// If any were removed, then prevent damage too
e.blockList().clear();
e.setCancelled(true);
return;
// Still allow player and mob damage
e.setCancelled(false);
}

// Check for griefing
Creeper creeper = (Creeper)e.getEntity();
if (!Flags.CREEPER_GRIEFING.isSetForWorld(e.getLocation().getWorld())
Expand All @@ -55,25 +54,6 @@ public void onExplosion(final EntityExplodeEvent e) {
}
}


/**
* 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
* @param e - event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector;
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.flags.FlagListener;
Expand Down Expand Up @@ -36,15 +37,16 @@ public void onTeleport(PlayerTeleportEvent 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
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))) {
return;
}

Optional<Island> islandFrom = getIslands().getProtectedIslandAt(from);
Optional<Island> islandTo = getIslands().getProtectedIslandAt(to);
Optional<Island> islandTo = to == null ? Optional.empty() : getIslands().getProtectedIslandAt(to);

/*
* Options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public CompositeCommand getCommand(@NonNull String command) {
}

/**
* Get a map of every command registered in BentoBox
* @return the commands
*/
@NonNull
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -1267,15 +1267,18 @@ public void load() throws IOException {
// These will be deleted later
deletedIslands.add(island.getUniqueId());
} // 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())) {
throw new IOException("Island distance mismatch!\n" + "World '" + island.getWorld().getName()
+ "' distance " + plugin.getIWM().getIslandDistance(island.getWorld()) + " != island range "
+ 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.");
} else {
// Fix island center if it is off
fixIslandCenter(island);
if (!plugin.getSettings().isOverrideSafetyCheck()) {
// Fix island center if it is off
fixIslandCenter(island);
}
islandCache.addIsland(island, true);

if (island.isSpawn()) {
Expand Down Expand Up @@ -1650,6 +1653,10 @@ public void clearArea(Location loc) {
* @param uniqueId - UUID of player
*/
public void clearRank(int rank, UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> clearRankSync(rank, uniqueId));
}

void clearRankSync(int rank, UUID uniqueId) {
islandCache.getCachedIslands().forEach(
i -> i.getMembers().entrySet().removeIf(e -> e.getKey().equals(uniqueId) && e.getValue() == rank));
}
Expand Down
Loading
Loading