Skip to content

Commit

Permalink
Merge pull request #2575 from BentoBoxWorld/2569_znpc_plus_hook
Browse files Browse the repository at this point in the history
2569 znpc plus hook
  • Loading branch information
tastybento authored Dec 26, 2024
2 parents 212166e + 945670b commit 6673d46
Show file tree
Hide file tree
Showing 12 changed files with 486 additions and 15 deletions.
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@
<name>FancyPlugins Repository</name>
<url>https://repo.fancyplugins.de/releases</url>
</repository>
<!-- ZNPCsPlus-->
<repository>
<id>pyr-snapshots</id>
<name>Pyr's Repo</name>
<url>https://repo.pyr.lol/snapshots</url>
</repository>
</repositories>

<dependencies>
Expand Down Expand Up @@ -406,6 +412,13 @@
<version>2.4.0</version>
<scope>provided</scope>
</dependency>
<!-- ZNPCs Plus -->
<dependency>
<groupId>lol.pyr</groupId>
<artifactId>znpcsplus-api</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/world/bentobox/bentobox/BentoBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
import world.bentobox.bentobox.api.hooks.Hook;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.Notifier;
import world.bentobox.bentobox.api.user.User;
Expand All @@ -33,6 +32,7 @@
import world.bentobox.bentobox.hooks.MythicMobsHook;
import world.bentobox.bentobox.hooks.SlimefunHook;
import world.bentobox.bentobox.hooks.VaultHook;
import world.bentobox.bentobox.hooks.ZNPCsPlusHook;
import world.bentobox.bentobox.hooks.placeholders.PlaceholderAPIHook;
import world.bentobox.bentobox.listeners.BannedCommands;
import world.bentobox.bentobox.listeners.BlockEndDragon;
Expand Down Expand Up @@ -196,6 +196,8 @@ private void completeSetup(long loadTime) {

// FancyNpcs
hooksManager.registerHook(new FancyNpcsHook());
// ZNPCsPlus
hooksManager.registerHook(new ZNPCsPlusHook());

// MythicMobs
hooksManager.registerHook(new MythicMobsHook());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -71,6 +72,7 @@ public class BlueprintClipboard {
private final BentoBox plugin = BentoBox.getInstance();
private Optional<MythicMobsHook> mmh;
private Optional<FancyNpcsHook> npc;
private Optional<ZNPCsPlusHook> znpc;

/**
* Create a clipboard for blueprint
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -143,6 +148,9 @@ private void copyAsync(World world, User user, List<Vector> 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, () -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ private void pasteEntities(Bits bits, int count, Optional<User> 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<BlueprintEntity> entities = entry.getValue();
entityMap.put(center, entities);
count++;
Expand Down
104 changes: 104 additions & 0 deletions src/main/java/world/bentobox/bentobox/hooks/ZNPCsPlusHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package world.bentobox.bentobox.hooks;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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 lol.pyr.znpcsplus.api.NpcApiProvider;
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.blueprints.dataobjects.BlueprintEntity;
import world.bentobox.bentobox.util.Util;

/**
* 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 static final String VERSION = "2.0.0-SNAPSHOT"; // Minimum version required

public ZNPCsPlusHook() {
super("ZNPCsPlus", Material.PLAYER_HEAD);
}

public String serializeNPC(NpcEntry entry, Vector origin) {
String result = NpcApiProvider.get().getNpcSerializerRegistry().getSerializer(YamlConfiguration.class)
.serialize(entry)
.saveToString();
return result;
}

public boolean spawnNpc(String yaml, Location pos) throws InvalidConfigurationException {
YamlConfiguration yaml2 = new YamlConfiguration();
yaml2.loadFromString(yaml);
NpcEntry entry = NpcApiProvider.get().getNpcSerializerRegistry().getSerializer(YamlConfiguration.class)
.deserialize(yaml2);
NpcLocation loc = new NpcLocation(pos);
entry.getNpc().setLocation(loc);
NpcApiProvider.get().getNpcRegistry().register(entry);

return true;
}

@Override
public boolean hook() {
boolean hooked = this.isPluginAvailable();
// Check version
String version = this.getPlugin().getDescription().getVersion();
if (!Util.isVersionCompatible(version, VERSION)) {
return false;
}
if (!hooked) {
BentoBox.getInstance().logError("Could not hook into FancyNpcs");
}
return hooked;
}

@Override
public String getFailureCause() {
// 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<BlueprintEntity>> getNpcsInArea(World world, List<Vector> vectorsToCopy,
@Nullable Vector origin) {
Map<Vector, List<BlueprintEntity>> bpEntities = new HashMap<>();

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.setNpc(this.serializeNPC(npcEntry, origin));
// Retrieve or create the list of entities and add this one
List<BlueprintEntity> entities = bpEntities.getOrDefault(loc, new ArrayList<>());
entities.add(cit);
// 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 = 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
}
}
return bpEntities;
}
}
24 changes: 21 additions & 3 deletions src/main/java/world/bentobox/bentobox/util/DefaultPasteUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -176,8 +177,8 @@ public static void setSpawner(CreatureSpawner spawner, BlueprintCreatureSpawner
public static CompletableFuture<Void> setEntity(Island island, Location location, List<BlueprintEntity> 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)));
}

/**
Expand All @@ -188,7 +189,7 @@ public static CompletableFuture<Void> 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 {
Expand All @@ -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")
Expand All @@ -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();
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/world/bentobox/bentobox/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,54 @@ public static int getMinecraftPatchVersion() {
return PaperLib.getMinecraftPatchVersion();
}

/**
* Checks if the given version is compatible with the required version.
*
* <p>
* A version is considered compatible if:
* <ul>
* <li>The major, minor, and patch components of the given version are greater than or equal to those of the required version.</li>
* <li>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).</li>
* </ul>
* </p>
*
* @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.
*
* <p>
* Examples:
* <ul>
* <li>{@code isVersionCompatible("2.1.0", "2.0.0-SNAPSHOT")} returns {@code true}</li>
* <li>{@code isVersionCompatible("2.0.0", "2.0.0-SNAPSHOT")} returns {@code true}</li>
* <li>{@code isVersionCompatible("2.0.0-SNAPSHOT", "2.0.0")} returns {@code false}</li>
* <li>{@code isVersionCompatible("1.9.9", "2.0.0-SNAPSHOT")} returns {@code false}</li>
* </ul>
* </p>
*/
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 <em>and</em> Paper environments
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ softdepend:
- LuckPerms
- EconomyPlus
- MythicMobs
- ZNPCsPlus

libraries:
- mysql:mysql-connector-java:${mysql.version}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()}.
*/
Expand Down
Loading

0 comments on commit 6673d46

Please sign in to comment.