Merge remote-tracking branch 'origin/2.X' into 2.X
This commit is contained in:
commit
71f52a987b
14 changed files with 268 additions and 14 deletions
|
@ -23,6 +23,7 @@ import lol.pyr.znpcsplus.commands.property.PropertyRemoveCommand;
|
||||||
import lol.pyr.znpcsplus.commands.property.PropertySetCommand;
|
import lol.pyr.znpcsplus.commands.property.PropertySetCommand;
|
||||||
import lol.pyr.znpcsplus.commands.storage.ImportCommand;
|
import lol.pyr.znpcsplus.commands.storage.ImportCommand;
|
||||||
import lol.pyr.znpcsplus.commands.storage.LoadAllCommand;
|
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.commands.storage.SaveAllCommand;
|
||||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||||
import lol.pyr.znpcsplus.conversion.DataImporterRegistry;
|
import lol.pyr.znpcsplus.conversion.DataImporterRegistry;
|
||||||
|
@ -39,6 +40,7 @@ import lol.pyr.znpcsplus.scheduling.SpigotScheduler;
|
||||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||||
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
|
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
|
||||||
|
import lol.pyr.znpcsplus.storage.NpcStorageType;
|
||||||
import lol.pyr.znpcsplus.tasks.HologramRefreshTask;
|
import lol.pyr.znpcsplus.tasks.HologramRefreshTask;
|
||||||
import lol.pyr.znpcsplus.tasks.NpcProcessorTask;
|
import lol.pyr.znpcsplus.tasks.NpcProcessorTask;
|
||||||
import lol.pyr.znpcsplus.tasks.ViewableHideOnLeaveListener;
|
import lol.pyr.znpcsplus.tasks.ViewableHideOnLeaveListener;
|
||||||
|
@ -127,7 +129,7 @@ public class ZNpcsPlus {
|
||||||
|
|
||||||
|
|
||||||
PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry, configManager);
|
PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry, configManager);
|
||||||
propertyRegistry.registerTypes(bootstrap, packetFactory, textSerializer);
|
propertyRegistry.registerTypes(bootstrap, packetFactory, textSerializer, scheduler);
|
||||||
|
|
||||||
BungeeConnector bungeeConnector = new BungeeConnector(bootstrap);
|
BungeeConnector bungeeConnector = new BungeeConnector(bootstrap);
|
||||||
ActionRegistryImpl actionRegistry = new ActionRegistryImpl();
|
ActionRegistryImpl actionRegistry = new ActionRegistryImpl();
|
||||||
|
@ -157,7 +159,7 @@ public class ZNpcsPlus {
|
||||||
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
||||||
|
|
||||||
registerCommands(npcRegistry, skinCache, adventure, actionRegistry,
|
registerCommands(npcRegistry, skinCache, adventure, actionRegistry,
|
||||||
typeRegistry, propertyRegistry, importerRegistry, configManager);
|
typeRegistry, propertyRegistry, importerRegistry, configManager, packetFactory);
|
||||||
|
|
||||||
log(ChatColor.WHITE + " * Starting tasks...");
|
log(ChatColor.WHITE + " * Starting tasks...");
|
||||||
if (configManager.getConfig().checkForUpdates()) {
|
if (configManager.getConfig().checkForUpdates()) {
|
||||||
|
@ -243,7 +245,7 @@ public class ZNpcsPlus {
|
||||||
private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure,
|
private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure,
|
||||||
ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry,
|
ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry,
|
||||||
EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry,
|
EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry,
|
||||||
ConfigManager configManager) {
|
ConfigManager configManager, PacketFactory packetFactory) {
|
||||||
|
|
||||||
Message<CommandContext> incorrectUsageMessage = context -> context.send(Component.text("Incorrect usage: /" + context.getUsage(), NamedTextColor.RED));
|
Message<CommandContext> incorrectUsageMessage = context -> context.send(Component.text("Incorrect usage: /" + context.getUsage(), NamedTextColor.RED));
|
||||||
CommandManager manager = new CommandManager(bootstrap, adventure, incorrectUsageMessage);
|
CommandManager manager = new CommandManager(bootstrap, adventure, incorrectUsageMessage);
|
||||||
|
@ -292,6 +294,7 @@ public class ZNpcsPlus {
|
||||||
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||||
registerEnumParser(manager, ArmadilloState.class, incorrectUsageMessage);
|
registerEnumParser(manager, ArmadilloState.class, incorrectUsageMessage);
|
||||||
registerEnumParser(manager, WoldVariant.class, incorrectUsageMessage);
|
registerEnumParser(manager, WoldVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, NpcStorageType.class, incorrectUsageMessage);
|
||||||
|
|
||||||
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||||
.addSubcommand("center", new CenterCommand(npcRegistry))
|
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||||
|
@ -316,7 +319,8 @@ public class ZNpcsPlus {
|
||||||
.addSubcommand("storage", new MultiCommand(bootstrap.loadHelpMessage("storage"))
|
.addSubcommand("storage", new MultiCommand(bootstrap.loadHelpMessage("storage"))
|
||||||
.addSubcommand("save", new SaveAllCommand(npcRegistry))
|
.addSubcommand("save", new SaveAllCommand(npcRegistry))
|
||||||
.addSubcommand("reload", new LoadAllCommand(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("holo", new MultiCommand(bootstrap.loadHelpMessage("holo"))
|
||||||
.addSubcommand("add", new HoloAddCommand(npcRegistry))
|
.addSubcommand("add", new HoloAddCommand(npcRegistry))
|
||||||
.addSubcommand("additem", new HoloAddItemCommand(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")
|
@DefaultString("znpcsplus")
|
||||||
String databaseName();
|
String databaseName();
|
||||||
|
|
||||||
|
@ConfKey("use-ssl")
|
||||||
|
@ConfComments("Should SSL be used when connecting to the database?")
|
||||||
|
@DefaultBoolean(false)
|
||||||
|
boolean useSSL();
|
||||||
|
|
||||||
default String createConnectionURL(String dbType) {
|
default String createConnectionURL(String dbType) {
|
||||||
if (dbType.equalsIgnoreCase("mysql")) {
|
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 {
|
} else {
|
||||||
throw new IllegalArgumentException("Unsupported database type: " + dbType);
|
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.properties.villager.VillagerTypeProperty;
|
||||||
import lol.pyr.znpcsplus.entity.serializers.*;
|
import lol.pyr.znpcsplus.entity.serializers.*;
|
||||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||||
|
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||||
import lol.pyr.znpcsplus.util.*;
|
import lol.pyr.znpcsplus.util.*;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
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();
|
ServerVersion ver = PacketEvents.getAPI().getServerManager().getVersion();
|
||||||
boolean legacyBooleans = ver.isOlderThan(ServerVersion.V_1_9);
|
boolean legacyBooleans = ver.isOlderThan(ServerVersion.V_1_9);
|
||||||
boolean legacyNames = 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 DummyProperty<>("permission_required", false));
|
||||||
|
|
||||||
register(new ForceBodyRotationProperty(plugin));
|
register(new ForceBodyRotationProperty(plugin, taskScheduler));
|
||||||
|
|
||||||
register(new DummyProperty<>("player_knockback", false));
|
register(new DummyProperty<>("player_knockback", false));
|
||||||
register(new DummyProperty<>("player_knockback_exempt_permission", String.class));
|
register(new DummyProperty<>("player_knockback_exempt_permission", String.class));
|
||||||
|
|
|
@ -3,24 +3,26 @@ package lol.pyr.znpcsplus.entity.properties;
|
||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||||
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
||||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||||
import org.bukkit.Bukkit;
|
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 ForceBodyRotationProperty extends DummyProperty<Boolean> {
|
public class ForceBodyRotationProperty extends DummyProperty<Boolean> {
|
||||||
private final ZNpcsPlusBootstrap plugin;
|
private final ZNpcsPlusBootstrap plugin;
|
||||||
|
private final TaskScheduler scheduler;
|
||||||
|
|
||||||
public ForceBodyRotationProperty(ZNpcsPlusBootstrap plugin) {
|
public ForceBodyRotationProperty(ZNpcsPlusBootstrap plugin, TaskScheduler scheduler) {
|
||||||
super("force_body_rotation", false);
|
super("force_body_rotation", false);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||||
if (entity.getProperty(this)) {
|
if (entity.getProperty(this)) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 2L);
|
scheduler.runLaterAsync(() -> entity.swingHand(player, false), 2L);
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> entity.swingHand(player, false), 6L);
|
scheduler.runLaterAsync(() -> entity.swingHand(player, false), 6L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,5 +207,10 @@ public class NpcRegistryImpl implements NpcRegistry {
|
||||||
|
|
||||||
public void unload() {
|
public void unload() {
|
||||||
npcList.forEach(npcEntry -> npcEntry.getNpc().delete());
|
npcList.forEach(npcEntry -> npcEntry.getNpc().delete());
|
||||||
|
storage.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NpcStorage getStorage() {
|
||||||
|
return storage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,7 @@ public interface NpcStorage {
|
||||||
Collection<NpcEntryImpl> loadNpcs();
|
Collection<NpcEntryImpl> loadNpcs();
|
||||||
void saveNpcs(Collection<NpcEntryImpl> npcs);
|
void saveNpcs(Collection<NpcEntryImpl> npcs);
|
||||||
void deleteNpc(NpcEntryImpl npc);
|
void deleteNpc(NpcEntryImpl npc);
|
||||||
|
default void close() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,6 @@ public abstract class Database {
|
||||||
public abstract Connection getSQLConnection();
|
public abstract Connection getSQLConnection();
|
||||||
|
|
||||||
public abstract void load();
|
public abstract void load();
|
||||||
|
|
||||||
|
public abstract void close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,14 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
public class MySQL extends Database {
|
public class MySQL extends Database {
|
||||||
private final String connectionURL;
|
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);
|
super(logger);
|
||||||
this.connectionURL = connectionURL;
|
this.connectionURL = connectionURL;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,7 +29,7 @@ public class MySQL extends Database {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
Class.forName("com.mysql.jdbc.Driver");
|
Class.forName("com.mysql.jdbc.Driver");
|
||||||
connection = java.sql.DriverManager.getConnection(connectionURL);
|
connection = java.sql.DriverManager.getConnection(connectionURL, username, password);
|
||||||
return connection;
|
return connection;
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
logger.severe("MySQL JDBC library not found" + ex);
|
logger.severe("MySQL JDBC library not found" + ex);
|
||||||
|
@ -56,6 +60,18 @@ public class MySQL extends Database {
|
||||||
connection = getSQLConnection();
|
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) {
|
public boolean tableExists(String tableName) {
|
||||||
try {
|
try {
|
||||||
Statement s = connection.createStatement();
|
Statement s = connection.createStatement();
|
||||||
|
|
|
@ -46,7 +46,8 @@ public class MySQLStorage implements NpcStorage {
|
||||||
this.typeRegistry = typeRegistry;
|
this.typeRegistry = typeRegistry;
|
||||||
this.propertyRegistry = propertyRegistry;
|
this.propertyRegistry = propertyRegistry;
|
||||||
this.textSerializer = textSerializer;
|
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();
|
database.load();
|
||||||
if (database.getSQLConnection() == null) {
|
if (database.getSQLConnection() == null) {
|
||||||
throw new RuntimeException("Failed to initialize MySQL Storage");
|
throw new RuntimeException("Failed to initialize MySQL Storage");
|
||||||
|
@ -313,4 +314,9 @@ public class MySQLStorage implements NpcStorage {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,18 @@ public class SQLite extends Database{
|
||||||
connection = getSQLConnection();
|
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) {
|
public boolean tableExists(String tableName) {
|
||||||
try {
|
try {
|
||||||
Statement s = connection.createStatement();
|
Statement s = connection.createStatement();
|
||||||
|
|
|
@ -312,4 +312,9 @@ public class SQLiteStorage implements NpcStorage {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
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/save}'><gold>* <yellow>/npc storage save</hover>
|
||||||
<hover:show_text:'{@storage-hover/reload}'><gold>* <yellow>/npc storage reload</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/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