From 6017a09a03a3b16d5a5482f66e22b0321ff49908 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 22 Dec 2024 08:05:20 -0800
Subject: [PATCH 1/7] 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 Repositoryhttps://repo.fancyplugins.de/releases
+
+
+ pyr-snapshots
+ Pyr's Repo
+ https://repo.pyr.lol/snapshots
+
@@ -406,6 +412,18 @@
2.4.0provided
+
+
+ lol.pyr
+ znpcsplus-api
+ 2.0.0-SNAPSHOT
+ provided
+
+
+ lol.pyr
+ ZNPCsPlus
+ 1.0.7
+
@@ -454,11 +472,11 @@
org.apache.maven.pluginsmaven-surefire-plugin
- 3.0.0-M5
+ 3.5.2classes
- 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 2/7] 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 class ZNPCSPlusHook extends Hook {
NpcType type = npc.getType();
for (EntityProperty> property : npc.getAppliedProperties())
try {
- property.toString();
PropertySerializer> serializer = propertyRegistry
.getSerializer(((EntityPropertyImpl>) property).getType());
if (serializer == null) {
From 180ccd9f5eaf373a0026babcab640383eaec3e79 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Thu, 26 Dec 2024 09:17:07 -0800
Subject: [PATCH 3/7] 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.BlueprintCreatureSpawner;
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 class BlueprintClipboard {
}
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 @@ public class BlueprintClipboard {
// 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 @@ public class BlueprintPaster {
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 @@ package world.bentobox.bentobox.hooks;
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 lol.pyr.znpcsplus.util.NpcLocation;
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 @@ import world.bentobox.bentobox.blueprints.dataobjects.BlueprintEntity;
*/
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 class ZNPCsPlusHook extends Hook {
String result = NpcApiProvider.get().getNpcSerializerRegistry().getSerializer(YamlConfiguration.class)
.serialize(entry)
.saveToString();
- BentoBox.getInstance().logDebug(result);
return result;
}
@@ -48,6 +54,7 @@ public class ZNPCsPlusHook extends Hook {
NpcLocation loc = new NpcLocation(pos);
entry.getNpc().setLocation(loc);
NpcApiProvider.get().getNpcRegistry().register(entry);
+
return true;
}
@@ -56,7 +63,9 @@ public class ZNPCsPlusHook extends 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 class ZNPCsPlusHook extends 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.blueprints.dataobjects.BlueprintEntity;
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 class DefaultPasteUtil {
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 class DefaultPasteUtil {
* @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 @@ public class DefaultPasteUtil {
// 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 @@ public class DefaultPasteUtil {
// 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 class Util {
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.
+ *
+ *