1010
1111import org .bukkit .Bukkit ;
1212import org .bukkit .GameMode ;
13+ import org .bukkit .Keyed ;
1314import org .bukkit .Location ;
1415import org .bukkit .Material ;
16+ import org .bukkit .World ;
1517import org .bukkit .block .BlockFace ;
1618import org .bukkit .entity .Entity ;
1719import org .bukkit .entity .Player ;
2022import org .bukkit .event .Listener ;
2123import org .bukkit .event .entity .EntityDismountEvent ;
2224import org .bukkit .event .entity .EntityMountEvent ;
25+ import org .bukkit .event .inventory .PrepareItemCraftEvent ;
26+ import org .bukkit .event .player .PlayerChangedWorldEvent ;
2327import org .bukkit .event .player .PlayerJoinEvent ;
2428import org .bukkit .event .player .PlayerMoveEvent ;
2529import org .bukkit .event .player .PlayerQuitEvent ;
2630import org .bukkit .event .player .PlayerRespawnEvent ;
2731import org .bukkit .event .player .PlayerTeleportEvent ;
2832import org .bukkit .event .player .PlayerTeleportEvent .TeleportCause ;
2933import org .bukkit .event .vehicle .VehicleMoveEvent ;
34+ import org .bukkit .inventory .Recipe ;
3035import org .bukkit .scheduler .BukkitTask ;
3136import org .bukkit .util .NumberConversions ;
3237import org .bukkit .util .RayTraceResult ;
@@ -71,11 +76,16 @@ public PlayerListener(StrangerRealms addon) {
7176 */
7277 @ EventHandler (priority = EventPriority .NORMAL , ignoreCancelled = true )
7378 public void onPlayerJoin (PlayerJoinEvent e ) {
79+ // Set the recipe
80+ updateRecipeAccess (e .getPlayer ());
81+
7482 Player player = e .getPlayer ();
7583 // Check if player is in the world
7684 if (!addon .inWorld (player .getWorld ())) {
7785 return ;
7886 }
87+
88+
7989 if (isOn (player )) {
8090 // Run one-tick after joining because metadata cannot be set otherwise
8191 Bukkit .getScheduler ().runTask (addon .getPlugin (), () -> processEvent (e ));
@@ -210,26 +220,26 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
210220 if (!outsideCheck (e .getPlayer (), from , e .getTo ())) {
211221 return ;
212222 }
213-
223+
214224 // If player is still in protected area, cancel movement and teleport back
215225 if (addon .getIslands ().getProtectedIslandAt (from ).isPresent ()) {
216226 e .setCancelled (true );
217227 inTeleport .add (p .getUniqueId ());
218228 Util .teleportAsync (p , from ).thenRun (() -> inTeleport .remove (p .getUniqueId ()));
219229 return ;
220230 }
221-
231+
222232 // If outside, calculate the closest safe position on border
223233 addon .getIslands ().getIslandAt (p .getLocation ()).ifPresent (i -> {
224234 // Calculate vector pointing from player to island center
225235 Vector unitVector = i .getProtectionCenter ().toVector ().subtract (p .getLocation ().toVector ()).normalize ()
226236 .multiply (new Vector (1 ,0 ,1 ));
227-
237+
228238 // Skip if no valid direction found
229239 if (unitVector .lengthSquared () <= 0D ) {
230240 return ;
231241 }
232-
242+
233243 // Perform ray trace to find intersection with border
234244 RayTraceResult r = i .getProtectionBoundingBox ().rayTrace (p .getLocation ().toVector (), unitVector , i .getRange ());
235245 if (r != null && checkFinite (r .getHitPosition ())) {
@@ -362,7 +372,7 @@ public void onVehicleMove(VehicleMoveEvent e) {
362372 // Remove head movement
363373 if (!e .getFrom ().toVector ().equals (e .getTo ().toVector ())) {
364374 e .getVehicle ().getPassengers ().stream ().filter (Player .class ::isInstance ).map (Player .class ::cast )
365- .filter (this ::isOn ).forEach (p -> show .refreshView (User .getInstance (p )));
375+ .filter (this ::isOn ).forEach (p -> show .refreshView (User .getInstance (p )));
366376 }
367377 }
368378
@@ -380,4 +390,54 @@ public void onProtectionRangeChange(IslandProtectionRangeChangeEvent e) {
380390 }
381391 });
382392 }
393+
394+ /**
395+ * Updates the player's access to the warped compass recipe based on their current world.
396+ * @param player The player to check.
397+ */
398+ private void updateRecipeAccess (Player player ) {
399+ World currentWorld = player .getWorld ();
400+
401+ // Check if the player is in the custom world
402+ if (addon .inWorld (currentWorld )) {
403+ // Player is in the custom world: grant the recipe
404+ if (!player .hasDiscoveredRecipe (StrangerRealms .WARPED_COMPASS_RECIPE )) {
405+ // Use a scheduler for safety, though for this specific task it might not be strictly needed.
406+ // It ensures the action is run on the main server thread, which is good practice.
407+ Bukkit .getScheduler ().runTask (addon .getPlugin (), () -> {
408+ player .discoverRecipe (StrangerRealms .WARPED_COMPASS_RECIPE );
409+ });
410+ }
411+ } else {
412+ Bukkit .getScheduler ().runTask (addon .getPlugin (), () -> {
413+ player .undiscoverRecipe (StrangerRealms .WARPED_COMPASS_RECIPE );
414+ });
415+ }
416+ }
417+
418+ /**
419+ * Handles players changing worlds (e.g., via /tp, portals) - add or remove recipe
420+ */
421+ @ EventHandler (priority = EventPriority .NORMAL , ignoreCancelled = true )
422+ public void onWorldChange (PlayerChangedWorldEvent event ) {
423+ updateRecipeAccess (event .getPlayer ());
424+ }
425+
426+ /**
427+ * Blocks the custom item from being crafted if the player is not
428+ * in the designated custom world.
429+ */
430+ @ EventHandler (priority = EventPriority .NORMAL , ignoreCancelled = true )
431+ public void onPrepareItemCraft (PrepareItemCraftEvent event ) {
432+ Recipe recipe = event .getRecipe ();
433+
434+ // Check if a recipe exists and if it is a keyed recipe
435+ if (recipe != null && recipe instanceof Keyed keyed
436+ && keyed .getKey ().equals (StrangerRealms .WARPED_COMPASS_RECIPE )
437+ && !addon .inWorld (event .getInventory ().getLocation ())) {
438+ // BLOCK: Set the result to null
439+ event .getInventory ().setResult (null );
440+ }
441+ }
383442}
443+
0 commit comments