From 4f6a574fcb48410a5db7f43001d2848218c2751d Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 21 Dec 2024 14:30:37 -0800
Subject: [PATCH 01/24] Try parallel class tests
---
pom.xml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pom.xml b/pom.xml
index ffb166b74..f4b64ccfc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -457,6 +457,8 @@
3.0.0-M5
+ classes
+ 4
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED
From fab7f08473fcd7197111c8c0e13999f0b9db7991 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 21 Dec 2024 14:31:08 -0800
Subject: [PATCH 02/24] Version 3.1.2
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index f4b64ccfc..360d19dc0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
-LOCAL
- 3.1.1
+ 3.1.2
bentobox-world
https://sonarcloud.io
${project.basedir}/lib
From b3b0d71af6becc05259b841de21b9171602d174e Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 21 Dec 2024 15:56:08 -0800
Subject: [PATCH 03/24] Update modrinth-publish.yml
---
.github/workflows/modrinth-publish.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/modrinth-publish.yml b/.github/workflows/modrinth-publish.yml
index 8244fe239..9f8b505a8 100644
--- a/.github/workflows/modrinth-publish.yml
+++ b/.github/workflows/modrinth-publish.yml
@@ -21,8 +21,8 @@ jobs:
cache: maven
# This step will take the version tag from the release and replace it in `pom.xml` before building.
- - name: Set version from release tag
- run: mvn -B versions:set -DnewVersion=${{ github.event.release.tag_name }} -DgenerateBackupPoms=false
+ #- name: Set version from release tag
+ # run: mvn -B versions:set -DnewVersion=${{ github.event.release.tag_name }} -DgenerateBackupPoms=false
- name: Build and package with Maven
run: mvn -B clean package --file pom.xml
From 4231bcfe35cc2dcb711f5b551ff0c6014870d45f Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 21 Dec 2024 18:58:08 -0800
Subject: [PATCH 04/24] Update build.yml
---
.github/workflows/build.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index dff7a8f18..47e1c74cd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,6 +3,7 @@ on:
push:
branches:
- develop
+ - master
pull_request:
types: [opened, synchronize, reopened]
jobs:
From 6017a09a03a3b16d5a5482f66e22b0321ff49908 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 08:05:20 -0800
Subject: [PATCH 05/24] WIP
---
pom.xml | 22 ++-
.../bentobox/hooks/ZNPCSPlusHook.java | 131 ++++++++++++++++++
2 files changed, 151 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
diff --git a/pom.xml b/pom.xml
index 360d19dc0..854b0e192 100644
--- a/pom.xml
+++ b/pom.xml
@@ -198,6 +198,12 @@
FancyPlugins Repository
https://repo.fancyplugins.de/releases
+
+
+ pyr-snapshots
+ Pyr's Repo
+ https://repo.pyr.lol/snapshots
+
@@ -406,6 +412,18 @@
2.4.0
provided
+
+
+ lol.pyr
+ znpcsplus-api
+ 2.0.0-SNAPSHOT
+ provided
+
+
+ lol.pyr
+ ZNPCsPlus
+ 1.0.7
+
@@ -454,11 +472,11 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
+ 3.5.2
classes
- 4
+ 8
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
new file mode 100644
index 000000000..cc080cdbb
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
@@ -0,0 +1,131 @@
+package world.bentobox.bentobox.hooks;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.util.Vector;
+import org.eclipse.jdt.annotation.Nullable;
+
+import de.oliver.fancynpcs.api.FancyNpcsPlugin;
+import lol.pyr.znpcsplus.ZNPCsPlus;
+import lol.pyr.znpcsplus.api.entity.EntityProperty;
+import lol.pyr.znpcsplus.api.interaction.InteractionAction;
+import lol.pyr.znpcsplus.api.npc.Npc;
+import lol.pyr.znpcsplus.api.npc.NpcType;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.hooks.Hook;
+import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
+
+/**
+ * Provides copy and pasting of ZNPCS Plus in blueprints https://github.com/Pyrbu/ZNPCsPlus
+ *
+ * @author tastybento
+ * @since 3.2.0
+ */
+public class ZNPCSPlusHook extends Hook {
+
+ private ZNPCsPlus plugin;
+
+ public ZNPCSPlusHook() {
+ super("ZNPCsPlus", Material.PLAYER_HEAD);
+
+ }
+
+ public String serializeNPC(Npc npc, Vector origin) {
+ if (npc == null) {
+ throw new IllegalArgumentException("NPC cannot be null.");
+ }
+ YamlConfiguration config = new YamlConfiguration();
+ NpcType type = npc.getType();
+ for (EntityProperty> property : npc.getAppliedProperties())
+ try {
+ property.toString();
+ PropertySerializer> serializer = propertyRegistry
+ .getSerializer(((EntityPropertyImpl>) property).getType());
+ if (serializer == null) {
+ BentoBox.getInstance().logWarning("Unknown serializer for property '" + property.getName()
+ + "' for npc '" + npc.getUuid() + "'. skipping ...");
+ continue;
+ }
+ config.set("properties." + property.getName(), serializer.UNSAFE_serialize(npc.getProperty(property)));
+ } catch (Exception exception) {
+ BentoBox.getInstance().logWarning(
+ "Failed to serialize property " + property.getName() + " for npc with id " + npc.getUuid());
+ exception.printStackTrace();
+ }
+
+ lol.pyr.znpcsplus.api.hologram.Hologram hologram = npc.getHologram();
+ if (hologram.getRefreshDelay() != -1)
+ config.set("hologram.refresh-delay", hologram.getRefreshDelay());
+ List lines = new ArrayList<>(npc.getHologram().lineCount());
+ for (int i = 0; i < npc.getHologram().lineCount(); i++) {
+ lines.add(hologram.getLine(i));
+ }
+ config.set("hologram.lines", lines);
+ config.set("actions", npc.getActions().stream().map(InteractionAction::toString).filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ return config.saveToString();
+ }
+
+ public boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationException {
+ YamlConfiguration npcConfig = new YamlConfiguration();
+ npcConfig.loadFromString(yaml);
+
+ String name = UUID.randomUUID().toString(); // Create a unique name
+
+ UUID creator = UUID.randomUUID(); // Random creator
+
+
+ return true;
+ }
+
+ @Override
+ public boolean hook() {
+ boolean hooked = this.isPluginAvailable();
+ if (!hooked) {
+ BentoBox.getInstance().logError("Could not hook into FancyNpcs");
+ }
+ return hooked; // The hook process shouldn't fail
+ }
+
+ @Override
+ public String getFailureCause() {
+ return null; // The hook process shouldn't fail
+ }
+
+ public Map extends Vector, ? extends List> getNpcsInArea(World world, List vectorsToCopy,
+ @Nullable Vector origin) {
+ Map> bpEntities = new HashMap<>();
+ for (Npc npc : FancyNpcsPlugin.get().getNpcManager().getAllNpcs()) {
+ Location npcLocation = npc.getData().getLocation();
+ Vector spot = new Vector(npcLocation.getBlockX(), npcLocation.getBlockY(), npcLocation.getBlockZ());
+ if (npcLocation.getWorld().equals(world) && vectorsToCopy.contains(spot)) {
+ BlueprintEntity cit = new BlueprintEntity();
+ cit.setType(npc.getData().getType());
+ cit.setNpc(this.serializeNPC(npc, origin));
+ // Retrieve or create the list, then add the entity
+ List entities = bpEntities.getOrDefault(spot, new ArrayList<>());
+ entities.add(cit);
+ // Create position
+ Vector origin2 = origin == null ? new Vector(0, 0, 0) : origin;
+ int x = spot.getBlockX() - origin2.getBlockX();
+ int y = spot.getBlockY() - origin2.getBlockY();
+ int z = spot.getBlockZ() - origin2.getBlockZ();
+ Vector pos = new Vector(x, y, z);
+ // Store
+ bpEntities.put(pos, entities); // Update the map
+ }
+ }
+ return bpEntities;
+ }
+}
From 8346405ab327a9415637a2478f97b81c99bc412a Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 08:05:47 -0800
Subject: [PATCH 06/24] WIP
---
src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
index cc080cdbb..d00e9e468 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCSPlusHook.java
@@ -49,7 +49,6 @@ public String serializeNPC(Npc npc, Vector origin) {
NpcType type = npc.getType();
for (EntityProperty> property : npc.getAppliedProperties())
try {
- property.toString();
PropertySerializer> serializer = propertyRegistry
.getSerializer(((EntityPropertyImpl>) property).getType());
if (serializer == null) {
From 2dbb522eb708696cdcd37482adc22c809c204c0c Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 08:48:50 -0800
Subject: [PATCH 07/24] Updated JavaDoc to avoid error.
---
src/main/java/world/bentobox/bentobox/database/Database.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/database/Database.java b/src/main/java/world/bentobox/bentobox/database/Database.java
index eca983ac2..8b0c4aea3 100644
--- a/src/main/java/world/bentobox/bentobox/database/Database.java
+++ b/src/main/java/world/bentobox/bentobox/database/Database.java
@@ -167,8 +167,8 @@ public static Set> getDataobjects() {
}
/**
- * Load all objects async
- * @return CompletableFuture>
+ * Load all objects asynchronously.
+ * @return {@code CompletableFuture>}
*/
public @NonNull CompletableFuture> loadObjectsASync() {
return handler.loadObjectsASync();
From 60f0110547a850f6087c1e3746d3e406fdc2c0a1 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 09:27:41 -0800
Subject: [PATCH 08/24] Remove the parallel test running
---
pom.xml | 2 --
.../bentobox/bentobox/panels/customizable/IslandHomesPanel.java | 1 -
2 files changed, 3 deletions(-)
diff --git a/pom.xml b/pom.xml
index 360d19dc0..faf1b955c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -457,8 +457,6 @@
3.0.0-M5
- classes
- 4
${argLine}
--add-opens java.base/java.lang=ALL-UNNAMED
diff --git a/src/main/java/world/bentobox/bentobox/panels/customizable/IslandHomesPanel.java b/src/main/java/world/bentobox/bentobox/panels/customizable/IslandHomesPanel.java
index c760a21d8..84e9898a3 100644
--- a/src/main/java/world/bentobox/bentobox/panels/customizable/IslandHomesPanel.java
+++ b/src/main/java/world/bentobox/bentobox/panels/customizable/IslandHomesPanel.java
@@ -60,7 +60,6 @@ public class IslandHomesPanel extends AbstractPanel
*
* @param command CompositeCommand
* @param user User who opens panel
- * @param islandMap map of island names and IslandInfo
*/
private IslandHomesPanel(@NonNull CompositeCommand command, @NonNull User user)
{
From 212166ebe806fbe4c4201b1ca3e68628e072b7c8 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 09:28:18 -0800
Subject: [PATCH 09/24] Update surefire plugin
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index faf1b955c..d932b91ca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -454,7 +454,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
+ 3.5.2
From 180ccd9f5eaf373a0026babcab640383eaec3e79 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 09:17:07 -0800
Subject: [PATCH 10/24] Tidied up and working
---
.../blueprints/BlueprintClipboard.java | 10 +++-
.../bentobox/blueprints/BlueprintPaster.java | 2 +-
.../bentobox/hooks/ZNPCsPlusHook.java | 41 ++++++++++------
.../bentobox/util/DefaultPasteUtil.java | 24 ++++++++--
.../world/bentobox/bentobox/util/Util.java | 48 +++++++++++++++++++
src/main/resources/plugin.yml | 1 +
6 files changed, 106 insertions(+), 20 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
index dc10da175..6d678bd08 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
@@ -45,6 +45,7 @@
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.hooks.FancyNpcsHook;
import world.bentobox.bentobox.hooks.MythicMobsHook;
+import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
/**
* The clipboard provides the holding spot for an active blueprint that is being
@@ -71,6 +72,7 @@ public class BlueprintClipboard {
private final BentoBox plugin = BentoBox.getInstance();
private Optional mmh;
private Optional npc;
+ private Optional znpc;
/**
* Create a clipboard for blueprint
@@ -82,12 +84,15 @@ public BlueprintClipboard(@NonNull Blueprint blueprint) {
}
public BlueprintClipboard() {
- // Citizens Hook
+ // Fancy NPCs Hook
npc = plugin.getHooks().getHook("FancyNpcs").filter(FancyNpcsHook.class::isInstance)
.map(FancyNpcsHook.class::cast);
// MythicMobs Hook
mmh = plugin.getHooks().getHook("MythicMobs").filter(MythicMobsHook.class::isInstance)
.map(MythicMobsHook.class::cast);
+ // ZNPCs Plus Hook
+ znpc = plugin.getHooks().getHook("ZNPCsPlus").filter(ZNPCsPlusHook.class::isInstance)
+ .map(ZNPCsPlusHook.class::cast);
}
/**
@@ -143,6 +148,9 @@ private void copyAsync(World world, User user, List vectorsToCopy, int s
// Add all the citizens for the area in one go. This is pretty fast.
bpEntities.putAll(npc.get().getNpcsInArea(world, vectorsToCopy, origin));
}
+ if (znpc.isPresent()) {
+ bpEntities.putAll(znpc.get().getNpcsInArea(world, vectorsToCopy, origin));
+ }
// Repeating copy task
copyTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
index 8ba1cb498..06a53e40a 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java
@@ -240,7 +240,7 @@ private void pasteEntities(Bits bits, int count, Optional owner, int paste
int x = location.getBlockX() + entry.getKey().getBlockX();
int y = location.getBlockY() + entry.getKey().getBlockY();
int z = location.getBlockZ() + entry.getKey().getBlockZ();
- Location center = new Location(world, x, y, z).add(new Vector(0.5, 0.5, 0.5));
+ Location center = new Location(world, x, y, z).add(new Vector(0.5, 0D, 0.5));
List entities = entry.getValue();
entityMap.put(center, entities);
count++;
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
index a4c99d990..d72df0847 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
@@ -3,13 +3,17 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Registry;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.EntityType;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
@@ -19,6 +23,7 @@
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.hooks.Hook;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
+import world.bentobox.bentobox.util.Util;
/**
* Provides copy and pasting of ZNPCS Plus in blueprints https://github.com/Pyrbu/ZNPCsPlus
@@ -28,6 +33,8 @@
*/
public class ZNPCsPlusHook extends Hook {
+ private static final String VERSION = "2.0.0-SNAPSHOT"; // Minimum version required
+
public ZNPCsPlusHook() {
super("ZNPCsPlus", Material.PLAYER_HEAD);
}
@@ -36,7 +43,6 @@ public String serializeNPC(NpcEntry entry, Vector origin) {
String result = NpcApiProvider.get().getNpcSerializerRegistry().getSerializer(YamlConfiguration.class)
.serialize(entry)
.saveToString();
- BentoBox.getInstance().logDebug(result);
return result;
}
@@ -48,6 +54,7 @@ public boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationEx
NpcLocation loc = new NpcLocation(pos);
entry.getNpc().setLocation(loc);
NpcApiProvider.get().getNpcRegistry().register(entry);
+
return true;
}
@@ -56,7 +63,9 @@ public boolean hook() {
boolean hooked = this.isPluginAvailable();
// Check version
String version = this.getPlugin().getDescription().getVersion();
- BentoBox.getInstance().logDebug("ZNPCsPlus version = " + version);
+ if (!Util.isVersionCompatible(version, VERSION)) {
+ return false;
+ }
if (!hooked) {
BentoBox.getInstance().logError("Could not hook into FancyNpcs");
}
@@ -65,28 +74,30 @@ public boolean hook() {
@Override
public String getFailureCause() {
- return null; // The hook process shouldn't fail
+ // The only failure is wrong version
+ return "ZNPCsPlus version " + VERSION + " required or later. You are running "
+ + this.getPlugin().getDescription().getVersion();
}
public Map extends Vector, ? extends List> getNpcsInArea(World world, List vectorsToCopy,
@Nullable Vector origin) {
Map> bpEntities = new HashMap<>();
- for (NpcEntry npc : NpcApiProvider.get().getNpcRegistry().getAll()) {
- NpcLocation npcLocation = npc.getNpc().getLocation();
- Vector spot = new Vector(npcLocation.getBlockX(), npcLocation.getBlockY(), npcLocation.getBlockZ());
- if (npc.getNpc().getWorld().equals(world) && vectorsToCopy.contains(spot)) {
+ for (NpcEntry npcEntry : NpcApiProvider.get().getNpcRegistry().getAll()) {
+ NpcLocation npcLocation = npcEntry.getNpc().getLocation();
+ Vector loc = new Vector(npcLocation.getBlockX(), npcLocation.getBlockY(), npcLocation.getBlockZ());
+ if (npcEntry.getNpc().getWorld().equals(world) && vectorsToCopy.contains(loc)) {
+ // Put the NPC into a BlueprintEntity - serialize it
BlueprintEntity cit = new BlueprintEntity();
- //cit.setType(npc.getNpc().getType());
- cit.setNpc(this.serializeNPC(npc, origin));
- // Retrieve or create the list, then add the entity
- List entities = bpEntities.getOrDefault(spot, new ArrayList<>());
+ cit.setNpc(this.serializeNPC(npcEntry, origin));
+ // Retrieve or create the list of entities and add this one
+ List entities = bpEntities.getOrDefault(loc, new ArrayList<>());
entities.add(cit);
- // Create position
+ // Create the position where this entity will be pasted relative to the location
Vector origin2 = origin == null ? new Vector(0, 0, 0) : origin;
- int x = spot.getBlockX() - origin2.getBlockX();
- int y = spot.getBlockY() - origin2.getBlockY();
- int z = spot.getBlockZ() - origin2.getBlockZ();
+ int x = loc.getBlockX() - origin2.getBlockX();
+ int y = loc.getBlockY() - origin2.getBlockY();
+ int z = loc.getBlockZ() - origin2.getBlockZ();
Vector pos = new Vector(x, y, z);
// Store
bpEntities.put(pos, entities); // Update the map
diff --git a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
index 86ee2e070..2e6083026 100644
--- a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
+++ b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
@@ -36,6 +36,7 @@
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.hooks.FancyNpcsHook;
import world.bentobox.bentobox.hooks.MythicMobsHook;
+import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
import world.bentobox.bentobox.nms.PasteHandler;
/**
@@ -176,8 +177,8 @@ public static void setSpawner(CreatureSpawner spawner, BlueprintCreatureSpawner
public static CompletableFuture setEntity(Island island, Location location, List list) {
World world = location.getWorld();
assert world != null;
- return Util.getChunkAtAsync(location).thenRun(() -> list.stream().filter(k -> k.getType() != null)
- .forEach(k -> spawnBlueprintEntity(k, location, island)));
+ return Util.getChunkAtAsync(location)
+ .thenRun(() -> list.stream().forEach(k -> spawnBlueprintEntity(k, location, island)));
}
/**
@@ -188,7 +189,7 @@ public static CompletableFuture setEntity(Island island, Location location
* @return true if Bukkit entity spawned, false another plugin entity spawned
*/
static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island island) {
- // Npc entity
+ // FancyNpc entity
if (k.getNpc() != null
&& plugin.getHooks().getHook("FancyNpcs").filter(mmh -> mmh instanceof FancyNpcsHook).map(mmh -> {
try {
@@ -201,6 +202,19 @@ static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island
// Npc has spawned.
return false;
}
+ // ZNPCsPlus
+ if (k.getNpc() != null
+ && plugin.getHooks().getHook("ZNPCsPlus").filter(mmh -> mmh instanceof ZNPCsPlusHook).map(znpch -> {
+ try {
+ return ((ZNPCsPlusHook) znpch).spawnNpc(k.getNpc(), location);
+ } catch (InvalidConfigurationException e) {
+ plugin.logError("ZNPCsPlus loading failed in blueprint.");
+ return false;
+ }
+ }).orElse(false)) {
+ // Npc has spawned.
+ return false;
+ }
// Mythic Mobs entity
if (k.getMythicMobsRecord() != null && plugin.getHooks().getHook("MythicMobs")
@@ -210,6 +224,10 @@ static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island
// MythicMob has spawned.
return false;
}
+ if (k.getType() == null) {
+ // Nothing
+ return false;
+ }
LivingEntity e = (LivingEntity) location.getWorld().spawnEntity(location, k.getType());
if (k.getCustomName() != null) {
String customName = k.getCustomName();
diff --git a/src/main/java/world/bentobox/bentobox/util/Util.java b/src/main/java/world/bentobox/bentobox/util/Util.java
index 00434d260..3cf2fac55 100644
--- a/src/main/java/world/bentobox/bentobox/util/Util.java
+++ b/src/main/java/world/bentobox/bentobox/util/Util.java
@@ -514,6 +514,54 @@ public static int getMinecraftPatchVersion() {
return PaperLib.getMinecraftPatchVersion();
}
+ /**
+ * Checks if the given version is compatible with the required version.
+ *
+ *
+ * A version is considered compatible if:
+ *
+ * The major, minor, and patch components of the given version are greater than or equal to those of the required version.
+ * If the numeric components are equal, the absence of "-SNAPSHOT" in the given version takes precedence (i.e., release versions are considered more compatible than SNAPSHOT versions).
+ *
+ *
+ *
+ * @param version the version to check, in the format "major.minor.patch[-SNAPSHOT]".
+ * @param requiredVersion the required version, in the format "major.minor.patch[-SNAPSHOT]".
+ * @return {@code true} if the given version is compatible with the required version; {@code false} otherwise.
+ *
+ *
+ * Examples:
+ *
+ * {@code isVersionCompatible("2.1.0", "2.0.0-SNAPSHOT")} returns {@code true}
+ * {@code isVersionCompatible("2.0.0", "2.0.0-SNAPSHOT")} returns {@code true}
+ * {@code isVersionCompatible("2.0.0-SNAPSHOT", "2.0.0")} returns {@code false}
+ * {@code isVersionCompatible("1.9.9", "2.0.0-SNAPSHOT")} returns {@code false}
+ *
+ *
+ */
+ public static boolean isVersionCompatible(String version, String requiredVersion) {
+ String[] versionParts = version.replace("-SNAPSHOT", "").split("\\.");
+ String[] requiredVersionParts = requiredVersion.replace("-SNAPSHOT", "").split("\\.");
+
+ for (int i = 0; i < Math.max(versionParts.length, requiredVersionParts.length); i++) {
+ int vPart = i < versionParts.length ? Integer.parseInt(versionParts[i]) : 0;
+ int rPart = i < requiredVersionParts.length ? Integer.parseInt(requiredVersionParts[i]) : 0;
+
+ if (vPart > rPart) {
+ return true;
+ } else if (vPart < rPart) {
+ return false;
+ }
+ }
+
+ // If numeric parts are equal, prioritize SNAPSHOT as lower precedence
+ boolean isVersionSnapshot = version.contains("-SNAPSHOT");
+ boolean isRequiredSnapshot = requiredVersion.contains("-SNAPSHOT");
+
+ // If required version is a full release but current version is SNAPSHOT, it's incompatible
+ return !(!isRequiredSnapshot && isVersionSnapshot);
+ }
+
/**
* Check if the server has access to the Spigot API
* @return True for Spigot and Paper environments
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index fcb054854..9ddec656a 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -24,6 +24,7 @@ softdepend:
- LuckPerms
- EconomyPlus
- MythicMobs
+ - ZNPCsPlus
libraries:
- mysql:mysql-connector-java:${mysql.version}
From d6c11e8098478cc02b2c980a5e6f98dcf435bdd0 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 09:28:18 -0800
Subject: [PATCH 11/24] Fix tests
---
.../world/bentobox/bentobox/util/DefaultPasteUtilTest.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/test/java/world/bentobox/bentobox/util/DefaultPasteUtilTest.java b/src/test/java/world/bentobox/bentobox/util/DefaultPasteUtilTest.java
index 38135c66d..768b1ad32 100644
--- a/src/test/java/world/bentobox/bentobox/util/DefaultPasteUtilTest.java
+++ b/src/test/java/world/bentobox/bentobox/util/DefaultPasteUtilTest.java
@@ -141,6 +141,9 @@ public void setUp() throws Exception {
when(plugin.getHooks()).thenReturn(hooksManager);
when(plugin.getPlayers()).thenReturn(pm);
+
+ // Blueprint Entity
+ when(blueprintEntity.getType()).thenReturn(EntityType.PLAYER);
}
/**
From 2edad796b446241283a4ca7fefd4cf5d0cc614a5 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 09:28:50 -0800
Subject: [PATCH 12/24] Remove unused import
---
.../java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
index d72df0847..33c1fb186 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
@@ -3,17 +3,13 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
-import org.bukkit.Registry;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.entity.EntityType;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
From 00ce92b9af2024f9517712c9db55c5c3ab8442f0 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 10:09:33 -0800
Subject: [PATCH 13/24] Improved tests
---
.../bentobox/hooks/ZNPCsPlusHook.java | 2 +-
.../bentobox/hooks/MythicMobsHookTest.java | 8 -
.../bentobox/hooks/ZNPCsPlusHookTest.java | 174 ++++++++++++++++++
3 files changed, 175 insertions(+), 9 deletions(-)
create mode 100644 src/test/java/world/bentobox/bentobox/hooks/ZNPCsPlusHookTest.java
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
index 33c1fb186..d9a31dfef 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
@@ -65,7 +65,7 @@ public boolean hook() {
if (!hooked) {
BentoBox.getInstance().logError("Could not hook into FancyNpcs");
}
- return hooked; // The hook process shouldn't fail
+ return hooked;
}
@Override
diff --git a/src/test/java/world/bentobox/bentobox/hooks/MythicMobsHookTest.java b/src/test/java/world/bentobox/bentobox/hooks/MythicMobsHookTest.java
index 87fe88631..c9dc48437 100644
--- a/src/test/java/world/bentobox/bentobox/hooks/MythicMobsHookTest.java
+++ b/src/test/java/world/bentobox/bentobox/hooks/MythicMobsHookTest.java
@@ -21,7 +21,6 @@
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -98,13 +97,6 @@ public void setUp() throws Exception {
hook = new MythicMobsHook();
}
- /**
- * @throws java.lang.Exception
- */
- @After
- public void tearDown() throws Exception {
- }
-
/**
* Test method for {@link world.bentobox.bentobox.hooks.MythicMobsHook#hook()}.
*/
diff --git a/src/test/java/world/bentobox/bentobox/hooks/ZNPCsPlusHookTest.java b/src/test/java/world/bentobox/bentobox/hooks/ZNPCsPlusHookTest.java
new file mode 100644
index 000000000..cdce3e51e
--- /dev/null
+++ b/src/test/java/world/bentobox/bentobox/hooks/ZNPCsPlusHookTest.java
@@ -0,0 +1,174 @@
+package world.bentobox.bentobox.hooks;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.PluginManager;
+import org.bukkit.util.Vector;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+import lol.pyr.znpcsplus.api.NpcApi;
+import lol.pyr.znpcsplus.api.NpcApiProvider;
+import lol.pyr.znpcsplus.api.npc.Npc;
+import lol.pyr.znpcsplus.api.npc.NpcEntry;
+import lol.pyr.znpcsplus.api.npc.NpcRegistry;
+import lol.pyr.znpcsplus.api.serialization.NpcSerializer;
+import lol.pyr.znpcsplus.api.serialization.NpcSerializerRegistry;
+import lol.pyr.znpcsplus.util.NpcLocation;
+import world.bentobox.bentobox.BentoBox;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ BentoBox.class, Bukkit.class, NpcApiProvider.class })
+public class ZNPCsPlusHookTest {
+
+ @Mock
+ private BentoBox plugin;
+ @Mock
+ private PluginManager pim;
+ @Mock
+ private Plugin mythicMobs;
+ @Mock
+ private Location location;
+ @Mock
+ private World world;
+ @Mock
+ private Plugin npcPlugin;
+ private ZNPCsPlusHook hook;
+ @Mock
+ private NpcEntry entry;
+ @Mock
+ private NpcApi npcApi;
+ @Mock
+ private NpcSerializerRegistry npcSerReg;
+ @Mock
+ private NpcSerializer ser;
+ @Mock
+ private NpcRegistry registry;
+ @Mock
+ private Npc npc;
+ @Mock
+ private NpcLocation npcLoc;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Set up plugin
+ plugin = mock(BentoBox.class);
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ // Bukkit
+ PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
+ when(Bukkit.getPluginManager()).thenReturn(pim);
+ when(npcPlugin.getDescription()).thenReturn(new PluginDescriptionFile("ZNPCsPlus", "2.0.0-SNAPSHOT", "main"));
+ when(pim.getPlugin("ZNPCsPlus")).thenReturn(npcPlugin);
+ // Location
+ when(world.getName()).thenReturn("bskyblock");
+ when(location.getWorld()).thenReturn(world);
+ // NpcApiProvider
+ PowerMockito.mockStatic(NpcApiProvider.class, Mockito.RETURNS_MOCKS);
+ when(NpcApiProvider.get()).thenReturn(npcApi);
+
+ when(registry.getAll()).thenAnswer(invocation -> List.of(entry));
+
+ when(npcLoc.getBlockX()).thenReturn(0);
+ when(npcLoc.getBlockY()).thenReturn(0);
+ when(npcLoc.getBlockZ()).thenReturn(0);
+ when(npc.getWorld()).thenReturn(world);
+
+ when(npc.getLocation()).thenReturn(npcLoc);
+
+ when(npcApi.getNpcRegistry()).thenReturn(registry);
+ when(npcApi.getNpcSerializerRegistry()).thenReturn(npcSerReg);
+ when(npcSerReg.getSerializer(any())).thenReturn(ser);
+ YamlConfiguration yaml = new YamlConfiguration();
+ yaml.set("test", "test");
+ when(ser.serialize(any())).thenReturn(yaml);
+ when(entry.getNpc()).thenReturn(npc);
+ when(ser.deserialize(any())).thenReturn(entry);
+
+
+ hook = new ZNPCsPlusHook();
+ }
+
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#hook()}.
+ */
+ @Test
+ public void testHook() {
+ // Not hooked
+ assertFalse(hook.hook());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#getFailureCause()}.
+ */
+ @Test
+ public void testGetFailureCause() {
+ when(npcPlugin.getDescription()).thenReturn(new PluginDescriptionFile("ZNPCsPlus", "1.0.0", "main"));
+ assertEquals("ZNPCsPlus version 2.0.0-SNAPSHOT required or later. You are running 1.0.0",
+ hook.getFailureCause());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#ZNPCsPlusHook()}.
+ */
+ @Test
+ public void testZNPCsPlusHook() {
+ assertNotNull(hook);
+ assertEquals(Material.PLAYER_HEAD, hook.getIcon());
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#serializeNPC(lol.pyr.znpcsplus.api.npc.NpcEntry, org.bukkit.util.Vector)}.
+ */
+ @Test
+ public void testSerializeNPC() {
+ assertEquals("test: test\n", hook.serializeNPC(entry, new Vector(1, 1, 1)));
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#spawnNpc(java.lang.String, org.bukkit.Location)}.
+ */
+ @Test
+ public void testSpawnNpc() {
+ try {
+ assertTrue(hook.spawnNpc("", location));
+ } catch (InvalidConfigurationException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Test method for {@link world.bentobox.bentobox.hooks.ZNPCsPlusHook#getNpcsInArea(org.bukkit.World, java.util.List, org.bukkit.util.Vector)}.
+ */
+ @Test
+ public void testGetNpcsInArea() {
+ hook.getNpcsInArea(world, List.of(new Vector(0, 0, 0)), new Vector(0, 0, 0));
+ }
+
+}
From 945670be04105e002b40775b968c20819eb95370 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 10:18:11 -0800
Subject: [PATCH 14/24] Add tests for Util.isVersionCompatible method
---
.../bentobox/bentobox/util/UtilTest.java | 110 +++++++++++++++++-
1 file changed, 109 insertions(+), 1 deletion(-)
diff --git a/src/test/java/world/bentobox/bentobox/util/UtilTest.java b/src/test/java/world/bentobox/bentobox/util/UtilTest.java
index 4745b6ce3..d6162354d 100644
--- a/src/test/java/world/bentobox/bentobox/util/UtilTest.java
+++ b/src/test/java/world/bentobox/bentobox/util/UtilTest.java
@@ -494,4 +494,112 @@ public void testTranslateColorCodesHex() {
assertEquals("§x§f§f§0§0§0§0full hex", Util.translateColorCodes("ff0000 full hex"));
assertEquals("ggg outside hex range", Util.translateColorCodes("ggg outside hex range"));
}
-}
+
+ /**
+ * Tests if the method returns true for identical versions without SNAPSHOT.
+ */
+ @Test
+ public void testVersionIsCompatible_SameVersion() {
+ assertTrue("Same versions should be compatible", Util.isVersionCompatible("2.0.0", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method returns true for identical SNAPSHOT versions.
+ */
+ @Test
+ public void testVersionIsCompatible_SnapshotToSnapshot() {
+ assertTrue("Same SNAPSHOT versions should be compatible",
+ Util.isVersionCompatible("2.0.0-SNAPSHOT", "2.0.0-SNAPSHOT"));
+ }
+
+ /**
+ * Tests if the method considers release versions compatible with their SNAPSHOT equivalents.
+ */
+ @Test
+ public void testVersionIsCompatible_ReleaseGreaterThanSnapshot() {
+ assertTrue("Release version should be compatible with SNAPSHOT of the same version",
+ Util.isVersionCompatible("2.0.0", "2.0.0-SNAPSHOT"));
+ }
+
+ /**
+ * Tests if the method considers SNAPSHOT versions less compatible than release versions.
+ */
+ @Test
+ public void testVersionIsCompatible_SnapshotLessThanRelease() {
+ assertFalse("SNAPSHOT version should not be compatible with release of the same version",
+ Util.isVersionCompatible("2.0.0-SNAPSHOT", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies compatibility for a higher major version.
+ */
+ @Test
+ public void testVersionIsCompatible_MajorVersionGreater() {
+ assertTrue("Higher major version should be compatible", Util.isVersionCompatible("3.0.0", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies incompatibility for a lower major version.
+ */
+ @Test
+ public void testVersionIsCompatible_MajorVersionLower() {
+ assertFalse("Lower major version should not be compatible", Util.isVersionCompatible("1.9.9", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies compatibility for a higher minor version.
+ */
+ @Test
+ public void testVersionIsCompatible_MinorVersionGreater() {
+ assertTrue("Higher minor version should be compatible", Util.isVersionCompatible("2.1.0", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies incompatibility for a lower minor version.
+ */
+ @Test
+ public void testVersionIsCompatible_MinorVersionLower() {
+ assertFalse("Lower minor version should not be compatible", Util.isVersionCompatible("2.0.0", "2.1.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies compatibility for a higher patch version.
+ */
+ @Test
+ public void testVersionIsCompatible_PatchVersionGreater() {
+ assertTrue("Higher patch version should be compatible", Util.isVersionCompatible("2.0.1", "2.0.0"));
+ }
+
+ /**
+ * Tests if the method correctly identifies incompatibility for a lower patch version.
+ */
+ @Test
+ public void testVersionIsCompatible_PatchVersionLower() {
+ assertFalse("Lower patch version should not be compatible", Util.isVersionCompatible("2.0.0", "2.0.1"));
+ }
+
+ /**
+ * Tests if the method correctly handles compatibility when both versions have a SNAPSHOT suffix.
+ */
+ @Test
+ public void testVersionIsCompatible_HandlesSnapshotSuffix() {
+ assertTrue("Higher patch version (SNAPSHOT) should be compatible with lower patch version (SNAPSHOT)",
+ Util.isVersionCompatible("2.0.1-SNAPSHOT", "2.0.0-SNAPSHOT"));
+ }
+
+ /**
+ * Tests if the method throws an exception for an empty version string.
+ */
+ @Test(expected = NumberFormatException.class)
+ public void testVersionIsCompatible_EmptyVersion() {
+ Util.isVersionCompatible("", "2.0.0");
+ }
+
+ /**
+ * Tests if the method throws an exception for a null version string.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testVersionIsCompatible_NullVersion() {
+ Util.isVersionCompatible(null, "2.0.0");
+ }
+}
\ No newline at end of file
From 64fd48ead6a57f9f21f830ad7d14f86977cd2203 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Fri, 27 Dec 2024 08:36:13 -0800
Subject: [PATCH 15/24] WIP - store data on Display Entities
---
pom.xml | 7 +
.../blueprints/BlueprintClipboard.java | 6 +
.../dataobjects/BlueprintEntity.java | 147 ++++++++++++++++++
.../json/adapters/MaterialTypeAdapter.java | 2 +-
.../bentobox/hooks/FancyHologramsHook.java | 35 +++++
.../bentobox/util/DefaultPasteUtil.java | 2 +
src/main/resources/plugin.yml | 2 +
7 files changed, 200 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
diff --git a/pom.xml b/pom.xml
index e29d7d061..3198bfad0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -419,6 +419,13 @@
2.0.0-SNAPSHOT
provided
+
+
+ de.oliver
+ FancyHolograms
+ 2.4.1
+ provided
+
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
index 6d678bd08..a5ae6ad1b 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
@@ -22,6 +22,7 @@
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.ChestedHorse;
+import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Player;
@@ -356,6 +357,11 @@ private List setEntities(List ents) {
mmh.filter(mm -> mm.isMythicMob(entity)).map(mm -> mm.getMythicMob(entity))
.ifPresent(bpe::setMythicMobsRecord);
+ // Display entities
+ if (entity instanceof Display disp) {
+ BentoBox.getInstance().logDebug(disp.getAsString());
+ bpe.storeDisplay(disp);
+ }
bpEnts.add(bpe);
}
return bpEnts;
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
index 2ce285fee..b37bc3fe5 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
@@ -2,19 +2,32 @@
import java.util.Map;
+import org.bukkit.Color;
import org.bukkit.DyeColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.data.BlockData;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
+import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.ChestedHorse;
+import org.bukkit.entity.Display;
+import org.bukkit.entity.Display.Billboard;
+import org.bukkit.entity.Display.Brightness;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Horse.Style;
+import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Tameable;
+import org.bukkit.entity.TextDisplay;
+import org.bukkit.entity.TextDisplay.TextAlignment;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Villager.Profession;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Colorable;
+import org.bukkit.util.Transformation;
import com.google.gson.annotations.Expose;
@@ -342,4 +355,138 @@ public String toString() {
+ (villagerType != null ? "villagerType=" + villagerType : "") + "]";
}
+
+
+
+ @Expose
+ public DisplayRec displayRec;
+ @Expose
+ public TextDisplayRec textDisp;
+ @Expose
+ public BlockData blockDisp;
+ @Expose
+ public ItemStack itemDisp;
+
+ public record DisplayRec(@Expose Billboard billboard, @Expose Brightness brightness, @Expose float height,
+ @Expose float width, @Expose Color glowColorOverride, @Expose int interpolationDelay,
+ @Expose int interpolationDuration, @Expose float shadowRadius, @Expose float shadowStrength,
+ @Expose int teleportDuration, @Expose Transformation transformation, @Expose float range) {
+ }
+
+ public record TextDisplayRec(@Expose String text, @Expose TextAlignment alignment, @Expose Color bgColor,
+ @Expose BlockFace face, @Expose int lWidth, @Expose byte opacity, @Expose boolean isShadowed,
+ @Expose boolean isSeeThrough, @Expose boolean isDefaultBg) {
+ }
+
+ /**
+ * BlockDisplay, ItemDisplay, TextDisplay
+ * @param disp display entity
+ */
+ public void storeDisplay(Display disp) {
+ // Generic items
+ displayRec = new DisplayRec(disp.getBillboard(), disp.getBrightness(), disp.getDisplayHeight(),
+ disp.getDisplayWidth(), disp.getGlowColorOverride(), disp.getInterpolationDelay(),
+ disp.getInterpolationDuration(), disp.getShadowRadius(), disp.getShadowStrength(),
+ disp.getTeleportDuration(), disp.getTransformation(), disp.getViewRange());
+ // Class specific items
+ if (disp instanceof BlockDisplay bd) {
+ this.blockDisp = bd.getBlock();
+ } else if (disp instanceof ItemDisplay id) {
+ itemDisp = id.getItemStack();
+ } else if (disp instanceof TextDisplay td) {
+ textDisp = new TextDisplayRec(td.getText(), td.getAlignment(), td.getBackgroundColor(),
+ td.getFacing(), td.getLineWidth(), td.getTextOpacity(), td.isShadowed(), td.isSeeThrough(),
+ td.isDefaultBackground());
+ }
+
+ // , getBrightness, getDisplayHeight, getDisplayWidth, getGlowColorOverride, getInterpolationDelay, getInterpolationDuration,
+ //getShadowRadius, getShadowStrength, getTeleportDuration, getTransformation, getViewRange, setBillboard, setBrightness,
+ // setDisplayHeight, setDisplayWidth, setGlowColorOverride, setInterpolationDelay, setInterpolationDuration, setShadowRadius, setShadowStrength, setTeleportDuration, setTransformation, setTransformationMatrix, setViewRange
+ }
+
+ /**
+ * Sets any display entity properties to the location, e.g. holograms
+ * @param pos location
+ */
+ public void setDisplay(Location pos) {
+ World world = pos.getWorld();
+ Display d = null;
+ if (this.blockDisp != null) {
+ // Block Display
+ d = world.spawn(pos, BlockDisplay.class);
+ ((BlockDisplay) d).setBlock(this.blockDisp);
+ } else if (this.itemDisp != null) {
+ // Item Display
+ d = world.spawn(pos, ItemDisplay.class);
+ ((ItemDisplay) d).setItemStack(itemDisp);
+ } else if (this.textDisp != null) {
+ // Block Display
+ d = world.spawn(pos, TextDisplay.class);
+ ((TextDisplay) d).setText(textDisp.text());
+ ((TextDisplay) d).setAlignment(textDisp.alignment());
+ ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
+ ((TextDisplay) d).setLineWidth(textDisp.lWidth());
+ ((TextDisplay) d).setTextOpacity(textDisp.opacity());
+ ((TextDisplay) d).setShadowed(textDisp.isShadowed());
+ ((TextDisplay) d).setSeeThrough(textDisp.isSeeThrough());
+ ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
+ }
+ if (d != null && this.displayRec != null) {
+ d.setBillboard(displayRec.billboard());
+ d.setBrightness(displayRec.brightness());
+ d.setDisplayHeight(displayRec.height());
+ d.setDisplayWidth(displayRec.width());
+ d.setGlowColorOverride(displayRec.glowColorOverride());
+ d.setInterpolationDelay(displayRec.interpolationDelay());
+ d.setInterpolationDuration(displayRec.interpolationDuration());
+ d.setShadowRadius(displayRec.shadowRadius());
+ d.setShadowStrength(displayRec.shadowStrength());
+ d.setTeleportDuration(displayRec.teleportDuration());
+ d.setTransformation(displayRec.transformation());
+ d.setViewRange(displayRec.range());
+ }
+ }
+
+ /**
+ * @return the displayRec
+ */
+ public DisplayRec getDisplayRec() {
+ return displayRec;
+ }
+
+ /**
+ * @param displayRec the displayRec to set
+ */
+ public void setDisplayRec(DisplayRec displayRec) {
+ this.displayRec = displayRec;
+ }
+
+ /**
+ * @return the blockDisp
+ */
+ public BlockData getBlockDisp() {
+ return blockDisp;
+ }
+
+ /**
+ * @param blockDisp the blockDisp to set
+ */
+ public void setBlockDisp(BlockData blockDisp) {
+ this.blockDisp = blockDisp;
+ }
+
+ /**
+ * @return the itemDisp
+ */
+ public ItemStack getItemDisp() {
+ return itemDisp;
+ }
+
+ /**
+ * @param itemDisp the itemDisp to set
+ */
+ public void setItemDisp(ItemStack itemDisp) {
+ this.itemDisp = itemDisp;
+ }
+
}
diff --git a/src/main/java/world/bentobox/bentobox/database/json/adapters/MaterialTypeAdapter.java b/src/main/java/world/bentobox/bentobox/database/json/adapters/MaterialTypeAdapter.java
index e5efa70a9..13e5d3401 100644
--- a/src/main/java/world/bentobox/bentobox/database/json/adapters/MaterialTypeAdapter.java
+++ b/src/main/java/world/bentobox/bentobox/database/json/adapters/MaterialTypeAdapter.java
@@ -17,7 +17,7 @@
/**
* Minecraft 1.20 changed GRASS to SHORT_GRASS. This class provides and backwards compatibility when loading
- * databased files stored with previous versions. It can be extended in the future if further enum changes are made.
+ * database files stored with previous versions. It can be extended in the future if further enum changes are made.
* @author tastybento
* @since 2.0.0
*/
diff --git a/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java b/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
new file mode 100644
index 000000000..650e39133
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
@@ -0,0 +1,35 @@
+package world.bentobox.bentobox.hooks;
+
+import org.bukkit.Material;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.hooks.Hook;
+
+/**
+ * Provides copy and pasting of FancyHolograms in blueprints
+ *
+ * @author tastybento
+ * @since 3.2.0
+ */
+public class FancyHologramsHook extends Hook {
+
+ public FancyHologramsHook() {
+ super("FancyHolograms", Material.END_PORTAL);
+ }
+
+
+ @Override
+ public boolean hook() {
+ boolean hooked = this.isPluginAvailable();
+ if (!hooked) {
+ BentoBox.getInstance().logError("Could not hook into FancyHolograms");
+ }
+ return hooked; // The hook process shouldn't fail
+ }
+
+ @Override
+ public String getFailureCause() {
+ return null; // The hook process shouldn't fail
+ }
+
+}
diff --git a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
index 2e6083026..2de5ae600 100644
--- a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
+++ b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
@@ -189,6 +189,8 @@ public static CompletableFuture setEntity(Island island, Location location
* @return true if Bukkit entity spawned, false another plugin entity spawned
*/
static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island island) {
+ // Display Entity (holograms, etc.)
+ k.setDisplay(location);
// FancyNpc entity
if (k.getNpc() != null
&& plugin.getHooks().getHook("FancyNpcs").filter(mmh -> mmh instanceof FancyNpcsHook).map(mmh -> {
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 9ddec656a..d314626f3 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -25,6 +25,8 @@ softdepend:
- EconomyPlus
- MythicMobs
- ZNPCsPlus
+ - FancyNpcs
+ - FancyHolograms
libraries:
- mysql:mysql-connector-java:${mysql.version}
From 62a4f63040b9deae520b907c34d13c1f772fe96e Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 28 Dec 2024 09:06:28 -0800
Subject: [PATCH 16/24] Working with debug
---
.../blueprints/BlueprintClipboard.java | 22 +--
.../bentobox/blueprints/DisplayListener.java | 51 +++++++
.../dataobjects/BlueprintEntity.java | 139 +++++++-----------
.../bentobox/managers/BlueprintsManager.java | 3 +
.../bentobox/util/DefaultPasteUtil.java | 1 +
5 files changed, 124 insertions(+), 92 deletions(-)
create mode 100644 src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
index a5ae6ad1b..f590469c7 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
@@ -18,6 +18,7 @@
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.Sign;
+import org.bukkit.block.data.Attachable;
import org.bukkit.block.sign.Side;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
@@ -30,7 +31,6 @@
import org.bukkit.entity.Villager;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.material.Attachable;
import org.bukkit.material.Colorable;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
@@ -163,9 +163,8 @@ private void copyAsync(World world, User user, List vectorsToCopy, int s
List ents = world.getEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player))
- .filter(e -> new Vector(Math.rint(e.getLocation().getX()),
- Math.rint(e.getLocation().getY()),
- Math.rint(e.getLocation().getZ())).equals(v))
+ .filter(e -> new Vector(e.getLocation().getBlockX(), e.getLocation().getBlockY(),
+ e.getLocation().getBlockZ()).equals(v))
.toList();
if (copyBlock(v.toLocation(world), copyAir, copyBiome, ents)) {
count++;
@@ -231,7 +230,7 @@ private boolean copyBlock(Location l, boolean copyAir, boolean copyBiome, List());
@@ -285,11 +287,11 @@ private BlueprintBlock bluePrintBlock(Vector pos, Block block, boolean copyBiome
}
}
}
-
+ BentoBox.getInstance().logDebug("Spawner");
if (blockState instanceof CreatureSpawner spawner) {
b.setCreatureSpawner(getSpawner(spawner));
}
-
+ BentoBox.getInstance().logDebug("Banners");
// Banners
if (blockState instanceof Banner banner) {
b.setBannerPatterns(banner.getPatterns());
@@ -359,7 +361,7 @@ private List setEntities(List ents) {
// Display entities
if (entity instanceof Display disp) {
- BentoBox.getInstance().logDebug(disp.getAsString());
+ BentoBox.getInstance().logDebug("Storing display: " + disp.getAsString());
bpe.storeDisplay(disp);
}
bpEnts.add(bpe);
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java b/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
new file mode 100644
index 000000000..c893e19b4
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
@@ -0,0 +1,51 @@
+package world.bentobox.bentobox.blueprints;
+
+import java.util.UUID;
+
+import org.bukkit.NamespacedKey;
+import org.bukkit.Sound;
+import org.bukkit.World;
+import org.bukkit.entity.ArmorStand;
+import org.bukkit.entity.Display;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractAtEntityEvent;
+import org.bukkit.persistence.PersistentDataType;
+
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.api.user.User;
+
+/**
+ * Provides a listener for the Display Objects pasted when a hologram is interacted with
+ * https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/player/PlayerInteractAtEntityEvent.html
+ */
+public class DisplayListener implements Listener {
+
+ @EventHandler
+ public void onPlayerInteractEntity(PlayerInteractAtEntityEvent event) {
+ BentoBox.getInstance().logDebug(event.getEventName());
+ if (event.getRightClicked() instanceof ArmorStand) {
+ ArmorStand armorStand = (ArmorStand) event.getRightClicked();
+ NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
+
+ if (armorStand.getPersistentDataContainer().has(key, PersistentDataType.STRING)) {
+ String displayEntityUUID = armorStand.getPersistentDataContainer().get(key, PersistentDataType.STRING);
+
+ // Fetch the associated DisplayEntity by UUID
+ World world = armorStand.getWorld();
+ world.getEntitiesByClass(Display.class).stream()
+ .filter(e -> e.getUniqueId().equals(UUID.fromString(displayEntityUUID))).findFirst()
+ .ifPresent(e -> {
+ User user = User.getInstance(event.getPlayer());
+ user.sendRawMessage("You interacted with a DisplayEntity! ");
+ event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.BLOCK_GLASS_BREAK, 1F,
+ 1F);
+ e.remove();
+
+ });
+ // Perform actions related to the DisplayEntity
+
+ }
+ }
+ }
+}
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
index b37bc3fe5..804cb165a 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
@@ -2,14 +2,17 @@
import java.util.Map;
+import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.Location;
+import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.Ageable;
+import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.ChestedHorse;
import org.bukkit.entity.Display;
@@ -20,6 +23,7 @@
import org.bukkit.entity.Horse;
import org.bukkit.entity.Horse.Style;
import org.bukkit.entity.ItemDisplay;
+import org.bukkit.entity.ItemDisplay.ItemDisplayTransform;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.TextDisplay;
import org.bukkit.entity.TextDisplay.TextAlignment;
@@ -27,10 +31,16 @@
import org.bukkit.entity.Villager.Profession;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Colorable;
+import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Transformation;
+import org.bukkit.util.Vector;
import com.google.gson.annotations.Expose;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.ItemDispRec.DisplayRec;
+import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.ItemDispRec.TextDisplayRec;
+
/**
* @author tastybento
* @since 1.5.0
@@ -81,8 +91,16 @@ public record MythicMobRecord(String type, String displayName, double level, flo
private Integer experience;
@Expose
private Villager.Type villagerType;
+ // Position within the block
+ @Expose
+ private double x;
+ @Expose
+ private double y;
+ @Expose
+ private double z;
/**
+ * Adjusts the entity according to how it was stored
* @since 1.8.0
*/
public void configureEntity(Entity e) {
@@ -115,6 +133,11 @@ public void configureEntity(Entity e) {
if (style != null && e instanceof Horse horse) {
horse.setStyle(style);
}
+ // Shift to the in-block location
+ Vector add = new Vector(x, y, z);
+ BentoBox.getInstance().logDebug("entity is at " + e.getLocation().toVector() + " and adding " + add);
+ e.getLocation().add(add);
+ BentoBox.getInstance().logDebug("entity is now at " + e.getLocation().toVector());
}
/**
@@ -330,42 +353,22 @@ public String getNpc() {
}
/**
- * @param citizen the citizen to set
+ * @param npc the citizen to set
*/
- public void setNpc(String citizen) {
- this.npc = citizen;
- }
-
- @Override
- public String toString() {
- return "BlueprintEntity [" + (npc != null ? "npc=" + npc + ", " : "")
- + (MMtype != null ? "MMtype=" + MMtype + ", " : "")
- + (MMLevel != null ? "MMLevel=" + MMLevel + ", " : "")
- + (MMStance != null ? "MMStance=" + MMStance + ", " : "")
- + (MMpower != null ? "MMpower=" + MMpower + ", " : "") + (color != null ? "color=" + color + ", " : "")
- + (type != null ? "type=" + type + ", " : "")
- + (customName != null ? "customName=" + customName + ", " : "")
- + (tamed != null ? "tamed=" + tamed + ", " : "") + (chest != null ? "chest=" + chest + ", " : "")
- + (adult != null ? "adult=" + adult + ", " : "")
- + (domestication != null ? "domestication=" + domestication + ", " : "")
- + (inventory != null ? "inventory=" + inventory + ", " : "")
- + (style != null ? "style=" + style + ", " : "") + (level != null ? "level=" + level + ", " : "")
- + (profession != null ? "profession=" + profession + ", " : "")
- + (experience != null ? "experience=" + experience + ", " : "")
- + (villagerType != null ? "villagerType=" + villagerType : "") + "]";
+ public void setNpc(String npc) {
+ this.npc = npc;
}
-
-
-
@Expose
public DisplayRec displayRec;
@Expose
public TextDisplayRec textDisp;
@Expose
- public BlockData blockDisp;
+ public BlueprintBlock blockDisp;
@Expose
- public ItemStack itemDisp;
+ public ItemDispRec itemDisp;
+
+ public record ItemDispRec(@Expose ItemStack item, @Expose ItemDisplayTransform itemDispTrans) {}
public record DisplayRec(@Expose Billboard billboard, @Expose Brightness brightness, @Expose float height,
@Expose float width, @Expose Color glowColorOverride, @Expose int interpolationDelay,
@@ -390,18 +393,18 @@ public void storeDisplay(Display disp) {
disp.getTeleportDuration(), disp.getTransformation(), disp.getViewRange());
// Class specific items
if (disp instanceof BlockDisplay bd) {
- this.blockDisp = bd.getBlock();
+ this.blockDisp = new BlueprintBlock(bd.getBlock().getAsString());
} else if (disp instanceof ItemDisplay id) {
- itemDisp = id.getItemStack();
+ itemDisp = new ItemDispRec(id.getItemStack(), id.getItemDisplayTransform());
} else if (disp instanceof TextDisplay td) {
textDisp = new TextDisplayRec(td.getText(), td.getAlignment(), td.getBackgroundColor(),
td.getFacing(), td.getLineWidth(), td.getTextOpacity(), td.isShadowed(), td.isSeeThrough(),
td.isDefaultBackground());
}
-
- // , getBrightness, getDisplayHeight, getDisplayWidth, getGlowColorOverride, getInterpolationDelay, getInterpolationDuration,
- //getShadowRadius, getShadowStrength, getTeleportDuration, getTransformation, getViewRange, setBillboard, setBrightness,
- // setDisplayHeight, setDisplayWidth, setGlowColorOverride, setInterpolationDelay, setInterpolationDuration, setShadowRadius, setShadowStrength, setTeleportDuration, setTransformation, setTransformationMatrix, setViewRange
+ // Store location within block
+ x = disp.getLocation().getX() - disp.getLocation().getBlockX();
+ y = disp.getLocation().getY() - disp.getLocation().getBlockY();
+ z = disp.getLocation().getZ() - disp.getLocation().getBlockZ();
}
/**
@@ -410,18 +413,22 @@ public void storeDisplay(Display disp) {
*/
public void setDisplay(Location pos) {
World world = pos.getWorld();
+ Location newPos = pos.clone().add(new Vector(x - 0.5D, y, z - 0.5D));
Display d = null;
if (this.blockDisp != null) {
// Block Display
- d = world.spawn(pos, BlockDisplay.class);
- ((BlockDisplay) d).setBlock(this.blockDisp);
+ d = world.spawn(newPos, BlockDisplay.class);
+ BlockData bd = Bukkit.createBlockData(this.blockDisp.getBlockData());
+ ((BlockDisplay) d).setBlock(bd);
} else if (this.itemDisp != null) {
// Item Display
- d = world.spawn(pos, ItemDisplay.class);
- ((ItemDisplay) d).setItemStack(itemDisp);
+ d = world.spawn(newPos, ItemDisplay.class);
+ ((ItemDisplay) d).setItemStack(itemDisp.item());
+ ((ItemDisplay) d).setItemDisplayTransform(itemDisp.itemDispTrans());
} else if (this.textDisp != null) {
- // Block Display
- d = world.spawn(pos, TextDisplay.class);
+ BentoBox.getInstance().logDebug("Text display - " + textDisp.text());
+ // Text Display
+ d = world.spawn(newPos, TextDisplay.class);
((TextDisplay) d).setText(textDisp.text());
((TextDisplay) d).setAlignment(textDisp.alignment());
((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
@@ -432,6 +439,8 @@ public void setDisplay(Location pos) {
((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
}
if (d != null && this.displayRec != null) {
+ BentoBox.getInstance().logDebug("General display");
+ d.setCustomName(getCustomName());
d.setBillboard(displayRec.billboard());
d.setBrightness(displayRec.brightness());
d.setDisplayHeight(displayRec.height());
@@ -445,48 +454,14 @@ public void setDisplay(Location pos) {
d.setTransformation(displayRec.transformation());
d.setViewRange(displayRec.range());
}
+ // Spawn an armor stand here so that we have a way to detect if a player interacts with the item
+ ArmorStand armorStand = (ArmorStand) world.spawnEntity(newPos, EntityType.ARMOR_STAND);
+ armorStand.setSmall(true); // Reduces size
+ armorStand.setGravity(false); // Prevents falling
+ //armorStand.setInvisible(true);
+ //armorStand.setMarker(true); // No hitbox
+ NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
+ armorStand.getPersistentDataContainer().set(key, PersistentDataType.STRING, d.getUniqueId().toString());
+ BentoBox.getInstance().logDebug("display set done");
}
-
- /**
- * @return the displayRec
- */
- public DisplayRec getDisplayRec() {
- return displayRec;
- }
-
- /**
- * @param displayRec the displayRec to set
- */
- public void setDisplayRec(DisplayRec displayRec) {
- this.displayRec = displayRec;
- }
-
- /**
- * @return the blockDisp
- */
- public BlockData getBlockDisp() {
- return blockDisp;
- }
-
- /**
- * @param blockDisp the blockDisp to set
- */
- public void setBlockDisp(BlockData blockDisp) {
- this.blockDisp = blockDisp;
- }
-
- /**
- * @return the itemDisp
- */
- public ItemStack getItemDisp() {
- return itemDisp;
- }
-
- /**
- * @param itemDisp the itemDisp to set
- */
- public void setItemDisp(ItemStack itemDisp) {
- this.itemDisp = itemDisp;
- }
-
}
diff --git a/src/main/java/world/bentobox/bentobox/managers/BlueprintsManager.java b/src/main/java/world/bentobox/bentobox/managers/BlueprintsManager.java
index d13332ed5..ca6a6cef6 100644
--- a/src/main/java/world/bentobox/bentobox/managers/BlueprintsManager.java
+++ b/src/main/java/world/bentobox/bentobox/managers/BlueprintsManager.java
@@ -44,6 +44,7 @@
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.blueprints.Blueprint;
import world.bentobox.bentobox.blueprints.BlueprintPaster;
+import world.bentobox.bentobox.blueprints.DisplayListener;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBlock;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
import world.bentobox.bentobox.database.json.BentoboxTypeAdapterFactory;
@@ -113,6 +114,8 @@ public BlueprintsManager(@NonNull BentoBox plugin) {
gson = builder.create();
// Loaded tracker
blueprintsLoaded = new HashSet<>();
+ // Register Display listeners
+ Bukkit.getPluginManager().registerEvents(new DisplayListener(), plugin);
}
/**
diff --git a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
index 2de5ae600..f688cb9de 100644
--- a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
+++ b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
@@ -189,6 +189,7 @@ public static CompletableFuture setEntity(Island island, Location location
* @return true if Bukkit entity spawned, false another plugin entity spawned
*/
static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island island) {
+ BentoBox.getInstance().logDebug("spawn blueprint entiy " + k + " at " + location);
// Display Entity (holograms, etc.)
k.setDisplay(location);
// FancyNpc entity
From 30d3fad81f68588381163c6a83f70c49bdf6afc2 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 28 Dec 2024 10:16:59 -0800
Subject: [PATCH 17/24] Fix pasting of other display entities. Remove debug.
---
.../blueprints/BlueprintClipboard.java | 78 +--
.../bentobox/blueprints/DisplayListener.java | 6 -
.../dataobjects/BlueprintEntity.java | 601 ++++++++++++------
.../bentobox/util/DefaultPasteUtil.java | 1 -
4 files changed, 402 insertions(+), 284 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
index f590469c7..5522ea867 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java
@@ -12,6 +12,7 @@
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.block.Banner;
import org.bukkit.block.Block;
@@ -20,18 +21,11 @@
import org.bukkit.block.Sign;
import org.bukkit.block.data.Attachable;
import org.bukkit.block.sign.Side;
-import org.bukkit.entity.AbstractHorse;
-import org.bukkit.entity.Ageable;
-import org.bukkit.entity.ChestedHorse;
-import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
-import org.bukkit.entity.Horse;
import org.bukkit.entity.Player;
-import org.bukkit.entity.Tameable;
-import org.bukkit.entity.Villager;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.material.Colorable;
+import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
@@ -58,6 +52,10 @@
*/
public class BlueprintClipboard {
+ /**
+ * Used to filter out hidden DisplayEntity armor stands when copying
+ */
+ private static final NamespacedKey KEY = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
private @Nullable Blueprint blueprint;
private @Nullable Location pos1;
private @Nullable Location pos2;
@@ -75,6 +73,7 @@ public class BlueprintClipboard {
private Optional npc;
private Optional znpc;
+
/**
* Create a clipboard for blueprint
* @param blueprint - the blueprint to load into the clipboard
@@ -149,6 +148,7 @@ private void copyAsync(World world, User user, List vectorsToCopy, int s
// Add all the citizens for the area in one go. This is pretty fast.
bpEntities.putAll(npc.get().getNpcsInArea(world, vectorsToCopy, origin));
}
+ // ZNPCsPlus NPCs
if (znpc.isPresent()) {
bpEntities.putAll(znpc.get().getNpcsInArea(world, vectorsToCopy, origin));
}
@@ -163,6 +163,7 @@ private void copyAsync(World world, User user, List vectorsToCopy, int s
List ents = world.getEntities().stream()
.filter(Objects::nonNull)
.filter(e -> !(e instanceof Player))
+ .filter(e -> !e.getPersistentDataContainer().has(KEY, PersistentDataType.STRING)) // Do not copy hidden display entities
.filter(e -> new Vector(e.getLocation().getBlockX(), e.getLocation().getBlockY(),
e.getLocation().getBlockZ()).equals(v))
.toList();
@@ -230,7 +231,6 @@ private boolean copyBlock(Location l, boolean copyAir, boolean copyBiome, List());
@@ -287,11 +283,9 @@ private BlueprintBlock bluePrintBlock(Vector pos, Block block, boolean copyBiome
}
}
}
- BentoBox.getInstance().logDebug("Spawner");
if (blockState instanceof CreatureSpawner spawner) {
b.setCreatureSpawner(getSpawner(spawner));
}
- BentoBox.getInstance().logDebug("Banners");
// Banners
if (blockState instanceof Banner banner) {
b.setBannerPatterns(banner.getPatterns());
@@ -320,67 +314,15 @@ private BlueprintCreatureSpawner getSpawner(CreatureSpawner spawner) {
private List setEntities(List ents) {
List bpEnts = new ArrayList<>();
for (Entity entity : ents) {
- BlueprintEntity bpe = new BlueprintEntity();
-
- bpe.setType(entity.getType());
- bpe.setCustomName(entity.getCustomName());
- if (entity instanceof Villager villager) {
- setVillager(villager, bpe);
- }
- if (entity instanceof Colorable c && c.getColor() != null) {
- bpe.setColor(c.getColor());
- }
- if (entity instanceof Tameable tameable) {
- bpe.setTamed(tameable.isTamed());
- }
- if (entity instanceof ChestedHorse chestedHorse) {
- bpe.setChest(chestedHorse.isCarryingChest());
- }
- // Only set if child. Most animals are adults
- if (entity instanceof Ageable ageable && !ageable.isAdult()) {
- bpe.setAdult(false);
- }
- if (entity instanceof AbstractHorse horse) {
- bpe.setDomestication(horse.getDomestication());
- bpe.setInventory(new HashMap<>());
- for (int i = 0; i < horse.getInventory().getSize(); i++) {
- ItemStack item = horse.getInventory().getItem(i);
- if (item != null) {
- bpe.getInventory().put(i, item);
- }
- }
- }
-
- if (entity instanceof Horse horse) {
- bpe.setStyle(horse.getStyle());
- }
-
+ BlueprintEntity bpe = new BlueprintEntity(entity);
// Mythic mob check
mmh.filter(mm -> mm.isMythicMob(entity)).map(mm -> mm.getMythicMob(entity))
.ifPresent(bpe::setMythicMobsRecord);
-
- // Display entities
- if (entity instanceof Display disp) {
- BentoBox.getInstance().logDebug("Storing display: " + disp.getAsString());
- bpe.storeDisplay(disp);
- }
bpEnts.add(bpe);
}
return bpEnts;
}
- /**
- * Set the villager stats
- * @param v - villager
- * @param bpe - Blueprint Entity
- */
- private void setVillager(Villager v, BlueprintEntity bpe) {
- bpe.setExperience(v.getVillagerExperience());
- bpe.setLevel(v.getVillagerLevel());
- bpe.setProfession(v.getProfession());
- bpe.setVillagerType(v.getVillagerType());
- }
-
/**
* @return the origin
*/
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java b/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
index c893e19b4..efa1dccf3 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/DisplayListener.java
@@ -13,7 +13,6 @@
import org.bukkit.persistence.PersistentDataType;
import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.api.user.User;
/**
* Provides a listener for the Display Objects pasted when a hologram is interacted with
@@ -23,7 +22,6 @@ public class DisplayListener implements Listener {
@EventHandler
public void onPlayerInteractEntity(PlayerInteractAtEntityEvent event) {
- BentoBox.getInstance().logDebug(event.getEventName());
if (event.getRightClicked() instanceof ArmorStand) {
ArmorStand armorStand = (ArmorStand) event.getRightClicked();
NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
@@ -36,15 +34,11 @@ public void onPlayerInteractEntity(PlayerInteractAtEntityEvent event) {
world.getEntitiesByClass(Display.class).stream()
.filter(e -> e.getUniqueId().equals(UUID.fromString(displayEntityUUID))).findFirst()
.ifPresent(e -> {
- User user = User.getInstance(event.getPlayer());
- user.sendRawMessage("You interacted with a DisplayEntity! ");
event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.BLOCK_GLASS_BREAK, 1F,
1F);
e.remove();
});
- // Perform actions related to the DisplayEntity
-
}
}
}
diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
index 804cb165a..e41ebcc9b 100644
--- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
+++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java
@@ -1,5 +1,6 @@
package world.bentobox.bentobox.blueprints.dataobjects;
+import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
@@ -38,8 +39,6 @@
import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.ItemDispRec.DisplayRec;
-import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity.ItemDispRec.TextDisplayRec;
/**
* @author tastybento
@@ -47,48 +46,82 @@
*/
public class BlueprintEntity {
- // Npc storage
- @Expose
- private String npc;
-
// MythicMobs storage
public record MythicMobRecord(String type, String displayName, double level, float power, String stance) {
}
- // GSON can serialize records, but the record class needs to be know in advance. So this breaks out the record entries
- @Expose
- String MMtype;
- @Expose
- Double MMLevel;
+ /**
+ * Item Display Entity store
+ * @since 3.2.0
+ */
+ public record ItemDispRec(@Expose ItemStack item, @Expose ItemDisplayTransform itemDispTrans) {}
+
+ /**
+ * Display Entity store
+ * @since 3.2.0
+ */
+ public record DisplayRec(@Expose Billboard billboard, @Expose Brightness brightness, @Expose float height,
+ @Expose float width, @Expose Color glowColorOverride, @Expose int interpolationDelay,
+ @Expose int interpolationDuration, @Expose float shadowRadius, @Expose float shadowStrength,
+ @Expose int teleportDuration, @Expose Transformation transformation, @Expose float range) {
+ }
+
+ /**
+ * TextDisplay entity store
+ * @since 3.2.0
+ */
+ public record TextDisplayRec(@Expose String text, @Expose TextAlignment alignment, @Expose Color bgColor,
+ @Expose BlockFace face, @Expose int lWidth, @Expose byte opacity, @Expose boolean isShadowed,
+ @Expose boolean isSeeThrough, @Expose boolean isDefaultBg) {
+ }
@Expose
- String MMStance;
+ private Boolean adult;
@Expose
- Float MMpower;
+ public BlueprintBlock blockDisp;
@Expose
- private DyeColor color;
+ private Boolean chest;
@Expose
- private EntityType type;
+ private DyeColor color;
@Expose
private String customName;
@Expose
- private Boolean tamed;
- @Expose
- private Boolean chest;
- @Expose
- private Boolean adult;
+ public DisplayRec displayRec;
@Expose
private Integer domestication;
@Expose
+ private Integer experience;
+ @Expose
private Map inventory;
@Expose
- private Style style;
+ public ItemDispRec itemDisp;
@Expose
private Integer level;
@Expose
+ Double MMLevel;
+ @Expose
+ Float MMpower;
+ @Expose
+ String MMStance;
+ // GSON can serialize records, but the record class needs to be know in advance. So this breaks out the record entries
+ @Expose
+ String MMtype;
+ // Npc storage
+ @Expose
+ private String npc;
+ @Expose
private Profession profession;
@Expose
- private Integer experience;
+ private Style style;
+
+ @Expose
+ private Boolean tamed;
+
+ @Expose
+ public TextDisplayRec textDisp;
+
+ @Expose
+ private EntityType type;
@Expose
private Villager.Type villagerType;
// Position within the block
@@ -98,12 +131,104 @@ public record MythicMobRecord(String type, String displayName, double level, flo
private double y;
@Expose
private double z;
+ @Expose
+ private boolean glowing;
+ @Expose
+ private boolean gravity;
+ @Expose
+ private boolean visualFire;
+ @Expose
+ private boolean silent;
+ @Expose
+ private boolean invulnerable;
+ @Expose
+ private int fireTicks;
+
+ /**
+ * Serializes an entity to a Blueprint Entity
+ * @param entity entity to serialize
+ * @since 3.2.0
+ */
+ public BlueprintEntity(Entity entity) {
+ this.setType(entity.getType());
+ this.setCustomName(entity.getCustomName());
+ this.setGlowing(entity.isGlowing());
+ this.setGravity(entity.hasGravity());
+ this.setVisualFire(entity.isVisualFire());
+ this.setSilent(entity.isSilent());
+ this.setInvulnerable(entity.isInvulnerable());
+ this.setFireTicks(entity.getFireTicks());
+
+ if (entity instanceof Villager villager) {
+ configVillager(villager);
+ }
+ if (entity instanceof Colorable c && c.getColor() != null) {
+ this.setColor(c.getColor());
+ }
+ if (entity instanceof Tameable tameable) {
+ this.setTamed(tameable.isTamed());
+ }
+ if (entity instanceof ChestedHorse chestedHorse) {
+ this.setChest(chestedHorse.isCarryingChest());
+ }
+ // Only set if child. Most animals are adults
+ if (entity instanceof Ageable ageable && !ageable.isAdult()) {
+ this.setAdult(false);
+ }
+ if (entity instanceof AbstractHorse horse) {
+ this.setDomestication(horse.getDomestication());
+ this.setInventory(new HashMap<>());
+ for (int i = 0; i < horse.getInventory().getSize(); i++) {
+ ItemStack item = horse.getInventory().getItem(i);
+ if (item != null) {
+ this.getInventory().put(i, item);
+ }
+ }
+ }
+
+ if (entity instanceof Horse horse) {
+ this.setStyle(horse.getStyle());
+ }
+
+ // Display entities
+ if (entity instanceof Display disp) {
+ this.storeDisplay(disp);
+ }
+
+ }
+
+ /**
+ * Makes a blank BlueprintEntity
+ */
+ public BlueprintEntity() {
+ // Blank constructor
+ }
+
+ /**
+ * Set the villager stats
+ * @param v - villager
+ * @param bpe - Blueprint Entity
+ */
+ private void configVillager(Villager v) {
+ this.setExperience(v.getVillagerExperience());
+ this.setLevel(v.getVillagerLevel());
+ this.setProfession(v.getProfession());
+ this.setVillagerType(v.getVillagerType());
+ }
/**
* Adjusts the entity according to how it was stored
* @since 1.8.0
*/
public void configureEntity(Entity e) {
+ // Set the general states
+ e.setGlowing(glowing);
+ e.setGravity(gravity);
+ e.setVisualFire(visualFire);
+ e.setSilent(silent);
+ e.setInvulnerable(invulnerable);
+ e.setFireTicks(fireTicks);
+
if (e instanceof Villager villager) {
setVillager(villager);
}
@@ -133,47 +258,26 @@ public void configureEntity(Entity e) {
if (style != null && e instanceof Horse horse) {
horse.setStyle(style);
}
- // Shift to the in-block location
- Vector add = new Vector(x, y, z);
- BentoBox.getInstance().logDebug("entity is at " + e.getLocation().toVector() + " and adding " + add);
- e.getLocation().add(add);
- BentoBox.getInstance().logDebug("entity is now at " + e.getLocation().toVector());
- }
-
- /**
- * @param v - villager
- * @since 1.16.0
- */
- private void setVillager(Villager v) {
- v.setProfession(profession == null ? Profession.NONE : profession);
- v.setVillagerExperience(experience == null ? 0 : experience);
- v.setVillagerLevel(level == null ? 0 : level);
- v.setVillagerType(villagerType == null ? Villager.Type.PLAINS : villagerType);
- }
-
- /**
- * @return the color
- */
- public DyeColor getColor() {
- return color;
+ // Shift to the in-block location (remove the 0.5 that the location serializer used)
+ e.getLocation().add(new Vector(x - 0.5D, y, z - 0.5D));
}
/**
- * @param color the color to set
+ * @return the adult
*/
- public void setColor(DyeColor color) {
- this.color = color;
+ public Boolean getAdult() {
+ return adult;
}
/**
- * @return the type
+ * @return the chest
*/
- public EntityType getType() {
- return type;
+ public Boolean getChest() {
+ return chest;
}
/**
- * @param type the type to set
+ * @return the color
*/
- public void setType(EntityType type) {
- this.type = type;
+ public DyeColor getColor() {
+ return color;
}
/**
* @return the customName
@@ -182,117 +286,173 @@ public String getCustomName() {
return customName;
}
/**
- * @param customName the customName to set
+ * @return the domestication
*/
- public void setCustomName(String customName) {
- this.customName = customName;
+ public Integer getDomestication() {
+ return domestication;
}
/**
- * @return the tamed
+ * @return the experience
*/
- public Boolean getTamed() {
- return tamed;
+ public Integer getExperience() {
+ return experience;
}
/**
- * @param tamed the tamed to set
+ * @return the inventory
*/
- public void setTamed(Boolean tamed) {
- this.tamed = tamed;
+ public Map getInventory() {
+ return inventory;
}
/**
- * @return the chest
+ * @return the level
*/
- public Boolean getChest() {
- return chest;
+ public Integer getLevel() {
+ return level;
}
/**
- * @param chest the chest to set
+ * @return the mythicMobsRecord
*/
- public void setChest(Boolean chest) {
- this.chest = chest;
+ public MythicMobRecord getMythicMobsRecord() {
+ if (this.MMtype == null || this.MMLevel == null || this.MMpower == null || this.MMStance == null) {
+ return null;
+ }
+ return new MythicMobRecord(this.MMtype, this.getCustomName(), this.MMLevel, this.MMpower, this.MMStance);
}
/**
- * @return the adult
+ * @return the npc
*/
- public Boolean getAdult() {
- return adult;
+ public String getNpc() {
+ return npc;
}
/**
- * @param adult the adult to set
+ * @return the profession
*/
- public void setAdult(Boolean adult) {
- this.adult = adult;
+ public Profession getProfession() {
+ return profession;
}
/**
- * @return the domestication
+ * @return the style
*/
- public Integer getDomestication() {
- return domestication;
+ public Style getStyle() {
+ return style;
}
+
/**
- * @param domestication the domestication to set
+ * @return the tamed
*/
- public void setDomestication(int domestication) {
- this.domestication = domestication;
+ public Boolean getTamed() {
+ return tamed;
}
+
/**
- * @return the inventory
+ * @return the type
*/
- public Map getInventory() {
- return inventory;
+ public EntityType getType() {
+ return type;
}
+
/**
- * @param inventory the inventory to set
+ * @return the villagerType
*/
- public void setInventory(Map inventory) {
- this.inventory = inventory;
+ public Villager.Type getVillagerType() {
+ return villagerType;
}
+
/**
- * @return the style
+ * @param adult the adult to set
*/
- public Style getStyle() {
- return style;
+ public void setAdult(Boolean adult) {
+ this.adult = adult;
}
+
/**
- * @param style the style to set
+ * @param chest the chest to set
*/
- public void setStyle(Style style) {
- this.style = style;
+ public void setChest(Boolean chest) {
+ this.chest = chest;
}
/**
- * @return the level
+ * @param color the color to set
*/
- public Integer getLevel() {
- return level;
+ public void setColor(DyeColor color) {
+ this.color = color;
}
/**
- * @param level the level to set
+ * @param customName the customName to set
*/
- public void setLevel(Integer level) {
- this.level = level;
+ public void setCustomName(String customName) {
+ this.customName = customName;
}
/**
- * @return the profession
+ * Sets any display entity properties to the location, e.g. holograms
+ * @param pos location
*/
- public Profession getProfession() {
- return profession;
+ public void setDisplay(Location pos) {
+ World world = pos.getWorld();
+ Location newPos = pos.clone().add(new Vector(x - 0.5D, y, z - 0.5D));
+ Display d = null;
+ if (this.blockDisp != null) {
+ // Block Display
+ d = world.spawn(newPos, BlockDisplay.class);
+ BlockData bd = Bukkit.createBlockData(this.blockDisp.getBlockData());
+ ((BlockDisplay) d).setBlock(bd);
+ } else if (this.itemDisp != null) {
+ // Item Display
+ d = world.spawn(newPos, ItemDisplay.class);
+ ((ItemDisplay) d).setItemStack(itemDisp.item());
+ ((ItemDisplay) d).setItemDisplayTransform(itemDisp.itemDispTrans());
+ } else if (this.textDisp != null) {
+ // Text Display
+ d = world.spawn(newPos, TextDisplay.class);
+ ((TextDisplay) d).setText(textDisp.text());
+ ((TextDisplay) d).setAlignment(textDisp.alignment());
+ ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
+ ((TextDisplay) d).setLineWidth(textDisp.lWidth());
+ ((TextDisplay) d).setTextOpacity(textDisp.opacity());
+ ((TextDisplay) d).setShadowed(textDisp.isShadowed());
+ ((TextDisplay) d).setSeeThrough(textDisp.isSeeThrough());
+ ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
+ }
+ if (d != null && this.displayRec != null) {
+ d.setCustomName(getCustomName());
+ d.setBillboard(displayRec.billboard());
+ d.setBrightness(displayRec.brightness());
+ d.setDisplayHeight(displayRec.height());
+ d.setDisplayWidth(displayRec.width());
+ d.setGlowColorOverride(displayRec.glowColorOverride());
+ d.setInterpolationDelay(displayRec.interpolationDelay());
+ d.setInterpolationDuration(displayRec.interpolationDuration());
+ d.setShadowRadius(displayRec.shadowRadius());
+ d.setShadowStrength(displayRec.shadowStrength());
+ d.setTeleportDuration(displayRec.teleportDuration());
+ d.setTransformation(displayRec.transformation());
+ d.setViewRange(displayRec.range());
+
+ // Spawn an armor stand here so that we have a way to detect if a player interacts with the item
+ ArmorStand armorStand = (ArmorStand) world.spawnEntity(newPos, EntityType.ARMOR_STAND);
+ armorStand.setSmall(true); // Reduces size
+ armorStand.setGravity(false); // Prevents falling
+ armorStand.setInvisible(true);
+ NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
+ armorStand.getPersistentDataContainer().set(key, PersistentDataType.STRING, d.getUniqueId().toString());
+ }
}
/**
- * @param profession the profession to set
+ * @param domestication the domestication to set
*/
- public void setProfession(Profession profession) {
- this.profession = profession;
+ public void setDomestication(int domestication) {
+ this.domestication = domestication;
}
/**
- * @return the experience
+ * @param domestication the domestication to set
*/
- public Integer getExperience() {
- return experience;
+ public void setDomestication(Integer domestication) {
+ this.domestication = domestication;
}
/**
@@ -303,34 +463,17 @@ public void setExperience(Integer experience) {
}
/**
- * @return the villagerType
- */
- public Villager.Type getVillagerType() {
- return villagerType;
- }
-
- /**
- * @param villagerType the villagerType to set
- */
- public void setVillagerType(Villager.Type villagerType) {
- this.villagerType = villagerType;
- }
-
- /**
- * @param domestication the domestication to set
+ * @param inventory the inventory to set
*/
- public void setDomestication(Integer domestication) {
- this.domestication = domestication;
+ public void setInventory(Map inventory) {
+ this.inventory = inventory;
}
/**
- * @return the mythicMobsRecord
+ * @param level the level to set
*/
- public MythicMobRecord getMythicMobsRecord() {
- if (this.MMtype == null || this.MMLevel == null || this.MMpower == null || this.MMStance == null) {
- return null;
- }
- return new MythicMobRecord(this.MMtype, this.getCustomName(), this.MMLevel, this.MMpower, this.MMStance);
+ public void setLevel(Integer level) {
+ this.level = level;
}
/**
@@ -344,41 +487,55 @@ public void setMythicMobsRecord(MythicMobRecord mmr) {
this.MMStance = mmr.stance();
this.MMpower = mmr.power();
}
-
/**
- * @return the npc
+ * @param npc the citizen to set
*/
- public String getNpc() {
- return npc;
+ public void setNpc(String npc) {
+ this.npc = npc;
+ }
+ /**
+ * @param profession the profession to set
+ */
+ public void setProfession(Profession profession) {
+ this.profession = profession;
+ }
+ /**
+ * @param style the style to set
+ */
+ public void setStyle(Style style) {
+ this.style = style;
}
/**
- * @param npc the citizen to set
+ * @param tamed the tamed to set
*/
- public void setNpc(String npc) {
- this.npc = npc;
+ public void setTamed(Boolean tamed) {
+ this.tamed = tamed;
}
- @Expose
- public DisplayRec displayRec;
- @Expose
- public TextDisplayRec textDisp;
- @Expose
- public BlueprintBlock blockDisp;
- @Expose
- public ItemDispRec itemDisp;
-
- public record ItemDispRec(@Expose ItemStack item, @Expose ItemDisplayTransform itemDispTrans) {}
+ /**
+ * @param type the type to set
+ */
+ public void setType(EntityType type) {
+ this.type = type;
+ }
- public record DisplayRec(@Expose Billboard billboard, @Expose Brightness brightness, @Expose float height,
- @Expose float width, @Expose Color glowColorOverride, @Expose int interpolationDelay,
- @Expose int interpolationDuration, @Expose float shadowRadius, @Expose float shadowStrength,
- @Expose int teleportDuration, @Expose Transformation transformation, @Expose float range) {
+ /**
+ * @param v - villager
+ * @since 1.16.0
+ */
+ private void setVillager(Villager v) {
+ v.setProfession(profession == null ? Profession.NONE : profession);
+ v.setVillagerExperience(experience == null ? 0 : experience);
+ v.setVillagerLevel(level == null ? 0 : level);
+ v.setVillagerType(villagerType == null ? Villager.Type.PLAINS : villagerType);
}
- public record TextDisplayRec(@Expose String text, @Expose TextAlignment alignment, @Expose Color bgColor,
- @Expose BlockFace face, @Expose int lWidth, @Expose byte opacity, @Expose boolean isShadowed,
- @Expose boolean isSeeThrough, @Expose boolean isDefaultBg) {
+ /**
+ * @param villagerType the villagerType to set
+ */
+ public void setVillagerType(Villager.Type villagerType) {
+ this.villagerType = villagerType;
}
/**
@@ -408,60 +565,86 @@ public void storeDisplay(Display disp) {
}
/**
- * Sets any display entity properties to the location, e.g. holograms
- * @param pos location
+ * @return the glowing
*/
- public void setDisplay(Location pos) {
- World world = pos.getWorld();
- Location newPos = pos.clone().add(new Vector(x - 0.5D, y, z - 0.5D));
- Display d = null;
- if (this.blockDisp != null) {
- // Block Display
- d = world.spawn(newPos, BlockDisplay.class);
- BlockData bd = Bukkit.createBlockData(this.blockDisp.getBlockData());
- ((BlockDisplay) d).setBlock(bd);
- } else if (this.itemDisp != null) {
- // Item Display
- d = world.spawn(newPos, ItemDisplay.class);
- ((ItemDisplay) d).setItemStack(itemDisp.item());
- ((ItemDisplay) d).setItemDisplayTransform(itemDisp.itemDispTrans());
- } else if (this.textDisp != null) {
- BentoBox.getInstance().logDebug("Text display - " + textDisp.text());
- // Text Display
- d = world.spawn(newPos, TextDisplay.class);
- ((TextDisplay) d).setText(textDisp.text());
- ((TextDisplay) d).setAlignment(textDisp.alignment());
- ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
- ((TextDisplay) d).setLineWidth(textDisp.lWidth());
- ((TextDisplay) d).setTextOpacity(textDisp.opacity());
- ((TextDisplay) d).setShadowed(textDisp.isShadowed());
- ((TextDisplay) d).setSeeThrough(textDisp.isSeeThrough());
- ((TextDisplay) d).setBackgroundColor(textDisp.bgColor());
- }
- if (d != null && this.displayRec != null) {
- BentoBox.getInstance().logDebug("General display");
- d.setCustomName(getCustomName());
- d.setBillboard(displayRec.billboard());
- d.setBrightness(displayRec.brightness());
- d.setDisplayHeight(displayRec.height());
- d.setDisplayWidth(displayRec.width());
- d.setGlowColorOverride(displayRec.glowColorOverride());
- d.setInterpolationDelay(displayRec.interpolationDelay());
- d.setInterpolationDuration(displayRec.interpolationDuration());
- d.setShadowRadius(displayRec.shadowRadius());
- d.setShadowStrength(displayRec.shadowStrength());
- d.setTeleportDuration(displayRec.teleportDuration());
- d.setTransformation(displayRec.transformation());
- d.setViewRange(displayRec.range());
- }
- // Spawn an armor stand here so that we have a way to detect if a player interacts with the item
- ArmorStand armorStand = (ArmorStand) world.spawnEntity(newPos, EntityType.ARMOR_STAND);
- armorStand.setSmall(true); // Reduces size
- armorStand.setGravity(false); // Prevents falling
- //armorStand.setInvisible(true);
- //armorStand.setMarker(true); // No hitbox
- NamespacedKey key = new NamespacedKey(BentoBox.getInstance(), "associatedDisplayEntity");
- armorStand.getPersistentDataContainer().set(key, PersistentDataType.STRING, d.getUniqueId().toString());
- BentoBox.getInstance().logDebug("display set done");
+ public boolean isGlowing() {
+ return glowing;
+ }
+
+ /**
+ * @param glowing the glowing to set
+ */
+ public void setGlowing(boolean glowing) {
+ this.glowing = glowing;
+ }
+
+ /**
+ * @return the gravity
+ */
+ public boolean isGravity() {
+ return gravity;
+ }
+
+ /**
+ * @param gravity the gravity to set
+ */
+ public void setGravity(boolean gravity) {
+ this.gravity = gravity;
+ }
+
+ /**
+ * @return the visualFire
+ */
+ public boolean isVisualFire() {
+ return visualFire;
+ }
+
+ /**
+ * @param visualFire the visualFire to set
+ */
+ public void setVisualFire(boolean visualFire) {
+ this.visualFire = visualFire;
+ }
+
+ /**
+ * @return the silent
+ */
+ public boolean isSilent() {
+ return silent;
+ }
+
+ /**
+ * @param silent the silent to set
+ */
+ public void setSilent(boolean silent) {
+ this.silent = silent;
+ }
+
+ /**
+ * @return the invulnerable
+ */
+ public boolean isInvulnerable() {
+ return invulnerable;
+ }
+
+ /**
+ * @param invulnerable the invulnerable to set
+ */
+ public void setInvulnerable(boolean invulnerable) {
+ this.invulnerable = invulnerable;
+ }
+
+ /**
+ * @return the fireTicks
+ */
+ public int getFireTicks() {
+ return fireTicks;
+ }
+
+ /**
+ * @param fireTicks the fireTicks to set
+ */
+ public void setFireTicks(int fireTicks) {
+ this.fireTicks = fireTicks;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
index f688cb9de..2de5ae600 100644
--- a/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
+++ b/src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
@@ -189,7 +189,6 @@ public static CompletableFuture setEntity(Island island, Location location
* @return true if Bukkit entity spawned, false another plugin entity spawned
*/
static boolean spawnBlueprintEntity(BlueprintEntity k, Location location, Island island) {
- BentoBox.getInstance().logDebug("spawn blueprint entiy " + k + " at " + location);
// Display Entity (holograms, etc.)
k.setDisplay(location);
// FancyNpc entity
From df814cce0f67587330990c84226241b3321fb1d2 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 28 Dec 2024 14:21:49 -0800
Subject: [PATCH 18/24] Fixed tests
---
.../bentobox/bentobox/api/hooks/NPCHook.java | 41 +++++++++++++++++++
.../bentobox/hooks/FancyNpcsHook.java | 29 +++++++++++--
.../bentobox/hooks/ZNPCsPlusHook.java | 34 +++++++++++++--
.../bentobox/nms/CopyWorldRegenerator.java | 34 ++++++++++++---
.../AdminBlueprintCopyCommandTest.java | 10 +++--
.../AdminBlueprintLoadCommandTest.java | 2 +
.../AdminBlueprintSaveCommandTest.java | 6 ++-
.../blueprints/BlueprintClipboardTest.java | 2 +
.../BlueprintClipboardManagerTest.java | 12 ++++--
9 files changed, 150 insertions(+), 20 deletions(-)
create mode 100644 src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
diff --git a/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java b/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
new file mode 100644
index 000000000..6a848215f
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
@@ -0,0 +1,41 @@
+package world.bentobox.bentobox.api.hooks;
+
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.util.Vector;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import de.oliver.fancynpcs.api.Npc;
+import lol.pyr.znpcsplus.api.npc.NpcEntry;
+import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
+
+/**
+ * NPC Hooks
+ * @author tastybento
+ * @since 3.2.0
+ */
+public abstract class NPCHook extends Hook {
+
+ protected NPCHook(@NonNull String pluginName, @NonNull Material icon) {
+ super(pluginName, icon);
+ }
+
+ public abstract boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationException;
+
+ public abstract Map extends Vector, ? extends List> getNpcsInArea(World world,
+ List vectorsToCopy, @Nullable Vector origin);
+
+ /**
+ * Remove all NPCs in chunk
+ * @param chunk chunk
+ */
+ public abstract void removeNPCsInChunk(Chunk chunk);
+
+}
diff --git a/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java b/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
index acc5ba7d8..c8c375f12 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
@@ -10,6 +10,7 @@
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -29,9 +30,10 @@
import de.oliver.fancynpcs.api.actions.NpcAction;
import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot;
import de.oliver.fancynpcs.api.utils.SkinFetcher;
+import lol.pyr.znpcsplus.api.npc.NpcEntry;
import net.kyori.adventure.text.format.NamedTextColor;
import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.api.hooks.Hook;
+import world.bentobox.bentobox.api.hooks.NPCHook;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
/**
@@ -40,13 +42,13 @@
* @author tastybento
* @since 3.1.0
*/
-public class FancyNpcsHook extends Hook {
+public class FancyNpcsHook extends NPCHook {
public FancyNpcsHook() {
super("FancyNpcs", Material.PLAYER_HEAD);
}
- public String serializeNPC(Npc npc, Vector origin) {
+ String serializeNPC(Npc npc, Vector origin) {
if (npc == null) {
throw new IllegalArgumentException("NPC cannot be null.");
}
@@ -265,6 +267,26 @@ public String getFailureCause() {
return null; // The hook process shouldn't fail
}
+ /**
+ * Return all NPCs in the chunk
+ * @param chunk chunk
+ * @return list of NPCs
+ */
+ public List getNPCsInChunk(Chunk chunk) {
+ return FancyNpcsPlugin.get().getNpcManager().getAllNpcs().stream()
+ .filter(npc -> npc.getData().getLocation().getChunk().equals(chunk)).toList();
+ }
+
+ /**
+ * Remove all NPCs in chunk
+ * @param chunk chunk
+ */
+ @Override
+ public void removeNPCsInChunk(Chunk chunk) {
+ getNPCsInChunk(chunk).forEach(npc -> npc.removeForAll());
+ }
+
+ @Override
public Map extends Vector, ? extends List> getNpcsInArea(World world, List vectorsToCopy,
@Nullable Vector origin) {
Map> bpEntities = new HashMap<>();
@@ -290,4 +312,5 @@ public String getFailureCause() {
}
return bpEntities;
}
+
}
diff --git a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
index d9a31dfef..9a538d7a5 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
@@ -5,6 +5,7 @@
import java.util.List;
import java.util.Map;
+import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -17,7 +18,7 @@
import lol.pyr.znpcsplus.api.npc.NpcEntry;
import lol.pyr.znpcsplus.util.NpcLocation;
import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.api.hooks.Hook;
+import world.bentobox.bentobox.api.hooks.NPCHook;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.util.Util;
@@ -27,7 +28,7 @@
* @author tastybento
* @since 3.2.0
*/
-public class ZNPCsPlusHook extends Hook {
+public class ZNPCsPlusHook extends NPCHook {
private static final String VERSION = "2.0.0-SNAPSHOT"; // Minimum version required
@@ -35,13 +36,20 @@ public ZNPCsPlusHook() {
super("ZNPCsPlus", Material.PLAYER_HEAD);
}
- public String serializeNPC(NpcEntry entry, Vector origin) {
+ /**
+ * Serialize a NpcEntry
+ * @param entry NPC entry
+ * @param origin origin point of blueprint
+ * @return string serializing the NPC Entry
+ */
+ String serializeNPC(NpcEntry entry, Vector origin) {
String result = NpcApiProvider.get().getNpcSerializerRegistry().getSerializer(YamlConfiguration.class)
.serialize(entry)
.saveToString();
return result;
}
+ @Override
public boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationException {
YamlConfiguration yaml2 = new YamlConfiguration();
yaml2.loadFromString(yaml);
@@ -75,6 +83,7 @@ public String getFailureCause() {
+ this.getPlugin().getDescription().getVersion();
}
+ @Override
public Map extends Vector, ? extends List> getNpcsInArea(World world, List vectorsToCopy,
@Nullable Vector origin) {
Map> bpEntities = new HashMap<>();
@@ -101,4 +110,23 @@ public String getFailureCause() {
}
return bpEntities;
}
+
+ /**
+ * Get a list of all the NPC IDs in this chunk
+ * @param chunk chunk
+ * @return list of NPC IDs
+ */
+ public List getNPCsInChunk(Chunk chunk) {
+ return NpcApiProvider.get().getNpcRegistry().getAll().stream()
+ .filter(npc -> npc.getNpc().getWorld().equals(chunk.getWorld())) // Only NPCs in this world
+ .filter(npc -> npc.getNpc().getLocation().toBukkitLocation(chunk.getWorld()).getChunk().equals(chunk)) // Only in this chunk
+ .map(npc -> npc.getId()) // IDs
+ .toList();
+ }
+
+ @Override
+ public void removeNPCsInChunk(Chunk chunk) {
+ getNPCsInChunk(chunk).forEach(NpcApiProvider.get().getNpcRegistry()::delete);
+ }
+
}
diff --git a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
index c3ac17183..4be154439 100644
--- a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
+++ b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
@@ -43,8 +43,10 @@
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.hooks.Hook;
import world.bentobox.bentobox.database.objects.IslandDeletion;
+import world.bentobox.bentobox.hooks.FancyNpcsHook;
import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.SlimefunHook;
+import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
import world.bentobox.bentobox.util.MyBiomeGrid;
/**
@@ -56,9 +58,18 @@
public abstract class CopyWorldRegenerator implements WorldRegenerator {
private final BentoBox plugin;
+ private Optional npc;
+ private Optional znpc;
protected CopyWorldRegenerator() {
this.plugin = BentoBox.getInstance();
+ // Fancy NPCs Hook
+ npc = plugin.getHooks().getHook("FancyNpcs").filter(FancyNpcsHook.class::isInstance)
+ .map(FancyNpcsHook.class::cast);
+ // ZNPCs Plus Hook
+ znpc = plugin.getHooks().getHook("ZNPCsPlus").filter(ZNPCsPlusHook.class::isInstance)
+ .map(ZNPCsPlusHook.class::cast);
+
}
/**
@@ -179,11 +190,20 @@ private CompletableFuture cleanChunk(CompletableFuture chunkFuture,
);
// Similarly, when the chunk is loaded, remove all the entities in the chunk apart from players
- CompletableFuture entitiesFuture = chunkFuture.thenAccept(chunk ->
- // Remove all entities in chunk, including any dropped items as a result of clearing the blocks above
- Arrays.stream(chunk.getEntities())
- .filter(e -> !(e instanceof Player) && di.inBounds(e.getLocation().getBlockX(), e.getLocation().getBlockZ()))
- .forEach(Entity::remove));
+ CompletableFuture entitiesFuture = chunkFuture.thenAccept(chunk -> {
+ // Remove all entities in chunk, including any dropped items as a result of clearing the blocks above
+ Arrays.stream(chunk.getEntities())
+ .filter(e -> !(e instanceof Player)
+ && di.inBounds(e.getLocation().getBlockX(), e.getLocation().getBlockZ()))
+ .forEach(Entity::remove);
+ // Remove any NPCs
+ // Fancy NPCs Hook
+ npc.ifPresent(hook -> hook.removeNPCsInChunk(chunk));
+ // ZNPCs Plus Hook
+ znpc.ifPresent(hook -> hook.removeNPCsInChunk(chunk));
+
+ });
+
return CompletableFuture.allOf(invFuture, entitiesFuture);
}
@@ -310,6 +330,10 @@ private void writeSign(Sign fromSign, Sign toSign, Side side) {
public CompletableFuture regenerateSimple(GameModeAddon gm, IslandDeletion di, World world) {
CompletableFuture bigFuture = new CompletableFuture<>();
+ if (world == null) {
+ bigFuture.complete(null);
+ return bigFuture;
+ }
new BukkitRunnable() {
private int chunkX = di.getMinXChunk();
private int chunkZ = di.getMinZChunk();
diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintCopyCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintCopyCommandTest.java
index cdcbe9bea..af3d086cd 100644
--- a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintCopyCommandTest.java
+++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintCopyCommandTest.java
@@ -47,13 +47,15 @@
@PrepareForTest({Bukkit.class, BentoBox.class, User.class })
public class AdminBlueprintCopyCommandTest {
+ @Mock
+ private BentoBox plugin;
@Mock
private AdminBlueprintCommand ac;
@Mock
private GameModeAddon addon;
@Mock
private User user;
- @Mock
+
private BlueprintClipboard clip;
private UUID uuid = UUID.randomUUID();
@Mock
@@ -64,10 +66,12 @@ public class AdminBlueprintCopyCommandTest {
*/
@Before
public void setUp() throws Exception {
- // Set up plugin
- BentoBox plugin = mock(BentoBox.class);
+ // Set up plugin // Set up plugin
+ // Required for NamespacedKey
+ when(plugin.getName()).thenReturn("BentoBox");
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+ clip = mock(BlueprintClipboard.class);
// Blueprints Manager
when(plugin.getBlueprintsManager()).thenReturn(bm);
diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java
index 284028a36..64c5963bc 100644
--- a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java
+++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintLoadCommandTest.java
@@ -76,6 +76,8 @@ public static void beforeClass() {
@Before
public void setUp() throws Exception {
+ // Required for NamespacedKey
+ when(plugin.getName()).thenReturn("BentoBox");
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java
index ac5386a6c..a8d382fc4 100644
--- a/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java
+++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/blueprints/AdminBlueprintSaveCommandTest.java
@@ -55,6 +55,8 @@
@PrepareForTest({Bukkit.class, BentoBox.class, User.class })
public class AdminBlueprintSaveCommandTest {
+ @Mock
+ private BentoBox plugin;
private AdminBlueprintSaveCommand absc;
@Mock
private AdminBlueprintCommand ac;
@@ -76,8 +78,8 @@ public static void beforeClass() {
@Before
public void setUp() throws Exception {
- // Set up plugin
- BentoBox plugin = mock(BentoBox.class);
+ // Required for NamespacedKey
+ when(plugin.getName()).thenReturn("BentoBox");
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
diff --git a/src/test/java/world/bentobox/bentobox/blueprints/BlueprintClipboardTest.java b/src/test/java/world/bentobox/bentobox/blueprints/BlueprintClipboardTest.java
index 861b0f8be..b951aa4e8 100644
--- a/src/test/java/world/bentobox/bentobox/blueprints/BlueprintClipboardTest.java
+++ b/src/test/java/world/bentobox/bentobox/blueprints/BlueprintClipboardTest.java
@@ -58,6 +58,8 @@ public class BlueprintClipboardTest {
*/
@Before
public void setUp() throws Exception {
+ // Required for NamespacedKey
+ when(plugin.getName()).thenReturn("BentoBox");
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
diff --git a/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java
index d6e4fc354..390257852 100644
--- a/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java
+++ b/src/test/java/world/bentobox/bentobox/managers/BlueprintClipboardManagerTest.java
@@ -57,7 +57,7 @@ public class BlueprintClipboardManagerTest {
@Mock
private BentoBox plugin;
- @Mock
+
private BlueprintClipboard clipboard;
private File blueprintFolder;
@@ -129,15 +129,19 @@ private void zip(File targetFile) throws IOException {
*/
@Before
public void setUp() throws Exception {
+ // Set up plugin
+ // Required for NamespacedKey
+ when(plugin.getName()).thenReturn("BentoBox");
+ Whitebox.setInternalState(BentoBox.class, "instance", plugin);
+
+ clipboard = mock(BlueprintClipboard.class);
+
server = ServerMocks.newServer();
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);
blueprintFolder = new File("blueprints");
// Clear any residual files
tearDown();
- // Set up plugin
- BentoBox plugin = mock(BentoBox.class);
- Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Hooks
HooksManager hooksManager = mock(HooksManager.class);
when(hooksManager.getHook(anyString())).thenReturn(Optional.empty());
From f4060254962c459d246ff4d1b2499d4ad70f352c Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 28 Dec 2024 15:03:38 -0800
Subject: [PATCH 19/24] Remove this for now
---
.../bentobox/hooks/FancyHologramsHook.java | 35 -------------------
1 file changed, 35 deletions(-)
delete mode 100644 src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
diff --git a/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java b/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
deleted file mode 100644
index 650e39133..000000000
--- a/src/main/java/world/bentobox/bentobox/hooks/FancyHologramsHook.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package world.bentobox.bentobox.hooks;
-
-import org.bukkit.Material;
-
-import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.api.hooks.Hook;
-
-/**
- * Provides copy and pasting of FancyHolograms in blueprints
- *
- * @author tastybento
- * @since 3.2.0
- */
-public class FancyHologramsHook extends Hook {
-
- public FancyHologramsHook() {
- super("FancyHolograms", Material.END_PORTAL);
- }
-
-
- @Override
- public boolean hook() {
- boolean hooked = this.isPluginAvailable();
- if (!hooked) {
- BentoBox.getInstance().logError("Could not hook into FancyHolograms");
- }
- return hooked; // The hook process shouldn't fail
- }
-
- @Override
- public String getFailureCause() {
- return null; // The hook process shouldn't fail
- }
-
-}
From c7d0095905646b5d99757eb2fecf30a60d497e90 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 29 Dec 2024 09:15:37 -0800
Subject: [PATCH 20/24] Update to Java 21
---
pom.xml | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/pom.xml b/pom.xml
index 3198bfad0..d5e5030f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,7 +59,7 @@
UTF-8
UTF-8
- 17
+ 21
2.0.9
@@ -161,12 +161,6 @@
papermc
https://repo.papermc.io/repository/maven-public/
-
-
- maven-snapshots
- https://repository.apache.org/content/repositories/snapshots/
-
minecraft-repo
https://libraries.minecraft.net/
@@ -548,7 +542,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.4.0
+ 3.6.0
true
${project.build.directory}/dependency-reduced-pom.xml
From f718b9be4b2d36d0d59e6097eebffa639afe2655 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 29 Dec 2024 09:17:09 -0800
Subject: [PATCH 21/24] Version 3.2.0
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index d5e5030f5..e580a33b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
-LOCAL
- 3.1.2
+ 3.2.0
bentobox-world
https://sonarcloud.io
${project.basedir}/lib
From 00d0735079477e62dbc88ea6d7fd9ef06d994642 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 29 Dec 2024 09:29:59 -0800
Subject: [PATCH 22/24] Abstract out all PaperLib so that it only exists in
Util class.
---
.../listeners/flags/protection/LockAndBanListener.java | 4 ++--
.../world/bentobox/bentobox/managers/IslandsManager.java | 5 ++---
.../world/bentobox/bentobox/nms/CopyWorldRegenerator.java | 7 ++++---
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
index 6a41cb2ca..9295eb8a7 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/LockAndBanListener.java
@@ -13,11 +13,11 @@
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
-import io.papermc.lib.PaperLib;
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.Util;
/**
* Listener for the lock flag
@@ -164,7 +164,7 @@ private void eject(Player player) {
// We'll try to teleport him to the spawn...
Location l = player.getWorld().getSpawnLocation();
if (l != null) {
- PaperLib.teleportAsync(player, l);
+ Util.teleportAsync(player, l);
}
// Switch him back to the default gamemode. He may die, sorry :(
diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
index 53c25b4ba..0e63adaa9 100644
--- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
+++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
@@ -40,7 +40,6 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.IslandBaseEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
@@ -1080,7 +1079,7 @@ private CompletableFuture homeTeleportAsync(@NonNull World world, @NonN
.ifFail(() -> goingHome.remove(user.getUniqueId())).buildFuture().thenAccept(result::complete);
return;
}
- PaperLib.teleportAsync(Objects.requireNonNull(player), home).thenAccept(b -> {
+ Util.teleportAsync(Objects.requireNonNull(player), home).thenAccept(b -> {
// Only run the commands if the player is successfully teleported
if (Boolean.TRUE.equals(b)) {
teleported(world, user, name, newIsland, island);
@@ -1469,7 +1468,7 @@ public void removePlayersFromIsland(Island island) {
} else {
// Move player to spawn
getSpawn(w).map(i -> i.getSpawnPoint(w.getEnvironment())).filter(Objects::nonNull)
- .ifPresentOrElse(sp -> PaperLib.teleportAsync(p, sp),
+ .ifPresentOrElse(sp -> Util.teleportAsync(p, sp),
() -> plugin.logWarning("Spawn exists but its location is null!"));
}
diff --git a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
index 4be154439..5affe938b 100644
--- a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
+++ b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
@@ -48,6 +48,7 @@
import world.bentobox.bentobox.hooks.SlimefunHook;
import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
import world.bentobox.bentobox.util.MyBiomeGrid;
+import world.bentobox.bentobox.util.Util;
/**
* Regenerates by using a seed world. The seed world is created using the same generator as the game
@@ -148,7 +149,7 @@ private CompletableFuture regenerateChunk(@Nullable IslandDeletion di, @No
CompletableFuture seedWorldFuture = getSeedWorldChunk(world, chunkX, chunkZ);
// Set up a future to get the chunk requests using Paper's Lib. If Paper is used, this should be done async
- CompletableFuture chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ);
+ CompletableFuture chunkFuture = Util.getChunkAtAsync(world, chunkX, chunkZ);
// If there is no island, do not clean chunk
CompletableFuture cleanFuture = di != null ? cleanChunk(chunkFuture, di) : CompletableFuture.completedFuture(null);
@@ -172,7 +173,7 @@ private CompletableFuture regenerateChunk(@Nullable IslandDeletion di, @No
private CompletableFuture getSeedWorldChunk(World world, int chunkX, int chunkZ) {
World seed = Bukkit.getWorld(world.getName() + "/bentobox");
if (seed == null) return CompletableFuture.completedFuture(null);
- return PaperLib.getChunkAtAsync(seed, chunkX, chunkZ);
+ return Util.getChunkAtAsync(seed, chunkX, chunkZ);
}
/**
@@ -374,7 +375,7 @@ private boolean isEnded(int chunkX) {
@SuppressWarnings("deprecation")
private CompletableFuture regenerateChunk(GameModeAddon gm, IslandDeletion di, @Nonnull World world,
int chunkX, int chunkZ) {
- CompletableFuture chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ);
+ CompletableFuture chunkFuture = Util.getChunkAtAsync(world, chunkX, chunkZ);
CompletableFuture invFuture = chunkFuture.thenAccept(chunk ->
Arrays.stream(chunk.getTileEntities()).filter(InventoryHolder.class::isInstance)
.filter(te -> di.inBounds(te.getLocation().getBlockX(), te.getLocation().getBlockZ()))
From 1fa2849053055424fe3e3a7c71a89f258b7cf514 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 29 Dec 2024 09:36:09 -0800
Subject: [PATCH 23/24] Adjust POM
---
pom.xml | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/pom.xml b/pom.xml
index e580a33b8..1e46541fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -233,6 +233,13 @@
4.2.2
test
+
+
+ io.papermc.paper
+ paper-api
+ ${paper.version}
+ provided
+
org.spigotmc
@@ -357,13 +364,6 @@
org.eclipse.jdt.annotation
2.2.600
-
-
- io.papermc
- paperlib
- 1.0.6
- compile
-
com.github.apachezy
From 4a55ea790eddb96f8f59e6a47c113a3d06e4df49 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 29 Dec 2024 13:40:10 -0800
Subject: [PATCH 24/24] Works on Paper and Spigot. Tests are a mess and won't
compile or run
TODO: Get test working in Paper-land.
Relates to ##2577
---
.../bentobox/bentobox/api/hooks/NPCHook.java | 2 -
.../bentobox/hooks/FancyNpcsHook.java | 1 -
.../bentobox/managers/IslandsManager.java | 1 -
.../bentobox/managers/island/NewIsland.java | 2 +-
.../bentobox/nms/CopyWorldRegenerator.java | 2 +-
.../world/bentobox/bentobox/util/Util.java | 131 +++++++-----------
.../team/IslandTeamInviteCommandTest.java | 3 +-
.../adapters/ItemStackTypeAdapterTest.java | 3 +-
.../protection/BreakBlocksListenerTest.java | 2 +-
.../InvincibleVisitorsListenerTest.java | 2 +-
.../bentobox/managers/IslandsManagerTest.java | 12 +-
.../bentobox/managers/PlayersManagerTest.java | 2 +-
.../bentobox/bentobox/mocks/ServerMocks.java | 19 ++-
.../panels/BlueprintManagementPanelTest.java | 2 +-
.../customizable/IslandCreationPanelTest.java | 10 +-
.../customizable/LanguagePanelTest.java | 2 +-
16 files changed, 88 insertions(+), 108 deletions(-)
diff --git a/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java b/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
index 6a848215f..fdcbca181 100644
--- a/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
+++ b/src/main/java/world/bentobox/bentobox/api/hooks/NPCHook.java
@@ -12,8 +12,6 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import de.oliver.fancynpcs.api.Npc;
-import lol.pyr.znpcsplus.api.npc.NpcEntry;
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
/**
diff --git a/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java b/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
index c8c375f12..528289e24 100644
--- a/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
+++ b/src/main/java/world/bentobox/bentobox/hooks/FancyNpcsHook.java
@@ -30,7 +30,6 @@
import de.oliver.fancynpcs.api.actions.NpcAction;
import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot;
import de.oliver.fancynpcs.api.utils.SkinFetcher;
-import lol.pyr.znpcsplus.api.npc.NpcEntry;
import net.kyori.adventure.text.format.NamedTextColor;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.hooks.NPCHook;
diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
index 0e63adaa9..30037e739 100644
--- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
+++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java
@@ -1191,7 +1191,6 @@ public void spawnTeleport(@NonNull World world, @NonNull Player player) {
*
* @param player player
*/
- @SuppressWarnings("deprecation")
private void readyPlayer(@NonNull Player player) {
// Stop any gliding
player.setGliding(false);
diff --git a/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java b/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java
index 198e8950c..59aec708d 100644
--- a/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java
+++ b/src/main/java/world/bentobox/bentobox/managers/island/NewIsland.java
@@ -15,9 +15,9 @@
import world.bentobox.bentobox.api.events.island.IslandCreateEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent;
import world.bentobox.bentobox.api.events.island.IslandEvent.Reason;
+import world.bentobox.bentobox.api.events.island.IslandResetEvent;
import world.bentobox.bentobox.api.logs.LogEntry;
import world.bentobox.bentobox.api.logs.LogEntry.LogType;
-import world.bentobox.bentobox.api.events.island.IslandResetEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.BlueprintsManager;
diff --git a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
index 5affe938b..dec80a8e3 100644
--- a/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
+++ b/src/main/java/world/bentobox/bentobox/nms/CopyWorldRegenerator.java
@@ -38,7 +38,6 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import io.papermc.lib.PaperLib;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.hooks.Hook;
@@ -248,6 +247,7 @@ private void copyChunkDataToChunk(Chunk toChunk, Chunk fromChunk, BoundingBox li
Arrays.stream(fromChunk.getTileEntities()).forEach(bs -> processTileEntity(bs.getBlock(), bs.getLocation().toVector().toLocation(toChunk.getWorld()).getBlock()));
}
+ @SuppressWarnings("deprecation")
private void processEntity(Entity entity, Location location) {
Entity bpe = location.getWorld().spawnEntity(location, entity.getType());
bpe.setCustomName(entity.getCustomName());
diff --git a/src/main/java/world/bentobox/bentobox/util/Util.java b/src/main/java/world/bentobox/bentobox/util/Util.java
index 3cf2fac55..4aa1ccc1f 100644
--- a/src/main/java/world/bentobox/bentobox/util/Util.java
+++ b/src/main/java/world/bentobox/bentobox/util/Util.java
@@ -1,6 +1,7 @@
package world.bentobox.bentobox.util;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -26,7 +27,6 @@
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.attribute.Attribute;
-import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Allay;
import org.bukkit.entity.Animals;
@@ -51,8 +51,6 @@
import com.google.common.base.Enums;
import com.google.common.base.Optional;
-import io.papermc.lib.PaperLib;
-import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.nms.PasteHandler;
@@ -382,7 +380,7 @@ public static boolean isTamableEntity(Entity entity) {
*/
@NonNull
public static CompletableFuture teleportAsync(@Nonnull Entity entity, @Nonnull Location location) {
- return PaperLib.teleportAsync(entity, location);
+ return teleportAsync(entity, location, TeleportCause.UNKNOWN);
}
/**
@@ -392,12 +390,26 @@ public static CompletableFuture teleportAsync(@Nonnull Entity entity, @
* @param cause The cause for the teleportation
* @return Future that completes with the result of the teleport
*/
+ @SuppressWarnings("unchecked")
@NonNull
public static CompletableFuture teleportAsync(@Nonnull Entity entity, @Nonnull Location location,
TeleportCause cause) {
- return PaperLib.teleportAsync(entity, location, cause);
+ try {
+ // Use reflection to check if the method exists
+ Method method = Entity.class.getMethod("teleportAsync", Location.class, TeleportCause.class);
+ if (method != null) {
+ // Invoke the method using reflection on the entity instance
+ return (CompletableFuture) method.invoke(entity, location, cause);
+ }
+ } catch (NoSuchMethodException e) {
+ // Method does not exist, fallback to Spigot behavior
+ } catch (Exception e) {
+ plugin.logStacktrace(e); // Report other exceptions
+ }
+ // Fallback for Spigot servers
+ entity.teleport(location, cause);
+ return CompletableFuture.completedFuture(true);
}
-
/**
* Gets the chunk at the target location, loading it asynchronously if needed.
* @param loc Location to get chunk for
@@ -440,9 +452,24 @@ public static CompletableFuture getChunkAtAsync(@Nonnull World world, int
* @param gen Should the chunk generate or not. Only respected on some MC versions, 1.13 for CB, 1.12 for Paper
* @return Future that completes with the chunk, or null if the chunk did not exists and generation was not requested.
*/
+ @SuppressWarnings("unchecked")
@NonNull
public static CompletableFuture getChunkAtAsync(@Nonnull World world, int x, int z, boolean gen) {
- return PaperLib.getChunkAtAsync(world, x, z, gen);
+ try {
+ // Use reflection to check if the method exists
+ Method method = World.class.getMethod("getChunkAtAsync", int.class, int.class, boolean.class);
+ if (method != null) {
+ // Invoke the method using reflection
+ return (CompletableFuture) method.invoke(world, x, z, gen);
+ }
+ } catch (NoSuchMethodException e) {
+ // Method does not exist, fallback to Spigot behavior
+ } catch (Exception e) {
+ e.printStackTrace(); // Handle other exceptions (optional)
+ }
+ // Fallback for Spigot servers
+ return CompletableFuture.completedFuture(world.getChunkAt(x, z, gen));
+
}
/**
@@ -462,56 +489,7 @@ public static boolean isChunkGenerated(@NonNull Location loc) {
* @return If the chunk is generated or not
*/
public static boolean isChunkGenerated(@Nonnull World world, int x, int z) {
- return PaperLib.isChunkGenerated(world, x, z);
- }
-
- /**
- * Get's a BlockState, optionally not using a snapshot
- * @param block The block to get a State of
- * @param useSnapshot Whether or not to use a snapshot when supported
- * @return The BlockState
- */
- @NonNull
- public static BlockStateSnapshotResult getBlockState(@Nonnull Block block, boolean useSnapshot) {
- return PaperLib.getBlockState(block, useSnapshot);
- }
-
- /**
- * Detects if the current MC version is at least the following version.
- *
- * Assumes 0 patch version.
- *
- * @param minor Min Minor Version
- * @return Meets the version requested
- */
- public static boolean isVersion(int minor) {
- return PaperLib.isVersion(minor);
- }
-
- /**
- * Detects if the current MC version is at least the following version.
- * @param minor Min Minor Version
- * @param patch Min Patch Version
- * @return Meets the version requested
- */
- public static boolean isVersion(int minor, int patch) {
- return PaperLib.isVersion(minor, patch);
- }
-
- /**
- * Gets the current Minecraft Minor version. IE: 1.13.1 returns 13
- * @return The Minor Version
- */
- public static int getMinecraftVersion() {
- return PaperLib.getMinecraftVersion();
- }
-
- /**
- * Gets the current Minecraft Patch version. IE: 1.13.1 returns 1
- * @return The Patch Version
- */
- public static int getMinecraftPatchVersion() {
- return PaperLib.getMinecraftPatchVersion();
+ return world.isChunkGenerated(x, z);
}
/**
@@ -562,42 +540,26 @@ public static boolean isVersionCompatible(String version, String requiredVersion
return !(!isRequiredSnapshot && isVersionSnapshot);
}
- /**
- * Check if the server has access to the Spigot API
- * @return True for Spigot and Paper environments
- */
- public static boolean isSpigot() {
- return PaperLib.isSpigot();
- }
-
/**
* Check if the server has access to the Paper API
* @return True for Paper environments
*/
public static boolean isPaper() {
- return !isJUnitTest() && PaperLib.isPaper();
- }
-
- /**
- * I don't like doing this, but otherwise we need to set a flag in every test
- */
- private static boolean isJUnitTest() {
- StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
- for (StackTraceElement element : stackTrace) {
- if (element.getClassName().startsWith("org.junit.")) {
- return true;
- }
+ try {
+ Class.forName("com.destroystokyo.paper.PaperConfig");
+ return true; // Paper-specific class exists
+ } catch (ClassNotFoundException e) {
+ return false; // Not a Paper server
}
- return false;
}
-
/**
* This method translates color codes in given string and strips whitespace after them.
* This code parses both: hex and old color codes.
* @param textToColor Text which color codes must be parsed.
* @return String text with parsed colors and stripped whitespaces after them.
*/
+ @SuppressWarnings("deprecation")
@NonNull
public static String translateColorCodes(@NonNull String textToColor) {
// Use matcher to find hex patterns in given text.
@@ -760,8 +722,14 @@ public static void runCommands(User user, String ownerName, @NonNull List