Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions src/main/java/world/bentobox/bentobox/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,13 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "island.obsidian-scooping-cooldown", since = "3.11.4")
private int obsidianScoopingCooldown = 1;

@ConfigComment("How long (in seconds) to show a hologram tip above newly formed obsidian")
@ConfigComment("that can be scooped back into lava. The hologram reminds players they can")
@ConfigComment("right-click obsidian with an empty bucket to recover lava.")
@ConfigComment("Set to 0 or less to disable the tip entirely. Default is 30 seconds.")
@ConfigEntry(path = "island.obsidian-scooping-lava-tip-duration", since = "3.12.0")
private int obsidianScoopingLavaTipDuration = 30;

/* WEB */
@ConfigComment("Toggle whether BentoBox can connect to GitHub to get data about updates and addons.")
@ConfigComment("Disabling this will result in the deactivation of the update checker and of some other")
Expand Down Expand Up @@ -1243,6 +1250,28 @@ public void setObsidianScoopingCooldown(int obsidianScoopingCooldown) {
this.obsidianScoopingCooldown = Math.max(1, obsidianScoopingCooldown);
}

/**
* Gets the duration (in seconds) for showing the lava tip hologram above
* newly formed obsidian blocks that can be scooped.
*
* @return the lava tip duration in seconds; 0 or less means disabled
* @since 3.12.0
*/
public int getObsidianScoopingLavaTipDuration() {
return obsidianScoopingLavaTipDuration;
}

/**
* Sets the duration (in seconds) for showing the lava tip hologram above
* newly formed obsidian blocks that can be scooped.
*
* @param obsidianScoopingLavaTipDuration the duration in seconds; 0 or less disables
* @since 3.12.0
*/
public void setObsidianScoopingLavaTipDuration(int obsidianScoopingLavaTipDuration) {
this.obsidianScoopingLavaTipDuration = obsidianScoopingLavaTipDuration;
}

/**
* @return the islandNumber
* @since 2.0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,31 @@
import org.bukkit.Bukkit;
import org.bukkit.FluidCollisionMode;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Display;
import org.bukkit.entity.Player;
import org.bukkit.entity.TextDisplay;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.RayTraceResult;

import net.kyori.adventure.text.Component;

import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.ExpiringSet;
import world.bentobox.bentobox.util.Util;

/**
* Enables changing of obsidian back into lava
Expand All @@ -34,6 +42,17 @@
*/
public class ObsidianScoopingListener extends FlagListener {

private static final String LAVA_TIP_REFERENCE = "protection.flags.OBSIDIAN_SCOOPING.lavaTip";

/**
* The preferred order for hologram placement: above, sides, then below.
*/
private static final BlockFace[] HOLOGRAM_FACES = {
BlockFace.UP,
BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST,
BlockFace.DOWN
};

/**
* Cooldown to prevent lava duplication by rapid obsidian scooping.
* Initialized lazily on first use so that the configured duration from settings
Expand Down Expand Up @@ -69,6 +88,88 @@ private ExpiringSet<UUID> getCooldowns() {
public void onPlayerInteractEvent(final PlayerInteractEvent e) {
onPlayerInteract(e);
}

/**
* Shows a hologram tip when obsidian forms from lava and water mixing,
* if the obsidian could potentially be scooped back into lava.
*
* @param e the block form event
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onObsidianForm(final BlockFormEvent e) {
handleObsidianForm(e);
}

/**
* Handles obsidian formation and shows a lava tip hologram if applicable.
*
* @param e the block form event
* @return true if a hologram was spawned, false otherwise
*/
boolean handleObsidianForm(final BlockFormEvent e) {
if (!Material.OBSIDIAN.equals(e.getNewState().getType())) {
return false;
}
Block b = e.getBlock();
if (!getIWM().inWorld(b.getLocation()) || !Flags.OBSIDIAN_SCOOPING.isSetForWorld(b.getWorld())) {
return false;
}
BentoBox bentoBox = BentoBox.getInstance();
int duration = bentoBox.getSettings().getObsidianScoopingLavaTipDuration();
if (duration <= 0) {
return false;
}
int radius = bentoBox.getSettings().getObsidianScoopingRadius();
// Check if this obsidian is solitary (could be scooped)
if (radius > 0 && getBlocksAround(b, radius).stream().anyMatch(block -> block.getType().equals(Material.OBSIDIAN))) {
return false;
}
// Find a suitable location for the hologram
Location holoLoc = findHologramLocation(b);
if (holoLoc == null) {
return false;
}
// Get the lava tip text from the locale
String tipText = bentoBox.getLocalesManager().getOrDefault(LAVA_TIP_REFERENCE, "");
if (tipText.isEmpty()) {
return false;
}
Component tipComponent = Util.parseMiniMessage(tipText);
// Spawn a TextDisplay hologram
TextDisplay hologram = b.getWorld().spawn(holoLoc, TextDisplay.class, td -> {
td.text(tipComponent);
td.setBillboard(Display.Billboard.CENTER);
td.setSeeThrough(true);
td.setGravity(false);
});
// Schedule removal after the configured duration
Bukkit.getScheduler().runTaskLater(bentoBox, () -> {
if (hologram.isValid()) {
hologram.remove();
}
}, duration * 20L);
return true;
}

/**
* Finds a suitable location for a hologram near the given block.
* Prefers above the block, then sides, then below.
* A location is suitable if the block there is air or a liquid.
*
* @param b the obsidian block
* @return a suitable location, or null if none found
*/
Location findHologramLocation(Block b) {
for (BlockFace face : HOLOGRAM_FACES) {
Block relative = b.getRelative(face);
Material type = relative.getType();
if (type.isAir() || relative.isLiquid()) {
return relative.getLocation().add(0.5, 0.5, 0.5);
}
}
return null;
}

/**
* Enables changing of obsidian back into lava
*
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,7 @@ protection:
cooldown: '<red>You must wait before scooping another obsidian block.</red>'
obsidian-nearby: '<red>There are obsidian blocks within a [radius]-block radius
of this obsidian. You cannot scoop it up into lava.</red>'
lavaTip: '<green>Scoop this up as lava with a bucket if you need it!</green>'
OFFLINE_GROWTH:
description: |-
<green>When disabled, plants</green>
Expand Down
Loading
Loading