Merge remote-tracking branch 'upstream/2.X' into 2.X
This commit is contained in:
commit
e61ff12b4f
30 changed files with 514 additions and 361 deletions
|
@ -43,6 +43,14 @@ public interface PropertyHolder {
|
|||
*/
|
||||
void setItemProperty(EntityProperty<?> key, ItemStack value);
|
||||
|
||||
/**
|
||||
* Weird fix which is sadly required in order to not decrease performance
|
||||
* when using item properties, read https://github.com/Pyrbu/ZNPCsPlus/pull/129#issuecomment-1948777764
|
||||
*
|
||||
* @param key Unique key representing a property
|
||||
*/
|
||||
ItemStack getItemProperty(EntityProperty<?> key);
|
||||
|
||||
/**
|
||||
* Method used to get a set of all of the property keys that this holder has a value for
|
||||
*
|
||||
|
|
|
@ -41,4 +41,16 @@ public interface Hologram {
|
|||
* @return The number of lines in the hologram
|
||||
*/
|
||||
int lineCount();
|
||||
|
||||
/**
|
||||
* Gets the refresh delay of the hologram
|
||||
* @return The refresh delay of the hologram
|
||||
*/
|
||||
long getRefreshDelay();
|
||||
|
||||
/**
|
||||
* Sets the refresh delay of the hologram
|
||||
* @param delay The delay to set
|
||||
*/
|
||||
void setRefreshDelay(long delay);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package lol.pyr.znpcsplus.util;
|
||||
|
||||
public enum ArmadilloState {
|
||||
IDLE,
|
||||
ROLLING,
|
||||
SCARED,
|
||||
UNROLLING
|
||||
}
|
23
api/src/main/java/lol/pyr/znpcsplus/util/WoldVariant.java
Normal file
23
api/src/main/java/lol/pyr/znpcsplus/util/WoldVariant.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package lol.pyr.znpcsplus.util;
|
||||
|
||||
public enum WoldVariant {
|
||||
PALE(3),
|
||||
SPOTTED(6),
|
||||
SNOWY(5),
|
||||
BLACK(1),
|
||||
ASHEN(0),
|
||||
RUSTY(4),
|
||||
WOODS(8),
|
||||
CHESTNUT(2),
|
||||
STRIPED(7);
|
||||
|
||||
private final int id;
|
||||
|
||||
WoldVariant(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ plugins {
|
|||
|
||||
runServer {
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
minecraftVersion "1.20.4"
|
||||
minecraftVersion "1.20.6"
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -32,18 +32,17 @@ publishing {
|
|||
|
||||
dependencies {
|
||||
compileOnly "me.clip:placeholderapi:2.11.5" // Placeholder support
|
||||
compileOnly "com.google.code.gson:gson:2.10.1" // JSON parsing
|
||||
compileOnly "org.bstats:bstats-bukkit:3.0.2" // Plugin stats
|
||||
compileOnly "me.robertlit:SpigotResourcesAPI:2.0" // Spigot API wrapper for update checker
|
||||
compileOnly "com.github.retrooper.packetevents:spigot:2.3.0" // Packets
|
||||
compileOnly "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1" // Configs
|
||||
compileOnly "lol.pyr:director-adventure:2.1.1" // Commands
|
||||
implementation "com.google.code.gson:gson:2.10.1" // JSON parsing
|
||||
implementation "org.bstats:bstats-bukkit:3.0.2" // Plugin stats
|
||||
implementation "me.robertlit:SpigotResourcesAPI:2.0" // Spigot API wrapper for update checker
|
||||
implementation "com.github.retrooper.packetevents:spigot:2.3.0" // Packets
|
||||
implementation "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1" // Configs
|
||||
implementation "lol.pyr:director-adventure:2.1.1" // Commands
|
||||
|
||||
// Fancy text library
|
||||
compileOnly "net.kyori:adventure-platform-bukkit:4.3.2"
|
||||
compileOnly "net.kyori:adventure-text-minimessage:4.15.0"
|
||||
implementation "net.kyori:adventure-platform-bukkit:4.3.2"
|
||||
implementation "net.kyori:adventure-text-minimessage:4.15.0"
|
||||
|
||||
implementation "me.lucko:jar-relocator:1.7"
|
||||
implementation project(":api")
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ public class ZNpcsPlus {
|
|||
MojangSkinCache skinCache = new MojangSkinCache(configManager);
|
||||
EntityPropertyRegistryImpl propertyRegistry = new EntityPropertyRegistryImpl(skinCache, configManager);
|
||||
PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry, configManager);
|
||||
propertyRegistry.registerTypes(packetFactory, textSerializer);
|
||||
propertyRegistry.registerTypes(bootstrap, packetFactory, textSerializer);
|
||||
|
||||
ActionRegistry actionRegistry = new ActionRegistry();
|
||||
NpcTypeRegistryImpl typeRegistry = new NpcTypeRegistryImpl();
|
||||
|
@ -131,7 +131,7 @@ public class ZNpcsPlus {
|
|||
scheduler, packetFactory, textSerializer, typeRegistry, getDataFolder().getParentFile(),
|
||||
propertyRegistry, skinCache, npcRegistry, bungeeConnector);
|
||||
|
||||
log(ChatColor.WHITE + " * Registerring components...");
|
||||
log(ChatColor.WHITE + " * Registering components...");
|
||||
|
||||
bungeeConnector.registerChannel();
|
||||
shutdownTasks.add(bungeeConnector::unregisterChannel);
|
||||
|
@ -276,10 +276,13 @@ public class ZNpcsPlus {
|
|||
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, ArmadilloState.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, WoldVariant.class, incorrectUsageMessage);
|
||||
|
||||
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||
.addSubcommand("create", new CreateCommand(npcRegistry, typeRegistry))
|
||||
.addSubcommand("clone", new CloneCommand(npcRegistry))
|
||||
.addSubcommand("reloadconfig", new ReloadConfigCommand(configManager))
|
||||
.addSubcommand("toggle", new ToggleCommand(npcRegistry))
|
||||
.addSubcommand("skin", new SkinCommand(skinCache, npcRegistry, typeRegistry, propertyRegistry))
|
||||
|
|
|
@ -2,7 +2,6 @@ package lol.pyr.znpcsplus;
|
|||
|
||||
import lol.pyr.director.adventure.command.CommandContext;
|
||||
import lol.pyr.director.common.message.Message;
|
||||
import lol.pyr.znpcsplus.libraries.LibraryLoader;
|
||||
import lol.pyr.znpcsplus.util.FileUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
|
@ -32,55 +31,6 @@ public class ZNpcsPlusBootstrap extends JavaPlugin {
|
|||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
getLogger().info("Downloading and loading libraries, this might take a while if this is the first time you're launching the plugin");
|
||||
LibraryLoader loader = new LibraryLoader(this, new File(getDataFolder(), "libraries"));
|
||||
|
||||
loader.addRelocation(decrypt("org..bstats"), "lol.pyr.znpcsplus.libraries.bstats");
|
||||
loader.addRelocation(decrypt("me..robertlit..spigotresources"), "lol.pyr.znpcsplus.libraries.spigotresources");
|
||||
loader.addRelocation(decrypt("net..kyori"), "lol.pyr.znpcsplus.libraries.kyori");
|
||||
loader.addRelocation(decrypt("org..checkerframework"), "lol.pyr.znpcsplus.libraries.checkerframework");
|
||||
loader.addRelocation(decrypt("com..google"), "lol.pyr.znpcsplus.libraries.google");
|
||||
loader.addRelocation(decrypt("com..github..retrooper..packetevents"), "lol.pyr.znpcsplus.libraries.packetevents.api");
|
||||
loader.addRelocation(decrypt("io..github..retrooper..packetevents"), "lol.pyr.znpcsplus.libraries.packetevents.impl");
|
||||
loader.addRelocation(decrypt("org..yaml..snakeyaml"), "lol.pyr.znpcsplus.libraries.snakeyaml");
|
||||
loader.addRelocation(decrypt("space..arim..dazzleconf"), "lol.pyr.znpcsplus.libraries.dazzleconf");
|
||||
loader.addRelocation(decrypt("lol..pyr..director"), "lol.pyr.znpcsplus.libraries.command");
|
||||
|
||||
loader.loadLibrary(decrypt("com..google..guava"), "guava", "18.0");
|
||||
loader.loadLibrary(decrypt("com..google..code..gson"), "gson", "2.10.1");
|
||||
|
||||
loader.loadLibrary(decrypt("org..bstats"), "bstats-base", "3.0.2");
|
||||
loader.loadLibrary(decrypt("org..bstats"), "bstats-bukkit", "3.0.2");
|
||||
|
||||
loader.loadLibrary("me.robertlit", "SpigotResourcesAPI", "2.0", "https://repo.pyr.lol/releases");
|
||||
|
||||
loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "api", "2.3.0", "https://repo.codemc.io/repository/maven-releases/");
|
||||
loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "spigot", "2.3.0", "https://repo.codemc.io/repository/maven-releases/");
|
||||
|
||||
loader.loadLibrary(decrypt("space..arim..dazzleconf"), "dazzleconf-core", "1.2.1");
|
||||
loader.loadLibrary(decrypt("space..arim..dazzleconf"), "dazzleconf-ext-snakeyaml", "1.2.1");
|
||||
loader.loadLibrary("org.yaml", "snakeyaml", "1.33");
|
||||
|
||||
loader.loadLibrary("lol.pyr", "director-adventure", "2.1.1", "https://repo.pyr.lol/releases");
|
||||
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-api", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-key", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-nbt", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-platform-facet", "4.3.2");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-platform-api", "4.3.2");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-platform-bukkit", "4.3.2");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-minimessage", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-bungeecord", "4.3.2");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-gson", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-gson-legacy-impl", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-json", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-json-legacy-impl", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "adventure-text-serializer-legacy", "4.15.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "examination-api", "1.3.0");
|
||||
loader.loadLibrary(decrypt("net..kyori"), "examination-string", "1.3.0");
|
||||
loader.deleteUnloadedLibraries();
|
||||
|
||||
getLogger().info("Loaded " + loader.loadedLibraryCount() + " libraries!");
|
||||
zNpcsPlus = new ZNpcsPlus(this);
|
||||
}
|
||||
|
||||
|
@ -120,9 +70,4 @@ public class ZNpcsPlusBootstrap extends JavaPlugin {
|
|||
public boolean movedLegacy() {
|
||||
return legacy;
|
||||
}
|
||||
|
||||
// Ugly hack because of https://github.com/johnrengelman/shadow/issues/232
|
||||
private static String decrypt(String packageName) {
|
||||
return packageName.replace("..", ".");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package lol.pyr.znpcsplus.commands;
|
||||
|
||||
import lol.pyr.director.adventure.command.CommandContext;
|
||||
import lol.pyr.director.adventure.command.CommandHandler;
|
||||
import lol.pyr.director.common.command.CommandExecutionException;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CloneCommand implements CommandHandler {
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
|
||||
public CloneCommand(NpcRegistryImpl npcRegistry) {
|
||||
this.npcRegistry = npcRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(CommandContext context) throws CommandExecutionException {
|
||||
context.setUsage(context.getLabel() + " clone <id> <new id>");
|
||||
Player player = context.ensureSenderIsPlayer();
|
||||
|
||||
String id = context.popString();
|
||||
if (npcRegistry.getById(id) == null) context.halt(Component.text("NPC with ID " + id + " does not exist.", NamedTextColor.RED));
|
||||
String newId = context.popString();
|
||||
if (npcRegistry.getById(newId) != null) context.halt(Component.text("NPC with ID " + newId + " already exists.", NamedTextColor.RED));
|
||||
|
||||
npcRegistry.clone(id, newId, player.getWorld(), new NpcLocation(player.getLocation()));
|
||||
|
||||
context.send(Component.text("Cloned NPC with ID " + id + " to ID " + newId + ".", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import org.bukkit.entity.Player;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MoveCommand implements CommandHandler {
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
|
@ -27,7 +28,7 @@ public class MoveCommand implements CommandHandler {
|
|||
Player player = context.ensureSenderIsPlayer();
|
||||
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||
npc.setLocation(new NpcLocation(player.getLocation()));
|
||||
if (!npc.getWorld().equals(player.getWorld())) npc.setWorld(player.getWorld());
|
||||
if (!Objects.equals(npc.getWorld(), player.getWorld())) npc.setWorld(player.getWorld());
|
||||
context.send(Component.text("NPC moved to your current location.", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ import lol.pyr.znpcsplus.util.NpcLocation;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class NearCommand implements CommandHandler {
|
||||
|
@ -30,8 +32,11 @@ public class NearCommand implements CommandHandler {
|
|||
double radius = Math.pow(raw, 2);
|
||||
|
||||
List<NpcEntryImpl> entries = npcRegistry.getAllModifiable().stream()
|
||||
.filter(entry -> entry.getNpc().getWorld().equals(player.getWorld()))
|
||||
.filter(entry -> entry.getNpc().getBukkitLocation().distanceSquared(player.getLocation()) < radius)
|
||||
.filter(entry -> Objects.equals(entry.getNpc().getWorld(), player.getWorld()))
|
||||
.filter(entry -> {
|
||||
Location loc = entry.getNpc().getBukkitLocation();
|
||||
return loc != null && loc.distanceSquared(player.getLocation()) < radius;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (entries.isEmpty()) context.halt(Component.text("There are no npcs within " + raw + " blocks around you.", NamedTextColor.RED));
|
||||
|
|
|
@ -9,6 +9,7 @@ import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
|||
import lol.pyr.znpcsplus.util.FoliaUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -26,7 +27,9 @@ public class TeleportCommand implements CommandHandler {
|
|||
context.setUsage(context.getLabel() + " teleport <id>");
|
||||
Player player = context.ensureSenderIsPlayer();
|
||||
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||
FoliaUtil.teleport(player, npc.getBukkitLocation());
|
||||
Location location = npc.getBukkitLocation();
|
||||
if (location == null) context.halt("Unable to teleport to NPC, the world is not loaded!");
|
||||
FoliaUtil.teleport(player, location);
|
||||
context.send(Component.text("Teleported to NPC!", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import lol.pyr.znpcsplus.config.ConfigManager;
|
|||
import lol.pyr.znpcsplus.conversion.DataImporter;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTrait;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTraitsRegistry;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.traits.TypeTrait;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
|
@ -52,7 +53,7 @@ public class CitizensImporter implements DataImporter {
|
|||
this.propertyRegistry = propertyRegistry;
|
||||
this.skinCache = skinCache;
|
||||
this.dataFile = dataFile;
|
||||
this.traitsRegistry = new CitizensTraitsRegistry(typeRegistry, propertyRegistry, skinCache);
|
||||
this.traitsRegistry = new CitizensTraitsRegistry(propertyRegistry, skinCache, taskScheduler, textSerializer);
|
||||
this.npcRegistry = npcRegistry;
|
||||
}
|
||||
|
||||
|
@ -81,11 +82,12 @@ public class CitizensImporter implements DataImporter {
|
|||
world = Bukkit.getWorlds().get(0).getName();
|
||||
}
|
||||
NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, world, typeRegistry.getByName("armor_stand"), new NpcLocation(0, 0, 0, 0, 0));
|
||||
npc.getType().applyDefaultProperties(npc);
|
||||
|
||||
npc.getHologram().addTextLineComponent(textSerializer.deserialize(name));
|
||||
ConfigurationSection traits = npcSection.getConfigurationSection("traits");
|
||||
if (traits != null) {
|
||||
TypeTrait typeTrait = new TypeTrait(typeRegistry);
|
||||
npc = typeTrait.apply(npc, traits.getString("type"));
|
||||
npc.getType().applyDefaultProperties(npc);
|
||||
for (String traitName : traits.getKeys(false)) {
|
||||
Object trait = traits.get(traitName);
|
||||
CitizensTrait citizensTrait = traitsRegistry.getByName(traitName);
|
||||
|
@ -94,6 +96,10 @@ public class CitizensImporter implements DataImporter {
|
|||
}
|
||||
}
|
||||
}
|
||||
boolean nameVisible = Boolean.parseBoolean(npcSection.getString("metadata.name-visible", "true"));
|
||||
if (nameVisible) {
|
||||
npc.getHologram().addTextLineComponent(textSerializer.deserialize(name));
|
||||
}
|
||||
String id = key.toLowerCase();
|
||||
while (npcRegistry.getById(id) != null) {
|
||||
id += "_"; // TODO: make a backup of the old npc instead
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
package lol.pyr.znpcsplus.conversion.citizens.model;
|
||||
|
||||
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.traits.*;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CitizensTraitsRegistry {
|
||||
private final HashMap<String, CitizensTrait> traitMap = new HashMap<>();
|
||||
|
||||
public CitizensTraitsRegistry(NpcTypeRegistry typeRegistry, EntityPropertyRegistry propertyRegistry, MojangSkinCache skinCache) {
|
||||
public CitizensTraitsRegistry(EntityPropertyRegistry propertyRegistry, MojangSkinCache skinCache, TaskScheduler taskScheduler, LegacyComponentSerializer textSerializer) {
|
||||
register(new LocationTrait());
|
||||
register(new TypeTrait(typeRegistry));
|
||||
register(new ProfessionTrait(propertyRegistry));
|
||||
register(new VillagerTrait(propertyRegistry));
|
||||
register(new SkinTrait(propertyRegistry));
|
||||
register(new MirrorTrait(propertyRegistry, skinCache));
|
||||
register(new SkinLayersTrait(propertyRegistry));
|
||||
register(new LookTrait(propertyRegistry));
|
||||
register(new CommandTrait(taskScheduler));
|
||||
register(new HologramTrait(textSerializer));
|
||||
register(new EquipmentTrait(propertyRegistry));
|
||||
register(new SpawnedTrait());
|
||||
}
|
||||
|
||||
public CitizensTrait getByName(String name) {
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package lol.pyr.znpcsplus.conversion.citizens.model.traits;
|
||||
|
||||
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait;
|
||||
import lol.pyr.znpcsplus.interaction.InteractionActionImpl;
|
||||
import lol.pyr.znpcsplus.interaction.consolecommand.ConsoleCommandAction;
|
||||
import lol.pyr.znpcsplus.interaction.playercommand.PlayerCommandAction;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class CommandTrait extends SectionCitizensTrait {
|
||||
private final TaskScheduler scheduler;
|
||||
|
||||
public CommandTrait(TaskScheduler scheduler) {
|
||||
super("commandtrait");
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) {
|
||||
ConfigurationSection commands = section.getConfigurationSection("commands");
|
||||
if (commands != null) {
|
||||
Set<String> keys = commands.getKeys(false);
|
||||
if (keys != null) {
|
||||
for (String key : keys) {
|
||||
ConfigurationSection commandSection = commands.getConfigurationSection(key);
|
||||
String command = commandSection.getString("command");
|
||||
String hand = commandSection.getString("hand", "BOTH");
|
||||
InteractionType clickType = wrapClickType(hand);
|
||||
boolean isPlayerCommand = commandSection.getBoolean("player", true);
|
||||
int cooldown = commandSection.getInt("cooldown", 0);
|
||||
int delay = commandSection.getInt("delay", 0);
|
||||
if (command != null) {
|
||||
InteractionActionImpl action;
|
||||
if (isPlayerCommand) {
|
||||
action = new PlayerCommandAction(scheduler, command, clickType, cooldown, delay);
|
||||
} else {
|
||||
action = new ConsoleCommandAction(scheduler, command, clickType, cooldown, delay);
|
||||
}
|
||||
npc.addAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return npc;
|
||||
}
|
||||
|
||||
private InteractionType wrapClickType(String hand) {
|
||||
if (hand == null) {
|
||||
return InteractionType.ANY_CLICK;
|
||||
}
|
||||
switch (hand) {
|
||||
case "RIGHT":
|
||||
case "SHIFT_RIGHT":
|
||||
return InteractionType.RIGHT_CLICK;
|
||||
case "LEFT":
|
||||
case "SHIFT_LEFT":
|
||||
return InteractionType.LEFT_CLICK;
|
||||
case "BOTH":
|
||||
return InteractionType.ANY_CLICK;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package lol.pyr.znpcsplus.conversion.citizens.model.traits;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EquipmentTrait extends SectionCitizensTrait {
|
||||
private final EntityPropertyRegistry propertyRegistry;
|
||||
private final HashMap<String, EquipmentSlot> EQUIPMENT_SLOT_MAP = new HashMap<>();
|
||||
|
||||
public EquipmentTrait(EntityPropertyRegistry propertyRegistry) {
|
||||
super("equipment");
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
EQUIPMENT_SLOT_MAP.put("hand", EquipmentSlot.MAIN_HAND);
|
||||
EQUIPMENT_SLOT_MAP.put("offhand", EquipmentSlot.OFF_HAND);
|
||||
EQUIPMENT_SLOT_MAP.put("helmet", EquipmentSlot.HELMET);
|
||||
EQUIPMENT_SLOT_MAP.put("chestplate", EquipmentSlot.CHEST_PLATE);
|
||||
EQUIPMENT_SLOT_MAP.put("leggings", EquipmentSlot.LEGGINGS);
|
||||
EQUIPMENT_SLOT_MAP.put("boots", EquipmentSlot.BOOTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) {
|
||||
for (String key : section.getKeys(false)) {
|
||||
EquipmentSlot slot = EQUIPMENT_SLOT_MAP.get(key);
|
||||
if (slot == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemStack itemStack = parseItemStack(section.getConfigurationSection(key));
|
||||
if (itemStack == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityProperty<ItemStack> property = propertyRegistry.getByName(key, ItemStack.class);
|
||||
npc.setProperty(property, itemStack);
|
||||
}
|
||||
|
||||
return npc;
|
||||
}
|
||||
|
||||
private ItemStack parseItemStack(ConfigurationSection section) {
|
||||
Material material = null;
|
||||
if (section.isString("type_key")) {
|
||||
material = Material.getMaterial(section.getString("type_key").toUpperCase());
|
||||
} else if (section.isString("type")) {
|
||||
material = Material.matchMaterial(section.getString("type").toUpperCase());
|
||||
} else if (section.isString("id")) {
|
||||
material = Material.matchMaterial(section.getString("id").toUpperCase());
|
||||
}
|
||||
if (material == null || material == Material.AIR) {
|
||||
return null;
|
||||
}
|
||||
org.bukkit.inventory.ItemStack itemStack = new org.bukkit.inventory.ItemStack(material, section.getInt("amount", 1),
|
||||
(short) section.getInt("durability", section.getInt("data", 0)));
|
||||
if (section.isInt("mdata")) {
|
||||
//noinspection deprecation
|
||||
itemStack.getData().setData((byte) section.getInt("mdata"));
|
||||
}
|
||||
if (section.isConfigurationSection("enchantments")) {
|
||||
ConfigurationSection enchantments = section.getConfigurationSection("enchantments");
|
||||
itemStack.addUnsafeEnchantments(deserializeEnchantments(enchantments));
|
||||
}
|
||||
if (section.isConfigurationSection("meta")) {
|
||||
ItemMeta itemMeta = deserializeMeta(section.getConfigurationSection("meta"));
|
||||
if (itemMeta != null) {
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
}
|
||||
}
|
||||
return SpigotConversionUtil.fromBukkitItemStack(itemStack);
|
||||
}
|
||||
|
||||
private Map<Enchantment, Integer> deserializeEnchantments(ConfigurationSection section) {
|
||||
Map<Enchantment, Integer> enchantments = new HashMap<>();
|
||||
for (String key : section.getKeys(false)) {
|
||||
Enchantment enchantment = Enchantment.getByName(key);
|
||||
if (enchantment == null) {
|
||||
continue;
|
||||
}
|
||||
enchantments.put(enchantment, section.getInt(key));
|
||||
}
|
||||
return enchantments;
|
||||
}
|
||||
|
||||
private ItemMeta deserializeMeta(ConfigurationSection section) {
|
||||
if (section.isString("encoded-meta")) {
|
||||
byte[] raw = BaseEncoding.base64().decode(section.getString("encoded-meta"));
|
||||
try {
|
||||
BukkitObjectInputStream inp = new BukkitObjectInputStream(new ByteArrayInputStream(raw));
|
||||
ItemMeta meta = (ItemMeta) inp.readObject();
|
||||
inp.close();
|
||||
return meta;
|
||||
} catch (IOException | ClassNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package lol.pyr.znpcsplus.conversion.citizens.model.traits;
|
||||
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.SectionCitizensTrait;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HologramTrait extends SectionCitizensTrait {
|
||||
private final LegacyComponentSerializer textSerializer;
|
||||
|
||||
public HologramTrait(LegacyComponentSerializer textSerializer) {
|
||||
super("hologramtrait");
|
||||
this.textSerializer = textSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NpcImpl apply(NpcImpl npc, ConfigurationSection section) {
|
||||
ConfigurationSection linesSection = section.getConfigurationSection("lines");
|
||||
if (linesSection != null) {
|
||||
List<String> keys = new ArrayList<>(linesSection.getKeys(false));
|
||||
for (int i = keys.size() - 1; i >= 0; i--) {
|
||||
String line = linesSection.getConfigurationSection(keys.get(i)).getString("text");
|
||||
if (line != null) {
|
||||
Component component = textSerializer.deserialize(line);
|
||||
npc.getHologram().addTextLineComponent(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
return npc;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package lol.pyr.znpcsplus.conversion.citizens.model.traits;
|
||||
|
||||
import lol.pyr.znpcsplus.conversion.citizens.model.CitizensTrait;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SpawnedTrait extends CitizensTrait {
|
||||
|
||||
public SpawnedTrait() {
|
||||
super("spawned");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull NpcImpl apply(NpcImpl npc, Object value) {
|
||||
if (value != null) {
|
||||
npc.setEnabled((boolean) value);
|
||||
}
|
||||
return npc;
|
||||
}
|
||||
}
|
|
@ -157,6 +157,7 @@ public class ZNpcImporter implements DataImporter {
|
|||
|
||||
HologramImpl hologram = npc.getHologram();
|
||||
hologram.setOffset(model.getHologramHeight());
|
||||
Collections.reverse(model.getHologramLines());
|
||||
for (String raw : model.getHologramLines()) {
|
||||
Component line = textSerializer.deserialize(raw);
|
||||
hologram.addTextLineComponent(line);
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
|||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
|
@ -86,6 +87,8 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
registerEnumSerializer(RabbitType.class);
|
||||
registerEnumSerializer(AttachDirection.class);
|
||||
registerEnumSerializer(Sound.class);
|
||||
registerEnumSerializer(ArmadilloState.class);
|
||||
registerEnumSerializer(WoldVariant.class);
|
||||
|
||||
registerPrimitiveSerializers(Integer.class, Boolean.class, Double.class, Float.class, Long.class, Short.class, Byte.class, String.class);
|
||||
|
||||
|
@ -101,7 +104,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
*/
|
||||
}
|
||||
|
||||
public void registerTypes(PacketFactory packetFactory, LegacyComponentSerializer textSerializer) {
|
||||
public void registerTypes(ZNpcsPlusBootstrap plugin, PacketFactory packetFactory, LegacyComponentSerializer textSerializer) {
|
||||
ServerVersion ver = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
boolean legacyBooleans = ver.isOlderThan(ServerVersion.V_1_9);
|
||||
boolean legacyNames = ver.isOlderThan(ServerVersion.V_1_9);
|
||||
|
@ -124,6 +127,8 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
|
||||
register(new DummyProperty<>("permission_required", false));
|
||||
|
||||
register(new ForceBodyRotationProperty(plugin));
|
||||
|
||||
register(new DummyProperty<>("player_knockback", false));
|
||||
register(new DummyProperty<>("player_knockback_exempt_permission", String.class));
|
||||
register(new DummyProperty<>("player_knockback_distance", 0.4));
|
||||
|
@ -411,7 +416,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
register(new EncodedByteProperty<>("wolf_collar", DyeColor.BLUE, wolfIndex++, DyeColor::getDyeData));
|
||||
} else register(new EncodedIntegerProperty<>("wolf_collar", DyeColor.RED, wolfIndex++, Enum::ordinal));
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_16)) {
|
||||
register(new EncodedIntegerProperty<>("wolf_angry", false, wolfIndex, b -> b ? 1 : 0));
|
||||
register(new EncodedIntegerProperty<>("wolf_angry", false, wolfIndex++, b -> b ? 1 : 0));
|
||||
linkProperties("tamed", "sitting");
|
||||
}
|
||||
else {
|
||||
|
@ -634,6 +639,9 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
// Frog
|
||||
register(new EncodedIntegerProperty<>("frog_variant", FrogVariant.TEMPERATE, 17, Enum::ordinal, EntityDataTypes.FROG_VARIANT));
|
||||
|
||||
// Warden
|
||||
register(new EncodedIntegerProperty<>("warden_anger", 0, 16, b -> Math.min(150, Math.max(0, b))));
|
||||
|
||||
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
|
||||
|
||||
// Camel
|
||||
|
@ -643,6 +651,14 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
|
||||
// Sniffer
|
||||
register(new CustomTypeProperty<>("sniffer_state", 17, SnifferState.IDLING, EntityDataTypes.SNIFFER_STATE, state -> com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState.valueOf(state.name())));
|
||||
|
||||
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20_5)) return;
|
||||
// Armadillo
|
||||
register(new CustomTypeProperty<>("armadillo_state", 17, ArmadilloState.IDLE, EntityDataTypes.ARMADILLO_STATE, state ->
|
||||
com.github.retrooper.packetevents.protocol.entity.armadillo.ArmadilloState.valueOf(state.name())));
|
||||
|
||||
// Wolf
|
||||
register(new EncodedIntegerProperty<>("wolf_variant", WoldVariant.PALE, wolfIndex, WoldVariant::getId, EntityDataTypes.WOLF_VARIANT));
|
||||
}
|
||||
|
||||
private void registerSerializer(PropertySerializer<?> serializer) {
|
||||
|
|
|
@ -107,6 +107,11 @@ public class PacketEntity implements PropertyHolder {
|
|||
properties.setItemProperty(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemProperty(EntityProperty<?> key) {
|
||||
return properties.getItemProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityProperty<?>> getAppliedProperties() {
|
||||
return properties.getAppliedProperties();
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package lol.pyr.znpcsplus.entity.properties;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ForceBodyRotationProperty extends DummyProperty<Boolean> {
|
||||
private final ZNpcsPlusBootstrap plugin;
|
||||
|
||||
public ForceBodyRotationProperty(ZNpcsPlusBootstrap plugin) {
|
||||
super("force_body_rotation", false);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 2L);
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 6L);
|
||||
}
|
||||
}
|
|
@ -147,10 +147,12 @@ public class HologramImpl extends Viewable implements Hologram {
|
|||
for (HologramLine<?> line : lines) line.hide(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRefreshDelay() {
|
||||
return refreshDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRefreshDelay(long refreshDelay) {
|
||||
this.refreshDelay = refreshDelay;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lol.pyr.znpcsplus.hologram;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
|
@ -76,6 +77,12 @@ public class HologramLine<M> implements PropertyHolder {
|
|||
throw new UnsupportedOperationException("Can't set properties on a hologram line");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemStack getItemProperty(EntityProperty<?> key) {
|
||||
return SpigotConversionUtil.toBukkitItemStack(((EntityProperty<com.github.retrooper.packetevents.protocol.item.ItemStack>) key).getDefaultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityProperty<?>> getAppliedProperties() {
|
||||
return properties;
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
package lol.pyr.znpcsplus.libraries;
|
||||
|
||||
import me.lucko.jarrelocator.JarRelocator;
|
||||
import me.lucko.jarrelocator.Relocation;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class LibraryLoader {
|
||||
private final static Logger logger = Logger.getLogger("ZNPCsPlus Library Loader");
|
||||
|
||||
private final UrlClassLoaderAccess loaderAccess;
|
||||
private final File librariesFolder;
|
||||
private final Set<File> loadedLibraries = new HashSet<>();
|
||||
private final List<Relocation> relocationRules = new ArrayList<>();
|
||||
|
||||
public LibraryLoader(Plugin plugin, File librariesFolder) {
|
||||
loaderAccess = UrlClassLoaderAccess.create((URLClassLoader) plugin.getClass().getClassLoader());
|
||||
this.librariesFolder = librariesFolder;
|
||||
if (!librariesFolder.exists()) librariesFolder.mkdirs();
|
||||
}
|
||||
|
||||
public void deleteUnloadedLibraries() {
|
||||
File[] files = librariesFolder.listFiles();
|
||||
if (files == null) return;
|
||||
for (File file : files) if (!loadedLibraries.contains(file)) file.delete();
|
||||
}
|
||||
|
||||
public void addRelocation(String pre, String post) {
|
||||
relocationRules.add(new Relocation(pre, post));
|
||||
}
|
||||
|
||||
public void loadSnapshotLibrary(String groupId, String artifactId, String version, String snapshotVersion, String repoUrl) {
|
||||
try {
|
||||
loadLibrary(groupId + ":" + artifactId + ":" + version,
|
||||
getDependencyFile(groupId, artifactId, version),
|
||||
getSnapshotDependencyUrl(groupId, artifactId, version, snapshotVersion, repoUrl));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int loadedLibraryCount() {
|
||||
return loadedLibraries.size();
|
||||
}
|
||||
|
||||
public void loadLibrary(String groupId, String artifactId, String version) {
|
||||
loadLibrary(groupId, artifactId, version, "https://repo1.maven.org/maven2");
|
||||
}
|
||||
|
||||
public void loadLibrary(String groupId, String artifactId, String version, String repoUrl) {
|
||||
try {
|
||||
loadLibrary(groupId + ":" + artifactId + ":" + version,
|
||||
getDependencyFile(groupId, artifactId, version),
|
||||
getDependencyUrl(groupId, artifactId, version, repoUrl));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLibrary(String name, File file, URL url) {
|
||||
if (!file.exists()) {
|
||||
try (InputStream in = url.openStream()) {
|
||||
File temp = new File(file.getParentFile(), file.getName() + ".temp");
|
||||
Files.copy(in, temp.toPath());
|
||||
new JarRelocator(temp, file, relocationRules).run();
|
||||
temp.delete();
|
||||
// logger.info("Downloaded library " + name);
|
||||
} catch (IOException e) {
|
||||
logger.severe("Failed to download library " + name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
loaderAccess.addURL(file.toURI().toURL());
|
||||
loadedLibraries.add(file);
|
||||
// logger.info("Loaded library " + name);
|
||||
} catch (Exception e) {
|
||||
logger.severe("Failed to load library, plugin may not work correctly (" + name + ")");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private File getDependencyFile(String groupId, String artifactId, String version) {
|
||||
return new File(librariesFolder, groupId.replace(".", "-") + "-"
|
||||
+ artifactId.replace(".", "-") + "-"
|
||||
+ version.replace(".", "-") + ".jar");
|
||||
}
|
||||
|
||||
private static URL getDependencyUrl(String groupId, String artifactId, String version, String repoUrl) throws MalformedURLException {
|
||||
String url = repoUrl.endsWith("/") ? repoUrl : repoUrl + "/";
|
||||
url += groupId.replace(".", "/") + "/";
|
||||
url += artifactId + "/";
|
||||
url += version + "/";
|
||||
url += artifactId + "-" + version + ".jar";
|
||||
return new URL(url);
|
||||
}
|
||||
|
||||
private static URL getSnapshotDependencyUrl(String groupId, String artifactId, String version, String snapshotVersion, String repoUrl) throws MalformedURLException {
|
||||
String url = repoUrl.endsWith("/") ? repoUrl : repoUrl + "/";
|
||||
url += groupId.replace(".", "/") + "/";
|
||||
url += artifactId + "/";
|
||||
url += version + "/";
|
||||
url += artifactId + "-" + snapshotVersion + ".jar";
|
||||
return new URL(url);
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
package lol.pyr.znpcsplus.libraries;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides access to {@link URLClassLoader}#addURL.
|
||||
* From https://github.com/lucko/helper/blob/master/helper/src/main/java/me/lucko/helper/maven/URLClassLoaderAccess.java
|
||||
*/
|
||||
public abstract class UrlClassLoaderAccess {
|
||||
|
||||
/**
|
||||
* Creates a {@link UrlClassLoaderAccess} for the given class loader.
|
||||
*
|
||||
* @param classLoader the class loader
|
||||
* @return the access object
|
||||
*/
|
||||
static UrlClassLoaderAccess create(URLClassLoader classLoader) {
|
||||
if (Reflection.isSupported()) {
|
||||
return new Reflection(classLoader);
|
||||
} else if (Unsafe.isSupported()) {
|
||||
return new Unsafe(classLoader);
|
||||
} else {
|
||||
return Noop.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private final URLClassLoader classLoader;
|
||||
|
||||
protected UrlClassLoaderAccess(URLClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given URL to the class loader.
|
||||
*
|
||||
* @param url the URL to add
|
||||
*/
|
||||
public abstract void addURL(@Nonnull URL url);
|
||||
|
||||
/**
|
||||
* Accesses using reflection, not supported on Java 9+.
|
||||
*/
|
||||
private static class Reflection extends UrlClassLoaderAccess {
|
||||
private static final Method ADD_URL_METHOD;
|
||||
|
||||
static {
|
||||
Method addUrlMethod;
|
||||
try {
|
||||
addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addUrlMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
addUrlMethod = null;
|
||||
}
|
||||
ADD_URL_METHOD = addUrlMethod;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return ADD_URL_METHOD != null;
|
||||
}
|
||||
|
||||
Reflection(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@Nonnull URL url) {
|
||||
try {
|
||||
ADD_URL_METHOD.invoke(super.classLoader, url);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses using sun.misc.Unsafe, supported on Java 9+.
|
||||
*
|
||||
* @author Vaishnav Anil (https://github.com/slimjar/slimjar)
|
||||
*/
|
||||
private static class Unsafe extends UrlClassLoaderAccess {
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
sun.misc.Unsafe unsafe;
|
||||
try {
|
||||
Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
unsafe = (sun.misc.Unsafe) unsafeField.get(null);
|
||||
} catch (Throwable t) {
|
||||
unsafe = null;
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return UNSAFE != null;
|
||||
}
|
||||
|
||||
private final Collection<URL> unopenedURLs;
|
||||
private final Collection<URL> pathURLs;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Unsafe(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
|
||||
Collection<URL> unopenedURLs;
|
||||
Collection<URL> pathURLs;
|
||||
try {
|
||||
Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
|
||||
unopenedURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "unopenedUrls");
|
||||
pathURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "path");
|
||||
} catch (Throwable e) {
|
||||
unopenedURLs = null;
|
||||
pathURLs = null;
|
||||
}
|
||||
this.unopenedURLs = unopenedURLs;
|
||||
this.pathURLs = pathURLs;
|
||||
}
|
||||
|
||||
private static Object fetchField(final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
return UNSAFE.getObject(object, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@Nonnull URL url) {
|
||||
this.unopenedURLs.add(url);
|
||||
this.pathURLs.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Noop extends UrlClassLoaderAccess {
|
||||
private static final Noop INSTANCE = new Noop();
|
||||
|
||||
private Noop() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@Nonnull URL url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import org.bukkit.Location;
|
|||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -75,8 +76,10 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
return location;
|
||||
}
|
||||
|
||||
public Location getBukkitLocation() {
|
||||
return location.toBukkitLocation(getWorld());
|
||||
public @Nullable Location getBukkitLocation() {
|
||||
World world = getWorld();
|
||||
if (world == null) return null;
|
||||
return location.toBukkitLocation(world);
|
||||
}
|
||||
|
||||
public void setLocation(NpcLocation location) {
|
||||
|
@ -112,7 +115,7 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
public @Nullable World getWorld() {
|
||||
return Bukkit.getWorld(worldName);
|
||||
}
|
||||
|
||||
|
@ -133,6 +136,7 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
}
|
||||
|
||||
private <T> void UNSAFE_refreshProperty(EntityPropertyImpl<T> property) {
|
||||
if (!type.isAllowedProperty(property)) return;
|
||||
for (Player viewer : getViewers()) {
|
||||
List<EntityData> data = property.applyStandalone(viewer, entity, true);
|
||||
if (!data.isEmpty()) packetFactory.sendMetadata(viewer, entity, data);
|
||||
|
@ -164,6 +168,12 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
setProperty((EntityPropertyImpl<com.github.retrooper.packetevents.protocol.item.ItemStack>) key, SpigotConversionUtil.fromBukkitItemStack(value));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemStack getItemProperty(EntityProperty<?> key) {
|
||||
return SpigotConversionUtil.toBukkitItemStack(getProperty((EntityProperty<com.github.retrooper.packetevents.protocol.item.ItemStack>) key));
|
||||
}
|
||||
|
||||
public <T> void setProperty(EntityPropertyImpl<T> key, T value) {
|
||||
if (key == null) return;
|
||||
if (value == null || value.equals(key.getDefaultValue())) propertyMap.remove(key);
|
||||
|
@ -176,6 +186,11 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
setProperty((EntityPropertyImpl<T>) property, (T) value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void UNSAFE_setProperty(EntityProperty<?> property, Object value) {
|
||||
setProperty((EntityPropertyImpl<T>) property, (T) value);
|
||||
}
|
||||
|
||||
public Set<EntityProperty<?>> getAllProperties() {
|
||||
return Collections.unmodifiableSet(propertyMap.keySet());
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package lol.pyr.znpcsplus.npc;
|
||||
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
|
||||
import lol.pyr.znpcsplus.api.npc.NpcType;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.hologram.HologramItem;
|
||||
import lol.pyr.znpcsplus.hologram.HologramLine;
|
||||
import lol.pyr.znpcsplus.hologram.HologramText;
|
||||
import lol.pyr.znpcsplus.interaction.ActionRegistry;
|
||||
import lol.pyr.znpcsplus.interaction.InteractionActionImpl;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.storage.NpcStorage;
|
||||
|
@ -153,6 +158,35 @@ public class NpcRegistryImpl implements NpcRegistry {
|
|||
return entry;
|
||||
}
|
||||
|
||||
public NpcEntryImpl clone(String id, String newId, World newWorld, NpcLocation newLocation) {
|
||||
NpcEntryImpl oldNpc = getById(id);
|
||||
if (oldNpc == null) return null;
|
||||
NpcEntryImpl newNpc = create(newId, newWorld, oldNpc.getNpc().getType(), newLocation);
|
||||
newNpc.enableEverything();
|
||||
|
||||
for (EntityProperty<?> property : oldNpc.getNpc().getAllProperties()) {
|
||||
newNpc.getNpc().UNSAFE_setProperty(property, oldNpc.getNpc().getProperty(property));
|
||||
}
|
||||
|
||||
for (InteractionActionImpl action : oldNpc.getNpc().getActions()) {
|
||||
newNpc.getNpc().addAction(action);
|
||||
}
|
||||
|
||||
for (HologramLine<?> line : oldNpc.getNpc().getHologram().getLines()) {
|
||||
if (line instanceof HologramText) {
|
||||
HologramText text = (HologramText) line;
|
||||
newNpc.getNpc().getHologram().addTextLineComponent(text.getValue());
|
||||
}
|
||||
else if (line instanceof HologramItem) {
|
||||
HologramItem item = (HologramItem) line;
|
||||
newNpc.getNpc().getHologram().addItemLinePEStack(item.getValue());
|
||||
}
|
||||
else throw new IllegalArgumentException("Unknown hologram line type during clone");
|
||||
}
|
||||
|
||||
return newNpc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
NpcEntryImpl entry = npcIdLookupMap.get(id.toLowerCase());
|
||||
|
|
|
@ -164,12 +164,18 @@ public class NpcTypeImpl implements NpcType {
|
|||
addProperties("panda_eating");
|
||||
}
|
||||
}
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_TAMEABLE_ANIMAL)) {
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.ABSTRACT_TAMEABLE_ANIMAL) &&
|
||||
!(version.isNewerThanOrEquals(ServerVersion.V_1_14) && type.equals(EntityTypes.OCELOT))) {
|
||||
addProperties("tamed", "sitting");
|
||||
}
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.GUARDIAN)) {
|
||||
addProperties("is_retracting_spikes");
|
||||
}
|
||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
|
||||
if (EntityTypes.isTypeInstanceOf(type, EntityTypes.WOLF)) {
|
||||
addProperties("wolf_variant");
|
||||
}
|
||||
}
|
||||
return new NpcTypeImpl(name, type, hologramOffset, new HashSet<>(allowedProperties), defaultProperties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
register(builder(p, "player", EntityTypes.PLAYER)
|
||||
.setHologramOffset(-0.15D)
|
||||
.addEquipmentProperties()
|
||||
.addProperties("skin_cape", "skin_jacket", "skin_left_sleeve", "skin_right_sleeve", "skin_left_leg", "skin_right_leg", "skin_hat", "shoulder_entity_left", "shoulder_entity_right")
|
||||
.addProperties("skin_cape", "skin_jacket", "skin_left_sleeve", "skin_right_sleeve", "skin_left_leg", "skin_right_leg", "skin_hat", "shoulder_entity_left", "shoulder_entity_right", "force_body_rotation")
|
||||
.addDefaultProperty("skin_cape", true)
|
||||
.addDefaultProperty("skin_jacket", true)
|
||||
.addDefaultProperty("skin_left_sleeve", true)
|
||||
|
@ -357,7 +357,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
.setHologramOffset(-1.675));
|
||||
|
||||
register(builder(p, "warden", EntityTypes.WARDEN)
|
||||
.setHologramOffset(0.925));
|
||||
.setHologramOffset(0.925)
|
||||
.addProperties("warden_anger"));
|
||||
|
||||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
|
||||
|
||||
|
@ -368,6 +369,12 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
register(builder(p, "camel", EntityTypes.CAMEL)
|
||||
.setHologramOffset(0.25)
|
||||
.addProperties("bashing", "camel_sitting"));
|
||||
|
||||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_20_5)) return;
|
||||
|
||||
register(builder(p, "armadillo", EntityTypes.ARMADILLO)
|
||||
.setHologramOffset(-1.475)
|
||||
.addProperties("armadillo_state"));
|
||||
}
|
||||
|
||||
public Collection<NpcType> getAll() {
|
||||
|
|
|
@ -14,21 +14,27 @@ import java.util.stream.Collectors;
|
|||
* pre-1.17 had all of their classes "flattened" into one package.
|
||||
*/
|
||||
public class ReflectionPackage {
|
||||
private static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
public static final String BUKKIT = "org.bukkit.craftbukkit." + VERSION;
|
||||
private static final String VERSION = generateVersion();
|
||||
public static final String BUKKIT = "org.bukkit.craftbukkit" + VERSION;
|
||||
private static final boolean flattened = !PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17);
|
||||
|
||||
/**
|
||||
* Check if the classes are flattened, if so we need to add the version string into the
|
||||
* package string which is another quirk of the old server jars.
|
||||
*/
|
||||
public static final String MINECRAFT = joinWithDot("net.minecraft", flattened ? "server." + VERSION : "");
|
||||
public static final String MINECRAFT = joinWithDot("net.minecraft", flattened ? "server" + VERSION : "");
|
||||
public static final String ENTITY = flattened ? MINECRAFT : joinWithDot(MINECRAFT, "world.entity");
|
||||
|
||||
public static String joinWithDot(String... parts) {
|
||||
return Arrays.stream(parts)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(p -> p.length() != 0)
|
||||
.filter(p -> !p.isEmpty())
|
||||
.collect(Collectors.joining("."));
|
||||
}
|
||||
|
||||
private static String generateVersion() {
|
||||
String[] parts = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
|
||||
if (parts.length > 3) return "." + parts[3];
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue