diff --git a/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionManager.java b/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionManager.java
new file mode 100644
index 000000000..2b2bfd634
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionManager.java
@@ -0,0 +1,105 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.expansions;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import me.wolfyscript.utilities.util.json.jackson.JacksonUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class ExpansionManager {
+
+ private final String LOG_PREFIX = "[Expansions] ";
+
+ private final WolfyUtilCore core;
+ private final File packsFolder;
+
+ private List packs;
+
+ public ExpansionManager(WolfyUtilCore core) {
+ this.core = core;
+ this.packsFolder = new File(core.getDataFolder(), "expansion_packs");
+ this.packs = new LinkedList<>();
+ }
+
+ public void initPacks() {
+ core.getLogger().info(LOG_PREFIX + "Initializing packs...");
+ File[] files = packsFolder.listFiles((dir, name) -> name.endsWith(".zip"));
+ if (files != null) {
+ this.packs = new LinkedList<>();
+ for (File file : files) {
+ try {
+ var pack = initPack(file);
+ if (pack != null) {
+ packs.add(pack);
+ }
+ } catch (IOException e) {
+ core.getLogger().warning(LOG_PREFIX + "Failed to read expansion zip file " + file.getName() + ": " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ public void loadPacks() {
+ core.getLogger().info(LOG_PREFIX + "Loading packs...");
+ var registry = core.getRegistries().getExpansionResourceLoaders();
+ List order = registry.getRegisterOrder();
+ for (ExpansionPack pack : packs) {
+ try {
+ pack.load(registry, order);
+ } catch (IOException e) {
+ core.getLogger().warning(LOG_PREFIX + "Failed to read expansion zip file " + pack.getFile().getName() + ": " + e.getMessage());
+ }
+ }
+ }
+
+ public ExpansionPack initPack(File file) throws IOException {
+ ZipFile zipFile = new ZipFile(file);
+ try (zipFile) {
+ if (zipFile.entries().hasMoreElements()) {
+ List entryNames = zipFile.stream().map(ZipEntry::getName).toList();
+ ZipEntry packInfoEntry = zipFile.getEntry(entryNames.get(0) + "pack.json");
+ if (packInfoEntry != null && !packInfoEntry.isDirectory()) {
+ PackMetaFile metaFile = JacksonUtil.getObjectMapper().readValue(zipFile.getInputStream(packInfoEntry), PackMetaFile.class);
+ if (metaFile.getPack().getVersion() != ExpansionPack.VERSION) {
+ //Invalid version!
+ return null;
+ }
+ ExpansionPack pack = new ExpansionPack(metaFile, file, entryNames, core);
+ if (packs.contains(pack)) {
+ core.getLogger().warning(LOG_PREFIX + "Pack already initialised: \"" + metaFile.getPack().getNamespace() +"\" in file " + file.getName());
+ return null;
+ }
+ return pack;
+ }
+ }
+ }
+ return null;
+ }
+
+ public List getPacks() {
+ return List.copyOf(packs);
+ }
+}
diff --git a/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionPack.java b/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionPack.java
new file mode 100644
index 000000000..cff999459
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/expansions/ExpansionPack.java
@@ -0,0 +1,101 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.expansions;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.registry.RegistryResourceLoader;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.zip.ZipFile;
+
+public class ExpansionPack {
+
+ static final int VERSION = 1;
+
+ private final WolfyUtilCore core;
+ private final PackMetaFile meta;
+ private final File file;
+ private final List zipEntryNames;
+ private final String rootDir;
+
+ ExpansionPack(@NotNull PackMetaFile meta, File file, List entryNames, WolfyUtilCore core) {
+ this.file = file;
+ this.core = core;
+ this.zipEntryNames = entryNames;
+ this.rootDir = entryNames.get(0);
+ this.meta = meta;
+ }
+
+ public void load(RegistryResourceLoader registry, List loaderOrder) throws IOException {
+ var zipFile = new ZipFile(file);
+ try (zipFile) {
+ for (NamespacedKey namespacedKey : loaderOrder) {
+ var loader = registry.get(namespacedKey);
+ if (loader != null) {
+ String loaderRoot = rootDir + loader.folderPath; //Get the root of the loader
+ int rootIndex = zipEntryNames.indexOf(loaderRoot); // Get the index of that root in the zip file.
+ if (rootIndex == -1) {
+ continue; // The loader root is not in the zip file.
+ }
+ //We start one index later, as the first one is always the root folder
+ for (int i = rootIndex + 1; i < zipEntryNames.size(); i++) {
+ String entryName = zipEntryNames.get(i);
+ if (!entryName.startsWith(loaderRoot)) {
+ break;
+ }
+ var entry = zipFile.getEntry(entryName);
+ if (entry != null) {
+ // Call the loader specific load method
+ try {
+ loader.load(this, zipFile, rootDir, entry, core);
+ } catch (Exception e) {
+ // We don't want a faulty loader to crash the whole loading process and/or plugin!
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public PackMetaFile getMeta() {
+ return meta;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ExpansionPack pack)) return false;
+ return meta.getPack().getNamespace().equals(pack.meta.getPack().getNamespace());
+ }
+
+ @Override
+ public int hashCode() {
+ return meta.getPack().getNamespace().hashCode();
+ }
+}
diff --git a/core/src/main/java/me/wolfyscript/utilities/expansions/PackMetaFile.java b/core/src/main/java/me/wolfyscript/utilities/expansions/PackMetaFile.java
new file mode 100644
index 000000000..8ff8b894d
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/expansions/PackMetaFile.java
@@ -0,0 +1,71 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.expansions;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class PackMetaFile {
+
+ private final PackInfo pack;
+
+ @JsonCreator
+ PackMetaFile(@JsonProperty("pack") PackInfo pack) {
+ this.pack = pack;
+ }
+
+ public PackInfo getPack() {
+ return pack;
+ }
+
+ public static class PackInfo {
+
+ private final int version;
+ private final String namespace;
+ private final List authors;
+ private final String description;
+
+ @JsonCreator
+ PackInfo(@JsonProperty("version") int version, @JsonProperty("namespace") String namespace, @JsonProperty("authors") List authors, @JsonProperty("description") String description) {
+ this.version = version;
+ this.namespace = namespace;
+ this.authors = List.copyOf(authors);
+ this.description = description;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public List getAuthors() {
+ return authors;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ }
+
+}
diff --git a/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoader.java b/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoader.java
new file mode 100644
index 000000000..40394cde5
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoader.java
@@ -0,0 +1,55 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.expansions;
+
+import com.google.common.base.Preconditions;
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.util.Keyed;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import org.bukkit.plugin.Plugin;
+
+import java.util.Locale;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public abstract class ResourceLoader implements Keyed {
+
+ private final Plugin plugin;
+ private final NamespacedKey key;
+ protected final String folderPath;
+
+ protected ResourceLoader(Plugin plugin, NamespacedKey namespacedKey) {
+ this.plugin = plugin;
+ String namespace = plugin.getName().toLowerCase(Locale.ROOT);
+ Preconditions.checkArgument(namespacedKey.getNamespace().equals(namespace), "The namespace must be equal to your plugin name! Expected " + namespace + " but got " + namespace);
+ this.key = namespacedKey;
+ this.folderPath = key.toString("/") + "/";
+ }
+
+ public Plugin getPlugin() {
+ return plugin;
+ }
+
+ public abstract void load(ExpansionPack pack, ZipFile zipFile, String root, ZipEntry entry, WolfyUtilCore core);
+
+ @Override
+ public NamespacedKey getNamespacedKey() {
+ return key;
+ }
+}
diff --git a/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoaderJson.java b/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoaderJson.java
new file mode 100644
index 000000000..c29ede4a4
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/expansions/ResourceLoaderJson.java
@@ -0,0 +1,60 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.expansions;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.util.Keyed;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import me.wolfyscript.utilities.util.json.jackson.JacksonUtil;
+import org.bukkit.plugin.Plugin;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public abstract class ResourceLoaderJson extends ResourceLoader {
+
+ private final Class type;
+
+ protected ResourceLoaderJson(Plugin plugin, NamespacedKey namespacedKey, Class type) {
+ super(plugin, namespacedKey);
+ this.type = type;
+ }
+
+ public abstract void register(NamespacedKey namespacedKey, T value, WolfyUtilCore core);
+
+ @Override
+ public void load(ExpansionPack pack, ZipFile zipFile, String root, ZipEntry entry, WolfyUtilCore core) {
+ if (entry.isDirectory()) {
+ //We can't read from a directory!
+ return;
+ }
+ String path = entry.getName().replace(root + folderPath, "");
+ path = path.substring(0, path.lastIndexOf(".")); // This the key of the effect.
+ try (var stream = new BufferedInputStream(zipFile.getInputStream(entry))) {
+ var item = JacksonUtil.getObjectMapper().readValue(stream, type);
+ if (item != null) {
+ this.register(new NamespacedKey(pack.getMeta().getPack().getNamespace(), path), item, core);
+ }
+ } catch (IOException e) {
+ core.getLogger().info("Failed to load animation \"" + path + "\"! Cause:" + e.getMessage());
+ }
+ }
+}
diff --git a/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java b/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java
index 610388766..5b98bd22f 100644
--- a/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java
+++ b/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java
@@ -80,12 +80,17 @@ public class Registries {
private final TypeRegistry particleShapes;
private final TypeRegistry particleTimer;
private final TypeRegistry customItemNbtChecks;
+ //Expansions
+ private final RegistryResourceLoader expansionLoaders;
private final TypeRegistry> customItemActions;
private final TypeRegistry> customItemEvents;
private final TypeRegistry> valueProviders;
private final TypeRegistry operators;
+ //Expansions
+ private final RegistryResourceLoader expansionLoaders;
+
public Registries(WolfyUtilCore core) {
this.core = core;
@@ -102,6 +107,8 @@ public Registries(WolfyUtilCore core) {
particleShapes = new TypeRegistrySimple<>(new NamespacedKey(core, "particles/shapes"), this);
particleTimer = new TypeRegistrySimple<>(new NamespacedKey(core, "particle_timers"), this);
customItemNbtChecks = new TypeRegistrySimple<>(new NamespacedKey(core, "custom_item_nbt_checks"), this);
+
+ expansionLoaders = new RegistryResourceLoader(this);
customItemActions = new TypeRegistrySimple<>(ITEM_ACTION_TYPES, this);
customItemEvents = new TypeRegistrySimple<>(ITEM_EVENT_TYPES, this);
valueProviders = new TypeRegistrySimple<>(new NamespacedKey(core, "value_providers"), this);
@@ -229,6 +236,10 @@ public TypeRegistry getParticleTimer() {
return particleTimer;
}
+ public RegistryResourceLoader getExpansionResourceLoaders() {
+ return expansionLoaders;
+ }
+
public TypeRegistry> getCustomItemActions() {
return customItemActions;
}
diff --git a/core/src/main/java/me/wolfyscript/utilities/registry/RegistryResourceLoader.java b/core/src/main/java/me/wolfyscript/utilities/registry/RegistryResourceLoader.java
new file mode 100644
index 000000000..30e417975
--- /dev/null
+++ b/core/src/main/java/me/wolfyscript/utilities/registry/RegistryResourceLoader.java
@@ -0,0 +1,51 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.registry;
+
+import me.wolfyscript.utilities.expansions.ResourceLoader;
+import me.wolfyscript.utilities.util.NamespacedKey;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class RegistryResourceLoader extends RegistrySimple {
+
+ private final List registerOrder = new LinkedList<>();
+
+ public RegistryResourceLoader(Registries registries) {
+ super(new NamespacedKey(registries.getCore(), "expansions/loaders"), registries);
+ }
+
+ @Override
+ public void register(ResourceLoader value) {
+ super.register(value);
+ if (!registerOrder.contains(value.getNamespacedKey())) {
+ registerOrder.add(value.getNamespacedKey());
+ }
+ }
+
+ @Override
+ public void register(NamespacedKey namespacedKey, ResourceLoader value) {
+ super.register(namespacedKey, value);
+ }
+
+ public List getRegisterOrder() {
+ return List.copyOf(registerOrder);
+ }
+}
diff --git a/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/WUPlugin.java b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/WUPlugin.java
index ec15ae5bd..962432be4 100644
--- a/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/WUPlugin.java
+++ b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/WUPlugin.java
@@ -59,11 +59,15 @@
import me.wolfyscript.utilities.api.inventory.custom_items.references.WolfyUtilitiesRef;
import me.wolfyscript.utilities.compatibility.CompatibilityManager;
import me.wolfyscript.utilities.compatibility.CompatibilityManagerImpl;
+import me.wolfyscript.utilities.expansions.ExpansionManager;
import me.wolfyscript.utilities.main.commands.ChatActionCommand;
import me.wolfyscript.utilities.main.commands.InputCommand;
import me.wolfyscript.utilities.main.commands.SpawnParticleAnimationCommand;
import me.wolfyscript.utilities.main.commands.SpawnParticleEffectCommand;
import me.wolfyscript.utilities.main.configs.WUConfig;
+import me.wolfyscript.utilities.main.resource_loader.ResourceLoaderCustomItems;
+import me.wolfyscript.utilities.main.resource_loader.ResourceLoaderParticleAnimations;
+import me.wolfyscript.utilities.main.resource_loader.ResourceLoaderParticleEffects;
import me.wolfyscript.utilities.main.listeners.BlockListener;
import me.wolfyscript.utilities.main.listeners.EquipListener;
import me.wolfyscript.utilities.main.listeners.GUIInventoryListener;
@@ -153,6 +157,7 @@ public final class WUPlugin extends WolfyUtilCore {
private final MessageFactory messageFactory;
private final CompatibilityManagerImpl compatibilityManager;
private BukkitAudiences adventure;
+ private final ExpansionManager expansionManager;
/**
* Constructor invoked by Spigot when the plugin is loaded.
@@ -166,6 +171,7 @@ public WUPlugin() {
this.messageHandler = new MessageHandler(this);
this.messageFactory = new MessageFactory(this);
this.compatibilityManager = new CompatibilityManagerImpl(this);
+ this.expansionManager = new ExpansionManager(this);
}
/**
@@ -180,6 +186,7 @@ private WUPlugin(JavaPluginLoader loader, PluginDescriptionFile description, Fil
this.messageHandler = new MessageHandler(this);
this.messageFactory = new MessageFactory(this);
this.compatibilityManager = new CompatibilityManagerImpl(this);
+ this.expansionManager = new ExpansionManager(this);
}
@Deprecated
@@ -316,6 +323,11 @@ public void onLoad() {
KeyedTypeIdResolver.registerTypeRegistry((Class>)(Object) Event.class, customItemEvents);
KeyedTypeIdResolver.registerTypeRegistry(Operator.class, operators);
KeyedTypeIdResolver.registerTypeRegistry((Class>) (Object)ValueProvider.class, valueProviders);
+
+ var expansionLoaders = getRegistries().getExpansionResourceLoaders();
+ expansionLoaders.register(new ResourceLoaderParticleEffects(this));
+ expansionLoaders.register(new ResourceLoaderParticleAnimations(this));
+ expansionLoaders.register(new ResourceLoaderCustomItems(this));
}
@Override
@@ -332,6 +344,9 @@ public void onEnable() {
registerAPIReference(new VanillaRef.Parser());
registerAPIReference(new WolfyUtilitiesRef.Parser());
+ expansionManager.initPacks();
+ expansionManager.loadPacks();
+
//Load Language
api.getLanguageAPI().loadLangFile("en_US");
diff --git a/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderCustomItems.java b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderCustomItems.java
new file mode 100644
index 000000000..4b6e1695a
--- /dev/null
+++ b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderCustomItems.java
@@ -0,0 +1,38 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.main.resource_loader;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem;
+import me.wolfyscript.utilities.expansions.ResourceLoaderJson;
+import me.wolfyscript.utilities.main.WUPlugin;
+import me.wolfyscript.utilities.util.NamespacedKey;
+
+public class ResourceLoaderCustomItems extends ResourceLoaderJson {
+
+ public ResourceLoaderCustomItems(WUPlugin plugin) {
+ super(plugin, new NamespacedKey(plugin, "items/items"), CustomItem.class);
+ }
+
+ @Override
+ public void register(NamespacedKey namespacedKey, CustomItem value, WolfyUtilCore core) {
+ core.getRegistries().getCustomItems().register(namespacedKey, value);
+ }
+
+}
diff --git a/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleAnimations.java b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleAnimations.java
new file mode 100644
index 000000000..cf6503b22
--- /dev/null
+++ b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleAnimations.java
@@ -0,0 +1,37 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.main.resource_loader;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.expansions.ResourceLoaderJson;
+import me.wolfyscript.utilities.main.WUPlugin;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import me.wolfyscript.utilities.util.particles.ParticleAnimation;
+
+public class ResourceLoaderParticleAnimations extends ResourceLoaderJson {
+
+ public ResourceLoaderParticleAnimations(WUPlugin plugin) {
+ super(plugin, new NamespacedKey(plugin, "particles/animations"), ParticleAnimation.class);
+ }
+
+ @Override
+ public void register(NamespacedKey namespacedKey, ParticleAnimation value, WolfyUtilCore core) {
+ core.getRegistries().getParticleAnimations().register(namespacedKey, value);
+ }
+}
diff --git a/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleEffects.java b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleEffects.java
new file mode 100644
index 000000000..db4f0e7a0
--- /dev/null
+++ b/wolfyutilities/src/main/java/me/wolfyscript/utilities/main/resource_loader/ResourceLoaderParticleEffects.java
@@ -0,0 +1,45 @@
+/*
+ * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins
+ * Copyright (C) 2021 WolfyScript
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.wolfyscript.utilities.main.resource_loader;
+
+import me.wolfyscript.utilities.api.WolfyUtilCore;
+import me.wolfyscript.utilities.expansions.ExpansionPack;
+import me.wolfyscript.utilities.expansions.ResourceLoader;
+import me.wolfyscript.utilities.expansions.ResourceLoaderJson;
+import me.wolfyscript.utilities.main.WUPlugin;
+import me.wolfyscript.utilities.util.NamespacedKey;
+import me.wolfyscript.utilities.util.json.jackson.JacksonUtil;
+import me.wolfyscript.utilities.util.particles.ParticleEffect;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class ResourceLoaderParticleEffects extends ResourceLoaderJson {
+
+ public ResourceLoaderParticleEffects(WUPlugin plugin) {
+ super(plugin, new NamespacedKey(plugin, "particles/effects"), ParticleEffect.class);
+ }
+
+ @Override
+ public void register(NamespacedKey namespacedKey, ParticleEffect value, WolfyUtilCore core) {
+ core.getRegistries().getParticleEffects().register(namespacedKey, value);
+ }
+}
diff --git a/wolfyutilities/src/main/resources/examples/extensionpack/pack.json b/wolfyutilities/src/main/resources/examples/extensionpack/pack.json
new file mode 100644
index 000000000..65b49c573
--- /dev/null
+++ b/wolfyutilities/src/main/resources/examples/extensionpack/pack.json
@@ -0,0 +1,8 @@
+{
+ "pack": {
+ "version": 1,
+ "namespace": " (Usually your lowercase plugin name. Spaces are not allowed! Must be unique from other packs, so make sure to pick a good name!)",
+ "authors": [],
+ "description": ""
+ }
+}
\ No newline at end of file