diff --git a/pom.xml b/pom.xml
index 04bb273..44659be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
com.rsscripting
RS-Warehouse
RS-Warehouse
- 1.4.0
+ 1.5.0
21
diff --git a/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenu.java b/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenu.java
index c3da23d..7a8f560 100644
--- a/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenu.java
+++ b/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenu.java
@@ -195,6 +195,16 @@ public class AdminMenu {
)
);
+ menu.setItem(
+ 14,
+ RSMenuUtils.createMenuItemWithLore(
+ Material.COMMAND_BLOCK,
+ "§aCreate Server Rule",
+ List.of(
+ "§7Create a server rule entry."
+ )
+ )
+ );
player.openInventory(menu);
diff --git a/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenuListener.java
index 9f87888..a866ceb 100644
--- a/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenuListener.java
+++ b/src/main/java/com/rsscripting/rswarehouse/adminmenu/AdminMenuListener.java
@@ -1,5 +1,6 @@
package com.rsscripting.rswarehouse.adminmenu;
+import com.rsscripting.rswarehouse.serverrule.ServerRuleInternalNameMenu;
import com.rsscripting.rswarehouse.session.admin.ServerCommandCreationSessionManager;
import com.rsscripting.rswarehouse.config.ConfigManager;
import com.rsscripting.rswarehouse.chestconvert.ConvertMenuListener;
@@ -9,6 +10,7 @@ import com.rsscripting.rswarehouse.constants.RSConstants;
import com.rsscripting.rswarehouse.navigation.NavigationManager;
import com.rsscripting.rswarehouse.servercommands.ServerCommandInternalNameMenu;
import com.rsscripting.rswarehouse.session.GuiSessionManager;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
import org.bukkit.block.Block;
import com.rsscripting.rswarehouse.utils.RSMessageUtils;
import org.bukkit.entity.Player;
@@ -147,6 +149,19 @@ public class AdminMenuListener
return;
}
+ if (event.getRawSlot() == 14) {
+
+ ServerRuleCreationSessionManager.createSession(
+ player.getUniqueId()
+ );
+
+ ServerRuleInternalNameMenu.open(
+ player
+ );
+
+ return;
+ }
+
}
}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/category/categorymenu/CategoryMenu.java b/src/main/java/com/rsscripting/rswarehouse/category/categorymenu/CategoryMenu.java
index 009070f..557e0a3 100644
--- a/src/main/java/com/rsscripting/rswarehouse/category/categorymenu/CategoryMenu.java
+++ b/src/main/java/com/rsscripting/rswarehouse/category/categorymenu/CategoryMenu.java
@@ -102,6 +102,9 @@ public class CategoryMenu {
WarehouseCategory serverCommands =
null;
+ WarehouseCategory serverRules =
+ null;
+
List displayCategories =
new ArrayList<>();
@@ -122,13 +125,21 @@ public class CategoryMenu {
}
else if (category.id() == 1001) {
-
if (ConfigManager.isServerCommandsEnabled()) {
serverCommands = category;
}
+ }
+ else if (category.id() == 1000) {
+
+ if (ConfigManager.isServerRulesEnabled()) {
+
+ serverRules = category;
+
+ }
+
}
else {
@@ -482,6 +493,54 @@ public class CategoryMenu {
}
+ if (serverRules != null) {
+
+ ItemStack icon =
+ RSMenuUtils.createMenuItemWithLore(
+ Material.valueOf(
+ serverRules.material()
+ ),
+ "§a"
+ + serverRules.displayName(),
+ serverRules.lore() == null
+ || serverRules.lore().isBlank()
+ ? List.of()
+ : Arrays.asList(
+ serverRules.lore()
+ .split("\n")
+ )
+ );
+
+ ItemMeta meta =
+ icon.getItemMeta();
+
+ if (meta != null) {
+
+ meta.addItemFlags(
+ ItemFlag.HIDE_ATTRIBUTES,
+ ItemFlag.HIDE_ADDITIONAL_TOOLTIP
+ );
+
+ meta.getPersistentDataContainer()
+ .set(
+ RSKeys.CATEGORY_ID,
+ PersistentDataType.INTEGER,
+ serverRules.id()
+ );
+
+ icon.setItemMeta(
+ meta
+ );
+
+ }
+
+ menu.setItem(
+ 7,
+ icon
+ );
+
+ }
+
player.openInventory(
menu
);
diff --git a/src/main/java/com/rsscripting/rswarehouse/config/ConfigManager.java b/src/main/java/com/rsscripting/rswarehouse/config/ConfigManager.java
index 254d1f5..4b15abf 100644
--- a/src/main/java/com/rsscripting/rswarehouse/config/ConfigManager.java
+++ b/src/main/java/com/rsscripting/rswarehouse/config/ConfigManager.java
@@ -81,5 +81,13 @@ public class ConfigManager {
}
+ public static boolean isServerRulesEnabled() {
+
+ return config.getBoolean(
+ "display.show-server-rules",
+ true
+ );
+
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/dao/admin/CreateServerRuleDAO.java b/src/main/java/com/rsscripting/rswarehouse/dao/admin/CreateServerRuleDAO.java
new file mode 100644
index 0000000..5835e7a
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/dao/admin/CreateServerRuleDAO.java
@@ -0,0 +1,257 @@
+package com.rsscripting.rswarehouse.dao.admin;
+
+import com.rsscripting.rswarehouse.database.DatabaseManager;
+import com.rsscripting.rswarehouse.utils.ItemStackUtils;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.SQLException;
+
+public class CreateServerRuleDAO {
+
+ public static int createServerRule(
+ String internalName,
+ String displayName,
+ String material,
+ String lore
+ ) {
+
+ try (
+ Connection connection =
+ DatabaseManager.getConnection()
+ ) {
+
+ connection.setAutoCommit(false);
+
+ try {
+
+ /*
+ * Create the Server Rule category.
+ */
+
+ int nextDisplayOrder = 1;
+
+ try (
+ PreparedStatement maxStatement =
+ connection.prepareStatement(
+ """
+ SELECT COALESCE(
+ MAX(display_order),
+ 0
+ )
+ FROM warehouse_categories
+ """
+ )
+ ) {
+
+ ResultSet resultSet =
+ maxStatement.executeQuery();
+
+ if (resultSet.next()) {
+
+ nextDisplayOrder =
+ resultSet.getInt(1) + 1;
+
+ }
+
+ }
+
+ int ruleCategoryId;
+
+ try (
+ PreparedStatement statement =
+ connection.prepareStatement(
+ """
+ INSERT INTO warehouse_categories (
+ parent_category_id,
+ internal_name,
+ display_name,
+ material,
+ lore,
+ display_order,
+ page,
+ slot
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ """,
+ Statement.RETURN_GENERATED_KEYS
+ )
+ ) {
+
+ statement.setInt(
+ 1,
+ 1000
+ );
+
+ statement.setString(
+ 2,
+ internalName
+ );
+
+ statement.setString(
+ 3,
+ displayName
+ );
+
+ statement.setString(
+ 4,
+ material
+ );
+
+ statement.setString(
+ 5,
+ lore
+ );
+
+ statement.setInt(
+ 6,
+ nextDisplayOrder
+ );
+
+ statement.setInt(
+ 7,
+ 0
+ );
+
+ statement.setInt(
+ 8,
+ 0
+ );
+
+ statement.executeUpdate();
+
+ ResultSet keys =
+ statement.getGeneratedKeys();
+
+ if (!keys.next()) {
+
+ connection.rollback();
+
+ return -1;
+
+ }
+
+ ruleCategoryId =
+ keys.getInt(1);
+
+ }
+
+
+ /*
+ * Create the display-only navigation item.
+ */
+
+ ItemStack item =
+ new ItemStack(
+ Material.valueOf(
+ material
+ )
+ );
+
+ String serializedItem =
+ ItemStackUtils.serialize(
+ item
+ );
+
+ try (
+ PreparedStatement statement =
+ connection.prepareStatement(
+ """
+ INSERT INTO warehouse_items (
+ category_id,
+ serialized_item,
+ default_lore,
+ inventory_id,
+ subcategory_id,
+ created_at,
+ page,
+ slot
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ """
+ )
+ ) {
+
+ statement.setInt(
+ 1,
+ 1000
+ );
+
+ statement.setString(
+ 2,
+ serializedItem
+ );
+
+ statement.setString(
+ 3,
+ null
+ );
+
+ statement.setObject(
+ 4,
+ null
+ );
+
+ statement.setInt(
+ 5,
+ ruleCategoryId
+ );
+
+ statement.setString(
+ 6,
+ String.valueOf(
+ System.currentTimeMillis()
+ )
+ );
+
+ statement.setObject(
+ 7,
+ null
+ );
+
+ statement.setObject(
+ 8,
+ null
+ );
+
+ statement.executeUpdate();
+
+ }
+
+ connection.commit();
+
+ return ruleCategoryId;
+
+ }
+
+ catch (SQLException exception) {
+
+ connection.rollback();
+
+ exception.printStackTrace();
+
+ }
+
+ finally {
+
+ connection.setAutoCommit(true);
+
+ }
+
+ }
+
+ catch (SQLException exception) {
+
+ exception.printStackTrace();
+
+ }
+
+ return -1;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/database/DatabaseTableCreator.java b/src/main/java/com/rsscripting/rswarehouse/database/DatabaseTableCreator.java
index b4d4011..4a5efa9 100644
--- a/src/main/java/com/rsscripting/rswarehouse/database/DatabaseTableCreator.java
+++ b/src/main/java/com/rsscripting/rswarehouse/database/DatabaseTableCreator.java
@@ -92,6 +92,31 @@ public class DatabaseTableCreator {
"""
);
+ connection.createStatement().execute(
+ """
+ INSERT OR IGNORE INTO warehouse_categories (
+ id,
+ internal_name,
+ display_name,
+ material,
+ lore,
+ display_order,
+ page,
+ slot
+ )
+ VALUES (
+ 1000,
+ 'server_rules',
+ 'Server Rules',
+ 'BOOK',
+ '\nRules and guidelines for this server.',
+ 0,
+ 0,
+ 7
+ )
+ """
+ );
+
connection.createStatement().execute(
"""
INSERT OR IGNORE INTO warehouse_categories (
diff --git a/src/main/java/com/rsscripting/rswarehouse/registration/ListenerRegistration.java b/src/main/java/com/rsscripting/rswarehouse/registration/ListenerRegistration.java
index c2d7f46..0970156 100644
--- a/src/main/java/com/rsscripting/rswarehouse/registration/ListenerRegistration.java
+++ b/src/main/java/com/rsscripting/rswarehouse/registration/ListenerRegistration.java
@@ -7,6 +7,7 @@ import com.rsscripting.rswarehouse.category.categoryedit.CategoryEditLoreMenuCha
import com.rsscripting.rswarehouse.category.categoryedit.CategoryEditLoreMenuListener;
import com.rsscripting.rswarehouse.category.categoryedit.CategoryEditMaterialMenuListener;
import com.rsscripting.rswarehouse.servercommands.*;
+import com.rsscripting.rswarehouse.serverrule.*;
import com.rsscripting.rswarehouse.subcategory.items.*;
import com.rsscripting.rswarehouse.adminmenu.AdminMenuListener;
import com.rsscripting.rswarehouse.assignpageslot.CategoryPageNumberMenuListener;
@@ -343,6 +344,33 @@ public final class ListenerRegistration {
new PartiallyFilledVariantsMenuListener()
);
+ /* Server Rules */
+
+ ListenerRegistrar.register(
+ plugin,
+ new ServerRuleDisplayNameMenuListener()
+ );
+
+ ListenerRegistrar.register(
+ plugin,
+ new ServerRuleInternalNameMenuListener()
+ );
+
+ ListenerRegistrar.register(
+ plugin,
+ new ServerRuleLoreChatListener()
+ );
+
+ ListenerRegistrar.register(
+ plugin,
+ new ServerRuleLoreMenuListener()
+ );
+
+ ListenerRegistrar.register(
+ plugin,
+ new ServerRuleMaterialPickerMenuListener()
+ );
+
}
}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenu.java b/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenu.java
index 18156be..b280846 100644
--- a/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenu.java
+++ b/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenu.java
@@ -121,7 +121,7 @@ public class ServerCommandLoreMenu {
22,
RSMenuUtils.createMenuItem(
Material.LIME_WOOL,
- "§aCreate Server Command"
+ "§aSave Lore and Proceed to Material Picker"
)
);
diff --git a/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenuListener.java
index 9aeb5e2..793837d 100644
--- a/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenuListener.java
+++ b/src/main/java/com/rsscripting/rswarehouse/servercommands/ServerCommandLoreMenuListener.java
@@ -122,7 +122,7 @@ public class ServerCommandLoreMenuListener
() -> {
if (
- session.getPendingServerCommandLoreExpiration()
+ session.getPendingServerCommandLoreExpiration()
!= expiration
) {
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenu.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenu.java
new file mode 100644
index 0000000..36429a8
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenu.java
@@ -0,0 +1,95 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.MenuType;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.view.AnvilView;
+
+import java.util.List;
+
+
+public class ServerRuleDisplayNameMenu {
+
+ public static final String TITLE =
+ "Rule Display Title";
+
+ public static void open(Player player) {
+
+ AnvilView view = MenuType.ANVIL
+ .builder()
+ .title(
+ Component.text(
+ TITLE
+ )
+ )
+ .build(player);
+
+
+ ItemStack confirm =
+ new ItemStack(
+ Material.LIME_WOOL
+ );
+
+ ItemMeta meta =
+ confirm.getItemMeta();
+
+ meta.displayName(
+ Component.text("")
+ );
+
+ meta.lore(
+ List.of(
+ Component.text(
+ "Save and proceed to description."
+ ).color(
+ NamedTextColor.WHITE
+ )
+ )
+ );
+
+ confirm.setItemMeta(meta);
+
+ view.setItem(
+ 0,
+ confirm
+ );
+
+
+ ItemStack cancel =
+ new ItemStack(
+ Material.RED_WOOL
+ );
+
+ ItemMeta metacancel =
+ cancel.getItemMeta();
+
+ metacancel.displayName(
+ Component.text("")
+ );
+
+ metacancel.lore(
+ List.of(
+ Component.text(
+ "Cancel"
+ ).color(
+ NamedTextColor.WHITE
+ )
+ )
+ );
+
+ cancel.setItemMeta(metacancel);
+
+ view.setItem(
+ 1,
+ cancel
+ );
+
+ view.open();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenuListener.java
new file mode 100644
index 0000000..d181500
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleDisplayNameMenuListener.java
@@ -0,0 +1,155 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.adminmenu.AdminMenu;
+import com.rsscripting.rswarehouse.utils.RSMessageUtils;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.inventory.view.AnvilView;
+
+
+public class ServerRuleDisplayNameMenuListener
+ implements Listener {
+
+
+ @EventHandler
+ public void onInventoryClick(
+ InventoryClickEvent event
+ ) {
+
+ if (!(event.getView()
+ instanceof AnvilView anvilView)) {
+
+ return;
+
+ }
+
+ if (!event.getView()
+ .title()
+ .toString()
+ .contains(
+ ServerRuleDisplayNameMenu.TITLE
+ )) {
+
+ return;
+
+ }
+
+ Player player =
+ (Player) event.getWhoClicked();
+
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+ if (session == null) {
+
+ return;
+
+ }
+
+ event.setCancelled(true);
+
+
+ if (event.getCurrentItem() == null) {
+
+ return;
+
+ }
+
+
+ if (event.getRawSlot() == 0) {
+
+ String categoryName =
+ anvilView.getRenameText();
+
+ if (categoryName.length() > 25) {
+
+ RSMessageUtils.error(
+ player,
+ "Rule titles may not exceed 25 characters."
+ );
+
+ return;
+
+ }
+
+ if (categoryName.isBlank()) {
+
+ RSMessageUtils.error(
+ player,
+ "Rule title cannot be empty."
+ );
+
+ return;
+
+ }
+
+ session.setPendingServerRuleDisplayName(
+ categoryName
+ );
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+ ServerRuleLoreMenu.open(
+ player
+ );
+
+ return;
+
+ }
+
+
+ if (event.getRawSlot() == 1) {
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+ AdminMenu.open(
+ player
+ );
+
+ }
+
+ }
+
+
+ @EventHandler
+ public void onInventoryClose(
+ InventoryCloseEvent event
+ ) {
+
+ if (!(event.getView()
+ instanceof AnvilView)) {
+
+ return;
+
+ }
+
+ if (!event.getView()
+ .title()
+ .toString()
+ .contains(
+ ServerRuleDisplayNameMenu.TITLE
+ )) {
+
+ return;
+
+ }
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenu.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenu.java
new file mode 100644
index 0000000..64e6eef
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenu.java
@@ -0,0 +1,95 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.MenuType;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.view.AnvilView;
+
+import java.util.List;
+
+
+public class ServerRuleInternalNameMenu {
+
+ public static final String TITLE =
+ "Rule Internal Name";
+
+ public static void open(Player player) {
+
+ AnvilView view = MenuType.ANVIL
+ .builder()
+ .title(
+ Component.text(
+ TITLE
+ )
+ )
+ .build(player);
+
+
+ ItemStack confirm =
+ new ItemStack(
+ Material.LIME_WOOL
+ );
+
+ ItemMeta meta =
+ confirm.getItemMeta();
+
+ meta.displayName(
+ Component.text("")
+ );
+
+ meta.lore(
+ List.of(
+ Component.text(
+ "Save and proceed to title."
+ ).color(
+ NamedTextColor.WHITE
+ )
+ )
+ );
+
+ confirm.setItemMeta(meta);
+
+ view.setItem(
+ 0,
+ confirm
+ );
+
+
+ ItemStack cancel =
+ new ItemStack(
+ Material.RED_WOOL
+ );
+
+ ItemMeta metacancel =
+ cancel.getItemMeta();
+
+ metacancel.displayName(
+ Component.text("")
+ );
+
+ metacancel.lore(
+ List.of(
+ Component.text(
+ "Cancel"
+ ).color(
+ NamedTextColor.WHITE
+ )
+ )
+ );
+
+ cancel.setItemMeta(metacancel);
+
+ view.setItem(
+ 1,
+ cancel
+ );
+
+ view.open();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenuListener.java
new file mode 100644
index 0000000..19b643c
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleInternalNameMenuListener.java
@@ -0,0 +1,156 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.adminmenu.AdminMenu;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import com.rsscripting.rswarehouse.utils.RSMessageUtils;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.inventory.view.AnvilView;
+
+
+public class ServerRuleInternalNameMenuListener
+ implements Listener {
+
+
+ @EventHandler
+ public void onInventoryClick(
+ InventoryClickEvent event
+ ) {
+
+ if (!(event.getView()
+ instanceof AnvilView anvilView)) {
+
+ return;
+
+ }
+
+ if (!event.getView()
+ .title()
+ .toString()
+ .contains(
+ ServerRuleInternalNameMenu.TITLE
+ )) {
+
+ return;
+
+ }
+
+ Player player =
+ (Player) event.getWhoClicked();
+
+ event.setCancelled(true);
+
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+ if (session == null) {
+
+ return;
+
+ }
+
+ if (event.getCurrentItem() == null) {
+
+ return;
+
+ }
+
+
+ if (event.getRawSlot() == 0) {
+
+ String categoryName =
+ anvilView.getRenameText();
+
+ if (categoryName.length() > 25) {
+
+ RSMessageUtils.error(
+ player,
+ "Rule names may not exceed 25 characters."
+ );
+
+ return;
+
+ }
+
+ if (categoryName.isBlank()) {
+
+ RSMessageUtils.error(
+ player,
+ "Rule name cannot be empty."
+ );
+
+ return;
+
+ }
+
+ session.setPendingServerRuleName(
+ categoryName
+ );
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+
+ ServerRuleDisplayNameMenu.open(
+ player
+ );
+
+
+ return;
+
+ }
+
+
+ if (event.getRawSlot() == 1) {
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+ AdminMenu.open(
+ player
+ );
+
+ }
+
+ }
+
+
+ @EventHandler
+ public void onInventoryClose(
+ InventoryCloseEvent event
+ ) {
+
+ if (!(event.getView()
+ instanceof AnvilView)) {
+
+ return;
+
+ }
+
+ if (!event.getView()
+ .title()
+ .toString()
+ .contains(
+ ServerRuleInternalNameMenu.TITLE
+ )) {
+
+ return;
+
+ }
+
+ event.getView()
+ .getTopInventory()
+ .clear();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreChatListener.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreChatListener.java
new file mode 100644
index 0000000..81eb0cc
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreChatListener.java
@@ -0,0 +1,100 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import com.rsscripting.rswarehouse.utils.RSMessageUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+
+public class ServerRuleLoreChatListener
+ implements Listener {
+
+ @EventHandler
+ public void onChat(
+ AsyncPlayerChatEvent event
+ ) {
+
+ Player player =
+ event.getPlayer();
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+ if (session == null) {
+
+ return;
+
+ }
+
+ int loreSlot =
+ session.getPendingServerRuleLoreSlot();
+
+ if (loreSlot < 0) {
+
+ return;
+
+ }
+
+ event.setCancelled(true);
+
+ String message =
+ event.getMessage();
+
+ if (
+ message.equalsIgnoreCase(
+ "cancel"
+ )
+ ) {
+
+ session.setPendingServerRuleLoreSlot(
+ -1
+ );
+
+ session.setPendingServerRuleLoreExpiration(
+ 0
+ );
+
+ ServerRuleLoreMenu.open(
+ player
+ );
+
+ return;
+
+ }
+
+ session.setPendingServerRuleLore(
+ loreSlot,
+ message
+ );
+
+ session.setPendingServerRuleLoreSlot(
+ -1
+ );
+
+ session.setPendingServerRuleLoreExpiration(
+ 0
+ );
+
+ RSMessageUtils.info(
+ player,
+ "Lore saved."
+ );
+
+ Bukkit.getScheduler().runTask(
+ Bukkit.getPluginManager()
+ .getPlugin(
+ "RS-Warehouse"
+ ),
+ () -> ServerRuleLoreMenu.open(
+ player
+ )
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenu.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenu.java
new file mode 100644
index 0000000..2506a29
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenu.java
@@ -0,0 +1,156 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.menuholder.RSMenuHolder;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import com.rsscripting.rswarehouse.utils.RSMenuUtils;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ServerRuleLoreMenu {
+
+ public static void open(
+ Player player
+ ) {
+
+ Inventory menu =
+ Bukkit.createInventory(
+ new RSMenuHolder(
+ "SERVER_RULE_LORE"
+ ),
+ 27,
+ Component.text(
+ "Server Rule Lore"
+ )
+ );
+
+
+ for (int i = 0; i < menu.getSize(); i++) {
+
+ menu.setItem(
+ i,
+ RSMenuUtils.createFillerPane()
+ );
+
+ }
+
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+
+ for (int i = 0; i < 5; i++) {
+
+ ItemStack book =
+ new ItemStack(
+ Material.WRITABLE_BOOK
+ );
+
+ ItemMeta meta =
+ book.getItemMeta();
+
+ meta.displayName(
+ Component.text(
+ "Lore Line "
+ + (i + 1)
+ )
+ );
+
+
+ List lore =
+ new ArrayList<>();
+
+ String value =
+ session.getPendingServerRuleLore(
+ i
+ );
+
+
+ if (
+ value == null
+ || value.isBlank()
+ ) {
+
+ lore.add(
+ Component.text(
+ "(Empty)"
+ )
+ );
+
+ }
+
+ else {
+
+ lore.add(
+ Component.text(
+ value
+ )
+ );
+
+ }
+
+
+ lore.add(
+ Component.empty()
+ );
+
+ lore.add(
+ Component.text(
+ "Click to edit."
+ )
+ );
+
+
+ meta.lore(
+ lore
+ );
+
+ book.setItemMeta(
+ meta
+ );
+
+
+ menu.setItem(
+ 11 + i,
+ book
+ );
+
+ }
+
+
+ menu.setItem(
+ 22,
+ RSMenuUtils.createMenuItem(
+ Material.LIME_WOOL,
+ "§aSave Lore and Proceed to Material Picker"
+ )
+ );
+
+
+ menu.setItem(
+ 4,
+ RSMenuUtils.createMenuItem(
+ Material.OAK_DOOR,
+ "§eBack"
+ )
+ );
+
+
+ player.openInventory(
+ menu
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenuListener.java
new file mode 100644
index 0000000..94ba0fb
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleLoreMenuListener.java
@@ -0,0 +1,182 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.menuholder.RSMenuHolder;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import com.rsscripting.rswarehouse.utils.RSMessageUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+
+
+public class ServerRuleLoreMenuListener
+ implements Listener {
+
+
+ @EventHandler
+ public void onInventoryClick(
+ InventoryClickEvent event
+ ) {
+
+ if (!(event.getInventory()
+ .getHolder()
+ instanceof RSMenuHolder holder)) {
+
+ return;
+
+ }
+
+ if (!holder.getMenuId().equals(
+ "SERVER_RULE_LORE"
+ )) {
+
+ return;
+
+ }
+
+ event.setCancelled(
+ true
+ );
+
+ Player player =
+ (Player) event.getWhoClicked();
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+ if (session == null) {
+
+ return;
+
+ }
+
+ switch (event.getSlot()) {
+
+ case 4 -> ServerRuleDisplayNameMenu.open(
+ player
+ );
+
+ case 11 -> editLore(
+ player,
+ session,
+ 0
+ );
+
+ case 12 -> editLore(
+ player,
+ session,
+ 1
+ );
+
+ case 13 -> editLore(
+ player,
+ session,
+ 2
+ );
+
+ case 14 -> editLore(
+ player,
+ session,
+ 3
+ );
+
+ case 15 -> editLore(
+ player,
+ session,
+ 4
+ );
+
+ case 22 -> {
+
+ ServerRuleMaterialPickerMenu.open(
+ player,
+ 0
+ );
+
+ }
+
+ }
+
+ }
+
+
+ private void editLore(
+ Player player,
+ ServerRuleCreationSession session,
+ int loreSlot
+ ) {
+
+ session.setPendingServerRuleLoreSlot(
+ loreSlot
+ );
+
+ session.setPendingServerRuleLoreExpiration(
+ System.currentTimeMillis()
+ + 30000
+ );
+
+ final long expiration =
+ session.getPendingServerRuleLoreExpiration();
+
+ Bukkit.getScheduler()
+ .runTaskLater(
+ Bukkit.getPluginManager()
+ .getPlugin(
+ "RS-Warehouse"
+ ),
+ () -> {
+
+ if (
+ session.getPendingServerRuleLoreExpiration()
+ != expiration
+ ) {
+
+ return;
+
+ }
+
+ session.setPendingServerRuleLoreSlot(
+ -1
+ );
+
+ session.setPendingServerRuleLoreExpiration(
+ 0
+ );
+
+ RSMessageUtils.error(
+ player,
+ "Lore input timed out."
+ );
+
+ },
+ 20L * 30
+ );
+
+
+ player.closeInventory();
+
+
+ RSMessageUtils.info(
+ player,
+ "Enter lore for line "
+ + (loreSlot + 1)
+ + " in chat."
+ );
+
+ RSMessageUtils.info(
+ player,
+ "Type 'cancel' to abort."
+ );
+
+ RSMessageUtils.info(
+ player,
+ "Auto-Cancels after 30 seconds."
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenu.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenu.java
new file mode 100644
index 0000000..1c5bbb5
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenu.java
@@ -0,0 +1,125 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.menuholder.RSMenuHolder;
+import com.rsscripting.rswarehouse.utils.RSMenuUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+public class ServerRuleMaterialPickerMenu {
+
+ public static void open(
+ Player player,
+ int page
+ ) {
+
+ Inventory menu =
+ Bukkit.createInventory(
+ new RSMenuHolder(
+ "SERVER_RULE_MATERIAL_PICKER"
+ ),
+ 54,
+ "Select Rule Material"
+ );
+
+
+ int slot = 0;
+
+
+ List materials =
+ Arrays.stream(
+ Material.values()
+ )
+ .filter(
+ Material::isItem
+ )
+ .filter(
+ material ->
+ !material.name().endsWith(
+ "_SMITHING_TEMPLATE"
+ )
+ )
+ .toList();
+
+
+ int startIndex =
+ page * 45;
+
+
+ int maxPages =
+ (int) Math.ceil(
+ (double) materials.size()
+ / 45
+ );
+
+
+ for (
+ int inventorySlot = 0;
+ inventorySlot < 45;
+ inventorySlot++
+ ) {
+
+ int materialIndex =
+ startIndex + inventorySlot;
+
+
+ if (
+ materialIndex >= materials.size()
+ ) {
+
+ break;
+
+ }
+
+
+ menu.setItem(
+ inventorySlot,
+ new ItemStack(
+ materials.get(
+ materialIndex
+ )
+ )
+ );
+
+ }
+
+
+ if (page > 0) {
+
+ menu.setItem(
+ 45,
+ RSMenuUtils.createMenuItem(
+ Material.ARROW,
+ "§cPrevious Page"
+ )
+ );
+
+ }
+
+
+ if (page < maxPages - 1) {
+
+ menu.setItem(
+ 53,
+ RSMenuUtils.createMenuItem(
+ Material.ARROW,
+ "§aNext Page"
+ )
+ );
+
+ }
+
+
+ player.openInventory(
+ menu
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenuListener.java b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenuListener.java
new file mode 100644
index 0000000..12c8857
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/serverrule/ServerRuleMaterialPickerMenuListener.java
@@ -0,0 +1,193 @@
+package com.rsscripting.rswarehouse.serverrule;
+
+import com.rsscripting.rswarehouse.dao.admin.CreateServerRuleDAO;
+import com.rsscripting.rswarehouse.item.ItemsMenu;
+import com.rsscripting.rswarehouse.menuholder.RSMenuHolder;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSession;
+import com.rsscripting.rswarehouse.session.admin.ServerRuleCreationSessionManager;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+
+
+public class ServerRuleMaterialPickerMenuListener
+ implements Listener {
+
+
+ @EventHandler
+ public void onInventoryClick(
+ InventoryClickEvent event
+ ) {
+
+ if (!(event.getInventory()
+ .getHolder()
+ instanceof RSMenuHolder holder)) {
+
+ return;
+
+ }
+
+
+ if (!holder.getMenuId().equals(
+ "SERVER_RULE_MATERIAL_PICKER"
+ )) {
+
+ return;
+
+ }
+
+
+ event.setCancelled(
+ true
+ );
+
+
+ if (event.getCurrentItem() == null) {
+
+ return;
+
+ }
+
+
+ Player player =
+ (Player) event.getWhoClicked();
+
+
+ ServerRuleCreationSession session =
+ ServerRuleCreationSessionManager.getSession(
+ player.getUniqueId()
+ );
+
+
+ if (session == null) {
+
+ player.closeInventory();
+
+ return;
+
+ }
+
+
+ /*
+ * Previous page
+ */
+
+ if (event.getSlot() == 45) {
+
+ ServerRuleMaterialPickerMenu.open(
+ player,
+ 0
+ );
+
+ return;
+
+ }
+
+
+ /*
+ * Next page
+ */
+
+ if (event.getSlot() == 53) {
+
+ ServerRuleMaterialPickerMenu.open(
+ player,
+ 1
+ );
+
+ return;
+
+ }
+
+
+ /*
+ * Save selected material.
+ */
+
+ session.setPendingServerRuleMaterial(
+ event.getCurrentItem()
+ .getType()
+ .name()
+ );
+
+
+ int ruleCategoryId =
+ CreateServerRuleDAO.createServerRule(
+ session.getPendingServerRuleName(),
+ session.getPendingServerRuleDisplayName(),
+ session.getPendingServerRuleMaterial(),
+ buildLore(session)
+ );
+
+
+ if (ruleCategoryId == -1) {
+
+ player.sendMessage(
+ "§cFailed to create Server Rule."
+ );
+
+ return;
+
+ }
+
+
+ player.sendMessage(
+ "§aServer Rule created successfully."
+ );
+
+
+ ItemsMenu.open(
+ player,
+ 1000,
+ "Server Rules",
+ 0
+ );
+
+ }
+
+
+ private String buildLore(
+ ServerRuleCreationSession session
+ ) {
+
+ StringBuilder loreBuilder =
+ new StringBuilder();
+
+
+ for (int i = 0; i < 5; i++) {
+
+ String line =
+ session.getPendingServerRuleLore(
+ i
+ );
+
+
+ if (line == null) {
+
+ line = "";
+
+ }
+
+
+ loreBuilder.append(
+ line
+ );
+
+
+ if (i < 4) {
+
+ loreBuilder.append(
+ "\n"
+ );
+
+ }
+
+ }
+
+
+ return loreBuilder.toString();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSession.java b/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSession.java
new file mode 100644
index 0000000..f35e2d5
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSession.java
@@ -0,0 +1,132 @@
+package com.rsscripting.rswarehouse.session.admin;
+
+public class ServerRuleCreationSession {
+
+ private String pendingServerRuleName;
+
+ private String pendingServerRuleDisplayName;
+
+ private final String[] pendingServerRuleLore =
+ new String[5];
+
+ private int pendingServerRuleLoreSlot = -1;
+
+ private long pendingServerRuleLoreExpiration;
+
+ private String pendingServerRuleMaterial;
+
+
+ public String getPendingServerRuleName() {
+
+ return pendingServerRuleName;
+
+ }
+
+ public void setPendingServerRuleName(
+ String pendingServerRuleName
+ ) {
+
+ this.pendingServerRuleName =
+ pendingServerRuleName;
+
+ }
+
+
+ public String getPendingServerRuleDisplayName() {
+
+ return pendingServerRuleDisplayName;
+
+ }
+
+ public void setPendingServerRuleDisplayName(
+ String pendingServerRuleDisplayName
+ ) {
+
+ this.pendingServerRuleDisplayName =
+ pendingServerRuleDisplayName;
+
+ }
+
+
+ public String getPendingServerRuleLore(
+ int index
+ ) {
+
+ return pendingServerRuleLore[index];
+
+ }
+
+ public void setPendingServerRuleLore(
+ int index,
+ String value
+ ) {
+
+ pendingServerRuleLore[index] =
+ value;
+
+ }
+
+ public void clearPendingServerRuleLore() {
+
+ for (
+ int i = 0;
+ i < pendingServerRuleLore.length;
+ i++
+ ) {
+
+ pendingServerRuleLore[i] =
+ null;
+
+ }
+
+ }
+
+
+ public int getPendingServerRuleLoreSlot() {
+
+ return pendingServerRuleLoreSlot;
+
+ }
+
+ public void setPendingServerRuleLoreSlot(
+ int pendingServerRuleLoreSlot
+ ) {
+
+ this.pendingServerRuleLoreSlot =
+ pendingServerRuleLoreSlot;
+
+ }
+
+
+ public long getPendingServerRuleLoreExpiration() {
+
+ return pendingServerRuleLoreExpiration;
+
+ }
+
+ public void setPendingServerRuleLoreExpiration(
+ long pendingServerRuleLoreExpiration
+ ) {
+
+ this.pendingServerRuleLoreExpiration =
+ pendingServerRuleLoreExpiration;
+
+ }
+
+
+ public String getPendingServerRuleMaterial() {
+
+ return pendingServerRuleMaterial;
+
+ }
+
+ public void setPendingServerRuleMaterial(
+ String pendingServerRuleMaterial
+ ) {
+
+ this.pendingServerRuleMaterial =
+ pendingServerRuleMaterial;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSessionManager.java b/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSessionManager.java
new file mode 100644
index 0000000..c60d163
--- /dev/null
+++ b/src/main/java/com/rsscripting/rswarehouse/session/admin/ServerRuleCreationSessionManager.java
@@ -0,0 +1,46 @@
+package com.rsscripting.rswarehouse.session.admin;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class ServerRuleCreationSessionManager {
+
+ private static final Map sessions =
+ new HashMap<>();
+
+
+ public static void createSession(
+ UUID uuid
+ ) {
+
+ sessions.put(
+ uuid,
+ new ServerRuleCreationSession()
+ );
+
+ }
+
+
+ public static ServerRuleCreationSession getSession(
+ UUID uuid
+ ) {
+
+ return sessions.get(
+ uuid
+ );
+
+ }
+
+
+ public static void removeSession(
+ UUID uuid
+ ) {
+
+ sessions.remove(
+ uuid
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 9bb0df7..242b1d0 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -13,6 +13,11 @@ display:
# execute any commands.
show-server-commands: true
+ # Display the Server Rules category.
+ # This category is a list of rules for
+ # your server.
+ show-server-rules: true
+
############################################
# Automatic-Chest scan and process settings.
############################################