add npc serialization methods to the api

This commit is contained in:
Pyrbu 2024-12-24 16:11:13 +01:00
parent d1227500ce
commit c780c0ec78
12 changed files with 289 additions and 121 deletions

View file

@ -5,6 +5,7 @@ import lol.pyr.znpcsplus.api.interaction.ActionFactory;
import lol.pyr.znpcsplus.api.interaction.ActionRegistry;
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry;
import lol.pyr.znpcsplus.api.serialization.NpcSerializerRegistry;
import lol.pyr.znpcsplus.api.skin.SkinDescriptorFactory;
/**
@ -46,4 +47,10 @@ public interface NpcApi {
* @return the skin descriptor factory
*/
SkinDescriptorFactory getSkinDescriptorFactory();
/**
* Gets the npc serializer registry.
* @return the npc serializer registry
*/
NpcSerializerRegistry getNpcSerializerRegistry();
}

View file

@ -64,4 +64,11 @@ public interface NpcRegistry {
* @param id The ID of the NPC entry
*/
void delete(String id);
/**
* Register an NPC to this registry
* NpcEntry instances can be obtained through the NpcSerializer classes
* @param entry The npc to be registered
*/
void register(NpcEntry entry);
}

View file

@ -0,0 +1,20 @@
package lol.pyr.znpcsplus.api.serialization;
import lol.pyr.znpcsplus.api.npc.NpcEntry;
public interface NpcSerializer<T> {
/**
* Serialize an npc into the type of this serializer
* @param entry The npc entry
* @return The serialized class
*/
T serialize(NpcEntry entry);
/**
* Deserialize an npc from a serialized class
* Note: This npc will not be registered, you need to also register it using the NpcRegistry#register(NpcEntry) method
* @param model The serialized class
* @return The deserialized NpcEntry
*/
NpcEntry deserialize(T model);
}

View file

@ -0,0 +1,19 @@
package lol.pyr.znpcsplus.api.serialization;
public interface NpcSerializerRegistry {
/**
* Get an NpcSerializer that serializes npcs into the provided class
* @param clazz The class to serialize into
* @return The npc serializer instance
* @param <T> The type of the class that the serializer serializes into
*/
<T> NpcSerializer<T> getSerializer(Class<T> clazz);
/**
* Register an NpcSerializer to be used by other plugins
* @param clazz The class that the serializer serializes into
* @param serializer The serializer itself
* @param <T> The type of the class that the serializer serializes into
*/
<T> void registerSerializer(Class<T> clazz, NpcSerializer<T> serializer);
}

View file

@ -38,6 +38,7 @@ import lol.pyr.znpcsplus.parsers.*;
import lol.pyr.znpcsplus.scheduling.FoliaScheduler;
import lol.pyr.znpcsplus.scheduling.SpigotScheduler;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
import lol.pyr.znpcsplus.storage.NpcStorageType;
@ -135,8 +136,9 @@ public class ZNpcsPlus {
ActionRegistryImpl actionRegistry = new ActionRegistryImpl();
ActionFactoryImpl actionFactory = new ActionFactoryImpl(scheduler, adventure, textSerializer, bungeeConnector);
NpcTypeRegistryImpl typeRegistry = new NpcTypeRegistryImpl();
NpcSerializerRegistryImpl serializerRegistry = new NpcSerializerRegistryImpl(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
NpcRegistryImpl npcRegistry = new NpcRegistryImpl(configManager, this, packetFactory, actionRegistry,
scheduler, typeRegistry, propertyRegistry, textSerializer);
scheduler, typeRegistry, propertyRegistry, serializerRegistry, textSerializer);
shutdownTasks.add(npcRegistry::unload);
UserManager userManager = new UserManager();
@ -159,7 +161,7 @@ public class ZNpcsPlus {
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
registerCommands(npcRegistry, skinCache, adventure, actionRegistry,
typeRegistry, propertyRegistry, importerRegistry, configManager, packetFactory);
typeRegistry, propertyRegistry, importerRegistry, configManager, packetFactory, serializerRegistry);
log(ChatColor.WHITE + " * Starting tasks...");
if (configManager.getConfig().checkForUpdates()) {
@ -193,7 +195,7 @@ public class ZNpcsPlus {
}
}
NpcApiProvider.register(bootstrap, new ZNpcsPlusApi(npcRegistry, typeRegistry, propertyRegistry, actionRegistry, actionFactory, skinCache));
NpcApiProvider.register(bootstrap, new ZNpcsPlusApi(npcRegistry, typeRegistry, propertyRegistry, actionRegistry, actionFactory, skinCache, serializerRegistry));
log(ChatColor.WHITE + " * Loading complete! (" + (System.currentTimeMillis() - before) + "ms)");
log("");
@ -246,7 +248,7 @@ public class ZNpcsPlus {
private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure,
ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry,
EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry,
ConfigManager configManager, PacketFactory packetFactory) {
ConfigManager configManager, PacketFactory packetFactory, NpcSerializerRegistryImpl serializerRegistry) {
Message<CommandContext> incorrectUsageMessage = context -> context.send(Component.text("Incorrect usage: /" + context.getUsage(), NamedTextColor.RED));
CommandManager manager = new CommandManager(bootstrap, adventure, incorrectUsageMessage);
@ -322,7 +324,7 @@ public class ZNpcsPlus {
.addSubcommand("save", new SaveAllCommand(npcRegistry))
.addSubcommand("reload", new LoadAllCommand(npcRegistry))
.addSubcommand("import", new ImportCommand(npcRegistry, importerRegistry))
.addSubcommand("migrate", new MigrateCommand(configManager, this, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, npcRegistry.getStorage(), configManager.getConfig().storageType(), npcRegistry)))
.addSubcommand("migrate", new MigrateCommand(configManager, this, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, npcRegistry.getStorage(), configManager.getConfig().storageType(), npcRegistry, serializerRegistry)))
.addSubcommand("holo", new MultiCommand(bootstrap.loadHelpMessage("holo"))
.addSubcommand("add", new HoloAddCommand(npcRegistry))
.addSubcommand("additem", new HoloAddItemCommand(npcRegistry))

View file

@ -12,6 +12,7 @@ import lol.pyr.znpcsplus.interaction.ActionFactoryImpl;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.skin.SkinDescriptorFactoryImpl;
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
@ -22,14 +23,16 @@ public class ZNpcsPlusApi implements NpcApi {
private final ActionRegistryImpl actionRegistry;
private final ActionFactoryImpl actionFactory;
private final SkinDescriptorFactoryImpl skinDescriptorFactory;
private final NpcSerializerRegistryImpl npcSerializerRegistry;
public ZNpcsPlusApi(NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, ActionRegistryImpl actionRegistry, ActionFactoryImpl actionFactory, MojangSkinCache skinCache) {
public ZNpcsPlusApi(NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, ActionRegistryImpl actionRegistry, ActionFactoryImpl actionFactory, MojangSkinCache skinCache, NpcSerializerRegistryImpl npcSerializerRegistry) {
this.npcRegistry = npcRegistry;
this.typeRegistry = typeRegistry;
this.propertyRegistry = propertyRegistry;
this.actionRegistry = actionRegistry;
this.actionFactory = actionFactory;
this.skinDescriptorFactory = new SkinDescriptorFactoryImpl(skinCache);
this.npcSerializerRegistry = npcSerializerRegistry;
}
@Override
@ -62,4 +65,9 @@ public class ZNpcsPlusApi implements NpcApi {
public SkinDescriptorFactory getSkinDescriptorFactory() {
return skinDescriptorFactory;
}
@Override
public NpcSerializerRegistryImpl getNpcSerializerRegistry() {
return npcSerializerRegistry;
}
}

View file

@ -11,6 +11,7 @@ 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.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.storage.NpcStorageType;
import net.kyori.adventure.text.Component;
@ -35,8 +36,9 @@ public class MigrateCommand implements CommandHandler {
private final NpcStorage currentStorage;
private final NpcStorageType currentStorageType;
private final NpcRegistryImpl npcRegistry;
private final NpcSerializerRegistryImpl serializerRegistry;
public MigrateCommand(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcStorage currentStorage, NpcStorageType currentStorageType, NpcRegistryImpl npcRegistry) {
public MigrateCommand(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcStorage currentStorage, NpcStorageType currentStorageType, NpcRegistryImpl npcRegistry, NpcSerializerRegistryImpl serializerRegistry) {
this.configManager = configManager;
this.plugin = plugin;
this.packetFactory = packetFactory;
@ -47,6 +49,7 @@ public class MigrateCommand implements CommandHandler {
this.currentStorage = currentStorage;
this.currentStorageType = currentStorageType;
this.npcRegistry = npcRegistry;
this.serializerRegistry = serializerRegistry;
}
@Override
@ -63,7 +66,7 @@ public class MigrateCommand implements CommandHandler {
if (currentStorageType == from) {
fromStorage = currentStorage;
} else {
fromStorage = from.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
fromStorage = from.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, serializerRegistry);
if (fromStorage == null) {
context.halt(Component.text("Failed to initialize the source storage. Please check the console for more information.", NamedTextColor.RED));
return;
@ -84,7 +87,7 @@ public class MigrateCommand implements CommandHandler {
if (currentStorageType == to) {
toStorage = currentStorage;
} else {
toStorage = to.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
toStorage = to.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, serializerRegistry);
if (toStorage == null) {
context.halt(Component.text("Failed to initialize the destination storage. Please check the console for more information.", NamedTextColor.RED));
return;

View file

@ -14,6 +14,7 @@ import lol.pyr.znpcsplus.hologram.HologramText;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.storage.NpcStorageType;
import lol.pyr.znpcsplus.util.NpcLocation;
@ -35,13 +36,13 @@ public class NpcRegistryImpl implements NpcRegistry {
private final Map<String, NpcEntryImpl> npcIdLookupMap = new HashMap<>();
private final Map<UUID, NpcEntryImpl> npcUuidLookupMap = new HashMap<>();
public NpcRegistryImpl(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, TaskScheduler scheduler, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
public NpcRegistryImpl(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, TaskScheduler scheduler, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, NpcSerializerRegistryImpl serializerRegistry, LegacyComponentSerializer textSerializer) {
this.textSerializer = textSerializer;
this.propertyRegistry = propertyRegistry;
storage = configManager.getConfig().storageType().create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
storage = configManager.getConfig().storageType().create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, serializerRegistry);
if (storage == null) {
Bukkit.getLogger().warning("Failed to initialize storage, falling back to YAML");
storage = NpcStorageType.YAML.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
storage = NpcStorageType.YAML.create(configManager, plugin, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, serializerRegistry);
}
this.packetFactory = packetFactory;
this.configManager = configManager;
@ -52,7 +53,13 @@ public class NpcRegistryImpl implements NpcRegistry {
}
}
@Override
public void register(NpcEntry entry) {
register((NpcEntryImpl) entry);
}
private void register(NpcEntryImpl entry) {
if (entry == null) throw new NullPointerException();
unregister(npcIdLookupMap.put(entry.getId(), entry));
unregister(npcUuidLookupMap.put(entry.getNpc().getUuid(), entry));
npcList.add(entry);

View file

@ -0,0 +1,33 @@
package lol.pyr.znpcsplus.serialization;
import lol.pyr.znpcsplus.api.serialization.NpcSerializer;
import lol.pyr.znpcsplus.api.serialization.NpcSerializerRegistry;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.configuration.file.YamlConfiguration;
import java.util.HashMap;
import java.util.Map;
public class NpcSerializerRegistryImpl implements NpcSerializerRegistry {
private final Map<Class<?>, NpcSerializer<?>> serializerMap = new HashMap<>();
public NpcSerializerRegistryImpl(PacketFactory packetFactory, ConfigManager configManager, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
registerSerializer(YamlConfiguration.class, new YamlSerializer(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer));
}
@SuppressWarnings("unchecked")
@Override
public <T> NpcSerializer<T> getSerializer(Class<T> clazz) {
return (NpcSerializer<T>) serializerMap.get(clazz);
}
@Override
public <T> void registerSerializer(Class<T> clazz, NpcSerializer<T> serializer) {
serializerMap.put(clazz, serializer);
}
}

View file

@ -0,0 +1,154 @@
package lol.pyr.znpcsplus.serialization;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.api.npc.NpcEntry;
import lol.pyr.znpcsplus.api.serialization.NpcSerializer;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.entity.PropertySerializer;
import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class YamlSerializer implements NpcSerializer<YamlConfiguration> {
private final static Logger logger = Logger.getLogger("YamlSerializer");
private final PacketFactory packetFactory;
private final ConfigManager configManager;
private final ActionRegistryImpl actionRegistry;
private final NpcTypeRegistryImpl typeRegistry;
private final EntityPropertyRegistryImpl propertyRegistry;
private final LegacyComponentSerializer textSerializer;
public YamlSerializer(PacketFactory packetFactory, ConfigManager configManager, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
this.packetFactory = packetFactory;
this.configManager = configManager;
this.actionRegistry = actionRegistry;
this.typeRegistry = typeRegistry;
this.propertyRegistry = propertyRegistry;
this.textSerializer = textSerializer;
}
@Override
public YamlConfiguration serialize(NpcEntry entry) {
YamlConfiguration config = new YamlConfiguration();
config.set("id", entry.getId());
config.set("is-processed", entry.isProcessed());
config.set("allow-commands", entry.isAllowCommandModification());
config.set("save", entry.isSave());
NpcImpl npc = (NpcImpl) entry.getNpc();
config.set("enabled", npc.isEnabled());
config.set("uuid", npc.getUuid().toString());
config.set("world", npc.getWorldName());
config.set("location", serializeLocation(npc.getLocation()));
config.set("type", npc.getType().getName());
for (EntityProperty<?> property : npc.getAllProperties()) try {
PropertySerializer<?> serializer = propertyRegistry.getSerializer(((EntityPropertyImpl<?>) property).getType());
if (serializer == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + property.getName() + "' for npc '" + entry.getId() + "'. skipping ...");
continue;
}
config.set("properties." + property.getName(), serializer.UNSAFE_serialize(npc.getProperty(property)));
} catch (Exception exception) {
logger.severe("Failed to serialize property " + property.getName() + " for npc with id " + entry.getId());
exception.printStackTrace();
}
HologramImpl hologram = npc.getHologram();
if (hologram.getOffset() != 0.0) config.set("hologram.offset", hologram.getOffset());
if (hologram.getRefreshDelay() != -1) config.set("hologram.refresh-delay", hologram.getRefreshDelay());
List<String> lines = new ArrayList<>(npc.getHologram().getLines().size());
for (int i = 0; i < hologram.getLines().size(); i++) {
lines.add(hologram.getLine(i));
}
config.set("hologram.lines", lines);
config.set("actions", npc.getActions().stream()
.map(actionRegistry::serialize)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
return config;
}
@Override
public NpcEntry deserialize(YamlConfiguration config) {
UUID uuid = config.contains("uuid") ? UUID.fromString(config.getString("uuid")) : UUID.randomUUID();
NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, config.getString("world"),
typeRegistry.getByName(config.getString("type")), deserializeLocation(config.getConfigurationSection("location")));
if (config.isBoolean("enabled")) npc.setEnabled(config.getBoolean("enabled"));
ConfigurationSection properties = config.getConfigurationSection("properties");
if (properties != null) {
for (String key : properties.getKeys(false)) {
EntityPropertyImpl<?> property = propertyRegistry.getByName(key);
if (property == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown property '" + key + "' for npc '" + config.getString("id") + "'. skipping ...");
continue;
}
PropertySerializer<?> serializer = propertyRegistry.getSerializer(property.getType());
if (serializer == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + key + "' for npc '" + config.getString("id") + "'. skipping ...");
continue;
}
Object value = serializer.deserialize(properties.getString(key));
if (value == null) {
Bukkit.getLogger().log(Level.WARNING, "Failed to deserialize property '" + key + "' for npc '" + config.getString("id") + "'. Resetting to default ...");
value = property.getDefaultValue();
}
npc.UNSAFE_setProperty(property, value);
}
}
HologramImpl hologram = npc.getHologram();
hologram.setOffset(config.getDouble("hologram.offset", 0.0));
hologram.setRefreshDelay(config.getLong("hologram.refresh-delay", -1));
for (String line : config.getStringList("hologram.lines")) hologram.addLine(line);
for (String s : config.getStringList("actions")) npc.addAction(actionRegistry.deserialize(s));
NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc);
entry.setProcessed(config.getBoolean("is-processed"));
entry.setAllowCommandModification(config.getBoolean("allow-commands"));
entry.setSave(config.getBoolean("save"));
return entry;
}
public NpcLocation deserializeLocation(ConfigurationSection section) {
return new NpcLocation(
section.getDouble("x"),
section.getDouble("y"),
section.getDouble("z"),
(float) section.getDouble("yaw"),
(float) section.getDouble("pitch")
);
}
public YamlConfiguration serializeLocation(NpcLocation location) {
YamlConfiguration config = new YamlConfiguration();
config.set("x", location.getX());
config.set("y", location.getY());
config.set("z", location.getZ());
config.set("yaw", location.getYaw());
config.set("pitch", location.getPitch());
return config;
}
}

View file

@ -6,6 +6,7 @@ import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.storage.mysql.MySQLStorage;
import lol.pyr.znpcsplus.storage.sqlite.SQLiteStorage;
import lol.pyr.znpcsplus.storage.yaml.YamlStorage;
@ -16,13 +17,13 @@ import java.io.File;
public enum NpcStorageType {
YAML {
@Override
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
return new YamlStorage(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer, new File(plugin.getDataFolder(), "data"));
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcSerializerRegistryImpl serializerRegistry) {
return new YamlStorage(serializerRegistry, new File(plugin.getDataFolder(), "data"));
}
},
SQLITE {
@Override
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcSerializerRegistryImpl serializerRegistry) {
try {
return new SQLiteStorage(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer, new File(plugin.getDataFolder(), "znpcsplus.sqlite"));
} catch (Exception e) {
@ -33,7 +34,7 @@ public enum NpcStorageType {
},
MYSQL {
@Override
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer) {
public NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcSerializerRegistryImpl serializerRegistry) {
try {
return new MySQLStorage(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
} catch (Exception e) {
@ -43,5 +44,5 @@ public enum NpcStorageType {
}
};
public abstract NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer);
public abstract NpcStorage create(ConfigManager configManager, ZNpcsPlus plugin, PacketFactory packetFactory, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, NpcSerializerRegistryImpl serializerRegistry);
}

View file

@ -1,47 +1,28 @@
package lol.pyr.znpcsplus.storage.yaml;
import lol.pyr.znpcsplus.api.entity.EntityProperty;
import lol.pyr.znpcsplus.config.ConfigManager;
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
import lol.pyr.znpcsplus.entity.PropertySerializer;
import lol.pyr.znpcsplus.hologram.HologramImpl;
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
import lol.pyr.znpcsplus.api.serialization.NpcSerializer;
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
import lol.pyr.znpcsplus.npc.NpcImpl;
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
import lol.pyr.znpcsplus.packets.PacketFactory;
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
import lol.pyr.znpcsplus.storage.NpcStorage;
import lol.pyr.znpcsplus.util.NpcLocation;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.*;
import java.util.logging.Level;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class YamlStorage implements NpcStorage {
private final static Logger logger = Logger.getLogger("YamlStorage");
private final PacketFactory packetFactory;
private final ConfigManager configManager;
private final ActionRegistryImpl actionRegistry;
private final NpcTypeRegistryImpl typeRegistry;
private final EntityPropertyRegistryImpl propertyRegistry;
private final LegacyComponentSerializer textSerializer;
private final File folder;
private final NpcSerializer<YamlConfiguration> yamlSerializer;
public YamlStorage(PacketFactory packetFactory, ConfigManager configManager, ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, LegacyComponentSerializer textSerializer, File folder) {
this.packetFactory = packetFactory;
this.configManager = configManager;
this.actionRegistry = actionRegistry;
this.typeRegistry = typeRegistry;
this.propertyRegistry = propertyRegistry;
this.textSerializer = textSerializer;
public YamlStorage(NpcSerializerRegistryImpl serializerRegistry, File folder) {
this.yamlSerializer = serializerRegistry.getSerializer(YamlConfiguration.class);
this.folder = folder;
if (!this.folder.exists()) this.folder.mkdirs();
}
@ -53,45 +34,7 @@ public class YamlStorage implements NpcStorage {
List<NpcEntryImpl> npcs = new ArrayList<>(files.length);
for (File file : files) if (file.isFile() && file.getName().toLowerCase().endsWith(".yml")) try {
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
UUID uuid = config.contains("uuid") ? UUID.fromString(config.getString("uuid")) : UUID.randomUUID();
NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, config.getString("world"),
typeRegistry.getByName(config.getString("type")), deserializeLocation(config.getConfigurationSection("location")));
if (config.isBoolean("enabled")) npc.setEnabled(config.getBoolean("enabled"));
ConfigurationSection properties = config.getConfigurationSection("properties");
if (properties != null) {
for (String key : properties.getKeys(false)) {
EntityPropertyImpl<?> property = propertyRegistry.getByName(key);
if (property == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown property '" + key + "' for npc '" + config.getString("id") + "'. skipping ...");
continue;
}
PropertySerializer<?> serializer = propertyRegistry.getSerializer(property.getType());
if (serializer == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + key + "' for npc '" + config.getString("id") + "'. skipping ...");
continue;
}
Object value = serializer.deserialize(properties.getString(key));
if (value == null) {
Bukkit.getLogger().log(Level.WARNING, "Failed to deserialize property '" + key + "' for npc '" + config.getString("id") + "'. Resetting to default ...");
value = property.getDefaultValue();
}
npc.UNSAFE_setProperty(property, value);
}
}
HologramImpl hologram = npc.getHologram();
hologram.setOffset(config.getDouble("hologram.offset", 0.0));
hologram.setRefreshDelay(config.getLong("hologram.refresh-delay", -1));
for (String line : config.getStringList("hologram.lines")) hologram.addLine(line);
for (String s : config.getStringList("actions")) npc.addAction(actionRegistry.deserialize(s));
NpcEntryImpl entry = new NpcEntryImpl(config.getString("id"), npc);
entry.setProcessed(config.getBoolean("is-processed"));
entry.setAllowCommandModification(config.getBoolean("allow-commands"));
entry.setSave(true);
npcs.add(entry);
npcs.add((NpcEntryImpl) yamlSerializer.deserialize(config));
} catch (Throwable t) {
logger.severe("Failed to load npc file: " + file.getName());
t.printStackTrace();
@ -102,43 +45,7 @@ public class YamlStorage implements NpcStorage {
@Override
public void saveNpcs(Collection<NpcEntryImpl> npcs) {
for (NpcEntryImpl entry : npcs) try {
YamlConfiguration config = new YamlConfiguration();
config.set("id", entry.getId());
config.set("is-processed", entry.isProcessed());
config.set("allow-commands", entry.isAllowCommandModification());
NpcImpl npc = entry.getNpc();
config.set("enabled", npc.isEnabled());
config.set("uuid", npc.getUuid().toString());
config.set("world", npc.getWorldName());
config.set("location", serializeLocation(npc.getLocation()));
config.set("type", npc.getType().getName());
for (EntityProperty<?> property : npc.getAllProperties()) try {
PropertySerializer<?> serializer = propertyRegistry.getSerializer(((EntityPropertyImpl<?>) property).getType());
if (serializer == null) {
Bukkit.getLogger().log(Level.WARNING, "Unknown serializer for property '" + property.getName() + "' for npc '" + entry.getId() + "'. skipping ...");
continue;
}
config.set("properties." + property.getName(), serializer.UNSAFE_serialize(npc.getProperty(property)));
} catch (Exception exception) {
logger.severe("Failed to serialize property " + property.getName() + " for npc with id " + entry.getId());
exception.printStackTrace();
}
HologramImpl hologram = npc.getHologram();
if (hologram.getOffset() != 0.0) config.set("hologram.offset", hologram.getOffset());
if (hologram.getRefreshDelay() != -1) config.set("hologram.refresh-delay", hologram.getRefreshDelay());
List<String> lines = new ArrayList<>(npc.getHologram().getLines().size());
for (int i = 0; i < hologram.getLines().size(); i++) {
lines.add(hologram.getLine(i));
}
config.set("hologram.lines", lines);
config.set("actions", npc.getActions().stream()
.map(actionRegistry::serialize)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
YamlConfiguration config = yamlSerializer.serialize(entry);
config.save(fileFor(entry));
} catch (Exception exception) {
logger.severe("Failed to save npc with id " + entry.getId());