diff --git a/Corvo/src/main/resources/plugin.yml b/Corvo/src/main/resources/plugin.yml
new file mode 100644
index 0000000..557f40e
--- /dev/null
+++ b/Corvo/src/main/resources/plugin.yml
@@ -0,0 +1,7 @@
+name: Corvo
+main: me.totalfreedom.corvo.Corvo
+version: 1.0.0
+author: TotalFreedom
+description: Services and Listeners for the Freedom Network Suite
+depend:
+ - Patchwork
\ No newline at end of file
diff --git a/Datura/src/main/resources/plugin.yml b/Datura/src/main/resources/plugin.yml
index 22bb0aa..0455676 100644
--- a/Datura/src/main/resources/plugin.yml
+++ b/Datura/src/main/resources/plugin.yml
@@ -3,6 +3,5 @@ main: me.totalfreedom.datura.Datura
version: 1.0.0
author: TotalFreedom
description: Data Manager for the Freedom Network Suite
-libraries:
- - com.discord4j:discord4j-core:3.2.3
- - com.discord4j:discord4j-commons:3.2.3
\ No newline at end of file
+depend:
+ - Patchwork
\ No newline at end of file
diff --git a/Fossil/src/main/java/me/totalfreedom/fossil/cmd/CakeCommand.java b/Fossil/src/main/java/me/totalfreedom/fossil/cmd/CakeCommand.java
new file mode 100644
index 0000000..7a6c437
--- /dev/null
+++ b/Fossil/src/main/java/me/totalfreedom/fossil/cmd/CakeCommand.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023 TotalFreedom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the “Software”), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package me.totalfreedom.fossil.cmd;
+
+import me.totalfreedom.command.CommandBase;
+import me.totalfreedom.command.annotation.Base;
+import me.totalfreedom.command.annotation.Info;
+import me.totalfreedom.command.annotation.Permissive;
+import me.totalfreedom.utils.FreedomMiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.plugin.java.JavaPlugin;
+
+@Info(name = "cake", description = "Gives everyone cake and broadcasts a message.", usage = "/cake")
+@Permissive(perm = "fossil.cake")
+public class CakeCommand extends CommandBase
+{
+ protected CakeCommand(JavaPlugin plugin)
+ {
+ super(plugin);
+ }
+
+ @Base
+ public void cake(final CommandSender sender)
+ {
+ Bukkit.broadcast(FreedomMiniMessage.deserialize(true, "But there's no sense crying over every mistake. You just keep on trying till you run out of cake."));
+
+ final ItemStack stack = new ItemStack(Material.CAKE, 1);
+ final ItemMeta meta = stack.getItemMeta();
+ meta.displayName(FreedomMiniMessage.deserialize(true, "The Lie"));
+ stack.setItemMeta(meta);
+
+ Bukkit.getOnlinePlayers().forEach(player -> player.getInventory().addItem(stack));
+ }
+}
diff --git a/Patchwork/src/main/java/me/totalfreedom/utils/FreedomMiniMessage.java b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomMiniMessage.java
new file mode 100644
index 0000000..e615906
--- /dev/null
+++ b/Patchwork/src/main/java/me/totalfreedom/utils/FreedomMiniMessage.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023 TotalFreedom
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the “Software”), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package me.totalfreedom.utils;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
+import net.kyori.adventure.text.minimessage.tag.standard.StandardTags;
+
+/**
+ * This class contains a wrapper for a MiniMessage serializer.
+ */
+public class FreedomMiniMessage
+{
+ private FreedomMiniMessage()
+ {
+ throw new UnsupportedOperationException("Instantiation of a static utility class is not supported.");
+ }
+
+ private static final MiniMessage unsafe = MiniMessage.miniMessage();
+
+ private static final MiniMessage safe = MiniMessage.builder().tags(TagResolver.resolver(
+ StandardTags.color(),
+ StandardTags.rainbow(),
+ StandardTags.gradient(),
+ StandardTags.newline(),
+ StandardTags.decorations(TextDecoration.ITALIC),
+ StandardTags.decorations(TextDecoration.BOLD),
+ StandardTags.decorations(TextDecoration.STRIKETHROUGH),
+ StandardTags.decorations(TextDecoration.UNDERLINED)
+ )).build();
+
+ /**
+ * Deserializes an input string using an instance of MiniMessage that is either safe (resolves only a specific set of tags)
+ * or unsafe (resolves all tags).
+ * @param safe Whether to use a safe instance of MiniMessage
+ * @param input An input string formatted with MiniMessage's input
+ * @param placeholders Custom placeholders to use when processing the input
+ * @return A processed Component
+ */
+ public static Component deserialize(boolean safe, String input, TagResolver... placeholders)
+ {
+ return (safe ? FreedomMiniMessage.safe : unsafe).deserialize(input, placeholders);
+ }
+
+ /**
+ * Serializes an input component using an instance of MiniMessage that is either safe (resolves only a specific set
+ * of tags) or unsafe (resolves all tags).
+ * @param safe Whether to use a safe instance of MiniMessage
+ * @param input An already processed component
+ * @return A processed Component
+ */
+ public static String serialize(boolean safe, Component input)
+ {
+ return (safe ? FreedomMiniMessage.safe : unsafe).serialize(input);
+ }
+}
diff --git a/Patchwork/src/main/resources/plugin.yml b/Patchwork/src/main/resources/plugin.yml
new file mode 100644
index 0000000..5cbde93
--- /dev/null
+++ b/Patchwork/src/main/resources/plugin.yml
@@ -0,0 +1,5 @@
+name: Patchwork
+main: me.totalfreedom.base.CommonsBase
+version: 1.0.0
+author: TotalFreedom
+description: The Core of Freedom Network Suite
\ No newline at end of file