Compare commits
29 commits
aec2854254
...
bf0b58b4b6
Author | SHA1 | Date | |
---|---|---|---|
bf0b58b4b6 | |||
|
8b1fde3652 | ||
|
7bffd2f79d | ||
|
9304c96723 | ||
|
a3b9bda53a | ||
|
79761cba92 | ||
|
7495493c27 | ||
|
d02d0cb5e9 | ||
|
71f52a987b | ||
|
5c99681561 | ||
|
79ede2b586 | ||
|
304278edd8 | ||
|
0272a9ef68 | ||
|
d7c0870546 | ||
|
0f7ad57b64 | ||
|
aeeba809be | ||
|
74463178fe | ||
|
1b3a197085 | ||
|
cf8ce5097f | ||
|
13a47fa743 | ||
|
36a939e497 | ||
|
979b95eed5 | ||
|
18c5cc0e24 | ||
|
e7a82d55e7 | ||
|
06889a221e | ||
|
aafdf0b3f9 | ||
|
71430afcc3 | ||
|
3248418464 | ||
|
18cdef4527 |
38 changed files with 494 additions and 61 deletions
BIN
.github/znpc.png
vendored
Normal file
BIN
.github/znpc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
|
@ -5,7 +5,7 @@
|
|||
that players can interact with to perform actions like switching servers on a network or executing commands.
|
||||
|
||||
This plugin is a remake of a plugin called ZNPCs, we originally started because the maintainer of ZNPCs decided to announce that he was
|
||||
[dropping support for the plugin](https://media.discordapp.net/attachments/1093914615873806477/1098409384855474237/znpc.png).
|
||||
[dropping support for the plugin](https://github.com/Pyrbu/ZNPCsPlus/blob/2.X/.github/znpc.png?raw=true).
|
||||
|
||||
Looking for up-to-date builds of the plugin? Check out our [Jenkins](https://ci.pyr.lol/job/ZNPCsPlus/)
|
||||
|
||||
|
@ -19,7 +19,7 @@ Looking for up-to-date builds of the plugin? Check out our [Jenkins](https://ci.
|
|||
### Requirements, Extensions & Supported Software
|
||||
Requirements:
|
||||
- Java 8+
|
||||
- Minecraft 1.8 - 1.20.4
|
||||
- Minecraft 1.8 - 1.21
|
||||
|
||||
Supported Softwares:
|
||||
- Spigot ([Website](https://www.spigotmc.org/))
|
||||
|
@ -43,7 +43,6 @@ Open an issue in the GitHub [issue tracker](https://github.com/Pyrbu/ZNPCsPlus/i
|
|||
- [wiki.vg](https://wiki.vg/Main_Page) - Minecraft protocol documentation
|
||||
- [gson](https://github.com/google/gson) - JSON parsing library made by Google
|
||||
- [Mineskin.org](https://mineskin.org/) - Website for raw skin file uploads
|
||||
- [SpigotResourcesAPI](https://github.com/robertlit/SpigotResourcesAPI/) - Spigot API wrapper used for updater
|
||||
- [adventure](https://docs.advntr.dev/) - Minecraft text api
|
||||
- [DazzleConf](https://github.com/A248/DazzleConf) - Configuration library
|
||||
- [Director](https://github.com/Pyrbu/Director) - Command library
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package lol.pyr.znpcsplus.api;
|
||||
|
||||
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* Provider for the registered entity property registry instance
|
||||
*/
|
||||
public class NpcPropertyRegistryProvider {
|
||||
private static EntityPropertyRegistry registry = null;
|
||||
|
||||
private NpcPropertyRegistryProvider() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method that returns the entity property registry instance of the plugin
|
||||
*
|
||||
* @return The instance of the entity property registry for the ZNPCsPlus plugin
|
||||
*/
|
||||
public static EntityPropertyRegistry get() {
|
||||
if (registry == null) throw new IllegalStateException(
|
||||
"ZNPCsPlus plugin isn't loaded yet!\n" +
|
||||
"Please add it to your plugin.yml as a depend or softdepend."
|
||||
);
|
||||
return registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used to register the main instance of the plugin as the entity property registry provider
|
||||
* You probably shouldn't call this method under any circumstances
|
||||
*
|
||||
* @param api Instance of the ZNPCsPlus entity property registry
|
||||
*/
|
||||
public static void register(EntityPropertyRegistry api) {
|
||||
NpcPropertyRegistryProvider.registry = api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method used to unregister the plugin from the provider when the plugin shuts down
|
||||
* You probably shouldn't call this method under any circumstances
|
||||
*/
|
||||
public static void unregister() {
|
||||
Bukkit.getServicesManager().unregister(registry);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,18 @@ public interface Npc extends PropertyHolder {
|
|||
*/
|
||||
void setLocation(NpcLocation location);
|
||||
|
||||
/**
|
||||
* Sets the world of this NPC
|
||||
* @param world The bukkit world to set
|
||||
*/
|
||||
void setWorld(World world);
|
||||
|
||||
/**
|
||||
* Sets the world of this NPC
|
||||
* @param name The name world to set
|
||||
*/
|
||||
void setWorld(String name);
|
||||
|
||||
/**
|
||||
* Gets the hologram of this NPC
|
||||
* @return The {@link Hologram} of this NPC
|
||||
|
@ -69,6 +81,13 @@ public interface Npc extends PropertyHolder {
|
|||
*/
|
||||
World getWorld();
|
||||
|
||||
/**
|
||||
* Gets the name of the world this NPC is in
|
||||
* Unlike {@link Npc#getWorld()} this will never be null
|
||||
* @return The name of the world this NPC is in
|
||||
*/
|
||||
String getWorldName();
|
||||
|
||||
/**
|
||||
* Gets the list of actions for this NPC
|
||||
* @return The {@link List} of {@link InteractionAction}s for this NPC
|
||||
|
|
|
@ -20,5 +20,8 @@ public enum NpcPose {
|
|||
ROARING,
|
||||
SNIFFING,
|
||||
EMERGING,
|
||||
DIGGING
|
||||
DIGGING,
|
||||
SLIDING,
|
||||
SHOOTING,
|
||||
INHALING,
|
||||
}
|
||||
|
|
|
@ -4,36 +4,27 @@ plugins {
|
|||
id "xyz.jpenilla.run-paper" version "2.2.0"
|
||||
}
|
||||
|
||||
runServer {
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
minecraftVersion "1.20.6"
|
||||
}
|
||||
|
||||
processResources {
|
||||
expand("version": version)
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
artifactId = "znpcsplus-plugin"
|
||||
|
||||
pom {
|
||||
name.set("znpcsplus-plugin")
|
||||
description.set("The ZNPCsPlus plugin")
|
||||
url.set("https://github.com/Pyrbu/ZNPCsPlus")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "me.clip:placeholderapi:2.11.6" // Placeholder support
|
||||
compileOnly "com.github.retrooper:packetevents-spigot:2.6.0" // Packets
|
||||
implementation "com.google.code.gson:gson:2.10.1" // JSON parsing
|
||||
implementation "org.bstats:bstats-bukkit:3.0.2" // Plugin stats
|
||||
implementation "me.robertlit:SpigotResourcesAPI:2.0" // Spigot API wrapper for update checker
|
||||
implementation "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1" // Configs
|
||||
implementation "lol.pyr:director-adventure:2.1.2" // Commands
|
||||
|
||||
// Fancy text library
|
||||
implementation "net.kyori:adventure-platform-bukkit:4.3.3"
|
||||
implementation "net.kyori:adventure-platform-bukkit:4.3.4"
|
||||
implementation "net.kyori:adventure-text-minimessage:4.17.0"
|
||||
|
||||
implementation project(":api")
|
||||
|
@ -52,6 +43,7 @@ shadowJar {
|
|||
relocate "net.kyori", "lol.pyr.znpcsplus.libraries.kyori"
|
||||
relocate "org.checkerframework", "lol.pyr.znpcsplus.libraries.checkerframework"
|
||||
relocate "com.google", "lol.pyr.znpcsplus.libraries.google"
|
||||
relocate "com.google.gson", "lol.pyr.znpcsplus.libraries.gson"
|
||||
relocate "org.yaml.snakeyaml", "lol.pyr.znpcsplus.libraries.snakeyaml"
|
||||
relocate "space.arim.dazzleconf", "lol.pyr.znpcsplus.libraries.dazzleconf"
|
||||
relocate "lol.pyr.director", "lol.pyr.znpcsplus.libraries.command"
|
||||
|
|
|
@ -14,6 +14,7 @@ import lol.pyr.director.adventure.parse.primitive.FloatParser;
|
|||
import lol.pyr.director.adventure.parse.primitive.IntegerParser;
|
||||
import lol.pyr.director.common.message.Message;
|
||||
import lol.pyr.znpcsplus.api.NpcApiProvider;
|
||||
import lol.pyr.znpcsplus.api.NpcPropertyRegistryProvider;
|
||||
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||
import lol.pyr.znpcsplus.commands.*;
|
||||
import lol.pyr.znpcsplus.commands.action.*;
|
||||
|
@ -22,6 +23,7 @@ import lol.pyr.znpcsplus.commands.property.PropertyRemoveCommand;
|
|||
import lol.pyr.znpcsplus.commands.property.PropertySetCommand;
|
||||
import lol.pyr.znpcsplus.commands.storage.ImportCommand;
|
||||
import lol.pyr.znpcsplus.commands.storage.LoadAllCommand;
|
||||
import lol.pyr.znpcsplus.commands.storage.MigrateCommand;
|
||||
import lol.pyr.znpcsplus.commands.storage.SaveAllCommand;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.conversion.DataImporterRegistry;
|
||||
|
@ -38,6 +40,7 @@ import lol.pyr.znpcsplus.scheduling.SpigotScheduler;
|
|||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
|
||||
import lol.pyr.znpcsplus.storage.NpcStorageType;
|
||||
import lol.pyr.znpcsplus.tasks.HologramRefreshTask;
|
||||
import lol.pyr.znpcsplus.tasks.NpcProcessorTask;
|
||||
import lol.pyr.znpcsplus.tasks.ViewableHideOnLeaveListener;
|
||||
|
@ -78,12 +81,23 @@ public class ZNpcsPlus {
|
|||
private final PacketEventsAPI<Plugin> packetEvents;
|
||||
private final ZNpcsPlusBootstrap bootstrap;
|
||||
|
||||
private final ConfigManager configManager;
|
||||
private final MojangSkinCache skinCache;
|
||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||
|
||||
public ZNpcsPlus(ZNpcsPlusBootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
packetEvents = SpigotPacketEventsBuilder.build(bootstrap);
|
||||
PacketEvents.setAPI(packetEvents);
|
||||
packetEvents.getSettings().checkForUpdates(false);
|
||||
packetEvents.load();
|
||||
|
||||
configManager = new ConfigManager(getDataFolder());
|
||||
skinCache = new MojangSkinCache(configManager);
|
||||
propertyRegistry = new EntityPropertyRegistryImpl(skinCache, configManager);
|
||||
|
||||
NpcPropertyRegistryProvider.register(propertyRegistry);
|
||||
shutdownTasks.add(NpcPropertyRegistryProvider::unregister);
|
||||
}
|
||||
|
||||
private void log(String str) {
|
||||
|
@ -113,11 +127,9 @@ public class ZNpcsPlus {
|
|||
TaskScheduler scheduler = FoliaUtil.isFolia() ? new FoliaScheduler(bootstrap) : new SpigotScheduler(bootstrap);
|
||||
shutdownTasks.add(scheduler::cancelAll);
|
||||
|
||||
ConfigManager configManager = new ConfigManager(getDataFolder());
|
||||
MojangSkinCache skinCache = new MojangSkinCache(configManager);
|
||||
EntityPropertyRegistryImpl propertyRegistry = new EntityPropertyRegistryImpl(skinCache, configManager);
|
||||
|
||||
PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry, configManager);
|
||||
propertyRegistry.registerTypes(bootstrap, packetFactory, textSerializer);
|
||||
propertyRegistry.registerTypes(bootstrap, packetFactory, textSerializer, scheduler);
|
||||
|
||||
BungeeConnector bungeeConnector = new BungeeConnector(bootstrap);
|
||||
ActionRegistryImpl actionRegistry = new ActionRegistryImpl();
|
||||
|
@ -147,7 +159,7 @@ public class ZNpcsPlus {
|
|||
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
||||
|
||||
registerCommands(npcRegistry, skinCache, adventure, actionRegistry,
|
||||
typeRegistry, propertyRegistry, importerRegistry, configManager);
|
||||
typeRegistry, propertyRegistry, importerRegistry, configManager, packetFactory);
|
||||
|
||||
log(ChatColor.WHITE + " * Starting tasks...");
|
||||
if (configManager.getConfig().checkForUpdates()) {
|
||||
|
@ -219,6 +231,7 @@ public class ZNpcsPlus {
|
|||
versions.put(ServerVersion.V_1_17, LazyLoader.of(() -> new V1_17PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||
versions.put(ServerVersion.V_1_19_3, LazyLoader.of(() -> new V1_19_3PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||
versions.put(ServerVersion.V_1_20_2, LazyLoader.of(() -> new V1_20_2PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||
versions.put(ServerVersion.V_1_21_3, LazyLoader.of(() -> new V1_21_3PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||
|
||||
ServerVersion version = packetEvents.getServerManager().getVersion();
|
||||
if (versions.containsKey(version)) return versions.get(version).get();
|
||||
|
@ -233,7 +246,7 @@ public class ZNpcsPlus {
|
|||
private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure,
|
||||
ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry,
|
||||
EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry,
|
||||
ConfigManager configManager) {
|
||||
ConfigManager configManager, PacketFactory packetFactory) {
|
||||
|
||||
Message<CommandContext> incorrectUsageMessage = context -> context.send(Component.text("Incorrect usage: /" + context.getUsage(), NamedTextColor.RED));
|
||||
CommandManager manager = new CommandManager(bootstrap, adventure, incorrectUsageMessage);
|
||||
|
@ -282,6 +295,7 @@ public class ZNpcsPlus {
|
|||
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, ArmadilloState.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, WoldVariant.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, NpcStorageType.class, incorrectUsageMessage);
|
||||
|
||||
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||
|
@ -306,7 +320,8 @@ public class ZNpcsPlus {
|
|||
.addSubcommand("storage", new MultiCommand(bootstrap.loadHelpMessage("storage"))
|
||||
.addSubcommand("save", new SaveAllCommand(npcRegistry))
|
||||
.addSubcommand("reload", new LoadAllCommand(npcRegistry))
|
||||
.addSubcommand("import", new ImportCommand(npcRegistry, importerRegistry)))
|
||||
.addSubcommand("import", new ImportCommand(npcRegistry, importerRegistry))
|
||||
.addSubcommand("migrate", new MigrateCommand(configManager, this, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, npcRegistry.getStorage(), configManager.getConfig().storageType(), npcRegistry)))
|
||||
.addSubcommand("holo", new MultiCommand(bootstrap.loadHelpMessage("holo"))
|
||||
.addSubcommand("add", new HoloAddCommand(npcRegistry))
|
||||
.addSubcommand("additem", new HoloAddItemCommand(npcRegistry))
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
package lol.pyr.znpcsplus.commands.storage;
|
||||
|
||||
import lol.pyr.director.adventure.command.CommandContext;
|
||||
import lol.pyr.director.adventure.command.CommandHandler;
|
||||
import lol.pyr.director.common.command.CommandExecutionException;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import lol.pyr.znpcsplus.storage.NpcStorage;
|
||||
import lol.pyr.znpcsplus.storage.NpcStorageType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MigrateCommand implements CommandHandler {
|
||||
private final ConfigManager configManager;
|
||||
private final ZNpcsPlus plugin;
|
||||
private final PacketFactory packetFactory;
|
||||
private final ActionRegistryImpl actionRegistry;
|
||||
private final NpcTypeRegistryImpl typeRegistry;
|
||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||
private final LegacyComponentSerializer textSerializer;
|
||||
private final NpcStorage currentStorage;
|
||||
private final NpcStorageType currentStorageType;
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
|
||||
public MigrateCommand(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcStorage currentStorage, NpcStorageType currentStorageType, NpcRegistryImpl npcRegistry) {
|
||||
this.configManager = configManager;
|
||||
this.plugin = plugin;
|
||||
this.packetFactory = packetFactory;
|
||||
this.actionRegistry = actionRegistry;
|
||||
this.typeRegistry = typeRegistry;
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
this.textSerializer = textSerializer;
|
||||
this.currentStorage = currentStorage;
|
||||
this.currentStorageType = currentStorageType;
|
||||
this.npcRegistry = npcRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(CommandContext context) throws CommandExecutionException {
|
||||
context.setUsage(context.getLabel() + " storage migrate <from> <to> [force]");
|
||||
NpcStorageType from = context.parse(NpcStorageType.class);
|
||||
NpcStorageType to = context.parse(NpcStorageType.class);
|
||||
boolean force = context.argSize() > 2 && context.parse(Boolean.class);
|
||||
if (from.equals(to)) {
|
||||
context.halt(Component.text("The storage types must be different.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
NpcStorage fromStorage;
|
||||
if (currentStorageType == from) {
|
||||
fromStorage = currentStorage;
|
||||
} else {
|
||||
fromStorage = from.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
|
||||
if (fromStorage == null) {
|
||||
context.halt(Component.text("Failed to initialize the source storage. Please check the console for more information.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
}
|
||||
Collection<NpcEntryImpl> entries;
|
||||
try {
|
||||
entries = fromStorage.loadNpcs();
|
||||
} catch (Exception e) {
|
||||
context.halt(Component.text("Failed to load NPCs from the source storage.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
if (entries.isEmpty()) {
|
||||
context.send(Component.text("No NPCs to migrate.", NamedTextColor.YELLOW));
|
||||
return;
|
||||
}
|
||||
NpcStorage toStorage;
|
||||
if (currentStorageType == to) {
|
||||
toStorage = currentStorage;
|
||||
} else {
|
||||
toStorage = to.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
|
||||
if (toStorage == null) {
|
||||
context.halt(Component.text("Failed to initialize the destination storage. Please check the console for more information.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Collection<NpcEntryImpl> existingEntries;
|
||||
try {
|
||||
existingEntries = toStorage.loadNpcs();
|
||||
} catch (Exception e) {
|
||||
context.halt(Component.text("Failed to load NPCs from the destination storage.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
if (existingEntries.isEmpty()) {
|
||||
toStorage.saveNpcs(entries);
|
||||
context.send(Component.text("Migrated " + entries.size() + " NPCs from the source storage (", NamedTextColor.GREEN)
|
||||
.append(Component.text(from.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(") to the destination storage (", NamedTextColor.GREEN))
|
||||
.append(Component.text(to.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(").", NamedTextColor.GREEN)));
|
||||
if (currentStorageType == to) {
|
||||
npcRegistry.reload();
|
||||
} else {
|
||||
toStorage.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!force) {
|
||||
Collection<NpcEntryImpl> toSave = entries.stream().filter(e -> existingEntries.stream().noneMatch(e2 -> e2.getId().equals(e.getId()))).collect(Collectors.toList());
|
||||
Collection<NpcEntryImpl> idExists = entries.stream().filter(e -> existingEntries.stream().anyMatch(e2 -> e2.getId().equals(e.getId()))).collect(Collectors.toList());
|
||||
if (toSave.isEmpty()) {
|
||||
context.send(Component.text("No NPCs to migrate.", NamedTextColor.YELLOW));
|
||||
if (currentStorageType != to) {
|
||||
toStorage.close();
|
||||
}
|
||||
} else {
|
||||
toStorage.saveNpcs(toSave);
|
||||
context.send(Component.text("Migrated " + toSave.size() + " NPCs from the source storage (", NamedTextColor.GREEN)
|
||||
.append(Component.text(from.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(") to the destination storage (", NamedTextColor.GREEN))
|
||||
.append(Component.text(to.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(").", NamedTextColor.GREEN)));
|
||||
if (currentStorageType == to) {
|
||||
npcRegistry.reload();
|
||||
} else {
|
||||
toStorage.close();
|
||||
}
|
||||
}
|
||||
if (!idExists.isEmpty()) {
|
||||
AtomicReference<Component> component = new AtomicReference<>(Component.text("The following NPCs were not migrated because their IDs already exist in the destination storage:").color(NamedTextColor.YELLOW));
|
||||
idExists.forEach(e -> {
|
||||
component.set(component.get().append(Component.newline()).append(Component.text(e.getId(), NamedTextColor.RED)));
|
||||
});
|
||||
component.set(component.get().append(Component.newline())
|
||||
.append(Component.text("Use the ", NamedTextColor.YELLOW))
|
||||
.append(Component.text("force", NamedTextColor.GOLD))
|
||||
.append(Component.text(" argument to overwrite them.", NamedTextColor.YELLOW)));
|
||||
context.send(component.get());
|
||||
}
|
||||
} else {
|
||||
toStorage.saveNpcs(entries);
|
||||
context.send(Component.text("Force migrated " + entries.size() + " NPCs from the source storage (", NamedTextColor.GREEN)
|
||||
.append(Component.text(from.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(") to the destination storage (", NamedTextColor.GREEN))
|
||||
.append(Component.text(to.name(), NamedTextColor.GOLD))
|
||||
.append(Component.text(").", NamedTextColor.GREEN)));
|
||||
if (currentStorageType == to) {
|
||||
npcRegistry.reload();
|
||||
} else {
|
||||
toStorage.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||
if (context.argSize() == 1) {
|
||||
return context.suggestEnum(NpcStorageType.values());
|
||||
} else if (context.argSize() == 2) {
|
||||
NpcStorageType from = context.suggestionParse(0, NpcStorageType.class);
|
||||
if (from == null) return Collections.emptyList();
|
||||
return context.suggestCollection(Arrays.stream(NpcStorageType.values())
|
||||
.filter(t -> t != from).map(Enum::name).collect(Collectors.toList()));
|
||||
} else if (context.argSize() == 3) {
|
||||
return context.suggestLiteral("true");
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
|
@ -30,9 +30,14 @@ public interface DatabaseConfig {
|
|||
@DefaultString("znpcsplus")
|
||||
String databaseName();
|
||||
|
||||
@ConfKey("use-ssl")
|
||||
@ConfComments("Should SSL be used when connecting to the database?")
|
||||
@DefaultBoolean(false)
|
||||
boolean useSSL();
|
||||
|
||||
default String createConnectionURL(String dbType) {
|
||||
if (dbType.equalsIgnoreCase("mysql")) {
|
||||
return "jdbc:mysql://" + host() + ":" + port() + "/" + databaseName() + "?useSSL=false&user=" + username() + "&password=" + password();
|
||||
return "jdbc:mysql://" + host() + ":" + port() + "/" + databaseName() + "?useSSL=" + useSSL();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported database type: " + dbType);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import lol.pyr.znpcsplus.entity.properties.villager.VillagerProfessionProperty;
|
|||
import lol.pyr.znpcsplus.entity.properties.villager.VillagerTypeProperty;
|
||||
import lol.pyr.znpcsplus.entity.serializers.*;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||
import lol.pyr.znpcsplus.util.*;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
@ -104,7 +105,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
*/
|
||||
}
|
||||
|
||||
public void registerTypes(ZNpcsPlusBootstrap plugin, PacketFactory packetFactory, LegacyComponentSerializer textSerializer) {
|
||||
public void registerTypes(ZNpcsPlusBootstrap plugin, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, TaskScheduler taskScheduler) {
|
||||
ServerVersion ver = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
boolean legacyBooleans = ver.isOlderThan(ServerVersion.V_1_9);
|
||||
boolean legacyNames = ver.isOlderThan(ServerVersion.V_1_9);
|
||||
|
@ -127,7 +128,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
|
||||
register(new DummyProperty<>("permission_required", false));
|
||||
|
||||
register(new ForceBodyRotationProperty(plugin));
|
||||
register(new ForceBodyRotationProperty(plugin, taskScheduler));
|
||||
|
||||
register(new DummyProperty<>("player_knockback", false));
|
||||
register(new DummyProperty<>("player_knockback_exempt_permission", String.class));
|
||||
|
@ -659,6 +660,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
|
||||
// Wolf
|
||||
register(new EncodedIntegerProperty<>("wolf_variant", WoldVariant.PALE, wolfIndex, WoldVariant::getId, EntityDataTypes.WOLF_VARIANT));
|
||||
|
||||
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_21)) return;
|
||||
|
||||
// Bogged
|
||||
register(new BooleanProperty("bogged_sheared", 16, false, legacyBooleans));
|
||||
}
|
||||
|
||||
private void registerSerializer(PropertySerializer<?> serializer) {
|
||||
|
|
|
@ -3,22 +3,26 @@ package lol.pyr.znpcsplus.entity.properties;
|
|||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import org.bukkit.Bukkit;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ForceBodyRotationProperty extends DummyProperty<Boolean> {
|
||||
private final ZNpcsPlusBootstrap plugin;
|
||||
private final TaskScheduler scheduler;
|
||||
|
||||
public ForceBodyRotationProperty(ZNpcsPlusBootstrap plugin) {
|
||||
public ForceBodyRotationProperty(ZNpcsPlusBootstrap plugin, TaskScheduler scheduler) {
|
||||
super("force_body_rotation", false);
|
||||
this.plugin = plugin;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 2L);
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 6L);
|
||||
if (entity.getProperty(this)) {
|
||||
scheduler.runLaterAsync(() -> entity.swingHand(player, false), 2L);
|
||||
scheduler.runLaterAsync(() -> entity.swingHand(player, false), 6L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ConsoleCommandActionType implements InteractionActionType<ConsoleCo
|
|||
|
||||
@Override
|
||||
public void appendUsage(CommandContext context) {
|
||||
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <server>");
|
||||
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <command>");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -43,7 +43,7 @@ public class PlayerChatActionType implements InteractionActionType<PlayerChatAct
|
|||
|
||||
@Override
|
||||
public void appendUsage(CommandContext context) {
|
||||
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <server>");
|
||||
context.setUsage(context.getUsage() + " " + getSubcommandName() + " <id> <click type> <cooldown seconds> <delay ticks> <message>");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -56,6 +56,7 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
UNSAFE_hideAll();
|
||||
this.type = type;
|
||||
entity = new PacketEntity(packetFactory, this, type.getType(), entity.getLocation());
|
||||
hologram.setLocation(location.withY(location.getY() + type.getHologramOffset()));
|
||||
UNSAFE_showAll();
|
||||
}
|
||||
|
||||
|
@ -231,10 +232,17 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
}
|
||||
|
||||
public void setWorld(World world) {
|
||||
if (world == null) throw new IllegalArgumentException("world can not be null");
|
||||
delete();
|
||||
this.worldName = world.getName();
|
||||
}
|
||||
|
||||
public void setWorld(String name) {
|
||||
if (name == null) throw new IllegalArgumentException("world name can not be null");
|
||||
delete();
|
||||
this.worldName = name;
|
||||
}
|
||||
|
||||
public void swingHand(boolean offHand) {
|
||||
for (Player viewer : getViewers()) entity.swingHand(viewer, offHand);
|
||||
}
|
||||
|
|
|
@ -207,5 +207,10 @@ public class NpcRegistryImpl implements NpcRegistry {
|
|||
|
||||
public void unload() {
|
||||
npcList.forEach(npcEntry -> npcEntry.getNpc().delete());
|
||||
storage.close();
|
||||
}
|
||||
|
||||
public NpcStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
// Most hologram offsets generated using Entity#getHeight() in 1.19.4
|
||||
|
||||
register(builder(p, "armor_stand", EntityTypes.ARMOR_STAND)
|
||||
.setHologramOffset(-0.15)
|
||||
.setHologramOffset(0)
|
||||
.addEquipmentProperties()
|
||||
.addProperties("small", "arms", "base_plate", "head_rotation", "body_rotation", "left_arm_rotation", "right_arm_rotation", "left_leg_rotation", "right_leg_rotation"));
|
||||
|
||||
|
@ -106,7 +106,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
register(builder(p, "iron_golem", EntityTypes.IRON_GOLEM)
|
||||
.setHologramOffset(0.725));
|
||||
|
||||
register(builder(p, "magma_cube", EntityTypes.MAGMA_CUBE)); // TODO: Hologram offset scaling with size property
|
||||
register(builder(p, "magma_cube", EntityTypes.MAGMA_CUBE)
|
||||
.setHologramOffset(-1.455)); // TODO: Hologram offset scaling with size property
|
||||
|
||||
register(builder(p, "mooshroom", EntityTypes.MOOSHROOM)
|
||||
.setHologramOffset(-0.575)
|
||||
|
@ -137,7 +138,8 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
register(builder(p, "skeleton_horse", EntityTypes.SKELETON_HORSE)
|
||||
.setHologramOffset(-0.375));
|
||||
|
||||
register(builder(p, "slime", EntityTypes.SLIME)); // TODO: Hologram offset scaling with size property
|
||||
register(builder(p, "slime", EntityTypes.SLIME)
|
||||
.setHologramOffset(-1.455)); // TODO: Hologram offset scaling with size property
|
||||
|
||||
register(builder(p, "snow_golem", EntityTypes.SNOW_GOLEM)
|
||||
.setHologramOffset(-0.075)
|
||||
|
@ -230,7 +232,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
.addEquipmentProperties());
|
||||
|
||||
register(builder(p, "zombie_villager", EntityTypes.ZOMBIE_VILLAGER)
|
||||
.setHologramOffset(-1.0)
|
||||
.setHologramOffset(-0.025)
|
||||
.addEquipmentProperties());
|
||||
|
||||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_12)) return;
|
||||
|
@ -315,7 +317,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
.addProperties("hoglin_immune_to_zombification"));
|
||||
|
||||
register(builder(p, "piglin", EntityTypes.PIGLIN)
|
||||
.setHologramOffset(-1.0)
|
||||
.setHologramOffset(-0.025)
|
||||
.addEquipmentProperties()
|
||||
.addProperties("piglin_baby", "piglin_charging_crossbow", "piglin_dancing"));
|
||||
|
||||
|
@ -363,19 +365,28 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
|
||||
|
||||
register(builder(p, "sniffer", EntityTypes.SNIFFER)
|
||||
.setHologramOffset(0.125)
|
||||
.setHologramOffset(0.075)
|
||||
.addProperties("sniffer_state"));
|
||||
|
||||
register(builder(p, "camel", EntityTypes.CAMEL)
|
||||
.setHologramOffset(0.25)
|
||||
.setHologramOffset(0.4)
|
||||
.addProperties("bashing", "camel_sitting"));
|
||||
|
||||
|
||||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_20_5)) return;
|
||||
|
||||
register(builder(p, "armadillo", EntityTypes.ARMADILLO)
|
||||
.setHologramOffset(-1.475)
|
||||
.setHologramOffset(-1.325)
|
||||
.addProperties("armadillo_state"));
|
||||
|
||||
if (!version.isNewerThanOrEquals(ServerVersion.V_1_21)) return;
|
||||
|
||||
register(builder(p, "bogged", EntityTypes.BOGGED)
|
||||
.setHologramOffset(0.015)
|
||||
.addProperties("bogged_sheared"));
|
||||
|
||||
register(builder(p, "breeze", EntityTypes.BREEZE)
|
||||
.setHologramOffset(-0.205));
|
||||
}
|
||||
|
||||
public Collection<NpcType> getAll() {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package lol.pyr.znpcsplus.packets;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.protocol.entity.EntityPositionData;
|
||||
import com.github.retrooper.packetevents.protocol.teleport.RelativeFlag;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class V1_21_3PacketFactory extends V1_20_2PacketFactory {
|
||||
public V1_21_3PacketFactory(TaskScheduler scheduler, PacketEventsAPI<Plugin> packetEvents, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, ConfigManager configManager) {
|
||||
super(scheduler, packetEvents, propertyRegistry, textSerializer, configManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teleportEntity(Player player, PacketEntity entity) {
|
||||
NpcLocation location = entity.getLocation();
|
||||
sendPacket(player, new WrapperPlayServerEntityTeleport(entity.getEntityId(), new EntityPositionData(npcLocationToVector(location), new Vector3d(0, 0, 0), location.getYaw(), location.getPitch()), RelativeFlag.NONE, false));
|
||||
sendPacket(player, new WrapperPlayServerEntityHeadLook(entity.getEntityId(), location.getYaw()));
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
|
|||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
@ -21,7 +22,7 @@ public interface BaseSkinDescriptor extends SkinDescriptor {
|
|||
static BaseSkinDescriptor deserialize(MojangSkinCache skinCache, String str) {
|
||||
String[] arr = str.split(";");
|
||||
if (arr[0].equalsIgnoreCase("mirror")) return new MirrorDescriptor(skinCache);
|
||||
else if (arr[0].equalsIgnoreCase("fetching")) return new FetchingDescriptor(skinCache, arr[1]);
|
||||
else if (arr[0].equalsIgnoreCase("fetching")) return new FetchingDescriptor(skinCache, String.join(";", Arrays.copyOfRange(arr, 1, arr.length)));
|
||||
else if (arr[0].equalsIgnoreCase("prefetched")) {
|
||||
List<TextureProperty> properties = new ArrayList<>();
|
||||
for (int i = 0; i < (arr.length - 1) / 3; i++) {
|
||||
|
|
|
@ -8,4 +8,7 @@ public interface NpcStorage {
|
|||
Collection<NpcEntryImpl> loadNpcs();
|
||||
void saveNpcs(Collection<NpcEntryImpl> npcs);
|
||||
void deleteNpc(NpcEntryImpl npc);
|
||||
default void close() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,6 @@ public abstract class Database {
|
|||
public abstract Connection getSQLConnection();
|
||||
|
||||
public abstract void load();
|
||||
|
||||
public abstract void close();
|
||||
}
|
||||
|
|
|
@ -10,10 +10,14 @@ import java.util.logging.Logger;
|
|||
|
||||
public class MySQL extends Database {
|
||||
private final String connectionURL;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public MySQL(String connectionURL, Logger logger) {
|
||||
public MySQL(String connectionURL, String username, String password, Logger logger) {
|
||||
super(logger);
|
||||
this.connectionURL = connectionURL;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +29,7 @@ public class MySQL extends Database {
|
|||
return connection;
|
||||
}
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
connection = java.sql.DriverManager.getConnection(connectionURL);
|
||||
connection = java.sql.DriverManager.getConnection(connectionURL, username, password);
|
||||
return connection;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
logger.severe("MySQL JDBC library not found" + ex);
|
||||
|
@ -56,6 +60,18 @@ public class MySQL extends Database {
|
|||
connection = getSQLConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.severe("An error occurred while closing the connection");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tableExists(String tableName) {
|
||||
try {
|
||||
Statement s = connection.createStatement();
|
||||
|
|
|
@ -46,7 +46,8 @@ public class MySQLStorage implements NpcStorage {
|
|||
this.typeRegistry = typeRegistry;
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
this.textSerializer = textSerializer;
|
||||
this.database = new MySQL(configManager.getConfig().databaseConfig().createConnectionURL("mysql"), logger);
|
||||
this.database = new MySQL(configManager.getConfig().databaseConfig().createConnectionURL("mysql"),
|
||||
configManager.getConfig().databaseConfig().username(), configManager.getConfig().databaseConfig().password(), logger);
|
||||
database.load();
|
||||
if (database.getSQLConnection() == null) {
|
||||
throw new RuntimeException("Failed to initialize MySQL Storage");
|
||||
|
@ -313,4 +314,9 @@ public class MySQLStorage implements NpcStorage {
|
|||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,18 @@ public class SQLite extends Database{
|
|||
connection = getSQLConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.severe("An error occurred while closing the connection");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tableExists(String tableName) {
|
||||
try {
|
||||
Statement s = connection.createStatement();
|
||||
|
|
|
@ -312,4 +312,9 @@ public class SQLiteStorage implements NpcStorage {
|
|||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
package lol.pyr.znpcsplus.updater;
|
||||
|
||||
import me.robertlit.spigotresources.api.Resource;
|
||||
import me.robertlit.spigotresources.api.SpigotResourcesAPI;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class UpdateChecker extends BukkitRunnable {
|
||||
private final static Logger logger = Logger.getLogger("ZNPCsPlus Update Checker");
|
||||
private final static int RESOURCE_ID = 109380;
|
||||
private final static String GET_RESOURCE = "https://api.spigotmc.org/simple/0.2/index.php?action=getResource&id=109380";
|
||||
public final static String DOWNLOAD_LINK = "https://www.spigotmc.org/resources/znpcsplus.109380/";
|
||||
|
||||
private final SpigotResourcesAPI api = new SpigotResourcesAPI(1, TimeUnit.MINUTES);
|
||||
|
||||
private final PluginDescriptionFile info;
|
||||
private Status status = Status.UNKNOWN;
|
||||
private String newestVersion = "N/A";
|
||||
|
@ -24,9 +25,29 @@ public class UpdateChecker extends BukkitRunnable {
|
|||
}
|
||||
|
||||
public void run() {
|
||||
Resource resource = api.getResource(RESOURCE_ID).join();
|
||||
if (resource == null) return;
|
||||
newestVersion = resource.getVersion();
|
||||
String foundVersion = null;
|
||||
try {
|
||||
URL getResource = new URL(GET_RESOURCE);
|
||||
HttpURLConnection httpRequest = ((HttpURLConnection) getResource.openConnection());
|
||||
httpRequest.setRequestMethod("GET");
|
||||
httpRequest.setConnectTimeout(5_000);
|
||||
httpRequest.setReadTimeout(5_000);
|
||||
|
||||
if (httpRequest.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||
try (InputStreamReader reader = new InputStreamReader(httpRequest.getInputStream())) {
|
||||
JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject();
|
||||
foundVersion = jsonObject.get("current_version").getAsString();
|
||||
}
|
||||
} else {
|
||||
logger.warning("Failed to check for updates: HTTP response code " + httpRequest.getResponseCode());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("Failed to check for updates: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (foundVersion == null) return;
|
||||
newestVersion = foundVersion;
|
||||
|
||||
status = compareVersions(info.getVersion(), newestVersion);
|
||||
if (status == Status.UPDATE_NEEDED) notifyConsole();
|
||||
|
|
|
@ -3,12 +3,12 @@ package lol.pyr.znpcsplus.user;
|
|||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class UserManager {
|
||||
private final Map<UUID, User> userMap = new HashMap<>();
|
||||
private final Map<UUID, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
public UserManager() {
|
||||
Bukkit.getOnlinePlayers().forEach(this::get);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<gray>Examples:
|
||||
<gold>* <yellow>/npc action add <gold>consolecommand cool_npc1 ANY_CLICK 0 0 say {player} just clicked a cool npc!
|
||||
<gold>* <yellow>/npc action add <gold>playerchat dog LEFT_CLICK 0 100 It has been 5 seconds since i clicked the npc
|
||||
<gold>* <yellow>/npc action add <gold>message npc123 RIGHT_CLICK 1 0 You can only click this npc once per second
|
||||
|
||||
<gray>Action Types:
|
||||
<gold>* <yellow>Console Command <gray>- Send a console command when a player interacts with the npc
|
||||
<gold>* <yellow>Message <gray>- Send a message to any player that interacts with the npc
|
||||
<gold>* <yellow>Player Chat <gray>- Make any player that interacts send something in the chat
|
||||
<gold>* <yellow>Player Command <gray>- Make any player that interacts send a command
|
||||
<gold>* <yellow>Switch Server <gray>- Send the player to a different server on the proxy using bungee messaging channel
|
||||
|
||||
<gray>Command used to add actions to an npc
|
|
@ -0,0 +1,3 @@
|
|||
<gray>Usage <gold>» <yellow>/npc action clear <gold><id>
|
||||
|
||||
<gray>Command used to clear all npc actions
|
|
@ -0,0 +1,3 @@
|
|||
<gray>Usage <gold>» <yellow>/npc action delete <gold><id> <action id>
|
||||
|
||||
<gray>Command used to delete a specific action from an npc
|
|
@ -0,0 +1,3 @@
|
|||
<gray>Usage <gold>» <yellow>/npc action edit <gold><id> <action id> <type> <args>
|
||||
|
||||
<gray>Command used to change a specific action on an npc
|
|
@ -0,0 +1,3 @@
|
|||
<gray>Usage <gold>» <yellow>/npc action list <gold><id>
|
||||
|
||||
<gray>Command used to list all actions of an npc
|
|
@ -3,9 +3,16 @@
|
|||
<gray>Hover over any command more info
|
||||
|
||||
<hover:show_text:'{@holo-hover/add}'><gold>* <yellow>/npc holo add <id> <text></hover>
|
||||
<hover:show_text:'{@holo-hover/delete}'><gold>* <yellow>/npc holo delete <id> <line></hover>
|
||||
<hover:show_text:'{@holo-hover/set}'><gold>* <yellow>/npc holo set <id> <line> <text></hover>
|
||||
<hover:show_text:'{@holo-hover/insert}'><gold>* <yellow>/npc holo insert <id> <line> <text></hover>
|
||||
|
||||
<hover:show_text:'{@holo-hover/additem}'><gold>* <yellow>/npc holo additem <id></hover>
|
||||
<hover:show_text:'{@holo-hover/setitem}'><gold>* <yellow>/npc holo setitem <id> <line></hover>
|
||||
<hover:show_text:'{@holo-hover/insertitem}'><gold>* <yellow>/npc holo insertitem <id> <line></hover>
|
||||
|
||||
<hover:show_text:'{@holo-hover/delete}'><gold>* <yellow>/npc holo delete <id> <line></hover>
|
||||
|
||||
<hover:show_text:'{@holo-hover/offset}'><gold>* <yellow>/npc holo offset <id> <amount></hover>
|
||||
<hover:show_text:'{@holo-hover/refreshdelay}'><gold>* <yellow>/npc holo refreshdelay <id> <delay></hover>
|
||||
<hover:show_text:'{@holo-hover/info}'><gold>* <yellow>/npc holo info <id></hover>
|
||||
|
||||
|
|
16
plugin/src/main/resources/messages/storage-hover/migrate.txt
Normal file
16
plugin/src/main/resources/messages/storage-hover/migrate.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
<gray>Usage <gold>» <yellow>/npc storage migrate <gold><from> <to> [force]
|
||||
|
||||
<gray>Storage Types:
|
||||
<gold>* <yellow>YAML <gray>- Npcs are stored in yaml files
|
||||
<gold>* <yellow>SQLite <gray>- Npcs are stored in a SQLite database
|
||||
<gold>* <yellow>MySQL <gray>- Npcs are stored in a MySQL database
|
||||
|
||||
<gray>Command used to migrate npcs from one storage type to another.
|
||||
|
||||
This command will NOT delete the original storage files or database,
|
||||
but will copy the npcs to the new storage type.
|
||||
|
||||
<gray>This will also not overwrite any existing npcs in the new storage
|
||||
type, unless the <gold>force <gray>argument is set to <gold>true<gray>.
|
||||
<red>Warning: <bold>force</bold> will overwrite any existing npcs with the same id
|
||||
in the new storage type and CANNOT be undone.
|
|
@ -5,4 +5,5 @@
|
|||
<hover:show_text:'{@storage-hover/save}'><gold>* <yellow>/npc storage save</hover>
|
||||
<hover:show_text:'{@storage-hover/reload}'><gold>* <yellow>/npc storage reload</hover>
|
||||
<hover:show_text:'{@storage-hover/import}'><gold>* <yellow>/npc storage import <importer></hover>
|
||||
<hover:show_text:'{@storage-hover/migrate}'><gold>* <yellow>/npc storage migrate <from> <to> [force]</hover>
|
||||
|
||||
|
|
Loading…
Reference in a new issue