make everything not static, it makes the api much easier to make

This commit is contained in:
Pyrbu 2023-05-16 14:46:11 +01:00
parent 1aeae3f12a
commit a08e973319
74 changed files with 796 additions and 507 deletions

View file

@ -51,6 +51,7 @@ shadowJar {
relocate "space.arim.dazzleconf", "lol.pyr.znpcsplus.lib.dazzleconf" relocate "space.arim.dazzleconf", "lol.pyr.znpcsplus.lib.dazzleconf"
relocate "lol.pyr.director", "lol.pyr.znpcsplus.lib.command" relocate "lol.pyr.director", "lol.pyr.znpcsplus.lib.command"
relocate "lol.pyr.serviceinjector", "lol.pyr.znpcsplus.lib.serviceinjector"
minimize() minimize()
} }

View file

@ -1,12 +0,0 @@
package lol.pyr.znpcsplus;
import lol.pyr.znpcsplus.api.ZApi;
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
public class ZNpcsApi implements ZApi {
@Override
public NpcRegistry getNpcRegistry() {
return NpcRegistryImpl.get();
}
}

View file

@ -1,13 +1,17 @@
package lol.pyr.znpcsplus; package lol.pyr.znpcsplus;
import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.event.PacketListenerPriority; import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import lol.pyr.director.adventure.command.CommandManager; import lol.pyr.director.adventure.command.CommandManager;
import lol.pyr.director.adventure.command.MultiCommand; import lol.pyr.director.adventure.command.MultiCommand;
import lol.pyr.director.adventure.parse.primitive.BooleanParser; import lol.pyr.director.adventure.parse.primitive.BooleanParser;
import lol.pyr.director.adventure.parse.primitive.IntegerParser; import lol.pyr.director.adventure.parse.primitive.IntegerParser;
import lol.pyr.znpcsplus.api.ZApi;
import lol.pyr.znpcsplus.api.ZApiProvider; import lol.pyr.znpcsplus.api.ZApiProvider;
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
import lol.pyr.znpcsplus.commands.*; import lol.pyr.znpcsplus.commands.*;
import lol.pyr.znpcsplus.commands.hologram.*; import lol.pyr.znpcsplus.commands.hologram.*;
import lol.pyr.znpcsplus.commands.parsers.EntityPropertyParser; import lol.pyr.znpcsplus.commands.parsers.EntityPropertyParser;
@ -16,72 +20,70 @@ import lol.pyr.znpcsplus.commands.parsers.NpcEntryParser;
import lol.pyr.znpcsplus.commands.parsers.NpcTypeParser; import lol.pyr.znpcsplus.commands.parsers.NpcTypeParser;
import lol.pyr.znpcsplus.commands.storage.LoadAllCommand; import lol.pyr.znpcsplus.commands.storage.LoadAllCommand;
import lol.pyr.znpcsplus.commands.storage.SaveAllCommand; import lol.pyr.znpcsplus.commands.storage.SaveAllCommand;
import lol.pyr.znpcsplus.config.Configs; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.interaction.InteractionPacketListener; import lol.pyr.znpcsplus.interaction.InteractionPacketListener;
import lol.pyr.znpcsplus.interaction.ActionRegistry;
import lol.pyr.znpcsplus.metadata.*;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcTypeImpl; import lol.pyr.znpcsplus.npc.NpcTypeImpl;
import lol.pyr.znpcsplus.packets.*;
import lol.pyr.znpcsplus.scheduling.FoliaScheduler; import lol.pyr.znpcsplus.scheduling.FoliaScheduler;
import lol.pyr.znpcsplus.scheduling.SpigotScheduler; import lol.pyr.znpcsplus.scheduling.SpigotScheduler;
import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.skin.cache.SkinCache;
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask; import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
import lol.pyr.znpcsplus.tasks.NpcVisibilityTask; import lol.pyr.znpcsplus.tasks.NpcVisibilityTask;
import lol.pyr.znpcsplus.updater.UpdateChecker; import lol.pyr.znpcsplus.updater.UpdateChecker;
import lol.pyr.znpcsplus.updater.UpdateNotificationListener; import lol.pyr.znpcsplus.updater.UpdateNotificationListener;
import lol.pyr.znpcsplus.user.User;
import lol.pyr.znpcsplus.user.UserListener; import lol.pyr.znpcsplus.user.UserListener;
import lol.pyr.znpcsplus.user.UserManager;
import lol.pyr.znpcsplus.util.BungeeUtil; import lol.pyr.znpcsplus.util.BungeeUtil;
import lol.pyr.znpcsplus.util.FoliaUtil; import lol.pyr.znpcsplus.util.FoliaUtil;
import lol.pyr.znpcsplus.util.LazyLoader;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.apache.commons.io.FileUtils;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File; import java.util.HashMap;
import java.io.IOException;
import java.util.logging.Logger;
public class ZNpcsPlus extends JavaPlugin { public class ZNpcsPlus extends JavaPlugin implements ZApi {
private static final int PLUGIN_ID = 18244; private static final int PLUGIN_ID = 18244;
public static boolean PLACEHOLDERS_SUPPORTED;
public static Logger LOGGER; private TaskScheduler scheduler;
public static File PLUGIN_FOLDER; private BukkitAudiences adventure;
public static File PATH_FOLDER; private SkinCache skinCache;
public static TaskScheduler SCHEDULER; private MetadataFactory metadataFactory;
public static BungeeUtil BUNGEE_UTIL;
public static BukkitAudiences ADVENTURE; private NpcRegistryImpl npcRegistry;
public static LegacyComponentSerializer LEGACY_AMPERSAND_SERIALIZER = LegacyComponentSerializer.builder()
private UserManager userManager;
private final LegacyComponentSerializer textSerializer = LegacyComponentSerializer.builder()
.character('&') .character('&')
.hexCharacter('#') .hexCharacter('#')
.hexColors().build(); .hexColors().build();
private PacketEventsAPI<Plugin> packetEvents;
private boolean enabled = false; private boolean enabled = false;
public static final String DEBUG_NPC_PREFIX = "debug_npc";
public static void debug(String str) {
if (!Configs.config().debugEnabled()) return;
LOGGER.info("[DEBUG] " + str);
}
@Override @Override
public void onLoad() { public void onLoad() {
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this)); packetEvents = SpigotPacketEventsBuilder.build(this);
PacketEvents.getAPI().getSettings().checkForUpdates(false); PacketEvents.setAPI(packetEvents);
PacketEvents.getAPI().load(); packetEvents.getSettings().checkForUpdates(false);
LOGGER = getLogger(); packetEvents.load();
PLUGIN_FOLDER = getDataFolder();
PATH_FOLDER = new File(PLUGIN_FOLDER, "paths");
} }
private void log(String str) { private void log(String str) {
@ -95,71 +97,71 @@ public class ZNpcsPlus extends JavaPlugin {
log(ChatColor.YELLOW + " /__ | \\| | |__ .__) " + ChatColor.GOLD + " | " + ChatColor.GRAY + "Maintained with " + ChatColor.RED + "\u2764 " + ChatColor.GRAY + " by Pyr#6969"); log(ChatColor.YELLOW + " /__ | \\| | |__ .__) " + ChatColor.GOLD + " | " + ChatColor.GRAY + "Maintained with " + ChatColor.RED + "\u2764 " + ChatColor.GRAY + " by Pyr#6969");
log(""); log("");
if (Bukkit.getPluginManager().isPluginEnabled("ServersNPC")) { PluginManager pluginManager = Bukkit.getPluginManager();
if (pluginManager.isPluginEnabled("ServersNPC")) {
log(ChatColor.DARK_RED + " * Detected old version of ZNPCs! Disabling the plugin."); log(ChatColor.DARK_RED + " * Detected old version of ZNPCs! Disabling the plugin.");
log(""); log("");
Bukkit.getPluginManager().disablePlugin(this); pluginManager.disablePlugin(this);
return; return;
} }
long before = System.currentTimeMillis(); long before = System.currentTimeMillis();
File oldFolder = new File(PLUGIN_FOLDER.getParent(), "ServersNPC");
if (!PLUGIN_FOLDER.exists() && oldFolder.exists()) {
log(ChatColor.WHITE + " * Converting old ZNPCs files...");
try {
FileUtils.moveDirectory(oldFolder, PLUGIN_FOLDER);
} catch (IOException e) {
log(ChatColor.RED + " * Failed to convert old ZNPCs files" + (e.getMessage() == null ? "" : " due to " + e.getMessage()));
}
}
log(ChatColor.WHITE + " * Initializing Adventure..."); log(ChatColor.WHITE + " * Initializing Adventure...");
ADVENTURE = BukkitAudiences.create(this); adventure = BukkitAudiences.create(this);
log(ChatColor.WHITE + " * Initializing PacketEvents..."); log(ChatColor.WHITE + " * Initializing PacketEvents...");
PacketEvents.getAPI().getEventManager().registerListener(new InteractionPacketListener(), PacketListenerPriority.MONITOR); packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry), PacketListenerPriority.MONITOR);
PacketEvents.getAPI().init(); packetEvents.init();
PLACEHOLDERS_SUPPORTED = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); metadataFactory = setupMetadataFactory();
if (PLACEHOLDERS_SUPPORTED) log(ChatColor.WHITE + " * Enabling PlaceholderAPI support..."); PacketFactory packetFactory = setupPacketFactory();
PLUGIN_FOLDER.mkdirs(); getDataFolder().mkdirs();
PATH_FOLDER.mkdirs();
log(ChatColor.WHITE + " * Loading configurations..."); log(ChatColor.WHITE + " * Loading configurations...");
Configs.init(PLUGIN_FOLDER); ConfigManager configManager = new ConfigManager(getDataFolder());
log(ChatColor.WHITE + " * Defining NPC types..."); log(ChatColor.WHITE + " * Defining NPC types...");
NpcTypeImpl.defineTypes(); NpcTypeImpl.defineTypes();
log(ChatColor.WHITE + " * Registering components..."); log(ChatColor.WHITE + " * Starting tasks & registering components...");
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
new Metrics(this, PLUGIN_ID); new Metrics(this, PLUGIN_ID);
SCHEDULER = FoliaUtil.isFolia() ? new FoliaScheduler(this) : new SpigotScheduler(this); scheduler = FoliaUtil.isFolia() ? new FoliaScheduler(this) : new SpigotScheduler(this);
BUNGEE_UTIL = new BungeeUtil(this); BungeeUtil bungeeUtil = new BungeeUtil(this);
Bukkit.getOnlinePlayers().forEach(User::get); userManager = new UserManager();
Bukkit.getOnlinePlayers().forEach(userManager::get);
pluginManager.registerEvents(new UserListener(userManager), this);
scheduler.runDelayedTimerAsync(new NpcVisibilityTask(npcRegistry, configManager), 60L, 10L);
skinCache = new SkinCache(configManager);
scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200);
registerCommands(); registerCommands();
log(ChatColor.WHITE + " * Starting tasks..."); if (configManager.getConfig().checkForUpdates()) {
new NpcVisibilityTask(); UpdateChecker updateChecker = new UpdateChecker(this.getDescription());
new SkinCacheCleanTask(); scheduler.runDelayedTimerAsync(updateChecker, 5L, 6000L);
new UserListener(this); pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker), this);
if (Configs.config().checkForUpdates()) new UpdateNotificationListener(this, new UpdateChecker(this)); }
log(ChatColor.WHITE+ " * Loading NPCs..."); log(ChatColor.WHITE+ " * Loading NPCs...");
NpcRegistryImpl.get().reload(); ActionRegistry actionRegistry = new ActionRegistry(scheduler, adventure, bungeeUtil);
npcRegistry = new NpcRegistryImpl(configManager, this, packetFactory, actionRegistry);
npcRegistry.reload();
ZApiProvider.register(new ZNpcsApi()); ZApiProvider.register(this);
enabled = true; enabled = true;
log(ChatColor.WHITE + " * Loading complete! (" + (System.currentTimeMillis() - before) + "ms)"); log(ChatColor.WHITE + " * Loading complete! (" + (System.currentTimeMillis() - before) + "ms)");
log(""); log("");
if (Configs.config().debugEnabled()) { if (configManager.getConfig().debugEnabled()) {
World world = Bukkit.getWorld("world"); World world = Bukkit.getWorld("world");
if (world == null) world = Bukkit.getWorlds().get(0); if (world == null) world = Bukkit.getWorlds().get(0);
int i = 0; int i = 0;
for (NpcTypeImpl type : NpcTypeImpl.values()) { for (NpcTypeImpl type : NpcTypeImpl.values()) {
NpcEntryImpl entry = NpcRegistryImpl.get().create(ZNpcsPlus.DEBUG_NPC_PREFIX + i, world, type, new ZLocation(i * 3, 200, 0, 0, 0)); NpcEntryImpl entry = npcRegistry.create("debug_npc_" + i, world, type, new ZLocation(i * 3, 200, 0, 0, 0));
entry.setProcessed(true); entry.setProcessed(true);
NpcImpl npc = entry.getNpc(); NpcImpl npc = entry.getNpc();
npc.getHologram().addLine(Component.text("Hello, World!")); npc.getHologram().addLine(Component.text("Hello, World!"));
@ -168,22 +170,61 @@ public class ZNpcsPlus extends JavaPlugin {
} }
} }
private PacketFactory setupPacketFactory() {
HashMap<ServerVersion, LazyLoader<? extends PacketFactory>> versions = new HashMap<>();
versions.put(ServerVersion.V_1_8, LazyLoader.of(() -> new V1_8PacketFactory(scheduler, metadataFactory)));
versions.put(ServerVersion.V_1_9, LazyLoader.of(() -> new V1_9PacketFactory(scheduler, metadataFactory)));
versions.put(ServerVersion.V_1_10, LazyLoader.of(() -> new V1_10PacketFactory(scheduler, metadataFactory)));
versions.put(ServerVersion.V_1_14, LazyLoader.of(() -> new V1_14PacketFactory(scheduler, metadataFactory)));
versions.put(ServerVersion.V_1_19, LazyLoader.of(() -> new V1_19PacketFactory(scheduler, metadataFactory)));
ServerVersion version = packetEvents.getServerManager().getVersion();
if (versions.containsKey(version)) return versions.get(version).get();
for (ServerVersion v : ServerVersion.reversedValues()) {
if (v.isNewerThan(version)) continue;
if (!versions.containsKey(v)) continue;
return versions.get(v).get();
}
throw new RuntimeException("Unsupported version!");
}
private MetadataFactory setupMetadataFactory() {
HashMap<ServerVersion, LazyLoader<? extends MetadataFactory>> versions = new HashMap<>();
versions.put(ServerVersion.V_1_8, LazyLoader.of(V1_8MetadataFactory::new));
versions.put(ServerVersion.V_1_9, LazyLoader.of(V1_9MetadataFactory::new));
versions.put(ServerVersion.V_1_10, LazyLoader.of(V1_10MetadataFactory::new));
versions.put(ServerVersion.V_1_13, LazyLoader.of(V1_13MetadataFactory::new));
versions.put(ServerVersion.V_1_14, LazyLoader.of(V1_14MetadataFactory::new));
versions.put(ServerVersion.V_1_16, LazyLoader.of(V1_16MetadataFactory::new));
versions.put(ServerVersion.V_1_17, LazyLoader.of(V1_17MetadataFactory::new));
ServerVersion version = packetEvents.getServerManager().getVersion();
if (versions.containsKey(version)) return versions.get(version).get();
for (ServerVersion v : ServerVersion.reversedValues()) {
if (v.isNewerThan(version)) continue;
if (!versions.containsKey(v)) continue;
return versions.get(v).get();
}
throw new RuntimeException("Unsupported version!");
}
@Override @Override
public void onDisable() { public void onDisable() {
if (!enabled) return; if (!enabled) return;
NpcRegistryImpl.get().save(); npcRegistry.save();
ZApiProvider.unregister(); ZApiProvider.unregister();
Bukkit.getOnlinePlayers().forEach(User::remove); Bukkit.getOnlinePlayers().forEach(userManager::remove);
ADVENTURE.close(); adventure.close();
ADVENTURE = null; adventure = null;
} }
private void registerCommands() { private void registerCommands() {
// TODO: Messages in here // TODO: Messages in here
CommandManager manager = new CommandManager(this, ADVENTURE, context -> {}); CommandManager manager = new CommandManager(this, adventure, context -> {});
manager.registerParser(NpcTypeImpl.class, new NpcTypeParser(context -> {})); manager.registerParser(NpcTypeImpl.class, new NpcTypeParser(context -> {}));
manager.registerParser(NpcEntryImpl.class, new NpcEntryParser(context -> {})); manager.registerParser(NpcEntryImpl.class, new NpcEntryParser(npcRegistry, context -> {}));
manager.registerParser(EntityPropertyImpl.class, new EntityPropertyParser(context -> {})); manager.registerParser(EntityPropertyImpl.class, new EntityPropertyParser(context -> {}));
manager.registerParser(Integer.class, new IntegerParser(context -> {})); manager.registerParser(Integer.class, new IntegerParser(context -> {}));
manager.registerParser(Boolean.class, new BooleanParser(context -> {})); manager.registerParser(Boolean.class, new BooleanParser(context -> {}));
@ -191,25 +232,30 @@ public class ZNpcsPlus extends JavaPlugin {
manager.registerCommand("npc", new MultiCommand() manager.registerCommand("npc", new MultiCommand()
.addSubcommand("action", new ActionCommand()) .addSubcommand("action", new ActionCommand())
.addSubcommand("create", new CreateCommand()) .addSubcommand("create", new CreateCommand(npcRegistry))
.addSubcommand("skin", new SkinCommand()) .addSubcommand("skin", new SkinCommand(skinCache, npcRegistry))
.addSubcommand("delete", new DeleteCommand()) .addSubcommand("delete", new DeleteCommand(npcRegistry, adventure))
.addSubcommand("move", new MoveCommand()) .addSubcommand("move", new MoveCommand(npcRegistry))
.addSubcommand("properties", new PropertiesCommand()) .addSubcommand("properties", new PropertiesCommand(npcRegistry))
.addSubcommand("teleport", new TeleportCommand()) .addSubcommand("teleport", new TeleportCommand(npcRegistry))
.addSubcommand("list", new ListCommand()) .addSubcommand("list", new ListCommand(npcRegistry))
.addSubcommand("near", new NearCommand()) .addSubcommand("near", new NearCommand(npcRegistry))
.addSubcommand("type", new TypeCommand()) .addSubcommand("type", new TypeCommand(npcRegistry))
.addSubcommand("storage", new MultiCommand() .addSubcommand("storage", new MultiCommand()
.addSubcommand("save", new SaveAllCommand()) .addSubcommand("save", new SaveAllCommand(npcRegistry))
.addSubcommand("load", new LoadAllCommand())) .addSubcommand("reload", new LoadAllCommand(npcRegistry)))
.addSubcommand("holo", new MultiCommand() .addSubcommand("holo", new MultiCommand()
.addSubcommand("add", new HoloAddCommand()) .addSubcommand("add", new HoloAddCommand(npcRegistry, textSerializer))
.addSubcommand("delete", new HoloDeleteCommand()) .addSubcommand("delete", new HoloDeleteCommand(npcRegistry))
.addSubcommand("info", new HoloInfoCommand()) .addSubcommand("info", new HoloInfoCommand(npcRegistry))
.addSubcommand("insert", new HoloInsertCommand()) .addSubcommand("insert", new HoloInsertCommand(npcRegistry, textSerializer))
.addSubcommand("set", new HoloSetCommand()) .addSubcommand("set", new HoloSetCommand(npcRegistry, textSerializer))
) )
); );
} }
@Override
public NpcRegistry getNpcRegistry() {
return npcRegistry;
}
} }

View file

@ -15,16 +15,22 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class CreateCommand implements CommandHandler { public class CreateCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public CreateCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " create <id> <type>"); context.setUsage(context.getLabel() + " create <id> <type>");
Player player = context.ensureSenderIsPlayer(); Player player = context.ensureSenderIsPlayer();
String id = context.popString(); String id = context.popString();
if (NpcRegistryImpl.get().get(id) != null) context.halt(Component.text("NPC with that ID already exists.", NamedTextColor.RED)); if (npcRegistry.get(id) != null) context.halt(Component.text("NPC with that ID already exists.", NamedTextColor.RED));
NpcTypeImpl type = context.parse(NpcTypeImpl.class); NpcTypeImpl type = context.parse(NpcTypeImpl.class);
NpcEntryImpl entry = NpcRegistryImpl.get().create(id, player.getWorld(), type, new ZLocation(player.getLocation())); NpcEntryImpl entry = npcRegistry.create(id, player.getWorld(), type, new ZLocation(player.getLocation()));
entry.enableEverything(); entry.enableEverything();
context.send(Component.text("Created a " + type.getName() + " NPC with ID " + id + ".", NamedTextColor.GREEN)); context.send(Component.text("Created a " + type.getName() + " NPC with ID " + id + ".", NamedTextColor.GREEN));
@ -32,7 +38,7 @@ public class CreateCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() == 2) return context.suggestStream(NpcTypeImpl.values().stream().map(NpcTypeImpl::getName)); if (context.argSize() == 2) return context.suggestStream(NpcTypeImpl.values().stream().map(NpcTypeImpl::getName));
return Collections.emptyList(); return Collections.emptyList();
} }

View file

@ -3,9 +3,9 @@ package lol.pyr.znpcsplus.commands;
import lol.pyr.director.adventure.command.CommandContext; import lol.pyr.director.adventure.command.CommandContext;
import lol.pyr.director.adventure.command.CommandHandler; import lol.pyr.director.adventure.command.CommandHandler;
import lol.pyr.director.common.command.CommandExecutionException; import lol.pyr.director.common.command.CommandExecutionException;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -13,17 +13,25 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class DeleteCommand implements CommandHandler { public class DeleteCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
private final BukkitAudiences adventure;
public DeleteCommand(NpcRegistryImpl npcRegistry, BukkitAudiences adventure) {
this.npcRegistry = npcRegistry;
this.adventure = adventure;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " delete <id>"); context.setUsage(context.getLabel() + " delete <id>");
NpcEntryImpl entry = context.parse(NpcEntryImpl.class); NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
NpcRegistryImpl.get().delete(entry.getId()); npcRegistry.delete(entry.getId());
ZNpcsPlus.ADVENTURE.sender(context.getSender()).sendMessage(Component.text("Deleted NPC with ID: " + entry.getId(), NamedTextColor.GREEN)); adventure.sender(context.getSender()).sendMessage(Component.text("Deleted NPC with ID: " + entry.getId(), NamedTextColor.GREEN));
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View file

@ -12,11 +12,17 @@ import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
public class ListCommand implements CommandHandler { public class ListCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public ListCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
TextComponent.Builder component = Component.text("Npc's:\n").color(NamedTextColor.GOLD).toBuilder(); TextComponent.Builder component = Component.text("Npc's:\n").color(NamedTextColor.GOLD).toBuilder();
for (String id : NpcRegistryImpl.get().modifiableIds()) { for (String id : npcRegistry.modifiableIds()) {
NpcImpl npc = NpcRegistryImpl.get().get(id).getNpc(); NpcImpl npc = npcRegistry.get(id).getNpc();
ZLocation location = npc.getLocation(); ZLocation location = npc.getLocation();
component.append(Component.text("ID: " + id, NamedTextColor.GREEN)) component.append(Component.text("ID: " + id, NamedTextColor.GREEN))
.append(Component.text(" | ", NamedTextColor.GRAY)) .append(Component.text(" | ", NamedTextColor.GRAY))

View file

@ -15,6 +15,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class MoveCommand implements CommandHandler { public class MoveCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public MoveCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " move <id>"); context.setUsage(context.getLabel() + " move <id>");
@ -26,7 +32,7 @@ public class MoveCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View file

@ -12,13 +12,19 @@ import org.bukkit.entity.Player;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class NearCommand implements CommandHandler { public class NearCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public NearCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
Player player = context.ensureSenderIsPlayer(); Player player = context.ensureSenderIsPlayer();
int raw = context.parse(Integer.class); int raw = context.parse(Integer.class);
double radius = Math.pow(raw, 2); double radius = Math.pow(raw, 2);
String npcs = NpcRegistryImpl.get().allModifiable().stream() String npcs = npcRegistry.allModifiable().stream()
.filter(entry -> entry.getNpc().getBukkitLocation().distanceSquared(player.getLocation()) < radius) .filter(entry -> entry.getNpc().getBukkitLocation().distanceSquared(player.getLocation()) < radius)
.map(NpcEntryImpl::getId) .map(NpcEntryImpl::getId)
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));

View file

@ -14,6 +14,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class PropertiesCommand implements CommandHandler { public class PropertiesCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public PropertiesCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
NpcEntryImpl entry = context.parse(NpcEntryImpl.class); NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
@ -29,7 +35,7 @@ public class PropertiesCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() == 2) return context.suggestStream(context.suggestionParse(0, NpcEntryImpl.class) if (context.argSize() == 2) return context.suggestStream(context.suggestionParse(0, NpcEntryImpl.class)
.getNpc().getType().getAllowedProperties().stream().map(EntityPropertyImpl::getName)); .getNpc().getType().getAllowedProperties().stream().map(EntityPropertyImpl::getName));
if (context.argSize() == 3) { if (context.argSize() == 3) {

View file

@ -8,6 +8,7 @@ import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcTypeImpl; import lol.pyr.znpcsplus.npc.NpcTypeImpl;
import lol.pyr.znpcsplus.skin.cache.SkinCache;
import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor; import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor;
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor; import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
@ -18,6 +19,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class SkinCommand implements CommandHandler { public class SkinCommand implements CommandHandler {
private final SkinCache skinCache;
private final NpcRegistryImpl npcRegistry;
public SkinCommand(SkinCache skinCache, NpcRegistryImpl npcRegistry) {
this.skinCache = skinCache;
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " skin <id> <type> [value]"); context.setUsage(context.getLabel() + " skin <id> <type> [value]");
@ -26,7 +35,7 @@ public class SkinCommand implements CommandHandler {
String type = context.popString(); String type = context.popString();
if (type.equalsIgnoreCase("mirror")) { if (type.equalsIgnoreCase("mirror")) {
npc.setProperty(EntityPropertyImpl.SKIN, new MirrorDescriptor()); npc.setProperty(EntityPropertyImpl.SKIN, new MirrorDescriptor(skinCache));
npc.respawn(); npc.respawn();
context.halt(Component.text("The NPC's skin will now mirror the player that it's being displayed to", NamedTextColor.GREEN)); context.halt(Component.text("The NPC's skin will now mirror the player that it's being displayed to", NamedTextColor.GREEN));
} }
@ -35,7 +44,7 @@ public class SkinCommand implements CommandHandler {
context.ensureArgsNotEmpty(); context.ensureArgsNotEmpty();
String name = context.dumpAllArgs(); String name = context.dumpAllArgs();
context.send(Component.text("Fetching skin \"" + name + "\"...", NamedTextColor.GREEN)); context.send(Component.text("Fetching skin \"" + name + "\"...", NamedTextColor.GREEN));
PrefetchedDescriptor.forPlayer(name).thenAccept(skin -> { PrefetchedDescriptor.forPlayer(skinCache, name).thenAccept(skin -> {
if (skin == null) { if (skin == null) {
context.send(Component.text("Failed to fetch skin, are you sure the player name is valid?", NamedTextColor.RED)); context.send(Component.text("Failed to fetch skin, are you sure the player name is valid?", NamedTextColor.RED));
return; return;
@ -50,7 +59,7 @@ public class SkinCommand implements CommandHandler {
if (type.equalsIgnoreCase("dynamic")) { if (type.equalsIgnoreCase("dynamic")) {
context.ensureArgsNotEmpty(); context.ensureArgsNotEmpty();
String name = context.dumpAllArgs(); String name = context.dumpAllArgs();
npc.setProperty(EntityPropertyImpl.SKIN, new FetchingDescriptor(name)); npc.setProperty(EntityPropertyImpl.SKIN, new FetchingDescriptor(skinCache, name));
npc.respawn(); npc.respawn();
context.halt(Component.text("The NPC's skin will now be resolved per-player from \"" + name + "\"")); context.halt(Component.text("The NPC's skin will now be resolved per-player from \"" + name + "\""));
} }
@ -59,7 +68,7 @@ public class SkinCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() == 2) return context.suggestLiteral("mirror", "static", "dynamic"); if (context.argSize() == 2) return context.suggestLiteral("mirror", "static", "dynamic");
if (context.matchSuggestion("*", "static")) return context.suggestPlayers(); if (context.matchSuggestion("*", "static")) return context.suggestPlayers();
return Collections.emptyList(); return Collections.emptyList();

View file

@ -15,6 +15,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class TeleportCommand implements CommandHandler { public class TeleportCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public TeleportCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " teleport <id>"); context.setUsage(context.getLabel() + " teleport <id>");
@ -26,7 +32,7 @@ public class TeleportCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View file

@ -14,6 +14,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class TypeCommand implements CommandHandler { public class TypeCommand implements CommandHandler {
private final NpcRegistryImpl registry;
public TypeCommand(NpcRegistryImpl registry) {
this.registry = registry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " type <id> <type>"); context.setUsage(context.getLabel() + " type <id> <type>");
@ -25,7 +31,7 @@ public class TypeCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(registry.modifiableIds());
if (context.argSize() == 2) return context.suggestStream(NpcTypeImpl.values().stream().map(NpcTypeImpl::getName)); if (context.argSize() == 2) return context.suggestStream(NpcTypeImpl.values().stream().map(NpcTypeImpl::getName));
return Collections.emptyList(); return Collections.emptyList();
} }

View file

@ -3,29 +3,37 @@ package lol.pyr.znpcsplus.commands.hologram;
import lol.pyr.director.adventure.command.CommandContext; import lol.pyr.director.adventure.command.CommandContext;
import lol.pyr.director.adventure.command.CommandHandler; import lol.pyr.director.adventure.command.CommandHandler;
import lol.pyr.director.common.command.CommandExecutionException; import lol.pyr.director.common.command.CommandExecutionException;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.hologram.HologramImpl; import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class HoloAddCommand implements CommandHandler { public class HoloAddCommand implements CommandHandler {
private final NpcRegistryImpl registry;
private final LegacyComponentSerializer textSerializer;
public HoloAddCommand(NpcRegistryImpl registry, LegacyComponentSerializer textSerializer) {
this.registry = registry;
this.textSerializer = textSerializer;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo add <id> <text>"); context.setUsage(context.getLabel() + " holo add <id> <text>");
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram(); HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
context.ensureArgsNotEmpty(); context.ensureArgsNotEmpty();
hologram.addLine(ZNpcsPlus.LEGACY_AMPERSAND_SERIALIZER.deserialize(context.dumpAllArgs())); hologram.addLine(textSerializer.deserialize(context.dumpAllArgs()));
context.send(Component.text("NPC line added!", NamedTextColor.GREEN)); context.send(Component.text("NPC line added!", NamedTextColor.GREEN));
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(registry.modifiableIds());
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View file

@ -14,6 +14,12 @@ import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
public class HoloDeleteCommand implements CommandHandler { public class HoloDeleteCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public HoloDeleteCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo delete <id> <line>"); context.setUsage(context.getLabel() + " holo delete <id> <line>");
@ -26,7 +32,7 @@ public class HoloDeleteCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1) if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size()) .limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size())
.map(String::valueOf)); .map(String::valueOf));

View file

@ -14,6 +14,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class HoloInfoCommand implements CommandHandler { public class HoloInfoCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public HoloInfoCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo info <id>"); context.setUsage(context.getLabel() + " holo info <id>");
@ -26,7 +32,7 @@ public class HoloInfoCommand implements CommandHandler {
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View file

@ -3,18 +3,26 @@ package lol.pyr.znpcsplus.commands.hologram;
import lol.pyr.director.adventure.command.CommandContext; import lol.pyr.director.adventure.command.CommandContext;
import lol.pyr.director.adventure.command.CommandHandler; import lol.pyr.director.adventure.command.CommandHandler;
import lol.pyr.director.common.command.CommandExecutionException; import lol.pyr.director.common.command.CommandExecutionException;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.hologram.HologramImpl; import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
public class HoloInsertCommand implements CommandHandler { public class HoloInsertCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
private final LegacyComponentSerializer componentSerializer;
public HoloInsertCommand(NpcRegistryImpl npcRegistry, LegacyComponentSerializer componentSerializer) {
this.npcRegistry = npcRegistry;
this.componentSerializer = componentSerializer;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo insert <id> <line> <text>"); context.setUsage(context.getLabel() + " holo insert <id> <line> <text>");
@ -22,13 +30,13 @@ public class HoloInsertCommand implements CommandHandler {
int line = context.parse(Integer.class); int line = context.parse(Integer.class);
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED)); if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
context.ensureArgsNotEmpty(); context.ensureArgsNotEmpty();
hologram.insertLine(line, ZNpcsPlus.LEGACY_AMPERSAND_SERIALIZER.deserialize(context.dumpAllArgs())); hologram.insertLine(line, componentSerializer.deserialize(context.dumpAllArgs()));
context.send(Component.text("NPC line inserted!", NamedTextColor.GREEN)); context.send(Component.text("NPC line inserted!", NamedTextColor.GREEN));
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1) if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size()) .limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size())
.map(String::valueOf)); .map(String::valueOf));

View file

@ -3,18 +3,26 @@ package lol.pyr.znpcsplus.commands.hologram;
import lol.pyr.director.adventure.command.CommandContext; import lol.pyr.director.adventure.command.CommandContext;
import lol.pyr.director.adventure.command.CommandHandler; import lol.pyr.director.adventure.command.CommandHandler;
import lol.pyr.director.common.command.CommandExecutionException; import lol.pyr.director.common.command.CommandExecutionException;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.hologram.HologramImpl; import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
public class HoloSetCommand implements CommandHandler { public class HoloSetCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
private final LegacyComponentSerializer componentSerializer;
public HoloSetCommand(NpcRegistryImpl npcRegistry, LegacyComponentSerializer componentSerializer) {
this.npcRegistry = npcRegistry;
this.componentSerializer = componentSerializer;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
context.setUsage(context.getLabel() + " holo set <id> <line> <text>"); context.setUsage(context.getLabel() + " holo set <id> <line> <text>");
@ -23,18 +31,18 @@ public class HoloSetCommand implements CommandHandler {
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED)); if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
context.ensureArgsNotEmpty(); context.ensureArgsNotEmpty();
hologram.removeLine(line); hologram.removeLine(line);
hologram.insertLine(line, ZNpcsPlus.LEGACY_AMPERSAND_SERIALIZER.deserialize(context.dumpAllArgs())); hologram.insertLine(line, componentSerializer.deserialize(context.dumpAllArgs()));
context.send(Component.text("NPC line set!", NamedTextColor.GREEN)); context.send(Component.text("NPC line set!", NamedTextColor.GREEN));
} }
@Override @Override
public List<String> suggest(CommandContext context) throws CommandExecutionException { public List<String> suggest(CommandContext context) throws CommandExecutionException {
if (context.argSize() == 1) return context.suggestCollection(NpcRegistryImpl.get().modifiableIds()); if (context.argSize() == 1) return context.suggestCollection(npcRegistry.modifiableIds());
if (context.argSize() >= 2) { if (context.argSize() >= 2) {
HologramImpl hologram = context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram(); HologramImpl hologram = context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram();
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1) if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
.limit(hologram.getLines().size()).map(String::valueOf)); .limit(hologram.getLines().size()).map(String::valueOf));
if (context.argSize() == 3) return context.suggestLiteral(ZNpcsPlus.LEGACY_AMPERSAND_SERIALIZER.serialize( if (context.argSize() == 3) return context.suggestLiteral(componentSerializer.serialize(
hologram.getLine(context.suggestionParse(1, Integer.class)))); hologram.getLine(context.suggestionParse(1, Integer.class))));
} }
return Collections.emptyList(); return Collections.emptyList();

View file

@ -10,13 +10,16 @@ import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import java.util.Deque; import java.util.Deque;
public class NpcEntryParser extends ParserType<NpcEntryImpl> { public class NpcEntryParser extends ParserType<NpcEntryImpl> {
public NpcEntryParser(Message<CommandContext> message) { private final NpcRegistryImpl npcRegistry;
public NpcEntryParser(NpcRegistryImpl npcRegistry, Message<CommandContext> message) {
super(message); super(message);
this.npcRegistry = npcRegistry;
} }
@Override @Override
public NpcEntryImpl parse(Deque<String> deque) throws CommandExecutionException { public NpcEntryImpl parse(Deque<String> deque) throws CommandExecutionException {
NpcEntryImpl entry = NpcRegistryImpl.get().get(deque.pop()); NpcEntryImpl entry = npcRegistry.get(deque.pop());
if (entry == null || !entry.isAllowCommandModification()) throw new CommandExecutionException(); if (entry == null || !entry.isAllowCommandModification()) throw new CommandExecutionException();
return entry; return entry;
} }

View file

@ -12,10 +12,16 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class LoadAllCommand implements CommandHandler { public class LoadAllCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public LoadAllCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
NpcRegistryImpl.get().reload(); npcRegistry.reload();
context.send(Component.text("All NPCs have been re-loaded from storage", NamedTextColor.GREEN)); context.send(Component.text("All NPCs have been re-loaded from storage", NamedTextColor.GREEN));
}); });
} }

View file

@ -12,10 +12,16 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class SaveAllCommand implements CommandHandler { public class SaveAllCommand implements CommandHandler {
private final NpcRegistryImpl npcRegistry;
public SaveAllCommand(NpcRegistryImpl npcRegistry) {
this.npcRegistry = npcRegistry;
}
@Override @Override
public void run(CommandContext context) throws CommandExecutionException { public void run(CommandContext context) throws CommandExecutionException {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
NpcRegistryImpl.get().save(); npcRegistry.save();
context.send(Component.text("All NPCs have been saved to storage", NamedTextColor.GREEN)); context.send(Component.text("All NPCs have been saved to storage", NamedTextColor.GREEN));
}); });
} }

View file

@ -1,6 +1,5 @@
package lol.pyr.znpcsplus.config; package lol.pyr.znpcsplus.config;
import lol.pyr.znpcsplus.ZNpcsPlus;
import space.arim.dazzleconf.ConfigurationFactory; import space.arim.dazzleconf.ConfigurationFactory;
import space.arim.dazzleconf.ConfigurationOptions; import space.arim.dazzleconf.ConfigurationOptions;
import space.arim.dazzleconf.error.ConfigFormatSyntaxException; import space.arim.dazzleconf.error.ConfigFormatSyntaxException;
@ -13,13 +12,22 @@ import space.arim.dazzleconf.serialiser.ValueSerialiser;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Logger;
public class Configs { public class ConfigManager {
private volatile static MainConfig config; private final static Logger logger = Logger.getLogger("ZNPCsPlus Configuration Manager");
private static ConfigurationHelper<MainConfig> configHelper;
private volatile static MessageConfig messages; private volatile MainConfig config;
private static ConfigurationHelper<MessageConfig> messagesHelper; private final ConfigurationHelper<MainConfig> configHelper;
private volatile MessageConfig messages;
private final ConfigurationHelper<MessageConfig> messagesHelper;
public ConfigManager(File pluginFolder) {
configHelper = createHelper(MainConfig.class, new File(pluginFolder, "config.yaml"));
messagesHelper = createHelper(MessageConfig.class, new File(pluginFolder, "messages.yaml"), new ComponentSerializer());
reload();
}
private static <T> ConfigurationHelper<T> createHelper(Class<T> configClass, File file, ValueSerialiser<?>... serialisers) { private static <T> ConfigurationHelper<T> createHelper(Class<T> configClass, File file, ValueSerialiser<?>... serialisers) {
SnakeYamlOptions yamlOptions = new SnakeYamlOptions.Builder().commentMode(CommentMode.fullComments()).build(); SnakeYamlOptions yamlOptions = new SnakeYamlOptions.Builder().commentMode(CommentMode.fullComments()).build();
@ -29,33 +37,27 @@ public class Configs {
return new ConfigurationHelper<>(file.getParentFile().toPath(), file.getName(), configFactory); return new ConfigurationHelper<>(file.getParentFile().toPath(), file.getName(), configFactory);
} }
public static void init(File pluginFolder) { public void reload() {
configHelper = createHelper(MainConfig.class, new File(pluginFolder, "config.yaml"));
messagesHelper = createHelper(MessageConfig.class, new File(pluginFolder, "messages.yaml"), new ComponentSerializer());
load();
}
public static void load() {
try { try {
config = configHelper.reloadConfigData(); config = configHelper.reloadConfigData();
messages = messagesHelper.reloadConfigData(); messages = messagesHelper.reloadConfigData();
} catch (IOException e) { } catch (IOException e) {
ZNpcsPlus.LOGGER.severe("Couldn't open config file!"); logger.severe("Couldn't open config file!");
e.printStackTrace(); e.printStackTrace();
} catch (ConfigFormatSyntaxException e) { } catch (ConfigFormatSyntaxException e) {
ZNpcsPlus.LOGGER.severe("Invalid config syntax!"); logger.severe("Invalid config syntax!");
e.printStackTrace(); e.printStackTrace();
} catch (InvalidConfigException e) { } catch (InvalidConfigException e) {
ZNpcsPlus.LOGGER.severe("Invalid config value!"); logger.severe("Invalid config value!");
e.printStackTrace(); e.printStackTrace();
} }
} }
public static MainConfig config() { public MainConfig getConfig() {
return config; return config;
} }
public static MessageConfig messages() { public MessageConfig getMessages() {
return messages; return messages;
} }
} }

View file

@ -89,7 +89,7 @@ public class EntityPropertyImpl<T> implements EntityProperty<T> {
private final static PropertyDeserializer<Component> COMPONENT_DESERIALIZER = str -> MiniMessage.miniMessage().deserialize(str); private final static PropertyDeserializer<Component> COMPONENT_DESERIALIZER = str -> MiniMessage.miniMessage().deserialize(str);
private final static PropertySerializer<SkinDescriptor> DESCRIPTOR_SERIALIZER = descriptor -> ((BaseSkinDescriptor) descriptor).serialize(); private final static PropertySerializer<SkinDescriptor> DESCRIPTOR_SERIALIZER = descriptor -> ((BaseSkinDescriptor) descriptor).serialize();
private final static PropertyDeserializer<SkinDescriptor> DESCRIPTOR_DESERIALIZER = BaseSkinDescriptor::deserialize; private final static PropertyDeserializer<SkinDescriptor> DESCRIPTOR_DESERIALIZER = property -> null; // TODO: An actual property registry // BaseSkinDescriptor::deserialize;
public static EntityPropertyImpl<NamedTextColor> GLOW = new EntityPropertyImpl<>("glow", NamedTextColor.class, COLOR_SERIALIZER, COLOR_DESERIALIZER); public static EntityPropertyImpl<NamedTextColor> GLOW = new EntityPropertyImpl<>("glow", NamedTextColor.class, COLOR_SERIALIZER, COLOR_DESERIALIZER);
public static EntityPropertyImpl<Boolean> SKIN_LAYERS = new EntityPropertyImpl<>("skin_layers", true, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER); public static EntityPropertyImpl<Boolean> SKIN_LAYERS = new EntityPropertyImpl<>("skin_layers", true, BOOLEAN_SERIALIZER, BOOLEAN_DESERIALIZER);

View file

@ -13,6 +13,8 @@ import java.util.Collection;
import java.util.UUID; import java.util.UUID;
public class PacketEntity { public class PacketEntity {
private final PacketFactory packetFactory;
private final PropertyHolder properties; private final PropertyHolder properties;
private final int entityId; private final int entityId;
private final UUID uuid; private final UUID uuid;
@ -20,7 +22,8 @@ public class PacketEntity {
private final EntityType type; private final EntityType type;
private ZLocation location; private ZLocation location;
public PacketEntity(PropertyHolder properties, EntityType type, ZLocation location) { public PacketEntity(PacketFactory packetFactory, PropertyHolder properties, EntityType type, ZLocation location) {
this.packetFactory = packetFactory;
this.properties = properties; this.properties = properties;
this.entityId = reserveEntityID(); this.entityId = reserveEntityID();
this.uuid = UUID.randomUUID(); this.uuid = UUID.randomUUID();
@ -46,25 +49,25 @@ public class PacketEntity {
public void setLocation(ZLocation location, Collection<Player> viewers) { public void setLocation(ZLocation location, Collection<Player> viewers) {
this.location = location; this.location = location;
for (Player viewer : viewers) PacketFactory.get().teleportEntity(viewer, this); for (Player viewer : viewers) packetFactory.teleportEntity(viewer, this);
} }
public void spawn(Player player) { public void spawn(Player player) {
if (type == EntityTypes.PLAYER) PacketFactory.get().spawnPlayer(player, this, properties); if (type == EntityTypes.PLAYER) packetFactory.spawnPlayer(player, this, properties);
else PacketFactory.get().spawnEntity(player, this, properties); else packetFactory.spawnEntity(player, this, properties);
} }
public void despawn(Player player) { public void despawn(Player player) {
PacketFactory.get().destroyEntity(player, this, properties); packetFactory.destroyEntity(player, this, properties);
} }
public void refreshMeta(Player player) { public void refreshMeta(Player player) {
PacketFactory.get().sendAllMetadata(player, this, properties); packetFactory.sendAllMetadata(player, this, properties);
} }
public void remakeTeam(Player player) { public void remakeTeam(Player player) {
PacketFactory.get().removeTeam(player, this); packetFactory.removeTeam(player, this);
PacketFactory.get().createTeam(player, this, properties); packetFactory.createTeam(player, this, properties);
} }
private static int reserveEntityID() { private static int reserveEntityID() {

View file

@ -1,7 +1,8 @@
package lol.pyr.znpcsplus.hologram; package lol.pyr.znpcsplus.hologram;
import lol.pyr.znpcsplus.api.hologram.Hologram; import lol.pyr.znpcsplus.api.hologram.Hologram;
import lol.pyr.znpcsplus.config.Configs; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.Viewable; import lol.pyr.znpcsplus.util.Viewable;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@ -12,15 +13,20 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class HologramImpl extends Viewable implements Hologram { public class HologramImpl extends Viewable implements Hologram {
private final ConfigManager configManager;
private final PacketFactory packetFactory;
private ZLocation location; private ZLocation location;
private final List<HologramLine> lines = new ArrayList<>(); private final List<HologramLine> lines = new ArrayList<>();
public HologramImpl(ZLocation location) { public HologramImpl(ConfigManager configManager, PacketFactory packetFactory, ZLocation location) {
this.configManager = configManager;
this.packetFactory = packetFactory;
this.location = location; this.location = location;
} }
public void addLine(Component line) { public void addLine(Component line) {
HologramLine newLine = new HologramLine(null, line); HologramLine newLine = new HologramLine(packetFactory, null, line);
lines.add(newLine); lines.add(newLine);
relocateLines(); relocateLines();
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer()); for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
@ -46,7 +52,7 @@ public class HologramImpl extends Viewable implements Hologram {
} }
public void insertLine(int index, Component line) { public void insertLine(int index, Component line) {
HologramLine newLine = new HologramLine(null, line); HologramLine newLine = new HologramLine(packetFactory, null, line);
lines.add(index, newLine); lines.add(index, newLine);
relocateLines(); relocateLines();
for (Player viewer : getViewers()) newLine.show(viewer.getPlayer()); for (Player viewer : getViewers()) newLine.show(viewer.getPlayer());
@ -72,7 +78,7 @@ public class HologramImpl extends Viewable implements Hologram {
} }
private void relocateLines(HologramLine newLine) { private void relocateLines(HologramLine newLine) {
final double lineSpacing = Configs.config().lineSpacing(); final double lineSpacing = configManager.getConfig().lineSpacing();
double height = location.getY() + (lines.size() - 1) * lineSpacing; double height = location.getY() + (lines.size() - 1) * lineSpacing;
for (HologramLine line : lines) { for (HologramLine line : lines) {
line.setLocation(location.withY(height), line == newLine ? Collections.emptySet() : getViewers()); line.setLocation(location.withY(height), line == newLine ? Collections.emptySet() : getViewers());

View file

@ -5,6 +5,7 @@ import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -15,9 +16,9 @@ public class HologramLine implements PropertyHolder {
private Component text; private Component text;
private final PacketEntity armorStand; private final PacketEntity armorStand;
public HologramLine(ZLocation location, Component text) { public HologramLine(PacketFactory packetFactory, ZLocation location, Component text) {
this.text = text; this.text = text;
armorStand = new PacketEntity(this, EntityTypes.ARMOR_STAND, location); armorStand = new PacketEntity(packetFactory, this, EntityTypes.ARMOR_STAND, location);
} }
public Component getText() { public Component getText() {

View file

@ -0,0 +1,46 @@
package lol.pyr.znpcsplus.interaction;
import lol.pyr.znpcsplus.interaction.types.*;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.util.BungeeUtil;
import lol.pyr.znpcsplus.util.StringSerializer;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class ActionRegistry {
private final Map<Class<?>, StringSerializer<?>> serializerMap = new HashMap<>();
public ActionRegistry(TaskScheduler taskScheduler, BukkitAudiences adventure, BungeeUtil bungeeUtil) {
register(ConsoleCommandAction.class, new ConsoleCommandActionSerializer(taskScheduler));
register(PlayerCommandAction.class, new PlayerCommandActionSerializer(taskScheduler));
register(SwitchServerAction.class, new SwitchServerActionSerializer(bungeeUtil));
register(MessageAction.class, new MessageActionSerializer(adventure));
}
public <T extends InteractionAction> void register(Class<T> clazz, StringSerializer<T> serializer) {
serializerMap.put(clazz, serializer);
}
@SuppressWarnings("unchecked")
public <T extends InteractionAction> T deserialize(String str) {
try {
String[] split = str.split(";");
Class<?> clazz = Class.forName(split[0]);
StringSerializer<T> serializer = (StringSerializer<T>) serializerMap.get(clazz);
if (serializer == null) return null;
return serializer.deserialize(String.join(";", Arrays.copyOfRange(split, 1, split.length)));
} catch (ClassNotFoundException e) {
return null;
}
}
@SuppressWarnings("unchecked")
public <T extends InteractionAction> String serialize(T action) {
StringSerializer<T> serializer = (StringSerializer<T>) serializerMap.get(action.getClass());
if (serializer == null) return null;
return action.getClass().getName() + ";" + serializer.serialize(action);
}
}

View file

@ -4,15 +4,13 @@ import org.bukkit.entity.Player;
import java.util.UUID; import java.util.UUID;
public abstract class NpcAction { public abstract class InteractionAction {
private final UUID id; private final UUID id;
private final long delay; private final long delay;
protected final String argument;
protected NpcAction(long delay, String argument) { protected InteractionAction(long delay) {
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
this.delay = delay; this.delay = delay;
this.argument = argument;
} }
public UUID getUuid() { public UUID getUuid() {
@ -23,11 +21,5 @@ public abstract class NpcAction {
return delay; return delay;
} }
public String getArgument() {
return argument;
}
public abstract void run(Player player); public abstract void run(Player player);
public abstract NpcActionType getType();
} }

View file

@ -8,23 +8,32 @@ import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import lol.pyr.znpcsplus.user.User; import lol.pyr.znpcsplus.user.User;
import lol.pyr.znpcsplus.user.UserManager;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class InteractionPacketListener implements PacketListener { public class InteractionPacketListener implements PacketListener {
private final UserManager userManager;
private final NpcRegistryImpl npcRegistry;
public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry) {
this.userManager = userManager;
this.npcRegistry = npcRegistry;
}
@Override @Override
public void onPacketReceive(PacketReceiveEvent event) { public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() != PacketType.Play.Client.INTERACT_ENTITY) return; if (event.getPacketType() != PacketType.Play.Client.INTERACT_ENTITY) return;
Player player = (Player) event.getPlayer(); Player player = (Player) event.getPlayer();
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event); WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
User user = User.get(player); User user = userManager.get(player);
if (!user.canInteract()) return; if (!user.canInteract()) return;
NpcEntryImpl entry = NpcRegistryImpl.get().getByEntityId(packet.getEntityId()); NpcEntryImpl entry = npcRegistry.getByEntityId(packet.getEntityId());
if (entry == null || !entry.isProcessed()) return; if (entry == null || !entry.isProcessed()) return;
NpcImpl npc = entry.getNpc(); NpcImpl npc = entry.getNpc();
for (NpcAction action : npc.getActions()) { for (InteractionAction action : npc.getActions()) {
if (action.getCooldown() > 0 && !user.actionCooldownCheck(action)) continue; if (action.getCooldown() > 0 && !user.actionCooldownCheck(action)) continue;
action.run(player); action.run(player);
} }

View file

@ -1,6 +0,0 @@
package lol.pyr.znpcsplus.interaction;
@FunctionalInterface
interface NpcActionDeserializer {
NpcAction deserialize(long delay, String argument);
}

View file

@ -1,21 +0,0 @@
package lol.pyr.znpcsplus.interaction;
import lol.pyr.znpcsplus.interaction.types.*;
public enum NpcActionType implements NpcActionDeserializer {
CONSOLE_CMD(ConsoleCommandAction::new),
MESSAGE(MessageAction::new),
PLAYER_CMD(PlayerCommandAction::new),
SERVER(SwitchServerAction::new);
private final NpcActionDeserializer deserializer;
NpcActionType(NpcActionDeserializer deserializer) {
this.deserializer = deserializer;
}
@Override
public NpcAction deserialize(long delay, String str) {
return deserializer.deserialize(delay, str);
}
}

View file

@ -1,25 +1,28 @@
package lol.pyr.znpcsplus.interaction.types; package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.interaction.InteractionAction;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.interaction.NpcActionType; import lol.pyr.znpcsplus.util.PapiUtil;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class ConsoleCommandAction extends NpcAction { public class ConsoleCommandAction extends InteractionAction {
public ConsoleCommandAction(long delay, String argument) { private final TaskScheduler scheduler;
super(delay, argument); private final String command;
public ConsoleCommandAction(TaskScheduler scheduler, String command, long delay) {
super(delay);
this.scheduler = scheduler;
this.command = command;
} }
@Override @Override
public void run(Player player) { public void run(Player player) {
String cmd = argument.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString()); String cmd = command.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString());
ZNpcsPlus.SCHEDULER.runSync(() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), ZNpcsPlus.PLACEHOLDERS_SUPPORTED ? PlaceholderAPI.setPlaceholders(player, cmd) : cmd)); scheduler.runSync(() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), PapiUtil.set(player, cmd)));
} }
@Override public String getCommand() {
public NpcActionType getType() { return command;
return NpcActionType.CONSOLE_CMD;
} }
} }

View file

@ -0,0 +1,26 @@
package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.util.StringSerializer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class ConsoleCommandActionSerializer implements StringSerializer<ConsoleCommandAction> {
private final TaskScheduler scheduler;
public ConsoleCommandActionSerializer(TaskScheduler scheduler) {
this.scheduler = scheduler;
}
@Override
public String serialize(ConsoleCommandAction obj) {
return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown();
}
@Override
public ConsoleCommandAction deserialize(String str) {
String[] split = str.split(";");
return new ConsoleCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), Long.parseLong(split[1]));
}
}

View file

@ -1,27 +1,26 @@
package lol.pyr.znpcsplus.interaction.types; package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.interaction.InteractionAction;
import lol.pyr.znpcsplus.interaction.NpcAction; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import lol.pyr.znpcsplus.interaction.NpcActionType;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class MessageAction extends NpcAction { public class MessageAction extends InteractionAction {
private final BukkitAudiences adventure;
private final Component message; private final Component message;
public MessageAction(long delay, String argument) { public MessageAction(BukkitAudiences adventure, Component message, long delay) {
super(delay, argument); super(delay);
message = MiniMessage.miniMessage().deserialize(argument); this.adventure = adventure;
this.message = message;
} }
@Override @Override
public void run(Player player) { public void run(Player player) {
ZNpcsPlus.ADVENTURE.player(player).sendMessage(message); adventure.player(player).sendMessage(message);
} }
@Override public Component getMessage() {
public NpcActionType getType() { return message;
return NpcActionType.MESSAGE;
} }
} }

View file

@ -0,0 +1,27 @@
package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.util.StringSerializer;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.minimessage.MiniMessage;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class MessageActionSerializer implements StringSerializer<MessageAction> {
private final BukkitAudiences adventure;
public MessageActionSerializer(BukkitAudiences adventure) {
this.adventure = adventure;
}
@Override
public String serialize(MessageAction obj) {
return Base64.getEncoder().encodeToString(MiniMessage.miniMessage().serialize(obj.getMessage()).getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown();
}
@Override
public MessageAction deserialize(String str) {
String[] split = str.split(";");
return new MessageAction(adventure, MiniMessage.miniMessage().deserialize(new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8)), Long.parseLong(split[1]));
}
}

View file

@ -1,25 +1,28 @@
package lol.pyr.znpcsplus.interaction.types; package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.interaction.InteractionAction;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.interaction.NpcActionType; import lol.pyr.znpcsplus.util.PapiUtil;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class PlayerCommandAction extends NpcAction { public class PlayerCommandAction extends InteractionAction {
public PlayerCommandAction(long delay, String argument) { private final TaskScheduler scheduler;
super(delay, argument); private final String command;
public PlayerCommandAction(TaskScheduler scheduler, String command, long delay) {
super(delay);
this.scheduler = scheduler;
this.command = command;
} }
@Override @Override
public void run(Player player) { public void run(Player player) {
String cmd = argument.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString()); String cmd = command.replace("{player}", player.getName()).replace("{uuid}", player.getUniqueId().toString());
ZNpcsPlus.SCHEDULER.runSync(() -> Bukkit.dispatchCommand(player, ZNpcsPlus.PLACEHOLDERS_SUPPORTED ? PlaceholderAPI.setPlaceholders(player, cmd) : cmd)); scheduler.runSync(() -> Bukkit.dispatchCommand(player, PapiUtil.set(player, cmd)));
} }
@Override public String getCommand() {
public NpcActionType getType() { return command;
return NpcActionType.PLAYER_CMD;
} }
} }

View file

@ -0,0 +1,26 @@
package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.util.StringSerializer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class PlayerCommandActionSerializer implements StringSerializer<PlayerCommandAction> {
private final TaskScheduler scheduler;
public PlayerCommandActionSerializer(TaskScheduler scheduler) {
this.scheduler = scheduler;
}
@Override
public String serialize(PlayerCommandAction obj) {
return Base64.getEncoder().encodeToString(obj.getCommand().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown();
}
@Override
public PlayerCommandAction deserialize(String str) {
String[] split = str.split(";");
return new PlayerCommandAction(scheduler, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), Long.parseLong(split[1]));
}
}

View file

@ -1,22 +1,25 @@
package lol.pyr.znpcsplus.interaction.types; package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.interaction.InteractionAction;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.util.BungeeUtil;
import lol.pyr.znpcsplus.interaction.NpcActionType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class SwitchServerAction extends NpcAction { public class SwitchServerAction extends InteractionAction {
public SwitchServerAction(long delay, String argument) { private final BungeeUtil bungeeUtil;
super(delay, argument); private final String server;
public SwitchServerAction(BungeeUtil bungeeUtil, String server, long delay) {
super(delay);
this.bungeeUtil = bungeeUtil;
this.server = server;
} }
@Override @Override
public void run(Player player) { public void run(Player player) {
ZNpcsPlus.BUNGEE_UTIL.sendPlayerToServer(player, argument); bungeeUtil.sendPlayerToServer(player, server);
} }
@Override public String getServer() {
public NpcActionType getType() { return server;
return NpcActionType.SERVER;
} }
} }

View file

@ -0,0 +1,26 @@
package lol.pyr.znpcsplus.interaction.types;
import lol.pyr.znpcsplus.util.BungeeUtil;
import lol.pyr.znpcsplus.util.StringSerializer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class SwitchServerActionSerializer implements StringSerializer<SwitchServerAction> {
private final BungeeUtil bungeeUtil;
public SwitchServerActionSerializer(BungeeUtil bungeeUtil) {
this.bungeeUtil = bungeeUtil;
}
@Override
public String serialize(SwitchServerAction obj) {
return Base64.getEncoder().encodeToString(obj.getServer().getBytes(StandardCharsets.UTF_8)) + ";" + obj.getCooldown();
}
@Override
public SwitchServerAction deserialize(String str) {
String[] split = str.split(";");
return new SwitchServerAction(bungeeUtil, new String(Base64.getDecoder().decode(split[0]), StandardCharsets.UTF_8), Long.parseLong(split[1]));
}
}

View file

@ -1,15 +1,9 @@
package lol.pyr.znpcsplus.metadata; package lol.pyr.znpcsplus.metadata;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.util.LazyLoader;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/** /**
* 1.8 https://wiki.vg/index.php?title=Entity_metadata&oldid=7415 * 1.8 https://wiki.vg/index.php?title=Entity_metadata&oldid=7415
@ -31,33 +25,4 @@ public interface MetadataFactory {
EntityData silent(boolean enabled); EntityData silent(boolean enabled);
Collection<EntityData> name(Component name); Collection<EntityData> name(Component name);
EntityData noGravity(); EntityData noGravity();
MetadataFactory factory = get();
static MetadataFactory get() {
if (factory != null) return factory;
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
Map<ServerVersion, LazyLoader<? extends MetadataFactory>> factories = buildFactoryMap();
if (factories.containsKey(version)) return factories.get(version).get();
for (ServerVersion v : ServerVersion.reversedValues()) {
if (v.isNewerThan(version)) continue;
if (!factories.containsKey(v)) continue;
MetadataFactory f = factories.get(v).get();
ZNpcsPlus.debug("Using MetadataFactory Version " + v.name() + " (" + f.getClass().getName() + ")");
return f;
}
throw new RuntimeException("Unsupported version!");
}
static Map<ServerVersion, LazyLoader<? extends MetadataFactory>> buildFactoryMap() {
HashMap<ServerVersion, LazyLoader<? extends MetadataFactory>> map = new HashMap<>();
map.put(ServerVersion.V_1_8, LazyLoader.of(V1_8Factory::new));
map.put(ServerVersion.V_1_9, LazyLoader.of(V1_9Factory::new));
map.put(ServerVersion.V_1_10, LazyLoader.of(V1_10Factory::new));
map.put(ServerVersion.V_1_13, LazyLoader.of(V1_13Factory::new));
map.put(ServerVersion.V_1_14, LazyLoader.of(V1_14Factory::new));
map.put(ServerVersion.V_1_16, LazyLoader.of(V1_16Factory::new));
map.put(ServerVersion.V_1_17, LazyLoader.of(V1_17Factory::new));
return map;
}
} }

View file

@ -3,7 +3,7 @@ package lol.pyr.znpcsplus.metadata;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
public class V1_10Factory extends V1_9Factory { public class V1_10MetadataFactory extends V1_9MetadataFactory {
@Override @Override
public EntityData noGravity() { public EntityData noGravity() {
return new EntityData(5, EntityDataTypes.BOOLEAN, true); return new EntityData(5, EntityDataTypes.BOOLEAN, true);

View file

@ -9,7 +9,7 @@ import net.kyori.adventure.text.Component;
import java.util.Collection; import java.util.Collection;
import java.util.Optional; import java.util.Optional;
public class V1_13Factory extends V1_10Factory { public class V1_13MetadataFactory extends V1_10MetadataFactory {
@Override @Override
public Collection<EntityData> name(Component name) { public Collection<EntityData> name(Component name) {
return ListUtil.immutableList( return ListUtil.immutableList(

View file

@ -2,7 +2,7 @@ package lol.pyr.znpcsplus.metadata;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
public class V1_14Factory extends V1_13Factory { public class V1_14MetadataFactory extends V1_13MetadataFactory {
@Override @Override
public EntityData skinLayers(boolean enabled) { public EntityData skinLayers(boolean enabled) {
return createSkinLayers(15, enabled); return createSkinLayers(15, enabled);

View file

@ -2,7 +2,7 @@ package lol.pyr.znpcsplus.metadata;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
public class V1_16Factory extends V1_14Factory { public class V1_16MetadataFactory extends V1_14MetadataFactory {
@Override @Override
public EntityData skinLayers(boolean enabled) { public EntityData skinLayers(boolean enabled) {
return createSkinLayers(16, enabled); return createSkinLayers(16, enabled);

View file

@ -2,7 +2,7 @@ package lol.pyr.znpcsplus.metadata;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
public class V1_17Factory extends V1_16Factory { public class V1_17MetadataFactory extends V1_16MetadataFactory {
@Override @Override
public EntityData skinLayers(boolean enabled) { public EntityData skinLayers(boolean enabled) {
return createSkinLayers(17, enabled); return createSkinLayers(17, enabled);

View file

@ -8,7 +8,7 @@ import net.kyori.adventure.text.Component;
import java.util.Collection; import java.util.Collection;
public class V1_8Factory implements MetadataFactory { public class V1_8MetadataFactory implements MetadataFactory {
@Override @Override
public EntityData skinLayers(boolean enabled) { public EntityData skinLayers(boolean enabled) {
return createSkinLayers(12, enabled); return createSkinLayers(12, enabled);

View file

@ -8,7 +8,7 @@ import net.kyori.adventure.text.Component;
import java.util.Collection; import java.util.Collection;
public class V1_9Factory extends V1_8Factory { public class V1_9MetadataFactory extends V1_8MetadataFactory {
@Override @Override
public EntityData skinLayers(boolean enabled) { public EntityData skinLayers(boolean enabled) {
return createSkinLayers(13, enabled); return createSkinLayers(13, enabled);

View file

@ -2,10 +2,12 @@ package lol.pyr.znpcsplus.npc;
import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.npc.Npc; import lol.pyr.znpcsplus.api.npc.Npc;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.hologram.HologramImpl; import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.interaction.InteractionAction;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.Viewable; import lol.pyr.znpcsplus.util.Viewable;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -16,6 +18,7 @@ import org.bukkit.entity.Player;
import java.util.*; import java.util.*;
public class NpcImpl extends Viewable implements Npc { public class NpcImpl extends Viewable implements Npc {
private final PacketFactory packetFactory;
private final String worldName; private final String worldName;
private PacketEntity entity; private PacketEntity entity;
private ZLocation location; private ZLocation location;
@ -23,25 +26,26 @@ public class NpcImpl extends Viewable implements Npc {
private final HologramImpl hologram; private final HologramImpl hologram;
private final Map<EntityPropertyImpl<?>, Object> propertyMap = new HashMap<>(); private final Map<EntityPropertyImpl<?>, Object> propertyMap = new HashMap<>();
private final Set<NpcAction> actions = new HashSet<>(); private final Set<InteractionAction> actions = new HashSet<>();
protected NpcImpl(World world, NpcTypeImpl type, ZLocation location) { protected NpcImpl(ConfigManager configManager, World world, NpcTypeImpl type, ZLocation location, PacketFactory packetFactory) {
this(world.getName(), type, location); this(configManager, packetFactory, world.getName(), type, location);
} }
public NpcImpl(String world, NpcTypeImpl type, ZLocation location) { public NpcImpl(ConfigManager configManager, PacketFactory packetFactory, String world, NpcTypeImpl type, ZLocation location) {
this.packetFactory = packetFactory;
this.worldName = world; this.worldName = world;
this.type = type; this.type = type;
this.location = location; this.location = location;
entity = new PacketEntity(this, type.getType(), location); entity = new PacketEntity(packetFactory, this, type.getType(), location);
hologram = new HologramImpl(location.withY(location.getY() + type.getHologramOffset())); hologram = new HologramImpl(configManager, packetFactory, location.withY(location.getY() + type.getHologramOffset()));
} }
public void setType(NpcTypeImpl type) { public void setType(NpcTypeImpl type) {
UNSAFE_hideAll(); UNSAFE_hideAll();
this.type = type; this.type = type;
entity = new PacketEntity(this, type.getType(), entity.getLocation()); entity = new PacketEntity(packetFactory, this, type.getType(), entity.getLocation());
UNSAFE_showAll(); UNSAFE_showAll();
} }
@ -130,11 +134,11 @@ public class NpcImpl extends Viewable implements Npc {
return Collections.unmodifiableSet(propertyMap.keySet()); return Collections.unmodifiableSet(propertyMap.keySet());
} }
public Collection<NpcAction> getActions() { public Collection<InteractionAction> getActions() {
return Collections.unmodifiableSet(actions); return Collections.unmodifiableSet(actions);
} }
public void addAction(NpcAction action) { public void addAction(InteractionAction action) {
actions.add(action); actions.add(action);
} }
} }

View file

@ -1,8 +1,11 @@
package lol.pyr.znpcsplus.npc; package lol.pyr.znpcsplus.npc;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.api.npc.NpcRegistry; import lol.pyr.znpcsplus.api.npc.NpcRegistry;
import lol.pyr.znpcsplus.api.npc.NpcType; import lol.pyr.znpcsplus.api.npc.NpcType;
import lol.pyr.znpcsplus.config.Configs; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.interaction.ActionRegistry;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.storage.NpcStorage; import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import org.bukkit.World; import org.bukkit.World;
@ -14,25 +17,23 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class NpcRegistryImpl implements NpcRegistry { public class NpcRegistryImpl implements NpcRegistry {
private final static NpcRegistryImpl registry = new NpcRegistryImpl(); private final NpcStorage storage;
public static NpcRegistryImpl get() { private final PacketFactory packetFactory;
return registry; private final ConfigManager configManager;
}
private final NpcStorage STORAGE; public NpcRegistryImpl(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistry actionRegistry) {
storage = configManager.getConfig().storageType().create(configManager, plugin, packetFactory, actionRegistry);
private NpcRegistryImpl() { this.packetFactory = packetFactory;
if (registry != null) throw new UnsupportedOperationException("This class can only be instanciated once!"); this.configManager = configManager;
STORAGE = Configs.config().storageType().create();
} }
public void reload() { public void reload() {
npcMap.clear(); npcMap.clear();
for (NpcEntryImpl entry : STORAGE.loadNpcs()) npcMap.put(entry.getId(), entry); for (NpcEntryImpl entry : storage.loadNpcs()) npcMap.put(entry.getId(), entry);
} }
public void save() { public void save() {
STORAGE.saveNpcs(npcMap.values().stream().filter(NpcEntryImpl::isSave).collect(Collectors.toList())); storage.saveNpcs(npcMap.values().stream().filter(NpcEntryImpl::isSave).collect(Collectors.toList()));
} }
private final Map<String, NpcEntryImpl> npcMap = new HashMap<>(); private final Map<String, NpcEntryImpl> npcMap = new HashMap<>();
@ -73,7 +74,7 @@ public class NpcRegistryImpl implements NpcRegistry {
public NpcEntryImpl create(String id, World world, NpcTypeImpl type, ZLocation location) { public NpcEntryImpl create(String id, World world, NpcTypeImpl type, ZLocation location) {
id = id.toLowerCase(); id = id.toLowerCase();
if (npcMap.containsKey(id)) throw new IllegalArgumentException("An npc with the id " + id + " already exists!"); if (npcMap.containsKey(id)) throw new IllegalArgumentException("An npc with the id " + id + " already exists!");
NpcImpl npc = new NpcImpl(world, type, location); NpcImpl npc = new NpcImpl(configManager, world, type, location, packetFactory);
NpcEntryImpl entry = new NpcEntryImpl(id, npc); NpcEntryImpl entry = new NpcEntryImpl(id, npc);
npcMap.put(id, entry); npcMap.put(id, entry);
return entry; return entry;

View file

@ -1,15 +1,12 @@
package lol.pyr.znpcsplus.packets; package lol.pyr.znpcsplus.packets;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData; import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.util.LazyLoader;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.*; import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface PacketFactory { public interface PacketFactory {
@ -24,31 +21,4 @@ public interface PacketFactory {
Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties); Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties);
void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties); void sendAllMetadata(Player player, PacketEntity entity, PropertyHolder properties);
void sendMetadata(Player player, PacketEntity entity, List<EntityData> data); void sendMetadata(Player player, PacketEntity entity, List<EntityData> data);
PacketFactory factory = get();
static PacketFactory get() {
if (factory != null) return factory;
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
Map<ServerVersion, LazyLoader<? extends PacketFactory>> factories = buildFactoryMap();
if (factories.containsKey(version)) return factories.get(version).get();
for (ServerVersion v : ServerVersion.reversedValues()) {
if (v.isNewerThan(version)) continue;
if (!factories.containsKey(v)) continue;
PacketFactory f = factories.get(v).get();
ZNpcsPlus.debug("Using PacketFactory Version " + v.name() + " (" + f.getClass().getName() + ")");
return f;
}
throw new RuntimeException("Unsupported version!");
}
static Map<ServerVersion, LazyLoader<? extends PacketFactory>> buildFactoryMap() {
HashMap<ServerVersion, LazyLoader<? extends PacketFactory>> map = new HashMap<>();
map.put(ServerVersion.V_1_8, LazyLoader.of(V1_8Factory::new));
map.put(ServerVersion.V_1_9, LazyLoader.of(V1_9Factory::new));
map.put(ServerVersion.V_1_10, LazyLoader.of(V1_10Factory::new));
map.put(ServerVersion.V_1_14, LazyLoader.of(V1_14Factory::new));
map.put(ServerVersion.V_1_19, LazyLoader.of(V1_19Factory::new));
return map;
}
} }

View file

@ -4,15 +4,20 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.metadata.MetadataFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Map; import java.util.Map;
public class V1_10Factory extends V1_9Factory { public class V1_10PacketFactory extends V1_9PacketFactory {
public V1_10PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory) {
super(scheduler, metadataFactory);
}
@Override @Override
public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) {
Map<Integer, EntityData> data = super.generateMetadata(player, entity, properties); Map<Integer, EntityData> data = super.generateMetadata(player, entity, properties);
add(data, MetadataFactory.get().noGravity()); add(data, metadataFactory.noGravity());
return data; return data;
} }
} }

View file

@ -4,12 +4,18 @@ import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.metadata.MetadataFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Optional; import java.util.Optional;
public class V1_14Factory extends V1_10Factory { public class V1_14PacketFactory extends V1_10PacketFactory {
public V1_14PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory) {
super(scheduler, metadataFactory);
}
@Override @Override
public void spawnEntity(Player player, PacketEntity entity, PropertyHolder properties) { public void spawnEntity(Player player, PacketEntity entity, PropertyHolder properties) {
ZLocation location = entity.getLocation(); ZLocation location = entity.getLocation();

View file

@ -7,13 +7,19 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPl
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate; import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.metadata.MetadataFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class V1_19Factory extends V1_14Factory { public class V1_19PacketFactory extends V1_14PacketFactory {
public V1_19PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory) {
super(scheduler, metadataFactory);
}
@Override @Override
public CompletableFuture<Void> addTabPlayer(Player player, PacketEntity entity, PropertyHolder properties) { public CompletableFuture<Void> addTabPlayer(Player player, PacketEntity entity, PropertyHolder properties) {
if (entity.getType() != EntityTypes.PLAYER) return CompletableFuture.completedFuture(null); if (entity.getType() != EntityTypes.PLAYER) return CompletableFuture.completedFuture(null);

View file

@ -10,11 +10,11 @@ import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.*; import com.github.retrooper.packetevents.wrapper.play.server.*;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.api.entity.PropertyHolder; import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.metadata.MetadataFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor; import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@ -24,7 +24,15 @@ import org.bukkit.entity.Player;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class V1_8Factory implements PacketFactory { public class V1_8PacketFactory implements PacketFactory {
protected final TaskScheduler scheduler;
protected final MetadataFactory metadataFactory;
public V1_8PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory) {
this.scheduler = scheduler;
this.metadataFactory = metadataFactory;
}
@Override @Override
public void spawnPlayer(Player player, PacketEntity entity, PropertyHolder properties) { public void spawnPlayer(Player player, PacketEntity entity, PropertyHolder properties) {
addTabPlayer(player, entity, properties).thenAccept(ignored -> { addTabPlayer(player, entity, properties).thenAccept(ignored -> {
@ -34,7 +42,7 @@ public class V1_8Factory implements PacketFactory {
entity.getUuid(), location.toVector3d(), location.getYaw(), location.getPitch(), Collections.emptyList())); entity.getUuid(), location.toVector3d(), location.getYaw(), location.getPitch(), Collections.emptyList()));
sendPacket(player, new WrapperPlayServerEntityHeadLook(entity.getEntityId(), location.getYaw())); sendPacket(player, new WrapperPlayServerEntityHeadLook(entity.getEntityId(), location.getYaw()));
sendAllMetadata(player, entity, properties); sendAllMetadata(player, entity, properties);
ZNpcsPlus.SCHEDULER.runLaterAsync(() -> removeTabPlayer(player, entity), 60); scheduler.runLaterAsync(() -> removeTabPlayer(player, entity), 60);
}); });
} }
@ -106,10 +114,10 @@ public class V1_8Factory implements PacketFactory {
@Override @Override
public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) {
HashMap<Integer, EntityData> data = new HashMap<>(); HashMap<Integer, EntityData> data = new HashMap<>();
if (entity.getType() == EntityTypes.PLAYER) add(data, MetadataFactory.get().skinLayers(properties.getProperty(EntityPropertyImpl.SKIN_LAYERS))); if (entity.getType() == EntityTypes.PLAYER) add(data, metadataFactory.skinLayers(properties.getProperty(EntityPropertyImpl.SKIN_LAYERS)));
add(data, MetadataFactory.get().effects(properties.getProperty(EntityPropertyImpl.FIRE), false, properties.getProperty(EntityPropertyImpl.INVISIBLE))); add(data, metadataFactory.effects(properties.getProperty(EntityPropertyImpl.FIRE), false, properties.getProperty(EntityPropertyImpl.INVISIBLE)));
add(data, MetadataFactory.get().silent(properties.getProperty(EntityPropertyImpl.SILENT))); add(data, metadataFactory.silent(properties.getProperty(EntityPropertyImpl.SILENT)));
if (properties.hasProperty(EntityPropertyImpl.NAME)) addAll(data, MetadataFactory.get().name(properties.getProperty(EntityPropertyImpl.NAME))); if (properties.hasProperty(EntityPropertyImpl.NAME)) addAll(data, metadataFactory.name(properties.getProperty(EntityPropertyImpl.NAME)));
return data; return data;
} }

View file

@ -5,15 +5,20 @@ import lol.pyr.znpcsplus.api.entity.PropertyHolder;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.PacketEntity; import lol.pyr.znpcsplus.entity.PacketEntity;
import lol.pyr.znpcsplus.metadata.MetadataFactory; import lol.pyr.znpcsplus.metadata.MetadataFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Map; import java.util.Map;
public class V1_9Factory extends V1_8Factory { public class V1_9PacketFactory extends V1_8PacketFactory {
public V1_9PacketFactory(TaskScheduler scheduler, MetadataFactory metadataFactory) {
super(scheduler, metadataFactory);
}
@Override @Override
public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) { public Map<Integer, EntityData> generateMetadata(Player player, PacketEntity entity, PropertyHolder properties) {
Map<Integer, EntityData> data = super.generateMetadata(player, entity, properties); Map<Integer, EntityData> data = super.generateMetadata(player, entity, properties);
add(data, MetadataFactory.get().effects(properties.getProperty(EntityPropertyImpl.FIRE), properties.hasProperty(EntityPropertyImpl.GLOW), properties.getProperty(EntityPropertyImpl.INVISIBLE))); add(data, metadataFactory.effects(properties.getProperty(EntityPropertyImpl.FIRE), properties.hasProperty(EntityPropertyImpl.GLOW), properties.getProperty(EntityPropertyImpl.INVISIBLE)));
return data; return data;
} }
} }

View file

@ -1,13 +1,14 @@
package lol.pyr.znpcsplus.reflection; package lol.pyr.znpcsplus.reflection;
import lol.pyr.znpcsplus.util.VersionUtil; import lol.pyr.znpcsplus.util.VersionUtil;
import lol.pyr.znpcsplus.ZNpcsPlus;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Logger;
public abstract class ReflectionLazyLoader<T> { public abstract class ReflectionLazyLoader<T> {
private final static Logger logger = Logger.getLogger("ZNPCsPlus Reflection");
protected final List<String> possibleClassNames; protected final List<String> possibleClassNames;
protected List<Class<?>> reflectionClasses = new ArrayList<>(); protected List<Class<?>> reflectionClasses = new ArrayList<>();
protected final boolean strict; protected final boolean strict;
@ -34,25 +35,21 @@ public abstract class ReflectionLazyLoader<T> {
if (eval == null) throw new RuntimeException("Returned value is null"); if (eval == null) throw new RuntimeException("Returned value is null");
} catch (Throwable throwable) { } catch (Throwable throwable) {
if (strict) { if (strict) {
warn(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON THE ZNPCSPLUS GITHUB ----- "); logger.warning(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON THE ZNPCSPLUS GITHUB ----- ");
warn(getClass().getSimpleName() + " failed!"); logger.warning(getClass().getSimpleName() + " failed!");
warn("Class Names: " + possibleClassNames); logger.warning("Class Names: " + possibleClassNames);
warn("Reflection Type: " + getClass().getCanonicalName()); logger.warning("Reflection Type: " + getClass().getCanonicalName());
warn("Bukkit Version: " + VersionUtil.BUKKIT_VERSION + " (" + VersionUtil.getBukkitPackage() + ")"); logger.warning("Bukkit Version: " + VersionUtil.BUKKIT_VERSION + " (" + VersionUtil.getBukkitPackage() + ")");
printDebugInfo(this::warn); printDebugInfo(logger::warning);
warn("Exception:"); logger.warning("Exception:");
throwable.printStackTrace(); throwable.printStackTrace();
warn(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON THE ZNPCSPLUS GITHUB ----- "); logger.warning(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON THE ZNPCSPLUS GITHUB ----- ");
} }
} }
this.loaded = true; this.loaded = true;
return this.cached; return this.cached;
} }
private void warn(String message) {
ZNpcsPlus.LOGGER.warning("[Reflection] " + message);
}
protected abstract T load() throws Exception; protected abstract T load() throws Exception;
protected void printDebugInfo(Consumer<String> logger) {} protected void printDebugInfo(Consumer<String> logger) {}
} }

View file

@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.skin;
import com.github.retrooper.packetevents.protocol.player.TextureProperty; import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor; import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.skin.cache.SkinCache;
import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor; import lol.pyr.znpcsplus.skin.descriptor.FetchingDescriptor;
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor; import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
@ -17,10 +18,10 @@ public interface BaseSkinDescriptor extends SkinDescriptor {
boolean supportsInstant(Player player); boolean supportsInstant(Player player);
String serialize(); String serialize();
static BaseSkinDescriptor deserialize(String str) { static BaseSkinDescriptor deserialize(SkinCache skinCache, String str) {
String[] arr = str.split(";"); String[] arr = str.split(";");
if (arr[0].equalsIgnoreCase("mirror")) return new MirrorDescriptor(); if (arr[0].equalsIgnoreCase("mirror")) return new MirrorDescriptor(skinCache);
else if (arr[0].equalsIgnoreCase("fetching")) return new FetchingDescriptor(arr[1]); else if (arr[0].equalsIgnoreCase("fetching")) return new FetchingDescriptor(skinCache, arr[1]);
else if (arr[0].equalsIgnoreCase("prefetched")) { else if (arr[0].equalsIgnoreCase("prefetched")) {
List<TextureProperty> properties = new ArrayList<>(); List<TextureProperty> properties = new ArrayList<>();
for (int i = 0; i < (arr.length - 1) / 3; i++) { for (int i = 0; i < (arr.length - 1) / 3; i++) {

View file

@ -3,8 +3,7 @@ package lol.pyr.znpcsplus.skin.cache;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.config.Configs;
import lol.pyr.znpcsplus.reflection.Reflections; import lol.pyr.znpcsplus.reflection.Reflections;
import lol.pyr.znpcsplus.skin.Skin; import lol.pyr.znpcsplus.skin.Skin;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -22,17 +21,26 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
public class SkinCache { public class SkinCache {
private final static Map<String, Skin> cache = new ConcurrentHashMap<>(); private final static Logger logger = Logger.getLogger("ZNPCsPlus Skin Cache");
private final static Map<String, CachedId> idCache = new ConcurrentHashMap<>();
public static void cleanCache() { private final ConfigManager configManager;
private final Map<String, Skin> cache = new ConcurrentHashMap<>();
private final Map<String, CachedId> idCache = new ConcurrentHashMap<>();
public SkinCache(ConfigManager configManager) {
this.configManager = configManager;
}
public void cleanCache() {
for (Map.Entry<String, Skin> entry : cache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey()); for (Map.Entry<String, Skin> entry : cache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey());
for (Map.Entry<String, CachedId> entry : idCache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey()); for (Map.Entry<String, CachedId> entry : idCache.entrySet()) if (entry.getValue().isExpired()) cache.remove(entry.getKey());
} }
public static CompletableFuture<Skin> fetchByName(String name) { public CompletableFuture<Skin> fetchByName(String name) {
Player player = Bukkit.getPlayerExact(name); Player player = Bukkit.getPlayerExact(name);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player)); if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
@ -52,8 +60,8 @@ public class SkinCache {
return fetchByUUID(id).join(); return fetchByUUID(id).join();
} }
} catch (IOException exception) { } catch (IOException exception) {
if (!Configs.config().disableSkinFetcherWarnings()) { if (!configManager.getConfig().disableSkinFetcherWarnings()) {
ZNpcsPlus.LOGGER.warning("Failed to uuid from player name:"); logger.warning("Failed to uuid from player name:");
exception.printStackTrace(); exception.printStackTrace();
} }
} finally { } finally {
@ -63,11 +71,11 @@ public class SkinCache {
}); });
} }
public static CompletableFuture<Skin> fetchByUUID(UUID uuid) { public CompletableFuture<Skin> fetchByUUID(UUID uuid) {
return fetchByUUID(uuid.toString().replace("-", "")); return fetchByUUID(uuid.toString().replace("-", ""));
} }
public static boolean isNameFullyCached(String s) { public boolean isNameFullyCached(String s) {
String name = s.toLowerCase(); String name = s.toLowerCase();
if (!idCache.containsKey(name)) return false; if (!idCache.containsKey(name)) return false;
CachedId id = idCache.get(name); CachedId id = idCache.get(name);
@ -76,7 +84,7 @@ public class SkinCache {
return !skin.isExpired(); return !skin.isExpired();
} }
public static Skin getFullyCachedByName(String s) { public Skin getFullyCachedByName(String s) {
String name = s.toLowerCase(); String name = s.toLowerCase();
if (!idCache.containsKey(name)) return null; if (!idCache.containsKey(name)) return null;
CachedId id = idCache.get(name); CachedId id = idCache.get(name);
@ -86,7 +94,7 @@ public class SkinCache {
return skin; return skin;
} }
public static CompletableFuture<Skin> fetchByUUID(String uuid) { public CompletableFuture<Skin> fetchByUUID(String uuid) {
Player player = Bukkit.getPlayer(uuid); Player player = Bukkit.getPlayer(uuid);
if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player)); if (player != null && player.isOnline()) return CompletableFuture.completedFuture(getFromPlayer(player));
@ -108,8 +116,8 @@ public class SkinCache {
return skin; return skin;
} }
} catch (IOException exception) { } catch (IOException exception) {
if (!Configs.config().disableSkinFetcherWarnings()) { if (!configManager.getConfig().disableSkinFetcherWarnings()) {
ZNpcsPlus.LOGGER.warning("Failed to fetch skin:"); logger.warning("Failed to fetch skin:");
exception.printStackTrace(); exception.printStackTrace();
} }
} finally { } finally {
@ -119,7 +127,7 @@ public class SkinCache {
}); });
} }
public static Skin getFromPlayer(Player player) { public Skin getFromPlayer(Player player) {
try { try {
Object playerHandle = Reflections.GET_HANDLE_PLAYER_METHOD.get().invoke(player); Object playerHandle = Reflections.GET_HANDLE_PLAYER_METHOD.get().invoke(player);
GameProfile gameProfile = (GameProfile) Reflections.GET_PROFILE_METHOD.get().invoke(playerHandle, new Object[0]); GameProfile gameProfile = (GameProfile) Reflections.GET_PROFILE_METHOD.get().invoke(playerHandle, new Object[0]);

View file

@ -1,15 +1,16 @@
package lol.pyr.znpcsplus.skin.cache; package lol.pyr.znpcsplus.skin.cache;
import lol.pyr.znpcsplus.ZNpcsPlus;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
public class SkinCacheCleanTask extends BukkitRunnable { public class SkinCacheCleanTask extends BukkitRunnable {
public SkinCacheCleanTask() { private final SkinCache skinCache;
ZNpcsPlus.SCHEDULER.runDelayedTimerAsync(this, 1200, 1200);
public SkinCacheCleanTask(SkinCache skinCache) {
this.skinCache = skinCache;
} }
@Override @Override
public void run() { public void run() {
SkinCache.cleanCache(); skinCache.cleanCache();
} }
} }

View file

@ -1,40 +1,36 @@
package lol.pyr.znpcsplus.skin.descriptor; package lol.pyr.znpcsplus.skin.descriptor;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.api.skin.SkinDescriptor; import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
import lol.pyr.znpcsplus.skin.BaseSkinDescriptor; import lol.pyr.znpcsplus.skin.BaseSkinDescriptor;
import lol.pyr.znpcsplus.skin.Skin; import lol.pyr.znpcsplus.skin.Skin;
import lol.pyr.znpcsplus.skin.cache.SkinCache; import lol.pyr.znpcsplus.skin.cache.SkinCache;
import me.clip.placeholderapi.PlaceholderAPI; import lol.pyr.znpcsplus.util.PapiUtil;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class FetchingDescriptor implements BaseSkinDescriptor, SkinDescriptor { public class FetchingDescriptor implements BaseSkinDescriptor, SkinDescriptor {
private final SkinCache skinCache;
private final String name; private final String name;
public FetchingDescriptor(String name) { public FetchingDescriptor(SkinCache skinCache, String name) {
this.skinCache = skinCache;
this.name = name; this.name = name;
} }
@Override @Override
public CompletableFuture<Skin> fetch(Player player) { public CompletableFuture<Skin> fetch(Player player) {
return SkinCache.fetchByName(papi(player)); return skinCache.fetchByName(PapiUtil.set(player, name));
} }
@Override @Override
public Skin fetchInstant(Player player) { public Skin fetchInstant(Player player) {
return SkinCache.getFullyCachedByName(papi(player)); return skinCache.getFullyCachedByName(PapiUtil.set(player, name));
} }
@Override @Override
public boolean supportsInstant(Player player) { public boolean supportsInstant(Player player) {
return SkinCache.isNameFullyCached(papi(player)); return skinCache.isNameFullyCached(PapiUtil.set(player, name));
}
private String papi(Player player) {
if (ZNpcsPlus.PLACEHOLDERS_SUPPORTED) return PlaceholderAPI.setPlaceholders(player, name);
return name;
} }
public String getName() { public String getName() {

View file

@ -9,17 +9,20 @@ import org.bukkit.entity.Player;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class MirrorDescriptor implements BaseSkinDescriptor, SkinDescriptor { public class MirrorDescriptor implements BaseSkinDescriptor, SkinDescriptor {
private final SkinCache skinCache;
public MirrorDescriptor() {} public MirrorDescriptor(SkinCache skinCache) {
this.skinCache = skinCache;
}
@Override @Override
public CompletableFuture<Skin> fetch(Player player) { public CompletableFuture<Skin> fetch(Player player) {
return CompletableFuture.completedFuture(SkinCache.getFromPlayer(player)); return CompletableFuture.completedFuture(skinCache.getFromPlayer(player));
} }
@Override @Override
public Skin fetchInstant(Player player) { public Skin fetchInstant(Player player) {
return SkinCache.getFromPlayer(player); return skinCache.getFromPlayer(player);
} }
@Override @Override

View file

@ -16,8 +16,8 @@ public class PrefetchedDescriptor implements BaseSkinDescriptor, SkinDescriptor
this.skin = skin; this.skin = skin;
} }
public static CompletableFuture<PrefetchedDescriptor> forPlayer(String name) { public static CompletableFuture<PrefetchedDescriptor> forPlayer(SkinCache cache, String name) {
return CompletableFuture.supplyAsync(() -> new PrefetchedDescriptor(SkinCache.fetchByName(name).join())); return CompletableFuture.supplyAsync(() -> new PrefetchedDescriptor(cache.fetchByName(name).join()));
} }
@Override @Override

View file

@ -1,14 +1,20 @@
package lol.pyr.znpcsplus.storage; package lol.pyr.znpcsplus.storage;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.interaction.ActionRegistry;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.storage.yaml.YamlStorage; import lol.pyr.znpcsplus.storage.yaml.YamlStorage;
import java.io.File;
public enum NpcStorageType { public enum NpcStorageType {
YAML { YAML {
@Override @Override
public NpcStorage create() { public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistry actionRegistry) {
return new YamlStorage(); return new YamlStorage(packetFactory, configManager, actionRegistry, new File(plugin.getDataFolder(), "data"));
} }
}; };
public abstract NpcStorage create(); public abstract NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistry actionRegistry);
} }

View file

@ -1,7 +0,0 @@
package lol.pyr.znpcsplus.storage;
public class SerializationException extends RuntimeException {
public SerializationException(String message) {
super(message);
}
}

View file

@ -1,13 +1,13 @@
package lol.pyr.znpcsplus.storage.yaml; package lol.pyr.znpcsplus.storage.yaml;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl; import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.hologram.HologramLine; import lol.pyr.znpcsplus.hologram.HologramLine;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.interaction.ActionRegistry;
import lol.pyr.znpcsplus.interaction.NpcActionType;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcTypeImpl; import lol.pyr.znpcsplus.npc.NpcTypeImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.storage.NpcStorage; import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.util.ZLocation; import lol.pyr.znpcsplus.util.ZLocation;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
@ -16,28 +16,32 @@ import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.Collection; import java.util.stream.Collectors;
import java.util.Collections;
import java.util.List;
public class YamlStorage implements NpcStorage { public class YamlStorage implements NpcStorage {
private final File npcsFolder; private final PacketFactory packetFactory;
private final ConfigManager configManager;
private final ActionRegistry actionRegistry;
private final File folder;
public YamlStorage() { public YamlStorage(PacketFactory packetFactory, ConfigManager configManager, ActionRegistry actionRegistry, File folder) {
npcsFolder = new File(ZNpcsPlus.PLUGIN_FOLDER, "npcs"); this.packetFactory = packetFactory;
if (!npcsFolder.exists()) npcsFolder.mkdirs(); this.configManager = configManager;
this.actionRegistry = actionRegistry;
this.folder = folder;
if (!this.folder.exists()) this.folder.mkdirs();
} }
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@Override @Override
public Collection<NpcEntryImpl> loadNpcs() { public Collection<NpcEntryImpl> loadNpcs() {
File[] files = npcsFolder.listFiles(); File[] files = folder.listFiles();
if (files == null || files.length == 0) return Collections.emptyList(); if (files == null || files.length == 0) return Collections.emptyList();
List<NpcEntryImpl> npcs = new ArrayList<>(); List<NpcEntryImpl> npcs = new ArrayList<>();
for (File file : files) if (file.isFile() && file.getName().toLowerCase().endsWith(".yml")) { for (File file : files) if (file.isFile() && file.getName().toLowerCase().endsWith(".yml")) {
YamlConfiguration config = YamlConfiguration.loadConfiguration(file); YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
NpcImpl npc = new NpcImpl(config.getString("world"), NpcTypeImpl.byName(config.getString("type")), NpcImpl npc = new NpcImpl(configManager, packetFactory, config.getString("world"), NpcTypeImpl.byName(config.getString("type")),
deserializeLocation(config.getConfigurationSection("location"))); deserializeLocation(config.getConfigurationSection("location")));
ConfigurationSection properties = config.getConfigurationSection("properties"); ConfigurationSection properties = config.getConfigurationSection("properties");
@ -48,16 +52,8 @@ public class YamlStorage implements NpcStorage {
} }
} }
for (String line : config.getStringList("hologram")) { for (String line : config.getStringList("hologram")) npc.getHologram().addLine(MiniMessage.miniMessage().deserialize(line));
npc.getHologram().addLine(MiniMessage.miniMessage().deserialize(line)); for (String s : config.getStringList("actions")) npc.addAction(actionRegistry.deserialize(s));
}
int amt = config.getInt("action-amount");
for (int i = 1; i <= amt; i++) {
String key = "actions." + i;
npc.addAction(NpcActionType.valueOf(config.getString(key + ".type"))
.deserialize(config.getInt(key + ".cooldown"), config.getString(key + ".argument")));
}
NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc); NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc);
entry.setProcessed(config.getBoolean("is-processed")); entry.setProcessed(config.getBoolean("is-processed"));
@ -71,7 +67,7 @@ public class YamlStorage implements NpcStorage {
@Override @Override
public void saveNpcs(Collection<NpcEntryImpl> npcs) { public void saveNpcs(Collection<NpcEntryImpl> npcs) {
File[] files = npcsFolder.listFiles(); File[] files = folder.listFiles();
if (files != null && files.length != 0) for (File file : files) file.delete(); if (files != null && files.length != 0) for (File file : files) file.delete();
for (NpcEntryImpl entry : npcs) try { for (NpcEntryImpl entry : npcs) try {
YamlConfiguration config = new YamlConfiguration(); YamlConfiguration config = new YamlConfiguration();
@ -93,17 +89,12 @@ public class YamlStorage implements NpcStorage {
lines.add(MiniMessage.miniMessage().serialize(line.getText())); lines.add(MiniMessage.miniMessage().serialize(line.getText()));
} }
config.set("hologram", lines); config.set("hologram", lines);
config.set("actions", npc.getActions().stream()
.map(actionRegistry::serialize)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
int i = 0; config.save(new File(folder, entry.getId() + ".yml"));
for (NpcAction action : npc.getActions()) { i++;
String key = "actions." + i;
config.set(key + ".type", action.getType().name());
config.set(key + ".cooldown", action.getCooldown());
config.set(key + ".argument", action.getArgument());
}
config.set("action-amount", i);
config.save(new File(npcsFolder, entry.getId() + ".yml"));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View file

@ -1,7 +1,6 @@
package lol.pyr.znpcsplus.tasks; package lol.pyr.znpcsplus.tasks;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.config.Configs;
import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
@ -11,13 +10,17 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.NumberConversions; import org.bukkit.util.NumberConversions;
public class NpcVisibilityTask extends BukkitRunnable { public class NpcVisibilityTask extends BukkitRunnable {
public NpcVisibilityTask() { private final NpcRegistryImpl npcRegistry;
ZNpcsPlus.SCHEDULER.runDelayedTimerAsync(this, 60L, 10L); private final ConfigManager configManager;
public NpcVisibilityTask(NpcRegistryImpl npcRegistry, ConfigManager configManager) {
this.npcRegistry = npcRegistry;
this.configManager = configManager;
} }
public void run() { public void run() {
double distSq = NumberConversions.square(Configs.config().viewDistance()); double distSq = NumberConversions.square(configManager.getConfig().viewDistance());
for (NpcEntryImpl entry : NpcRegistryImpl.get().all()) { for (NpcEntryImpl entry : npcRegistry.all()) {
if (!entry.isProcessed()) continue; if (!entry.isProcessed()) continue;
NpcImpl npc = entry.getNpc(); NpcImpl npc = entry.getNpc();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {

View file

@ -1,24 +1,26 @@
package lol.pyr.znpcsplus.updater; package lol.pyr.znpcsplus.updater;
import lol.pyr.znpcsplus.ZNpcsPlus;
import me.robertlit.spigotresources.api.Resource; import me.robertlit.spigotresources.api.Resource;
import me.robertlit.spigotresources.api.SpigotResourcesAPI; import me.robertlit.spigotresources.api.SpigotResourcesAPI;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class UpdateChecker extends BukkitRunnable { public class UpdateChecker extends BukkitRunnable {
private final static SpigotResourcesAPI api = new SpigotResourcesAPI(1, TimeUnit.MINUTES); private final static Logger logger = Logger.getLogger("ZNPCsPlus Update Checker");
public final static int RESOURCE_ID = 109380; private final static int RESOURCE_ID = 109380;
public final static String DOWNLOAD_LINK = "https://www.spigotmc.org/resources/znpcsplus.109380/"; public final static String DOWNLOAD_LINK = "https://www.spigotmc.org/resources/znpcsplus.109380/";
private final ZNpcsPlus plugin; private final SpigotResourcesAPI api = new SpigotResourcesAPI(1, TimeUnit.MINUTES);
private final PluginDescriptionFile info;
private Status status = Status.UNKNOWN; private Status status = Status.UNKNOWN;
private String newestVersion = "N/A"; private String newestVersion = "N/A";
public UpdateChecker(ZNpcsPlus plugin) { public UpdateChecker(PluginDescriptionFile info) {
this.plugin = plugin; this.info = info;
ZNpcsPlus.SCHEDULER.runDelayedTimerAsync(this, 5L, 6000L);
} }
public void run() { public void run() {
@ -26,7 +28,7 @@ public class UpdateChecker extends BukkitRunnable {
if (resource == null) return; if (resource == null) return;
newestVersion = resource.getVersion(); newestVersion = resource.getVersion();
int current = versionToNumber(plugin.getDescription().getVersion()); int current = versionToNumber(info.getVersion());
int newest = versionToNumber(newestVersion); int newest = versionToNumber(newestVersion);
status = current >= newest ? Status.LATEST_VERSION : Status.UPDATE_NEEDED; status = current >= newest ? Status.LATEST_VERSION : Status.UPDATE_NEEDED;
@ -34,8 +36,8 @@ public class UpdateChecker extends BukkitRunnable {
} }
private void notifyConsole() { private void notifyConsole() {
ZNpcsPlus.LOGGER.warning("Version " + getLatestVersion() + " of " + plugin.getDescription().getName() + " is available now!"); logger.warning("Version " + getLatestVersion() + " of " + info.getName() + " is available now!");
ZNpcsPlus.LOGGER.warning("Download it at " + UpdateChecker.DOWNLOAD_LINK); logger.warning("Download it at " + UpdateChecker.DOWNLOAD_LINK);
} }
private int versionToNumber(String version) { private int versionToNumber(String version) {

View file

@ -1,6 +1,7 @@
package lol.pyr.znpcsplus.updater; package lol.pyr.znpcsplus.updater;
import lol.pyr.znpcsplus.ZNpcsPlus; import lol.pyr.znpcsplus.ZNpcsPlus;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -11,12 +12,13 @@ import org.bukkit.event.player.PlayerJoinEvent;
public class UpdateNotificationListener implements Listener { public class UpdateNotificationListener implements Listener {
private final ZNpcsPlus plugin; private final ZNpcsPlus plugin;
private final BukkitAudiences adventure;
private final UpdateChecker updateChecker; private final UpdateChecker updateChecker;
public UpdateNotificationListener(ZNpcsPlus plugin, UpdateChecker updateChecker) { public UpdateNotificationListener(ZNpcsPlus plugin, BukkitAudiences adventure, UpdateChecker updateChecker) {
this.plugin = plugin; this.plugin = plugin;
this.adventure = adventure;
this.updateChecker = updateChecker; this.updateChecker = updateChecker;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@EventHandler @EventHandler
@ -25,7 +27,7 @@ public class UpdateNotificationListener implements Listener {
if (updateChecker.getStatus() != UpdateChecker.Status.UPDATE_NEEDED) return; if (updateChecker.getStatus() != UpdateChecker.Status.UPDATE_NEEDED) return;
Bukkit.getScheduler().runTaskLater(plugin, () -> { Bukkit.getScheduler().runTaskLater(plugin, () -> {
if (!event.getPlayer().isOnline()) return; if (!event.getPlayer().isOnline()) return;
ZNpcsPlus.ADVENTURE.player(event.getPlayer()) adventure.player(event.getPlayer())
.sendMessage(Component.text(plugin.getDescription().getName() + " v" + updateChecker.getLatestVersion() + " is available now!", NamedTextColor.GOLD).appendNewline() .sendMessage(Component.text(plugin.getDescription().getName() + " v" + updateChecker.getLatestVersion() + " is available now!", NamedTextColor.GOLD).appendNewline()
.append(Component.text("Click this message to open the Spigot page (CLICK)", NamedTextColor.YELLOW)).clickEvent(ClickEvent.openUrl(UpdateChecker.DOWNLOAD_LINK))); .append(Component.text("Click this message to open the Spigot page (CLICK)", NamedTextColor.YELLOW)).clickEvent(ClickEvent.openUrl(UpdateChecker.DOWNLOAD_LINK)));
}, 100L); }, 100L);

View file

@ -1,6 +1,6 @@
package lol.pyr.znpcsplus.user; package lol.pyr.znpcsplus.user;
import lol.pyr.znpcsplus.interaction.NpcAction; import lol.pyr.znpcsplus.interaction.InteractionAction;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -9,24 +9,6 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
public class User { public class User {
private final static Map<UUID, User> USER_MAP = new HashMap<>();
public static User get(Player player) {
return get(player.getUniqueId());
}
public static User get(UUID uuid) {
return USER_MAP.computeIfAbsent(uuid, User::new);
}
public static void remove(Player player) {
remove(player.getUniqueId());
}
public static void remove(UUID uuid) {
USER_MAP.remove(uuid);
}
private final UUID uuid; private final UUID uuid;
private long lastNpcInteraction; private long lastNpcInteraction;
private final Map<UUID, Long> actionCooldownMap = new HashMap<>(); private final Map<UUID, Long> actionCooldownMap = new HashMap<>();
@ -51,7 +33,7 @@ public class User {
return uuid; return uuid;
} }
public boolean actionCooldownCheck(NpcAction action) { public boolean actionCooldownCheck(InteractionAction action) {
UUID id = action.getUuid(); UUID id = action.getUuid();
if (System.currentTimeMillis() - actionCooldownMap.getOrDefault(id, 0L) >= action.getCooldown()) { if (System.currentTimeMillis() - actionCooldownMap.getOrDefault(id, 0L) >= action.getCooldown()) {
actionCooldownMap.put(id, System.currentTimeMillis()); actionCooldownMap.put(id, System.currentTimeMillis());

View file

@ -1,24 +1,24 @@
package lol.pyr.znpcsplus.user; package lol.pyr.znpcsplus.user;
import lol.pyr.znpcsplus.ZNpcsPlus;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
public class UserListener implements Listener { public class UserListener implements Listener {
public UserListener(ZNpcsPlus plugin) { private final UserManager manager;
Bukkit.getPluginManager().registerEvents(this, plugin);
public UserListener(UserManager manager) {
this.manager = manager;
} }
@EventHandler @EventHandler
public void onJoin(PlayerJoinEvent event) { public void onJoin(PlayerJoinEvent event) {
User.get(event.getPlayer()); manager.get(event.getPlayer());
} }
@EventHandler @EventHandler
public void onQuit(PlayerQuitEvent event) { public void onQuit(PlayerQuitEvent event) {
User.remove(event.getPlayer().getUniqueId()); manager.remove(event.getPlayer().getUniqueId());
} }
} }

View file

@ -0,0 +1,27 @@
package lol.pyr.znpcsplus.user;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class UserManager {
private final Map<UUID, User> userMap = new HashMap<>();
public User get(Player player) {
return get(player.getUniqueId());
}
public User get(UUID uuid) {
return userMap.computeIfAbsent(uuid, User::new);
}
public void remove(Player player) {
remove(player.getUniqueId());
}
public void remove(UUID uuid) {
userMap.remove(uuid);
}
}

View file

@ -1,6 +1,5 @@
package lol.pyr.znpcsplus.util; package lol.pyr.znpcsplus.util;
import lol.pyr.znpcsplus.ZNpcsPlus;
import lol.pyr.znpcsplus.reflection.Reflections; import lol.pyr.znpcsplus.reflection.Reflections;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -24,7 +23,7 @@ public class FoliaUtil {
else try { else try {
Reflections.FOLIA_TELEPORT_ASYNC.get().invoke(entity, location); Reflections.FOLIA_TELEPORT_ASYNC.get().invoke(entity, location);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
ZNpcsPlus.LOGGER.severe("Error while teleporting entity:"); System.err.println("Error while teleporting entity:");
e.printStackTrace(); e.printStackTrace();
} }
} }

View file

@ -0,0 +1,19 @@
package lol.pyr.znpcsplus.util;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class PapiUtil {
private static boolean isSupported() {
return Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
}
public static String set(String str) {
return set(null, str);
}
public static String set(Player player, String str) {
return isSupported() ? PlaceholderAPI.setPlaceholders(player, str) : str;
}
}

View file

@ -0,0 +1,6 @@
package lol.pyr.znpcsplus.util;
public interface StringSerializer<T> {
String serialize(T obj);
T deserialize(String str);
}

View file

@ -1,7 +0,0 @@
package lol.pyr.znpcsplus.util;
public class StringUtil {
public static boolean startsWithIgnoreCase(String s1, String s2) {
return s1.toLowerCase().startsWith(s2.toLowerCase());
}
}