diff --git a/README.md b/README.md
index 172034e..38bd275 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,9 @@ As a BentoBox game mode, survival hinges on laying claim to your piece of the wo
### The Warped Compass
* **Chunk Regeneration:** Discover the custom recipe for the **Warped Compass**. When a player holds this powerful item while traveling through a Nether Portal, it forces the regeneration of chunks in all directions, ensuring you always have fresh territory to explore based on the Overworld.
+The recipe is:
+
+
### Dynamic World Border (Admin Feature)
diff --git a/pom.xml b/pom.xml
index 8b82624..9bf4650 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,7 +61,7 @@
-LOCAL
- 1.0.2
+ 1.0.3
bentobox-world
diff --git a/src/main/java/world/bentobox/stranger/StrangerRealms.java b/src/main/java/world/bentobox/stranger/StrangerRealms.java
index a236794..5b1ccd2 100644
--- a/src/main/java/world/bentobox/stranger/StrangerRealms.java
+++ b/src/main/java/world/bentobox/stranger/StrangerRealms.java
@@ -20,10 +20,12 @@
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitTask;
import org.eclipse.jdt.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
+import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.commands.admin.DefaultAdminCommand;
import world.bentobox.bentobox.api.commands.island.DefaultPlayerCommand;
@@ -57,7 +59,8 @@ public class StrangerRealms extends GameModeAddon {
private static final String THE_END = "_the_end";
// Define a static key for the custom item, primarily for referencing its material later if needed.
- public static final Material WARPED_COMPASS_MATERIAL = Material.COMPASS;
+ private static final Material WARPED_COMPASS_MATERIAL = Material.COMPASS;
+ public static final @NotNull NamespacedKey WARPED_COMPASS_RECIPE = new NamespacedKey(BentoBox.getInstance(), "warped_compass");
// Settings
@@ -223,24 +226,12 @@ private World getWorld(String worldName2, Environment env) {
}
private void setSpawnRates(World w) {
- if (getSettings().getSpawnLimitMonsters() > 0) {
w.setSpawnLimit(SpawnCategory.MONSTER, getSettings().getSpawnLimitMonsters());
- }
- if (getSettings().getSpawnLimitAmbient() > 0) {
w.setSpawnLimit(SpawnCategory.AMBIENT, getSettings().getSpawnLimitAmbient());
- }
- if (getSettings().getSpawnLimitAnimals() > 0) {
- w.setSpawnLimit(SpawnCategory.ANIMAL, getSettings().getSpawnLimitAnimals());
- }
- if (getSettings().getSpawnLimitWaterAnimals() > 0) {
- w.setSpawnLimit(SpawnCategory.WATER_ANIMAL, getSettings().getSpawnLimitWaterAnimals());
- }
- if (getSettings().getTicksPerAnimalSpawns() > 0) {
+ w.setSpawnLimit(SpawnCategory.ANIMAL, getSettings().getSpawnLimitAnimals());
+ w.setSpawnLimit(SpawnCategory.WATER_ANIMAL, getSettings().getSpawnLimitWaterAnimals());
w.setTicksPerSpawns(SpawnCategory.ANIMAL, getSettings().getTicksPerAnimalSpawns());
- }
- if (getSettings().getTicksPerMonsterSpawns() > 0) {
w.setTicksPerSpawns(SpawnCategory.MONSTER, getSettings().getTicksPerMonsterSpawns());
- }
}
@Override
@@ -384,8 +375,7 @@ private void registerWarpedCompassRecipe() {
// --- 2. Create the NamespacedKey and ShapedRecipe ---
// A NamespacedKey is required for the recipe to be uniquely identified.
- NamespacedKey key = new NamespacedKey(this.getPlugin(), "warped_compass");
- ShapedRecipe recipe = new ShapedRecipe(key, warpedCompass);
+ ShapedRecipe recipe = new ShapedRecipe(WARPED_COMPASS_RECIPE, warpedCompass);
// --- 3. Define the Recipe Shape ---
recipe.shape(
diff --git a/src/main/java/world/bentobox/stranger/listeners/PlayerListener.java b/src/main/java/world/bentobox/stranger/listeners/PlayerListener.java
index 6548591..95ee919 100644
--- a/src/main/java/world/bentobox/stranger/listeners/PlayerListener.java
+++ b/src/main/java/world/bentobox/stranger/listeners/PlayerListener.java
@@ -10,8 +10,10 @@
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
+import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -20,6 +22,8 @@
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDismountEvent;
import org.bukkit.event.entity.EntityMountEvent;
+import org.bukkit.event.inventory.PrepareItemCraftEvent;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@@ -27,6 +31,7 @@
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.vehicle.VehicleMoveEvent;
+import org.bukkit.inventory.Recipe;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.RayTraceResult;
@@ -71,11 +76,16 @@ public PlayerListener(StrangerRealms addon) {
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent e) {
+ // Set the recipe
+ updateRecipeAccess(e.getPlayer());
+
Player player = e.getPlayer();
// Check if player is in the world
if (!addon.inWorld(player.getWorld())) {
return;
}
+
+
if (isOn(player)) {
// Run one-tick after joining because metadata cannot be set otherwise
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> processEvent(e));
@@ -210,7 +220,7 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
if (!outsideCheck(e.getPlayer(), from, e.getTo())) {
return;
}
-
+
// If player is still in protected area, cancel movement and teleport back
if (addon.getIslands().getProtectedIslandAt(from).isPresent()) {
e.setCancelled(true);
@@ -218,18 +228,18 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
Util.teleportAsync(p, from).thenRun(() -> inTeleport.remove(p.getUniqueId()));
return;
}
-
+
// If outside, calculate the closest safe position on border
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> {
// Calculate vector pointing from player to island center
Vector unitVector = i.getProtectionCenter().toVector().subtract(p.getLocation().toVector()).normalize()
.multiply(new Vector(1,0,1));
-
+
// Skip if no valid direction found
if (unitVector.lengthSquared() <= 0D) {
return;
}
-
+
// Perform ray trace to find intersection with border
RayTraceResult r = i.getProtectionBoundingBox().rayTrace(p.getLocation().toVector(), unitVector, i.getRange());
if (r != null && checkFinite(r.getHitPosition())) {
@@ -362,7 +372,7 @@ public void onVehicleMove(VehicleMoveEvent e) {
// Remove head movement
if (!e.getFrom().toVector().equals(e.getTo().toVector())) {
e.getVehicle().getPassengers().stream().filter(Player.class::isInstance).map(Player.class::cast)
- .filter(this::isOn).forEach(p -> show.refreshView(User.getInstance(p)));
+ .filter(this::isOn).forEach(p -> show.refreshView(User.getInstance(p)));
}
}
@@ -380,4 +390,54 @@ public void onProtectionRangeChange(IslandProtectionRangeChangeEvent e) {
}
});
}
+
+ /**
+ * Updates the player's access to the warped compass recipe based on their current world.
+ * @param player The player to check.
+ */
+ private void updateRecipeAccess(Player player) {
+ World currentWorld = player.getWorld();
+
+ // Check if the player is in the custom world
+ if (addon.inWorld(currentWorld)) {
+ // Player is in the custom world: grant the recipe
+ if (!player.hasDiscoveredRecipe(StrangerRealms.WARPED_COMPASS_RECIPE)) {
+ // Use a scheduler for safety, though for this specific task it might not be strictly needed.
+ // It ensures the action is run on the main server thread, which is good practice.
+ Bukkit.getScheduler().runTask(addon.getPlugin(), () -> {
+ player.discoverRecipe(StrangerRealms.WARPED_COMPASS_RECIPE);
+ });
+ }
+ } else {
+ Bukkit.getScheduler().runTask(addon.getPlugin(), () -> {
+ player.undiscoverRecipe(StrangerRealms.WARPED_COMPASS_RECIPE);
+ });
+ }
+ }
+
+ /**
+ * Handles players changing worlds (e.g., via /tp, portals) - add or remove recipe
+ */
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
+ public void onWorldChange(PlayerChangedWorldEvent event) {
+ updateRecipeAccess(event.getPlayer());
+ }
+
+ /**
+ * Blocks the custom item from being crafted if the player is not
+ * in the designated custom world.
+ */
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
+ public void onPrepareItemCraft(PrepareItemCraftEvent event) {
+ Recipe recipe = event.getRecipe();
+
+ // Check if a recipe exists and if it is a keyed recipe
+ if (recipe != null && recipe instanceof Keyed keyed
+ && keyed.getKey().equals(StrangerRealms.WARPED_COMPASS_RECIPE)
+ && !addon.inWorld(event.getInventory().getLocation())) {
+ // BLOCK: Set the result to null
+ event.getInventory().setResult(null);
+ }
+ }
}
+