Added README.md and updated the global rule guis.
This commit is contained in:
571
Documentation.md
571
Documentation.md
@@ -1,128 +1,3 @@
|
|||||||
|
|
||||||
# DupeAlias - An Advanced Dupe Plugin
|
|
||||||
**Make your server stand out by switching to DupeAlias, a powerful dupe plugin with niche features for unique servers.**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌟 Why Choose DupeAlias?
|
|
||||||
|
|
||||||
DupeAlias isn't just another dupe plugin - it's a complete ecosystem for managing item behavior on your server. Whether you're running a creative build server, a unique survival experience, or a custom game mode. DupeAlias gives you unprecedented control over how items behave.
|
|
||||||
|
|
||||||
### ✨ Key Features
|
|
||||||
|
|
||||||
**🎯 Smart Item Tagging System**
|
|
||||||
- **UNIQUE** - Prevent specific items from being duplicated
|
|
||||||
- **FINAL** - Lock items against any modifications
|
|
||||||
- **INFINITE** - Create truly infinite resources that never run out
|
|
||||||
- **PROTECTED** - Make items completely inert and unusable
|
|
||||||
|
|
||||||
**🔧 Advanced Global Rules Engine**
|
|
||||||
- Create complex rules based on item properties
|
|
||||||
- Match by material, enchantments, name patterns, lore, and more
|
|
||||||
- Support for armor trims, potion effects, attributes, and custom model data
|
|
||||||
- Flexible matching modes (AND, OR, NAND, XOR)
|
|
||||||
|
|
||||||
**🖥️ Multiple Duplication Interfaces**
|
|
||||||
- **Replicator GUI** - Single-item duplication with visual feedback
|
|
||||||
- **Chest GUI** - Multi-item container-style duplication
|
|
||||||
- **Inventory GUI** - Mirror your entire inventory for easy access
|
|
||||||
- **Menu GUI** - Central hub for all duplication options
|
|
||||||
|
|
||||||
**⚡ Performance & Customization**
|
|
||||||
- Per-permission refresh rates and cooldowns
|
|
||||||
- Extensive configuration options
|
|
||||||
- Session persistence (optional)
|
|
||||||
- Beautiful, modern GUIs with progress indicators
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎮 Perfect For These Server Types
|
|
||||||
|
|
||||||
- **Creative Servers** - Give builders infinite blocks while protecting special items
|
|
||||||
- **Survival+** - Create unique economies with controlled item flow
|
|
||||||
- **Minigames** - Provide infinite consumables while preventing exploitation
|
|
||||||
- **RPG Servers** - Protect quest items and create unbreakable gear
|
|
||||||
- **Prison Servers** - Control contraband while allowing resource flow
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📸 Screenshots
|
|
||||||
|
|
||||||
*[Image: Main admin panel showing the clean, modern interface with gradient backgrounds and intuitive navigation]*
|
|
||||||
|
|
||||||
*[Image: Global rules editor displaying the complex criteria system with material selection, enchantment matching, and tag application]*
|
|
||||||
|
|
||||||
*[Image: Replicator GUI in action showing the animated rings, progress bars, and real-time item duplication]*
|
|
||||||
|
|
||||||
*[Image: Held item management interface demonstrating individual tag application with conflict warnings]*
|
|
||||||
|
|
||||||
*[Image: Configuration menu showcasing the extensive customization options and color-coded settings]*
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚙️ Quick Setup
|
|
||||||
|
|
||||||
1. Drop `DupeAlias.jar` into your plugins folder
|
|
||||||
2. Restart your server
|
|
||||||
3. Use `/da` to open the admin panel
|
|
||||||
4. Configure your global rules and permissions
|
|
||||||
5. Let your players use `/dupe` to start duplicating!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔑 Permissions Overview
|
|
||||||
|
|
||||||
- `dupealias.admin` - Access to admin panel and configuration
|
|
||||||
- `dupealias.dupe` - Basic duplication command access
|
|
||||||
- `dupealias.gui.*` - Access to specific GUI types
|
|
||||||
- `dupealias.*.bypass` - Bypass tag restrictions (use carefully!)
|
|
||||||
- Permission-based refresh rates: `dupealias.gui.replicator.refresh.1`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Advanced Use Cases
|
|
||||||
|
|
||||||
**Crate Key Protection**
|
|
||||||
Create a global rule that makes all items containing "key" in their name both UNIQUE and PROTECTED, preventing duplication and accidental use.
|
|
||||||
|
|
||||||
**Infinite Building Materials**
|
|
||||||
Set up INFINITE tags on common building blocks, giving your builders unlimited resources while maintaining server economy balance.
|
|
||||||
|
|
||||||
**Quest Item Security**
|
|
||||||
Use FINAL tags on story items to prevent players from renaming or modifying important quest objects.
|
|
||||||
|
|
||||||
**Admin Tool Management**
|
|
||||||
Combine PROTECTED and UNIQUE tags to create admin-only items that can't be duplicated or used by regular players.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠️ Developer-Friendly
|
|
||||||
|
|
||||||
Built on the robust Alias Development Framework with:
|
|
||||||
- Clean, documented API
|
|
||||||
- Event-driven architecture
|
|
||||||
- Extensive configuration options
|
|
||||||
- JSON-based data storage
|
|
||||||
- Full backward compatibility
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Requirements
|
|
||||||
|
|
||||||
- **Minecraft Version**: 1.21+
|
|
||||||
- **Server Software**: Paper, Purpur, or compatible
|
|
||||||
- **Java Version**: 17+
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🤝 Support & Updates
|
|
||||||
|
|
||||||
DupeAlias is actively maintained with regular updates and feature additions. Join our community for support, suggestions, and to see what's coming next!
|
|
||||||
|
|
||||||
**Get DupeAlias today and revolutionize how items work on your server!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# DupeAlias Documentation
|
# DupeAlias Documentation
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
@@ -135,17 +10,15 @@ DupeAlias is actively maintained with regular updates and feature additions. Joi
|
|||||||
6. [Permissions System](#permissions-system)
|
6. [Permissions System](#permissions-system)
|
||||||
7. [Configuration](#configuration)
|
7. [Configuration](#configuration)
|
||||||
8. [Commands](#commands)
|
8. [Commands](#commands)
|
||||||
9. [Common Scenarios](#common-scenarios)
|
9. [Troubleshooting](#troubleshooting)
|
||||||
10. [Troubleshooting](#troubleshooting)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
---
|
||||||
## Installation & Setup
|
## Installation & Setup
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
- Minecraft 1.21 or higher
|
- Minecraft 1.21.5
|
||||||
- Paper, Purpur, or compatible server software
|
- Paper server software
|
||||||
- Java 17 or higher
|
- Java 21 or higher
|
||||||
|
|
||||||
### Installation Steps
|
### Installation Steps
|
||||||
1. Download the DupeAlias JAR file
|
1. Download the DupeAlias JAR file
|
||||||
@@ -159,8 +32,7 @@ DupeAlias is actively maintained with regular updates and feature additions. Joi
|
|||||||
3. Navigate to Configuration → Common Config to customize colors and branding
|
3. Navigate to Configuration → Common Config to customize colors and branding
|
||||||
4. Set up your first global rules or start tagging items manually
|
4. Set up your first global rules or start tagging items manually
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Core Concepts
|
## Core Concepts
|
||||||
|
|
||||||
### Item Tags
|
### Item Tags
|
||||||
@@ -178,8 +50,7 @@ Individual item tags **always override** global rules. This allows for fine-grai
|
|||||||
- **Individual Tags**: Stored directly on the item's metadata, apply only to that specific item instance
|
- **Individual Tags**: Stored directly on the item's metadata, apply only to that specific item instance
|
||||||
- **Global Rules**: Server-wide rules that apply tags based on item properties like material, name, enchantments, etc.
|
- **Global Rules**: Server-wide rules that apply tags based on item properties like material, name, enchantments, etc.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Item Tags System
|
## Item Tags System
|
||||||
|
|
||||||
### UNIQUE Tag
|
### UNIQUE Tag
|
||||||
@@ -191,13 +62,9 @@ Individual item tags **always override** global rules. This allows for fine-grai
|
|||||||
- Admin-only equipment
|
- Admin-only equipment
|
||||||
- Currency items
|
- Currency items
|
||||||
|
|
||||||
**Conflicts**: Cannot be combined with INFINITE (creates a logical paradox)
|
**Conflicts**: Cannot be combined with INFINITE.
|
||||||
|
|
||||||
**Example**: A crate key that should never be duplicated
|
**Example**: A crate key that should never be duplicated
|
||||||
```
|
|
||||||
Individual: Right-click key in hand → Apply UNIQUE tag
|
|
||||||
Global: All items with "key" in name → Apply UNIQUE tag
|
|
||||||
```
|
|
||||||
|
|
||||||
### FINAL Tag
|
### FINAL Tag
|
||||||
**Purpose**: Prevents any modification to the item
|
**Purpose**: Prevents any modification to the item
|
||||||
@@ -214,12 +81,6 @@ Global: All items with "key" in name → Apply UNIQUE tag
|
|||||||
- Rank kits that shouldn't be modified
|
- Rank kits that shouldn't be modified
|
||||||
- Event rewards with special formatting
|
- Event rewards with special formatting
|
||||||
|
|
||||||
**Example**: A quest sword that must keep its name
|
|
||||||
```
|
|
||||||
Individual: Apply FINAL tag to specific sword
|
|
||||||
Global: All items with "Quest" in lore → Apply FINAL tag
|
|
||||||
```
|
|
||||||
|
|
||||||
### INFINITE Tag
|
### INFINITE Tag
|
||||||
**Purpose**: Maintains maximum stack size and refills items
|
**Purpose**: Maintains maximum stack size and refills items
|
||||||
|
|
||||||
@@ -230,17 +91,11 @@ Global: All items with "Quest" in lore → Apply FINAL tag
|
|||||||
|
|
||||||
**Use Cases**:
|
**Use Cases**:
|
||||||
- Creative-style building materials
|
- Creative-style building materials
|
||||||
- Infinite arrows for archery ranges
|
- "Infinity" enchantment for tipped arrows
|
||||||
- Unlimited consumables for events
|
- Unlimited consumables for events
|
||||||
|
|
||||||
**Conflicts**: Cannot be combined with UNIQUE or PROTECTED
|
**Conflicts**: Cannot be combined with UNIQUE or PROTECTED
|
||||||
|
|
||||||
**Example**: Infinite building blocks for creative areas
|
|
||||||
```
|
|
||||||
Individual: Apply INFINITE to held stone blocks
|
|
||||||
Global: All concrete blocks → Apply INFINITE tag
|
|
||||||
```
|
|
||||||
|
|
||||||
### PROTECTED Tag
|
### PROTECTED Tag
|
||||||
**Purpose**: Makes items completely inert and unusable
|
**Purpose**: Makes items completely inert and unusable
|
||||||
|
|
||||||
@@ -260,14 +115,7 @@ Global: All concrete blocks → Apply INFINITE tag
|
|||||||
|
|
||||||
**Conflicts**: Cannot be combined with INFINITE
|
**Conflicts**: Cannot be combined with INFINITE
|
||||||
|
|
||||||
**Example**: A decorative trophy that can't be used
|
---
|
||||||
```
|
|
||||||
Individual: Apply PROTECTED to specific trophy
|
|
||||||
Global: All items with "Display" in name → Apply PROTECTED tag
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Global Rules Engine
|
## Global Rules Engine
|
||||||
|
|
||||||
### Creating Global Rules
|
### Creating Global Rules
|
||||||
@@ -289,92 +137,64 @@ Select which tags this rule will apply to matching items. Multiple tags can be s
|
|||||||
- **NAND**: Not all criteria match
|
- **NAND**: Not all criteria match
|
||||||
- **XOR**: Exactly one criteria matches
|
- **XOR**: Exactly one criteria matches
|
||||||
|
|
||||||
|
Note that if no criteria are selected, any material or ItemsAdder item will match.
|
||||||
|
|
||||||
#### Material Matching
|
#### Material Matching
|
||||||
- **IGNORE**: Apply to all materials
|
- **IGNORE**: Apply to all materials and ItemsAdder items
|
||||||
- **WHITELIST**: Only apply to selected materials
|
- **WHITELIST**: Only apply to selected materials and ItemsAdder items
|
||||||
- **BLACKLIST**: Apply to all except selected materials
|
- **BLACKLIST**: Apply to all except selected materials and ItemsAdder items
|
||||||
|
|
||||||
### Criteria Types
|
### Criteria Types
|
||||||
|
|
||||||
#### Name Regex
|
#### Name Regex
|
||||||
Match items based on display name patterns using regular expressions.
|
Match items based on display name patterns using regular expressions.
|
||||||
```
|
``` Example: ".*[Kk]ey.*" matches any item with "key" or "Key" in the name ```
|
||||||
Example: ".*[Kk]ey.*" matches any item with "key" or "Key" in the name
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Lore Regex
|
#### Lore Regex
|
||||||
Match items based on lore content using regular expressions.
|
Match items based on lore content using regular expressions.
|
||||||
```
|
``` Example: ".*Special.*" matches items with "Special" anywhere in lore ```
|
||||||
Example: ".*Special.*" matches items with "Special" anywhere in lore
|
#### Compound Tag Regex
|
||||||
```
|
Match an item based on its compound tag generated from `ItemStack#getAsComponentString()`
|
||||||
|
```Example: ".*(nutrition).*|.*(saturation).*" Matches any custom food item```
|
||||||
|
#### NBT Tag Regex
|
||||||
|
Match an item based on its NBT tag generated from `ItemStack#getAsString()`
|
||||||
|
```Example: .*{dupenotallowed: 1b}.* matches items from DupePlus's blacklist```
|
||||||
#### Enchantments
|
#### Enchantments
|
||||||
Match items that have specific enchantments at minimum levels.
|
Match items that have specific enchantments at minimum levels.
|
||||||
```
|
``` Example: Sharpness V → matches items with Sharpness 5 or higher ```
|
||||||
Example: Sharpness V → matches items with Sharpness 5 or higher
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Attributes
|
#### Attributes
|
||||||
Match items with specific attribute modifiers.
|
Match items with specific attribute modifiers.
|
||||||
```
|
``` Example: Attack Damage ≥ 10.0 → matches weapons with high damage ```
|
||||||
Example: Attack Damage ≥ 10.0 → matches weapons with high damage
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Potion Effects
|
#### Potion Effects
|
||||||
Match potions/foods with specific effects and amplifiers.
|
Match potions/foods with specific effects and amplifiers.
|
||||||
```
|
``` Example: Strength II → matches items giving Strength 2 or higher ```
|
||||||
Example: Strength II → matches items giving Strength 2 or higher
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Model Data
|
#### Model Data
|
||||||
Match items with specific custom model data values.
|
Match items with specific custom model data values.
|
||||||
```
|
``` Example: 12345 → matches items with CustomModelData: 12345 ```
|
||||||
Example: 12345 → matches items with CustomModelData: 12345
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Item Flags
|
#### Item Flags
|
||||||
Match items with specific visibility flags.
|
Match items with specific visibility flags.
|
||||||
```
|
``` Example: HIDE_ENCHANTS → matches items that hide enchantments ```
|
||||||
Example: HIDE_ENCHANTS → matches items that hide enchantments
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Armor Trim
|
#### Armor Trim
|
||||||
Match armor pieces with specific trim patterns or materials.
|
Match armor pieces with specific trim patterns or materials.
|
||||||
```
|
``` Example: Silence Pattern + Gold Material → matches gold silence trim armor ```
|
||||||
Example: Silence Pattern + Gold Material → matches gold silence trim armor
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example Rules
|
### Example Rules
|
||||||
|
|
||||||
#### Protect All Crate Keys
|
#### Protect All Crate Keys
|
||||||
```
|
``` Applied Tags: UNIQUE, PROTECTED, FINAL Match Mode: OR NBT Tag Regex: ".*excellentcrates.*" Lore Regex: ".*[Cc]rate.*" ```
|
||||||
Applied Tags: UNIQUE, PROTECTED, FINAL
|
|
||||||
Match Mode: OR
|
|
||||||
Name Regex: ".*[Kk]ey.*"
|
|
||||||
Lore Regex: ".*[Cc]rate.*"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Make Netherite Gear Unmodifiable
|
#### Make Netherite Gear Unmodifiable
|
||||||
```
|
``` Applied Tags: FINAL Match Mode: AND Material Mode: WHITELIST Materials: NETHERITE_SWORD, NETHERITE_AXE, NETHERITE_PICKAXE, etc. ```
|
||||||
Applied Tags: FINAL
|
|
||||||
Match Mode: AND
|
|
||||||
Material Mode: WHITELIST
|
|
||||||
Materials: NETHERITE_SWORD, NETHERITE_AXE, NETHERITE_PICKAXE, etc.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Infinite Creative Blocks
|
#### Infinite Creative Blocks
|
||||||
```
|
``` Applied Tags: INFINITE Match Mode: AND Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants ```
|
||||||
Applied Tags: INFINITE
|
---
|
||||||
Match Mode: AND
|
|
||||||
Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Duplication GUIs
|
## Duplication GUIs
|
||||||
|
|
||||||
### Replicator GUI
|
### Replicator GUI
|
||||||
**Access**: `/dupe replicator` or through main menu
|
**Access**: `/dupe replicator` or through main menu
|
||||||
|
**Permissions**:
|
||||||
|
- `dupealias.gui.replicator`: Main Access
|
||||||
|
- `dupealias.gui.replicator.cooldown.<integer>`: Sets the input swap cooldown time (milliseconds).
|
||||||
|
- `dupealias.gui.replicator.refresh.<integer>`: Sets the amount of ticks it takes for the output item to restock.
|
||||||
|
- `dupealias.gui.replicator.keep`: Determines if the player should keep the items in the chest when they close it.
|
||||||
|
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Single-item focused duplication
|
- Single-item focused duplication
|
||||||
@@ -391,13 +211,18 @@ Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants
|
|||||||
**Best For**: Quick duplication of single item types
|
**Best For**: Quick duplication of single item types
|
||||||
|
|
||||||
### Chest GUI
|
### Chest GUI
|
||||||
**Access**: `/dupe chest` or through main menu
|
**Access**: `/dupe chest` or through main menu
|
||||||
|
**Permissions**:
|
||||||
|
- `dupealias.gui.chest`: Main Access
|
||||||
|
- `dupealias.gui.chest.cooldown.<integer>`: Sets the input swap cooldown time (milliseconds).
|
||||||
|
- `dupealias.gui.chest.keep`: Determines if the player should keep the items in the chest when they close it.
|
||||||
|
- `dupealias.gui.chest.keepondeath`: If set to false, all items in the chest will be dropped on the ground on death.
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Multi-item container interface
|
- Multi-item container interface
|
||||||
- 4 input columns, 4 output columns
|
- 4 input columns, 4 output columns
|
||||||
- Individual item refresh timers
|
- Individual item refresh timers
|
||||||
- Session persistence (if enabled)
|
- Session persistence (doesn't persist over reboots)
|
||||||
|
|
||||||
**How to Use**:
|
**How to Use**:
|
||||||
1. Open the GUI
|
1. Open the GUI
|
||||||
@@ -405,10 +230,13 @@ Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants
|
|||||||
3. Take duplicated copies from the right 4 columns
|
3. Take duplicated copies from the right 4 columns
|
||||||
4. Items refresh based on configured delays
|
4. Items refresh based on configured delays
|
||||||
|
|
||||||
**Best For**: Bulk duplication of multiple item types
|
**Best For**: Duplication of items you'll commonly need through session persistence.
|
||||||
|
|
||||||
### Inventory GUI
|
### Inventory GUI
|
||||||
**Access**: `/dupe inventory` or through main menu
|
**Access**: `/dupe inventory` or through main menu
|
||||||
|
**Permissions**:
|
||||||
|
- `dupealias.gui.chest`: Main Access
|
||||||
|
- `dupealias.gui.chest.refresh.<integer>`: Sets the amount of ticks for the output items to restock
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Mirror of your actual inventory
|
- Mirror of your actual inventory
|
||||||
@@ -425,7 +253,8 @@ Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants
|
|||||||
**Best For**: Easy access to copies of everything you're carrying
|
**Best For**: Easy access to copies of everything you're carrying
|
||||||
|
|
||||||
### Menu GUI
|
### Menu GUI
|
||||||
**Access**: `/dupe gui` or `/dupe` (if set as default)
|
**Access**: `/dupe gui` or `/dupe` (if set as default)
|
||||||
|
**Permission**: `dupealias.gui` If granted, all other GUIs will be granted too unless specifically set to false.
|
||||||
|
|
||||||
**Features**:
|
**Features**:
|
||||||
- Central hub for all GUI types
|
- Central hub for all GUI types
|
||||||
@@ -437,167 +266,170 @@ Material Mode: WHITELIST Materials: STONE, DIRT, WOOD, CONCRETE variants
|
|||||||
2. Click on the GUI type you want to use
|
2. Click on the GUI type you want to use
|
||||||
3. Access is controlled by permissions
|
3. Access is controlled by permissions
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Permissions System
|
## Permissions System
|
||||||
|
|
||||||
### Core Permissions
|
### Core Permissions
|
||||||
|
|
||||||
#### Admin Access
|
#### Admin Access
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.admin: true # Access to admin panel and configuration
|
dupealias.admin: true # Access to admin panel and configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Basic Duplication
|
#### Basic Duplication
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.dupe: true # Access to /dupe command
|
dupealias.dupe: true # Access to /dupe command
|
||||||
dupealias.dupe.cooldown.<integer>: false # Cooldown for command duping (milliseconds)
|
dupealias.dupe.cooldown.<integer>: false # Cooldown for command duping (milliseconds)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### GUI Access
|
#### GUI Access
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.gui: true # Access to all GUIs
|
dupealias.gui: true # Access to all GUIs
|
||||||
dupealias.gui.replicator: true # Access to replicator GUI
|
dupealias.gui.replicator: true # Access to replicator GUI
|
||||||
dupealias.gui.inventory: true # Access to inventory GUI dupealias.gui.chest: true # Access to chest GUI
|
dupealias.gui.inventory: true # Access to inventory GUI
|
||||||
```
|
dupealias.gui.chest: true # Access to chest GUI
|
||||||
|
```
|
||||||
### Advanced Permissions
|
### Advanced Permissions
|
||||||
|
|
||||||
#### Session Persistence
|
#### Session Persistence
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.gui.replicator.keep: false # Keep replicator items on close
|
dupealias.gui.replicator.keep: false # Keep replicator items on close
|
||||||
dupealias.gui.chest.keep: false # Keep chest items on close
|
dupealias.gui.chest.keep: false # Keep chest items on close
|
||||||
dupealias.gui.chest.keepondeath: false # Keep chest items on death
|
dupealias.gui.chest.keepondeath: false # Keep chest items on death
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Permission Based Refresh Rates
|
#### Permission Based Refresh Rates
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.gui.replicator.refresh.<integer>: false # Ticks of refresh cooldown
|
dupealias.gui.replicator.refresh.<integer>: false # Ticks of refresh cooldown
|
||||||
dupealias.gui.replicator.cooldown.<integer>: false # Ticks of re-input cooldown
|
dupealias.gui.replicator.cooldown.<integer>: false # Ticks of re-input cooldown
|
||||||
dupealias.gui.inventory.refresh.<integer>: false # Ticks of refresh cooldown
|
dupealias.gui.inventory.refresh.<integer>: false # Ticks of refresh cooldown
|
||||||
dupealias.gui.chest.refresh.<integer>: false # Ticks of refresh cooldown
|
dupealias.gui.chest.refresh.<integer>: false # Ticks of refresh cooldown
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tag Bypasses (Use Carefully!)
|
#### Tag Bypasses (Use Carefully!)
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.unique.bypass: false # Can dupe UNIQUE items
|
dupealias.unique.bypass: false # Can dupe UNIQUE items
|
||||||
dupealias.final.bypass: false # Can modify FINAL items
|
dupealias.final.bypass: false # Can modify FINAL items
|
||||||
dupealias.protected.bypass: false # Can use PROTECTED items
|
dupealias.protected.bypass: false # Can use PROTECTED items
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Special Permissions
|
#### Special Permissions
|
||||||
```yaml
|
```yaml
|
||||||
dupealias.infinite: true # Can use INFINITE items
|
dupealias.infinite: true # Can use INFINITE items
|
||||||
```
|
```
|
||||||
|
|
||||||
### Permission Hierarchy
|
### Permission Hierarchy
|
||||||
|
|
||||||
The plugin uses a "lowest value wins" system for numeric permissions. If a player has both `refresh.20` and `refresh.5`, they will get the 5-tick refresh cooldown.
|
The plugin generally uses a "lowest value wins" system for numeric permissions. If a player has both `refresh.20` and `refresh.5`, they will get the 5-tick refresh cooldown. There is an exception to this rule however. For the permission `dupealias.dupe.limit.<integer>`, it will take the highest value given. This is because I am lazy and did not add a default limit for non ranked players.
|
||||||
|
|
||||||
### Example Permission Sets
|
### Example Permission Sets
|
||||||
|
|
||||||
#### VIP Player
|
#### VIP Player
|
||||||
```yaml
|
```yaml
|
||||||
groups:
|
groups:
|
||||||
vip:
|
vip:
|
||||||
permissions:
|
permissions:
|
||||||
- dupealias.dupe - dupealias.gui - dupealias.gui.replicator.refresh.5 # Faster refresh
|
- dupealias.dupe
|
||||||
- dupealias.gui.replicator.cooldown.10 # Shorter cooldown
|
- dupealias.gui
|
||||||
- dupealias.dupe.cooldown.0 # No command cooldown
|
- dupealias.gui.replicator.refresh.5 # Faster refresh
|
||||||
```
|
- dupealias.gui.replicator.cooldown.10 # Shorter cooldown
|
||||||
|
- dupealias.dupe.cooldown.0 # No command cooldown
|
||||||
|
```
|
||||||
#### Staff Member
|
#### Staff Member
|
||||||
```yaml
|
```yaml
|
||||||
groups:
|
groups:
|
||||||
staff:
|
staff:
|
||||||
permissions: - dupealias.admin # Full admin access
|
permissions:
|
||||||
- dupealias.gui.replicator.refresh.1 # Instant refresh
|
- dupealias.admin # Full admin access
|
||||||
- dupealias.gui.*.keep # Session persistence
|
- dupealias.gui.replicator.refresh.1 # Instant refresh
|
||||||
- dupealias.final.bypass # Can modify final items
|
- dupealias.gui.*.keep # Session persistence
|
||||||
```
|
- dupealias.final.bypass # Can modify final items
|
||||||
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Main Configuration (`config.json`)
|
### Main Configuration (`config.json`)
|
||||||
|
|
||||||
#### Duplication Settings
|
#### Duplication Settings
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"dupeCooldownMillis": 1000, // Command cooldown in milliseconds
|
"dupeCooldownMillis": 1000, // Command cooldown in milliseconds
|
||||||
"defaultDupeGui": "REPLICATOR" // Default GUI (REPLICATOR/INVENTORY/CHEST/MENU)
|
"defaultDupeGui": "REPLICATOR" // Default GUI (REPLICATOR/INVENTORY/CHEST/MENU)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### GUI Refresh Rates
|
#### GUI Refresh Rates
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"replicator": {
|
"replicator": {
|
||||||
"baseRefreshDelayTicks": 1, // Base item refresh delay
|
"baseRefreshDelayTicks": 1, // Base item refresh delay
|
||||||
"baseInputCooldownTicks": 20 // Base input change cooldown
|
"baseInputCooldownTicks": 20 // Base input change cooldown
|
||||||
}, "chest": {
|
},
|
||||||
"baseRefreshDelayTicks": 1 // Base item refresh delay
|
"chest": {
|
||||||
},
|
"baseRefreshDelayTicks": 1 // Base item refresh delay
|
||||||
"inventory": {
|
},
|
||||||
"baseRefreshDelayTicks": 1 // Base item refresh delay
|
"inventory": {
|
||||||
}}
|
"baseRefreshDelayTicks": 1 // Base item refresh delay
|
||||||
```
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Command Blocking
|
#### Command Blocking
|
||||||
```json
|
|
||||||
{
|
```json
|
||||||
"finalCommandRegex": [
|
{
|
||||||
"\"(?:itemname|iname)\"gmi", // Block item naming commands "\"(?:itemlore|lore)\"gmi" // Block lore modification commands ]}
|
"finalCommandRegex": [
|
||||||
```
|
"\"(?:itemname|iname)\"gmi", // Block item naming commands
|
||||||
|
"\"(?:itemlore|lore)\"gmi" // Block lore modification commands
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
#### Tag Lore Customization (MiniMessage)
|
#### Tag Lore Customization (MiniMessage)
|
||||||
```json
|
|
||||||
{
|
```json
|
||||||
"trueTagLore": {
|
{
|
||||||
"UNIQUE": "<dark_blue><bold>|</bold><blue> Unique",
|
"trueTagLore": {
|
||||||
"FINAL": "<dark_red><bold>|</bold><red> Final",
|
"UNIQUE": "<dark_blue><bold>|</bold><blue> Unique",
|
||||||
"INFINITE": "<dark_green><bold>|</bold><green> Infinite",
|
"FINAL": "<dark_red><bold>|</bold><red> Final",
|
||||||
"PROTECTED": "<dark_purple><bold>|</bold><light_purple> Protected"
|
"INFINITE": "<dark_green><bold>|</bold><green> Infinite",
|
||||||
},
|
"PROTECTED": "<dark_purple><bold>|</bold><light_purple> Protected"
|
||||||
"falseTagLore": {
|
},
|
||||||
"UNIQUE": "<dark_blue><bold>|</bold><blue> Dupeable",
|
"falseTagLore": {
|
||||||
"FINAL": "<dark_red><bold>|</bold><red> Mutable",
|
"UNIQUE": "<dark_blue><bold>|</bold><blue> Dupeable",
|
||||||
"INFINITE": "<dark_green><bold>|</bold><green> Finite",
|
"FINAL": "<dark_red><bold>|</bold><red> Mutable",
|
||||||
"PROTECTED": "<dark_purple><bold>|</bold><light_purple> Unprotected"
|
"INFINITE": "<dark_green><bold>|</bold><green> Finite",
|
||||||
}
|
"PROTECTED": "<dark_purple><bold>|</bold><light_purple> Unprotected"
|
||||||
}
|
}
|
||||||
```
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Common Configuration (`common.json`)
|
### Common Configuration (`common.json`)
|
||||||
|
|
||||||
#### Visual Customization
|
#### Visual Customization
|
||||||
```json
|
|
||||||
{
|
```json
|
||||||
"mainColor": 11184895, // Primary color (hex: AAAAFF)
|
{
|
||||||
"secondaryColor": 909055, // Secondary color (hex: 00DDFF)
|
"mainColor": 11184895, // Primary color (hex: AAAAFF)
|
||||||
"pluginName": "DupeAlias", // Display name
|
"secondaryColor": 909055, // Secondary color (hex: 00DDFF)
|
||||||
"flatPrefix": "&9DupeAlias> &7", // Legacy chat prefix
|
"pluginName": "DupeAlias", // Display name
|
||||||
"flat": false // Use legacy formatting
|
"flatPrefix": "&9DupeAlias> &7", // Legacy chat prefix
|
||||||
}
|
"flat": false // Use legacy formatting
|
||||||
```
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
#### Debug Settings
|
#### Debug Settings
|
||||||
```json
|
|
||||||
{
|
|
||||||
"debugMode": false, // Enable debug output
|
|
||||||
"debuggerExclusions": [] // Methods to exclude from debug
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"debugMode": false, // Enable debug output
|
||||||
|
"debuggerExclusions": [] // Methods to exclude from debug
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
### Administrative Commands
|
### Administrative Commands
|
||||||
|
|
||||||
#### `/dupealias` (Aliases: `/da`)
|
#### `/dupealias` (Aliases: `/da`)
|
||||||
**Permission**: `dupealias.admin`
|
**Permission**: `dupealias.admin`
|
||||||
**Description**: Main administrative command
|
**Description**: Main administrative command
|
||||||
|
|
||||||
**Subcommands**:
|
**Subcommands**:
|
||||||
@@ -625,7 +457,7 @@ groups:
|
|||||||
### Player Commands
|
### Player Commands
|
||||||
|
|
||||||
#### `/dupe`
|
#### `/dupe`
|
||||||
**Permission**: `dupealias.dupe`
|
**Permission**: `dupealias.dupe`
|
||||||
**Description**: Main duplication command
|
**Description**: Main duplication command
|
||||||
|
|
||||||
**Usage**:
|
**Usage**:
|
||||||
@@ -642,35 +474,35 @@ groups:
|
|||||||
### Common Issues
|
### Common Issues
|
||||||
|
|
||||||
#### "You cannot dupe unique items"
|
#### "You cannot dupe unique items"
|
||||||
**Cause**: Item has UNIQUE tag or matches global rule
|
**Cause**: Item has UNIQUE tag or matches global rule
|
||||||
**Solution**:
|
**Solution**:
|
||||||
- Check `/da` → Held Item Actions to see current tags
|
- Check `/da` → Held Item Actions to see current tags
|
||||||
- Review global rules that might be applying UNIQUE tag
|
- Review global rules that might be applying UNIQUE tag
|
||||||
- Use `/da tag UNIQUE remove` to remove individual tag
|
- Use `/da tag UNIQUE remove` to remove individual tag
|
||||||
|
|
||||||
#### Items not refreshing in GUI
|
#### Items not refreshing in GUI
|
||||||
**Cause**: Long refresh delay or permission issues
|
**Cause**: Long refresh delay or permission issues
|
||||||
**Solution**:
|
**Solution**:
|
||||||
- Check player has appropriate GUI permissions
|
- Check player has appropriate GUI permissions
|
||||||
- Verify refresh rate permissions (lower numbers = faster)
|
- Verify refresh rate permissions (lower numbers = faster)
|
||||||
- Ensure player isn't hitting cooldown limits
|
- Ensure player isn't hitting cooldown limits
|
||||||
|
|
||||||
#### "You cannot modify final items"
|
#### "You cannot modify final items"
|
||||||
**Cause**: Item has FINAL tag blocking modifications
|
**Cause**: Item has FINAL tag blocking modifications
|
||||||
**Solution**:
|
**Solution**:
|
||||||
- Check item tags in admin panel
|
- Check item tags in admin panel
|
||||||
- Use `/da tag FINAL remove` if needed
|
- Use `/da tag FINAL remove` if needed
|
||||||
- Grant `dupealias.final.bypass` permission for admins
|
- Grant `dupealias.final.bypass` permission for admins
|
||||||
|
|
||||||
#### Global rules not applying
|
#### Global rules not applying
|
||||||
**Cause**: Rule criteria not matching or individual tags overriding
|
**Cause**: Rule criteria not matching or individual tags overriding
|
||||||
**Solution**:
|
**Solution**:
|
||||||
- Test rule criteria with `/da rule info <index>`
|
- Test rule criteria with `/da rule info <index>`
|
||||||
- Check match mode (AND vs OR)
|
- Check match mode (AND vs OR)
|
||||||
- Remember individual tags override global rules
|
- Remember individual tags override global rules
|
||||||
|
|
||||||
#### GUI won't open
|
#### GUI won't open
|
||||||
**Cause**: Missing permissions or plugin conflicts
|
**Cause**: Missing permissions or plugin conflicts
|
||||||
**Solution**:
|
**Solution**:
|
||||||
- Verify player has `dupealias.gui` permission
|
- Verify player has `dupealias.gui` permission
|
||||||
- Check for inventory plugin conflicts
|
- Check for inventory plugin conflicts
|
||||||
@@ -678,26 +510,19 @@ groups:
|
|||||||
|
|
||||||
### Debug Mode
|
### Debug Mode
|
||||||
|
|
||||||
Enable debug mode to troubleshoot issues:
|
Enable debug mode to troubleshoot issues: ``` /da debug toggle ```
|
||||||
```
|
|
||||||
/da debug toggle
|
|
||||||
```
|
|
||||||
|
|
||||||
This will show detailed information about:
|
This will show detailed information about:
|
||||||
- Tag checking processes
|
- Tag checking processes
|
||||||
- Global rule matching
|
- Global rule matching
|
||||||
- Permission calculations
|
- Permission calculations
|
||||||
- GUI state changes
|
- GUI state changes
|
||||||
|
|
||||||
Exclude noisy methods:
|
Exclude noisy methods: ``` /da debug exclude <method_name> ```
|
||||||
```
|
|
||||||
/da debug exclude <method_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance Considerations
|
### Performance Considerations
|
||||||
|
|
||||||
#### Large Player Counts
|
#### Large Player Counts
|
||||||
- Use session persistence sparingly
|
- Use session persistence sparingly
|
||||||
|
- Don't use GUI refresh or input cooldowns.
|
||||||
- Monitor server TPS with `/tps`
|
- Monitor server TPS with `/tps`
|
||||||
|
|
||||||
#### Complex Global Rules
|
#### Complex Global Rules
|
||||||
@@ -706,19 +531,17 @@ Exclude noisy methods:
|
|||||||
- Limit the number of active global rules
|
- Limit the number of active global rules
|
||||||
|
|
||||||
#### GUI Optimization
|
#### GUI Optimization
|
||||||
- Set appropriate refresh rates based on server performance
|
|
||||||
- Consider disabling session persistence for busy servers
|
- Consider disabling session persistence for busy servers
|
||||||
- Use cooldowns to prevent spam
|
- Use cooldowns to prevent spam
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Getting Help
|
### Getting Help
|
||||||
|
|
||||||
If you encounter issues not covered in this documentation:
|
If you encounter issues not covered in this documentation:
|
||||||
|
|
||||||
1. Enable debug mode and check console logs
|
1. Enable debug mode and check console logs
|
||||||
2. Test with a minimal permission set
|
2. Verify your global rules are correctly configured
|
||||||
3. Verify your global rules are correctly configured
|
3. Check for conflicts with other plugins
|
||||||
4. Check for conflicts with other plugins
|
4. Join the [Alias Development](https://trouper.me/alias) discord
|
||||||
|
|
||||||
Remember that individual item tags always override global rules, and bypass permissions should be used carefully as they can compromise your server's item security system.
|
Remember that individual item tags always override global rules, and bypass permissions should be used carefully as they can compromise your server's item security system.
|
||||||
87
README.md
Normal file
87
README.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# DupeAlias - An Advanced Dupe Plugin
|
||||||
|
**Make your server stand out by switching to DupeAlias, a powerful dupe plugin with niche features for unique servers.**
|
||||||
|
|
||||||
|
---
|
||||||
|
## Why Choose DupeAlias?
|
||||||
|
DupeAlias gives you unprecedented control over how items can be copied or duplicated on your server. Configurable through a sleek in-game GUI, DupeAlias provides a friction-free administration experience.
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
**Smart Item Tagging System**
|
||||||
|
- **UNIQUE** - Prevent specific items from being duplicated
|
||||||
|
- **FINAL** - Lock items against any modifications
|
||||||
|
- **INFINITE** - Create stacks that never run out
|
||||||
|
- **PROTECTED** - Make items completely inert and unusable
|
||||||
|
|
||||||
|
**Advanced Global Rules Engine**
|
||||||
|
- Create complex rules based on item properties
|
||||||
|
- Match by material, enchantments, name patterns, lore, attributes, and more
|
||||||
|
- Support for ItemsAdder
|
||||||
|
- Flexible matching modes (AND, OR, NAND, XOR)
|
||||||
|
|
||||||
|
**Multiple Duplication Interfaces**
|
||||||
|
- **Replicator GUI** - Single-item duplication with visual feedback
|
||||||
|
- **Chest GUI** - Multi-item container-style duplication
|
||||||
|
- **Inventory GUI** - Mirror your entire inventory for easy access
|
||||||
|
- **Menu GUI** - Central hub for all duplication options
|
||||||
|
|
||||||
|
**Performance & Customization**
|
||||||
|
- Per-permission refresh rates and cooldowns
|
||||||
|
- Extensive configuration options
|
||||||
|
- Session persistence (optional)
|
||||||
|
- Beautiful, modern GUIs with progress indicators
|
||||||
|
|
||||||
|
---
|
||||||
|
## Perfect For These Server Types
|
||||||
|
- **Survival/Creative** - Give players infinite building blocks while protecting valuable items
|
||||||
|
- **Dupe Servers** - Create economies in an otherwise chaotic server class
|
||||||
|
- **Minigames** - Provide infinite consumables while preventing exploitation
|
||||||
|
- **RPG Servers** - Protect quest items and create unbreakable gear (You don't *have* to use the dupe feature!)
|
||||||
|
|
||||||
|
---
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
|
||||||
|
The main Admin Panel, click on the green book for a quick guide on how to use the plugin.
|
||||||
|

|
||||||
|
The Replicator GUI is a great choice for the default dupe GUI. It is clean, simple, and you have good control over how its used.
|
||||||
|

|
||||||
|
The Global Rule Editor is designed to be intuitive to use, with quick buttons for changing match modes and toggling tags.
|
||||||
|

|
||||||
|
Want to know how an item is processed? Head over to the help GUI and hover on you held item's icon. An explanation will be generated for you.
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
## Quick Setup
|
||||||
|
1. Drop `DupeAlias.jar` into your plugins folder
|
||||||
|
2. Restart your server
|
||||||
|
3. Use `/da` to open the admin panel
|
||||||
|
4. Configure your global rules and permissions
|
||||||
|
5. Let your players use `/dupe` to start duplicating!
|
||||||
|
|
||||||
|
---
|
||||||
|
## Permissions Overview
|
||||||
|
- `dupealias.admin` - Access to admin panel and configuration
|
||||||
|
- `dupealias.dupe` - Basic duplication command access
|
||||||
|
- `dupealias.gui.*` - Access to specific GUI types
|
||||||
|
- `dupealias.*.bypass` - Bypass tag restrictions (use carefully!)
|
||||||
|
- Permission-based refresh rates: `dupealias.gui.replicator.refresh.1`
|
||||||
|
|
||||||
|
---
|
||||||
|
## Use Cases
|
||||||
|
**Crate Key Protection** Create a global rule that makes all items containing `"excellentcrates:crate_key.id"` in their NBT tag, UNIQUE, FINAL, and PROTECTED, preventing duplication and accidental use.
|
||||||
|
|
||||||
|
**Infinite Building Materials** Set up INFINITE tags on common building blocks, giving your players unlimited resources for creative purposes.
|
||||||
|
|
||||||
|
**Rank Kit Exclusivity** Combine both FINAL and UNIQUE tags on rank crates to prevent ranked players from modifying and redistributing exclusive branded kits.
|
||||||
|
|
||||||
|
**Admin Tool Management** Add the UNIQUE tag to admin-only items so they cannot be duplicated by regular players.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- **Minecraft Version**: 1.21.5
|
||||||
|
- **Server Software**: Paper
|
||||||
|
- **Java Version**: 21+
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
- [Documentation is available in Documentation.md](Documentation.md)
|
||||||
@@ -16,11 +16,16 @@ java {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
|
maven {
|
||||||
|
name = "matteodev"
|
||||||
|
url = uri("https://maven.devs.beer/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
|
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
|
||||||
implementation("me.trouper:alias:1.0-1.21.5-SNAPSHOT")
|
implementation("me.trouper:alias:1.0-1.21.5-SNAPSHOT")
|
||||||
|
compileOnly("dev.lone:api-itemsadder:4.0.10")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
|||||||
BIN
images/conflicts.gif
Normal file
BIN
images/conflicts.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
BIN
images/maingui.gif
Normal file
BIN
images/maingui.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
images/replicator.gif
Normal file
BIN
images/replicator.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
images/rules.gif
Normal file
BIN
images/rules.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 MiB |
@@ -2,6 +2,7 @@ package me.trouper.dupealias.data;
|
|||||||
|
|
||||||
import me.trouper.alias.data.enums.*;
|
import me.trouper.alias.data.enums.*;
|
||||||
import me.trouper.alias.utils.misc.MapUtils;
|
import me.trouper.alias.utils.misc.MapUtils;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
import me.trouper.dupealias.server.ItemTag;
|
import me.trouper.dupealias.server.ItemTag;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
@@ -21,7 +22,7 @@ import java.util.*;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class GlobalRule {
|
public class GlobalRule implements DupeContext {
|
||||||
|
|
||||||
public enum MatchMode {
|
public enum MatchMode {
|
||||||
AND, OR, NAND, XOR
|
AND, OR, NAND, XOR
|
||||||
@@ -36,9 +37,12 @@ public class GlobalRule {
|
|||||||
public MatchMode matchMode = MatchMode.AND;
|
public MatchMode matchMode = MatchMode.AND;
|
||||||
public MaterialMatchMode materialMode = MaterialMatchMode.IGNORE;
|
public MaterialMatchMode materialMode = MaterialMatchMode.IGNORE;
|
||||||
public Set<Material> effectedMaterials = EnumSet.noneOf(Material.class);
|
public Set<Material> effectedMaterials = EnumSet.noneOf(Material.class);
|
||||||
|
public List<ItemsAdderItem> effectedItemsAdderMaterials = new ArrayList<>();
|
||||||
|
|
||||||
public String nameContainsRegex = "";
|
public String nameContainsRegex = "";
|
||||||
public String loreContainsRegex = "";
|
public String loreContainsRegex = "";
|
||||||
|
public String compoundTagContainsRegex = "";
|
||||||
|
public String nbtTagContainsRegex = "";
|
||||||
public Set<Integer> legacyModelData = new HashSet<>();
|
public Set<Integer> legacyModelData = new HashSet<>();
|
||||||
public Set<ItemFlag> itemFlags = EnumSet.noneOf(ItemFlag.class);
|
public Set<ItemFlag> itemFlags = EnumSet.noneOf(ItemFlag.class);
|
||||||
public Map<ValidEnchantment, Integer> enchantments = new HashMap<>();
|
public Map<ValidEnchantment, Integer> enchantments = new HashMap<>();
|
||||||
@@ -51,14 +55,19 @@ public class GlobalRule {
|
|||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public boolean doesMatch(ItemStack item) {
|
public boolean doesMatch(ItemStack item) {
|
||||||
if (item == null || item.getType() == Material.AIR) return false;
|
if (item == null || item.isEmpty()) return false;
|
||||||
|
|
||||||
|
ItemsAdderItem iai = new ItemsAdderItem();
|
||||||
|
try {
|
||||||
|
iai = new ItemsAdderItem(item);
|
||||||
|
} catch (IllegalArgumentException ignored) {}
|
||||||
|
|
||||||
switch (materialMode) {
|
switch (materialMode) {
|
||||||
case WHITELIST -> {
|
case WHITELIST -> {
|
||||||
if (!effectedMaterials.contains(item.getType())) return false;
|
if (!effectedMaterials.contains(item.getType()) && !effectedItemsAdderMaterials.contains(iai)) return false;
|
||||||
}
|
}
|
||||||
case BLACKLIST -> {
|
case BLACKLIST -> {
|
||||||
if (effectedMaterials.contains(item.getType())) return false;
|
if (effectedMaterials.contains(item.getType()) || effectedItemsAdderMaterials.contains(iai)) return false;
|
||||||
}
|
}
|
||||||
case IGNORE -> {}
|
case IGNORE -> {}
|
||||||
}
|
}
|
||||||
@@ -66,6 +75,7 @@ public class GlobalRule {
|
|||||||
ItemMeta meta = item.getItemMeta();
|
ItemMeta meta = item.getItemMeta();
|
||||||
if (meta == null) return false;
|
if (meta == null) return false;
|
||||||
|
|
||||||
|
|
||||||
List<Boolean> results = new ArrayList<>();
|
List<Boolean> results = new ArrayList<>();
|
||||||
|
|
||||||
if (!nameContainsRegex.isEmpty()) {
|
if (!nameContainsRegex.isEmpty()) {
|
||||||
@@ -82,6 +92,18 @@ public class GlobalRule {
|
|||||||
results.add(found);
|
results.add(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!compoundTagContainsRegex.isEmpty()) {
|
||||||
|
Pattern compoundPatten = safeCompileRegex(compoundTagContainsRegex);
|
||||||
|
String compound = meta.getAsComponentString();
|
||||||
|
results.add(compoundPatten.matcher(compound).find());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nbtTagContainsRegex.isEmpty()) {
|
||||||
|
Pattern nbtPattern = safeCompileRegex(compoundTagContainsRegex);
|
||||||
|
String nbt = meta.getAsString();
|
||||||
|
results.add(nbtPattern.matcher(nbt).find());
|
||||||
|
}
|
||||||
|
|
||||||
if (!enchantments.isEmpty()) {
|
if (!enchantments.isEmpty()) {
|
||||||
Map<Enchantment, Integer> itemEnchants = item.getEnchantments();
|
Map<Enchantment, Integer> itemEnchants = item.getEnchantments();
|
||||||
results.add(MapUtils.allValuesMatch(itemEnchants, enchantments.entrySet().stream().collect(Collectors.toMap(
|
results.add(MapUtils.allValuesMatch(itemEnchants, enchantments.entrySet().stream().collect(Collectors.toMap(
|
||||||
@@ -135,6 +157,8 @@ public class GlobalRule {
|
|||||||
int trueCount = (int) results.stream().filter(Boolean::booleanValue).count();
|
int trueCount = (int) results.stream().filter(Boolean::booleanValue).count();
|
||||||
int total = results.size();
|
int total = results.size();
|
||||||
|
|
||||||
|
if (getCriteriaCount() == 0) return true;
|
||||||
|
|
||||||
return switch (matchMode) {
|
return switch (matchMode) {
|
||||||
case AND -> trueCount == total;
|
case AND -> trueCount == total;
|
||||||
case OR -> trueCount > 0;
|
case OR -> trueCount > 0;
|
||||||
@@ -156,11 +180,13 @@ public class GlobalRule {
|
|||||||
int criteriaCount = 0;
|
int criteriaCount = 0;
|
||||||
if (!nameContainsRegex.isEmpty()) criteriaCount++;
|
if (!nameContainsRegex.isEmpty()) criteriaCount++;
|
||||||
if (!loreContainsRegex.isEmpty()) criteriaCount++;
|
if (!loreContainsRegex.isEmpty()) criteriaCount++;
|
||||||
|
if (!nbtTagContainsRegex.isEmpty()) criteriaCount++;
|
||||||
|
if (!compoundTagContainsRegex.isEmpty()) criteriaCount++;
|
||||||
|
if (!legacyModelData.isEmpty()) criteriaCount++;
|
||||||
if (!enchantments.isEmpty()) criteriaCount++;
|
if (!enchantments.isEmpty()) criteriaCount++;
|
||||||
if (!potionEffects.isEmpty()) criteriaCount++;
|
if (!potionEffects.isEmpty()) criteriaCount++;
|
||||||
if (!attributes.isEmpty()) criteriaCount++;
|
if (!attributes.isEmpty()) criteriaCount++;
|
||||||
if (!itemFlags.isEmpty()) criteriaCount++;
|
if (!itemFlags.isEmpty()) criteriaCount++;
|
||||||
if (!legacyModelData.isEmpty()) criteriaCount++;
|
|
||||||
if (!trimPatterns.isEmpty()) criteriaCount++;
|
if (!trimPatterns.isEmpty()) criteriaCount++;
|
||||||
if (!trimMaterials.isEmpty()) criteriaCount++;
|
if (!trimMaterials.isEmpty()) criteriaCount++;
|
||||||
return criteriaCount;
|
return criteriaCount;
|
||||||
|
|||||||
90
src/main/java/me/trouper/dupealias/data/ItemsAdderItem.java
Normal file
90
src/main/java/me/trouper/dupealias/data/ItemsAdderItem.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package me.trouper.dupealias.data;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ItemsAdderItem {
|
||||||
|
|
||||||
|
public final String namespace;
|
||||||
|
|
||||||
|
public final String id;
|
||||||
|
|
||||||
|
private static final Gson GSON = new Gson();
|
||||||
|
|
||||||
|
public ItemsAdderItem() {
|
||||||
|
this.namespace = null;
|
||||||
|
this.id = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ItemsAdderItem(ItemStack itemStack) throws IllegalArgumentException {
|
||||||
|
if (itemStack == null) {
|
||||||
|
throw new IllegalArgumentException("ItemStack provided cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
if (itemMeta == null) {
|
||||||
|
throw new IllegalArgumentException("ItemStack has no ItemMeta. It cannot be an ItemsAdder item.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String itemMetaJson = itemMeta.getAsString();
|
||||||
|
if (itemMetaJson.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ItemMeta.getAsString() returned null or an empty string. No NBT data found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> components;
|
||||||
|
try {
|
||||||
|
components = GSON.fromJson(itemMetaJson, Map.class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse ItemMeta JSON string: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
Object customDataObj = components.get("minecraft:custom_data");
|
||||||
|
if (!(customDataObj instanceof Map)) {
|
||||||
|
throw new IllegalArgumentException("Missing or invalid 'minecraft:custom_data' component in ItemStack NBT. Expected a JSON object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> customData = (Map<String, Object>) customDataObj;
|
||||||
|
|
||||||
|
Object itemsAdderObj = customData.get("itemsadder");
|
||||||
|
if (!(itemsAdderObj instanceof Map)) {
|
||||||
|
throw new IllegalArgumentException("Missing or invalid 'itemsadder' object within 'minecraft:custom_data'. Expected a JSON object.");
|
||||||
|
}
|
||||||
|
Map<String, Object> itemsAdderData = (Map<String, Object>) itemsAdderObj;
|
||||||
|
|
||||||
|
Object namespaceObj = itemsAdderData.get("namespace");
|
||||||
|
Object idObj = itemsAdderData.get("id");
|
||||||
|
|
||||||
|
if (!(namespaceObj instanceof String) || ((String) namespaceObj).trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Missing, invalid, or empty 'namespace' field in ItemsAdder custom data. Expected a non-empty string.");
|
||||||
|
}
|
||||||
|
this.namespace = (String) namespaceObj;
|
||||||
|
|
||||||
|
if (!(idObj instanceof String) || ((String) idObj).trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Missing, invalid, or empty 'id' field in ItemsAdder custom data. Expected a non-empty string.");
|
||||||
|
}
|
||||||
|
this.id = (String) idObj;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ItemsAdderItem{namespace='" + namespace + "', id='" + id + "'}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ItemsAdderItem that = (ItemsAdderItem) o;
|
||||||
|
return Objects.equals(namespace, that.namespace) &&
|
||||||
|
Objects.equals(id, that.id);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(namespace, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,10 @@ import me.trouper.dupealias.data.GlobalRule;
|
|||||||
import me.trouper.dupealias.server.ItemTag;
|
import me.trouper.dupealias.server.ItemTag;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class DupeConfig implements JsonSerializable<DupeConfig>, DupeContext {
|
public class DupeConfig implements JsonSerializable<DupeConfig>, DupeContext {
|
||||||
@Override
|
@Override
|
||||||
@@ -36,6 +39,8 @@ public class DupeConfig implements JsonSerializable<DupeConfig>, DupeContext {
|
|||||||
ItemTag.UNIQUE, "<dark_blue><bold>|</bold><blue> Dupeable",
|
ItemTag.UNIQUE, "<dark_blue><bold>|</bold><blue> Dupeable",
|
||||||
ItemTag.INFINITE, "<dark_green><bold>|</bold><green> Finite"
|
ItemTag.INFINITE, "<dark_green><bold>|</bold><green> Finite"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
public boolean blockDupePlus = false;
|
||||||
|
|
||||||
public List<GlobalRule> globalRules = new ArrayList<>();
|
public List<GlobalRule> globalRules = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class DupeManager implements DupeContext {
|
public class DupeManager implements DupeContext {
|
||||||
|
|
||||||
@@ -77,7 +79,9 @@ public class DupeManager implements DupeContext {
|
|||||||
* Checks if any global rule applies this tag to the given item
|
* Checks if any global rule applies this tag to the given item
|
||||||
*/
|
*/
|
||||||
public boolean checkGlobalRuleTag(ItemStack input, ItemTag tag) {
|
public boolean checkGlobalRuleTag(ItemStack input, ItemTag tag) {
|
||||||
|
getVerbose().send("Checking tag {0} on item {1}",tag,input.getType());
|
||||||
for (GlobalRule rule : getConfig().globalRules) {
|
for (GlobalRule rule : getConfig().globalRules) {
|
||||||
|
getVerbose().send("Scanning rule with tags {0}",rule.appliedTags.toString());
|
||||||
if (rule.appliedTags.contains(tag) && rule.doesMatch(input)) {
|
if (rule.appliedTags.contains(tag) && rule.doesMatch(input)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -122,12 +126,11 @@ public class DupeManager implements DupeContext {
|
|||||||
* Adds a global rule for a specific material and tag
|
* Adds a global rule for a specific material and tag
|
||||||
*/
|
*/
|
||||||
public boolean addGlobalRuleForMaterial(Material material, ItemTag tag) {
|
public boolean addGlobalRuleForMaterial(Material material, ItemTag tag) {
|
||||||
// Check if rule already exists
|
|
||||||
for (GlobalRule rule : getConfig().globalRules) {
|
for (GlobalRule rule : getConfig().globalRules) {
|
||||||
if (rule.appliedTags.contains(tag) &&
|
if (rule.appliedTags.contains(tag) &&
|
||||||
rule.materialMode == GlobalRule.MaterialMatchMode.WHITELIST &&
|
rule.materialMode == GlobalRule.MaterialMatchMode.WHITELIST &&
|
||||||
rule.effectedMaterials.contains(material)) {
|
rule.effectedMaterials.contains(material)) {
|
||||||
return false; // Rule already exists
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +239,8 @@ public class DupeManager implements DupeContext {
|
|||||||
throw new IllegalArgumentException("Invalid NameSpacedKey '%s'".formatted(key.value()));
|
throw new IllegalArgumentException("Invalid NameSpacedKey '%s'".formatted(key.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPermissionValue(Player player, String rootPermission, int fallback) {
|
public int getPermissionValue(Player player, String rootPermission, int fallback, boolean takeHighest) {
|
||||||
int lowestCooldown = Integer.MAX_VALUE;
|
int result = takeHighest ? Integer.MIN_VALUE : Integer.MAX_VALUE;
|
||||||
|
|
||||||
for (PermissionAttachmentInfo permInfo : player.getEffectivePermissions()) {
|
for (PermissionAttachmentInfo permInfo : player.getEffectivePermissions()) {
|
||||||
String perm = permInfo.getPermission();
|
String perm = permInfo.getPermission();
|
||||||
@@ -246,13 +249,24 @@ public class DupeManager implements DupeContext {
|
|||||||
String valueStr = perm.substring(rootPermission.length());
|
String valueStr = perm.substring(rootPermission.length());
|
||||||
try {
|
try {
|
||||||
int value = Integer.parseInt(valueStr);
|
int value = Integer.parseInt(valueStr);
|
||||||
if (value < lowestCooldown) {
|
if (takeHighest) {
|
||||||
lowestCooldown = value;
|
if (value > result) {
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value < result) {
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ignored) {}
|
} catch (NumberFormatException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (lowestCooldown == Integer.MAX_VALUE) ? fallback : lowestCooldown;
|
if (takeHighest) {
|
||||||
|
return (result == Integer.MIN_VALUE) ? fallback : result;
|
||||||
|
} else {
|
||||||
|
return (result == Integer.MAX_VALUE) ? fallback : result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import me.trouper.alias.server.commands.QuickCommand;
|
|||||||
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
import me.trouper.dupealias.DupeContext;
|
import me.trouper.dupealias.DupeContext;
|
||||||
import me.trouper.dupealias.data.GlobalRule;
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.data.ItemsAdderItem;
|
||||||
import me.trouper.dupealias.server.ItemTag;
|
import me.trouper.dupealias.server.ItemTag;
|
||||||
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
import me.trouper.dupealias.server.gui.admin.MainAdminGui;
|
import me.trouper.dupealias.server.gui.admin.MainAdminGui;
|
||||||
@@ -49,6 +50,10 @@ public class AdminCommand implements QuickCommand, DupeContext {
|
|||||||
handleRule(sender,args);
|
handleRule(sender,args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "test" -> {
|
||||||
|
handleDebugTests(sender,args);
|
||||||
|
}
|
||||||
|
|
||||||
default -> {
|
default -> {
|
||||||
errorAny(sender,"Invalid subcommand!");
|
errorAny(sender,"Invalid subcommand!");
|
||||||
}
|
}
|
||||||
@@ -93,13 +98,20 @@ public class AdminCommand implements QuickCommand, DupeContext {
|
|||||||
)
|
)
|
||||||
).then(
|
).then(
|
||||||
b.arg("gui")
|
b.arg("gui")
|
||||||
|
).then(
|
||||||
|
|
||||||
|
b.arg("test")
|
||||||
|
.then(
|
||||||
|
b.arg("nbt","component","itemsadder")
|
||||||
|
)
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleDebug(CommandSender sender, Args args) {
|
private void handleDebug(CommandSender sender, Args args) {
|
||||||
if (args.getSize() < 2) {
|
if (args.getSize() < 2) {
|
||||||
errorAny(sender, "Usage: debug <toggle|include|exclude>");
|
errorAny(sender, "Usage: debug <toggle|include|exclude|test>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +153,43 @@ public class AdminCommand implements QuickCommand, DupeContext {
|
|||||||
|
|
||||||
successAny(sender, "Removed exclusion for {0} on the debugger.", exclusion);
|
successAny(sender, "Removed exclusion for {0} on the debugger.", exclusion);
|
||||||
}
|
}
|
||||||
|
case "test" -> handleDebugTests(sender, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDebugTests(CommandSender sender, Args args) {
|
||||||
|
if (args.getSize() < 2) {
|
||||||
|
errorAny(sender, "Usage: test <nbt|component>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String sub = args.get(1).toString();
|
||||||
|
|
||||||
|
switch (sub) {
|
||||||
|
case "nbt" -> {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
String tag = player.getInventory().getItemInMainHand().getItemMeta().getAsString();
|
||||||
|
infoAny(player,"The item you are holding has a visible NBT String of {0} to the plugin.", tag);
|
||||||
|
getInstance().getLogger().info(tag);
|
||||||
|
}
|
||||||
|
case "component" -> {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
String component = player.getInventory().getItemInMainHand().getItemMeta().getAsComponentString();
|
||||||
|
infoAny(player,"The item you are holding has a visible Component String of {0} to the plugin.", component);
|
||||||
|
getInstance().getLogger().info(component);
|
||||||
|
}
|
||||||
|
case "itemsadder" -> {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
ItemsAdderItem item;
|
||||||
|
try {
|
||||||
|
item = new ItemsAdderItem(player.getInventory().getItemInMainHand());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
errorAny(player,"That item is not being detected as from ItemsAdder.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
successAny(player,"Your item has an ID of {0} in the namespace of {1}.",item.id,item.namespace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package me.trouper.dupealias.server.commands;
|
|||||||
|
|
||||||
import me.trouper.alias.server.commands.Args;
|
import me.trouper.alias.server.commands.Args;
|
||||||
import me.trouper.alias.server.commands.CommandRegistry;
|
import me.trouper.alias.server.commands.CommandRegistry;
|
||||||
import me.trouper.alias.server.commands.Permission;
|
|
||||||
import me.trouper.alias.server.commands.QuickCommand;
|
import me.trouper.alias.server.commands.QuickCommand;
|
||||||
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
import me.trouper.alias.server.commands.completions.CompletionBuilder;
|
||||||
import me.trouper.alias.utils.misc.Cooldown;
|
import me.trouper.alias.utils.misc.Cooldown;
|
||||||
@@ -84,7 +83,7 @@ public class DupeCommand implements QuickCommand, DupeContext {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerMax = getDupe().getPermissionValue(player,"dupealias.dupe.limit.",Integer.MAX_VALUE);
|
int playerMax = getDupe().getPermissionValue(player,"dupealias.dupe.limit.",Integer.MAX_VALUE,true);
|
||||||
if (amount > playerMax) {
|
if (amount > playerMax) {
|
||||||
warningAny(player,"Your maximum permitted dupe amplifier is {0}!", playerMax);
|
warningAny(player,"Your maximum permitted dupe amplifier is {0}!", playerMax);
|
||||||
return false;
|
return false;
|
||||||
@@ -109,7 +108,7 @@ public class DupeCommand implements QuickCommand, DupeContext {
|
|||||||
|
|
||||||
dupeStack(player,toDupe,amount);
|
dupeStack(player,toDupe,amount);
|
||||||
|
|
||||||
int playerCooldown = getDupe().getPermissionValue(player,"dupealias.dupe.cooldown.",getConfig().baseDupeCooldownMillis);
|
int playerCooldown = getDupe().getPermissionValue(player,"dupealias.dupe.cooldown.",getConfig().baseDupeCooldownMillis,false);
|
||||||
dupeCooldown.setCooldown(player.getUniqueId(), playerCooldown);
|
dupeCooldown.setCooldown(player.getUniqueId(), playerCooldown);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,17 +2,12 @@ package me.trouper.dupealias.server.functions;
|
|||||||
|
|
||||||
import me.trouper.dupealias.server.ItemTag;
|
import me.trouper.dupealias.server.ItemTag;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
|
||||||
|
|
||||||
public class UniqueCheck implements Check<ItemStack> {
|
public class UniqueCheck implements Check<ItemStack> {
|
||||||
@Override
|
@Override
|
||||||
public boolean passes(ItemStack input) {
|
public boolean passes(ItemStack input) {
|
||||||
boolean globallyUnique = getDupe().checkGlobalRuleTag(input,ItemTag.UNIQUE);
|
boolean isUnique = getDupe().checkEffectiveTag(input,ItemTag.UNIQUE);
|
||||||
boolean set = input.hasItemMeta() && input.getPersistentDataContainer().has(ItemTag.UNIQUE.getKey());
|
if (isUnique) return false;
|
||||||
boolean individuallyUnique = Boolean.TRUE.equals(input.getPersistentDataContainer().get(ItemTag.UNIQUE.getKey(), PersistentDataType.BOOLEAN));
|
|
||||||
|
|
||||||
if (set && individuallyUnique) return false;
|
|
||||||
if (!set && globallyUnique) return false;
|
|
||||||
|
|
||||||
return new ItemInventoryCheck(this).passes(input);
|
return new ItemInventoryCheck(this).passes(input);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,9 @@ import me.trouper.alias.utils.ItemBuilder;
|
|||||||
import me.trouper.dupealias.DupeAlias;
|
import me.trouper.dupealias.DupeAlias;
|
||||||
import me.trouper.dupealias.DupeContext;
|
import me.trouper.dupealias.DupeContext;
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.block.BlockState;
|
|
||||||
import org.bukkit.block.data.type.Light;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
public interface CommonItems extends DupeContext {
|
public interface CommonItems extends DupeContext {
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin;
|
package me.trouper.dupealias.server.gui.admin;
|
||||||
|
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
|
||||||
import me.trouper.alias.utils.ItemBuilder;
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
import me.trouper.dupealias.DupeContext;
|
import me.trouper.dupealias.DupeContext;
|
||||||
import me.trouper.dupealias.data.GlobalRule;
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.data.ItemsAdderItem;
|
||||||
import me.trouper.dupealias.server.ItemTag;
|
import me.trouper.dupealias.server.ItemTag;
|
||||||
import me.trouper.dupealias.server.gui.CommonItems;
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
import me.trouper.dupealias.server.gui.admin.config.ConfigGui;
|
import me.trouper.dupealias.server.gui.admin.config.ConfigGui;
|
||||||
import me.trouper.dupealias.server.gui.admin.globalrule.*;
|
import me.trouper.dupealias.server.gui.admin.globalrule.GlobalRuleEditorGui;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.globalrule.GlobalRuleListGui;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.globalrule.criteria.*;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex.*;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.stream.Collectors;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class AdminPanelManager implements DupeContext, CommonItems {
|
public class AdminPanelManager implements DupeContext, CommonItems {
|
||||||
|
|
||||||
@@ -50,73 +55,6 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
new GlobalRuleMaterialSelector(this, rule).createGUI(player).open(player);
|
new GlobalRuleMaterialSelector(this, rule).createGUI(player).open(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openNameCriteriaEditor(Player player, GlobalRule rule) {
|
|
||||||
QuickGui gui = QuickGui.create()
|
|
||||||
.titleMini("<gradient:#ffeb3b:#ffc107><bold>Name Contains</bold></gradient>")
|
|
||||||
.rows(3)
|
|
||||||
.item(13, ItemBuilder.create(Material.NAME_TAG)
|
|
||||||
.displayName("<yellow><bold>Current Pattern")
|
|
||||||
.loreMiniMessage(Arrays.asList(
|
|
||||||
"<gray>Set a regex pattern to match",
|
|
||||||
"<gray>against item display names",
|
|
||||||
"",
|
|
||||||
"<white>Current: <yellow>" + (rule.nameContainsRegex.isEmpty() ? "Not set" : rule.nameContainsRegex),
|
|
||||||
"",
|
|
||||||
"<yellow>▶ <white>Click to set pattern",
|
|
||||||
"<yellow>▶ <white>Right-click to clear"
|
|
||||||
))
|
|
||||||
.build(), (g, e) -> {
|
|
||||||
if (e.isRightClick()) {
|
|
||||||
rule.nameContainsRegex = "";
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Cleared name pattern");
|
|
||||||
openGlobalRuleEditor(player, rule);
|
|
||||||
} else {
|
|
||||||
g.requestInput(player, "modelData");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.item(31, BACK(), (g, e) -> openGlobalRuleEditor(player, rule))
|
|
||||||
.fillEmpty(EMPTY())
|
|
||||||
.callback("modelData", new QuickGui.GuiCallback() {
|
|
||||||
@Override
|
|
||||||
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
|
||||||
try {
|
|
||||||
int value = Integer.parseInt(input);
|
|
||||||
if (rule.legacyModelData.contains(value)) {
|
|
||||||
infoAny(player, "Model data value {0} already exists", value);
|
|
||||||
} else {
|
|
||||||
rule.legacyModelData.add(value);
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Added model data value: {0}", value);
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
errorAny(player, "Invalid number: {0}", input);
|
|
||||||
}
|
|
||||||
openModelDataEditor(player, rule);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
int slot = 19;
|
|
||||||
for (Integer value : rule.legacyModelData.stream().limit(5).toList()) {
|
|
||||||
gui.updateItem(slot++, ItemBuilder.create(Material.FILLED_MAP)
|
|
||||||
.displayName("<aqua><bold>Value: " + value)
|
|
||||||
.loreMiniMessage(Arrays.asList(
|
|
||||||
"<gray>Model data value",
|
|
||||||
"",
|
|
||||||
"<yellow>▶ <white>Click to remove"
|
|
||||||
))
|
|
||||||
.build(), (g, e) -> {
|
|
||||||
rule.legacyModelData.remove(value);
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Removed model data value: {0}", value);
|
|
||||||
openModelDataEditor(player, rule);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.open(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openPotionEffectEditor(Player player, GlobalRule rule) {
|
public void openPotionEffectEditor(Player player, GlobalRule rule) {
|
||||||
new GlobalRulePotionEffectEditor(this, rule).createGUI(player).open(player);
|
new GlobalRulePotionEffectEditor(this, rule).createGUI(player).open(player);
|
||||||
}
|
}
|
||||||
@@ -125,44 +63,28 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
new GlobalRuleArmorTrimEditor(this, rule).open(player);
|
new GlobalRuleArmorTrimEditor(this, rule).open(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void openNameCriteriaEditor(Player player, GlobalRule rule) {
|
||||||
|
new GlobalRuleNameEditor(this,rule).open(player);
|
||||||
|
}
|
||||||
|
|
||||||
public void openLoreCriteriaEditor(Player player, GlobalRule rule) {
|
public void openLoreCriteriaEditor(Player player, GlobalRule rule) {
|
||||||
QuickGui gui = QuickGui.create()
|
new GlobalRuleLoreEditor(this,rule).open(player);
|
||||||
.titleMini("<gradient:#9c27b0:#7b1fa2><bold>Lore Contains</bold></gradient>")
|
}
|
||||||
.rows(3)
|
|
||||||
.item(13, ItemBuilder.create(Material.WRITABLE_BOOK)
|
public void openNbtCriteriaEditor(Player player, GlobalRule rule) {
|
||||||
.displayName("<light_purple><bold>Current Pattern")
|
new GlobalRuleNbtTagEditor(this,rule).open(player);
|
||||||
.loreMiniMessage(Arrays.asList(
|
}
|
||||||
"<gray>Set a regex pattern to match",
|
|
||||||
"<gray>against item lore lines",
|
public void openCompoundCriteriaEditor(Player player, GlobalRule rule) {
|
||||||
"",
|
new GlobalRuleCompoundTagEditor(this,rule).open(player);
|
||||||
"<white>Current: <light_purple>" + (rule.loreContainsRegex.isEmpty() ? "Not set" : rule.loreContainsRegex),
|
}
|
||||||
"",
|
|
||||||
"<yellow>▶ <white>Click to set pattern",
|
public void openModelDataEditor(Player player, GlobalRule rule) {
|
||||||
"<yellow>▶ <white>Right-click to clear"
|
new GlobalRuleModelDataEditor(this,rule).open(player);
|
||||||
))
|
}
|
||||||
.build(), (g, e) -> {
|
|
||||||
if (e.isRightClick()) {
|
public void openItemsAdderParser(Player player, GlobalRule rule) {
|
||||||
rule.loreContainsRegex = "";
|
new GlobalRuleItemsAdderParser(this,rule).open(player);
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Cleared lore pattern");
|
|
||||||
openGlobalRuleEditor(player, rule);
|
|
||||||
} else {
|
|
||||||
g.requestInput(player, "lorePattern");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.item(22, BACK(), (g, e) -> openGlobalRuleEditor(player, rule))
|
|
||||||
.fillEmpty(EMPTY())
|
|
||||||
.callback("lorePattern", new QuickGui.GuiCallback() {
|
|
||||||
@Override
|
|
||||||
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
|
||||||
rule.loreContainsRegex = input;
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Set lore pattern to: " + input);
|
|
||||||
openGlobalRuleEditor(player, rule);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
gui.open(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openEnchantmentEditor(Player player, GlobalRule rule) {
|
public void openEnchantmentEditor(Player player, GlobalRule rule) {
|
||||||
@@ -177,51 +99,6 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
new GlobalRuleItemFlagEditor(this, rule).open(player);
|
new GlobalRuleItemFlagEditor(this, rule).open(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openModelDataEditor(Player player, GlobalRule rule) {
|
|
||||||
QuickGui gui = QuickGui.create()
|
|
||||||
.titleMini("<gradient:#00bcd4:#0097a7><bold>Model Data Values</bold></gradient>")
|
|
||||||
.rows(4)
|
|
||||||
.item(13, ItemBuilder.create(Material.COMPASS)
|
|
||||||
.displayName("<aqua><bold>Model Data Values")
|
|
||||||
.loreMiniMessage(Arrays.asList(
|
|
||||||
"<gray>Manage custom model data values",
|
|
||||||
"<gray>that items must have",
|
|
||||||
"",
|
|
||||||
"<white>Current values: <aqua>" + rule.legacyModelData.size(),
|
|
||||||
rule.legacyModelData.isEmpty() ? "" : "<gray>" + rule.legacyModelData.stream()
|
|
||||||
.limit(5)
|
|
||||||
.map(String::valueOf)
|
|
||||||
.collect(Collectors.joining(", ")),
|
|
||||||
rule.legacyModelData.size() > 5 ? "<gray>... and " + (rule.legacyModelData.size() - 5) + " more" : "",
|
|
||||||
"",
|
|
||||||
"<yellow>▶ <white>Click to add value",
|
|
||||||
"<yellow>▶ <white>Right-click to clear all"
|
|
||||||
))
|
|
||||||
.build(), (g, e) -> {
|
|
||||||
if (e.isRightClick()) {
|
|
||||||
rule.legacyModelData.clear();
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Cleared all model data values");
|
|
||||||
openModelDataEditor(player, rule);
|
|
||||||
} else {
|
|
||||||
g.requestInput(player,"namePattern");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.item(22, BACK(), (g, e) -> openGlobalRuleEditor(player, rule))
|
|
||||||
.fillEmpty(EMPTY())
|
|
||||||
.callback("namePattern", new QuickGui.GuiCallback() {
|
|
||||||
@Override
|
|
||||||
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
|
||||||
rule.nameContainsRegex = input;
|
|
||||||
getConfig().save();
|
|
||||||
successAny(player, "Set name pattern to: " + input);
|
|
||||||
openGlobalRuleEditor(player, rule);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
gui.open(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack createExplainedItem(ItemStack item) {
|
public ItemStack createExplainedItem(ItemStack item) {
|
||||||
if (item == null || item.isEmpty()) {
|
if (item == null || item.isEmpty()) {
|
||||||
return ItemBuilder.create(Material.GRAY_STAINED_GLASS_PANE)
|
return ItemBuilder.create(Material.GRAY_STAINED_GLASS_PANE)
|
||||||
@@ -230,6 +107,11 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemsAdderItem iai = new ItemsAdderItem();
|
||||||
|
try {
|
||||||
|
iai = new ItemsAdderItem(item);
|
||||||
|
} catch (IllegalArgumentException ignored) {}
|
||||||
|
|
||||||
List<String> lore = new ArrayList<>();
|
List<String> lore = new ArrayList<>();
|
||||||
lore.add("<white><bold>Held Item Explanation:</bold>");
|
lore.add("<white><bold>Held Item Explanation:</bold>");
|
||||||
|
|
||||||
@@ -266,6 +148,10 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
activeTags.add(ItemTag.UNIQUE);
|
activeTags.add(ItemTag.UNIQUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!iai.equals(new ItemsAdderItem())) {
|
||||||
|
lore.add("<gray>• Is from ItemsAdder. (" + iai.namespace + ":" + iai.id + ")");
|
||||||
|
}
|
||||||
|
|
||||||
if (lore.size() == 1) {
|
if (lore.size() == 1) {
|
||||||
lore.add("<gray>• No DupeAlias tags apply to this item");
|
lore.add("<gray>• No DupeAlias tags apply to this item");
|
||||||
}
|
}
|
||||||
@@ -338,6 +224,4 @@ public class AdminPanelManager implements DupeContext, CommonItems {
|
|||||||
case PROTECTED -> "dark_purple";
|
case PROTECTED -> "dark_purple";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@ package me.trouper.dupealias.server.gui.admin;
|
|||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
import me.trouper.alias.utils.ItemBuilder;
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
import me.trouper.dupealias.server.gui.CommonItems;
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
import me.trouper.dupealias.server.gui.admin.config.ConfigGui;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class CommonConfigGui implements DupeContext, CommonItems {
|
|||||||
errorAny(p, "Invalid hex color format. Use RRGGBB (e.g., AAAAFF).");
|
errorAny(p, "Invalid hex color format. Use RRGGBB (e.g., AAAAFF).");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.item(10, ItemBuilder.create(Material.BLUE_WOOL)
|
.item(11, ItemBuilder.create(Material.BLUE_WOOL)
|
||||||
.displayName("<blue><bold>Main Color</bold>")
|
.displayName("<blue><bold>Main Color</bold>")
|
||||||
.loreMiniMessage(List.of(
|
.loreMiniMessage(List.of(
|
||||||
"<gray>The color for the message border.",
|
"<gray>The color for the message border.",
|
||||||
@@ -69,7 +69,7 @@ public class CommonConfigGui implements DupeContext, CommonItems {
|
|||||||
errorAny(p, "Invalid hex color format. Use RRGGBB (e.g., 00DDFF).");
|
errorAny(p, "Invalid hex color format. Use RRGGBB (e.g., 00DDFF).");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.item(11, ItemBuilder.create(Material.CYAN_WOOL)
|
.item(12, ItemBuilder.create(Material.CYAN_WOOL)
|
||||||
.displayName("<aqua><bold>Secondary Color</bold>")
|
.displayName("<aqua><bold>Secondary Color</bold>")
|
||||||
.loreMiniMessage(List.of(
|
.loreMiniMessage(List.of(
|
||||||
"<gray>The color used for the plugin's name.",
|
"<gray>The color used for the plugin's name.",
|
||||||
@@ -88,7 +88,7 @@ public class CommonConfigGui implements DupeContext, CommonItems {
|
|||||||
successAny(p, "Plugin name set to: {0}", input);
|
successAny(p, "Plugin name set to: {0}", input);
|
||||||
open(p);
|
open(p);
|
||||||
})
|
})
|
||||||
.item(12, ItemBuilder.create(Material.NAME_TAG)
|
.item(13, ItemBuilder.create(Material.NAME_TAG)
|
||||||
.displayName("<green><bold>Plugin Name</bold>")
|
.displayName("<green><bold>Plugin Name</bold>")
|
||||||
.loreMiniMessage(List.of(
|
.loreMiniMessage(List.of(
|
||||||
"<gray>The name of the plugin displayed in messages.",
|
"<gray>The name of the plugin displayed in messages.",
|
||||||
@@ -107,7 +107,7 @@ public class CommonConfigGui implements DupeContext, CommonItems {
|
|||||||
successAny(p, "Flat prefix set to: {0}", input);
|
successAny(p, "Flat prefix set to: {0}", input);
|
||||||
open(p);
|
open(p);
|
||||||
})
|
})
|
||||||
.item(13, ItemBuilder.create(Material.PAPER)
|
.item(14, ItemBuilder.create(Material.PAPER)
|
||||||
.displayName("<gray><bold>Flat Prefix</bold>")
|
.displayName("<gray><bold>Flat Prefix</bold>")
|
||||||
.loreMiniMessage(List.of(
|
.loreMiniMessage(List.of(
|
||||||
"<gray>The prefix used when 'flat' mode is enabled.",
|
"<gray>The prefix used when 'flat' mode is enabled.",
|
||||||
@@ -120,7 +120,7 @@ public class CommonConfigGui implements DupeContext, CommonItems {
|
|||||||
getDupe().getGuiListener().requestChatInput(g, player, "flat_prefix",
|
getDupe().getGuiListener().requestChatInput(g, player, "flat_prefix",
|
||||||
"<gray>Enter the new flat prefix."))
|
"<gray>Enter the new flat prefix."))
|
||||||
|
|
||||||
.item(14, ItemBuilder.create(config.flat ? Material.LIME_DYE : Material.GRAY_DYE)
|
.item(15, ItemBuilder.create(config.flat ? Material.LIME_DYE : Material.GRAY_DYE)
|
||||||
.displayName("<white><bold>Flat Mode</bold>")
|
.displayName("<white><bold>Flat Mode</bold>")
|
||||||
.loreMiniMessage(List.of(
|
.loreMiniMessage(List.of(
|
||||||
"<gray>If true, uses the simple flat message system",
|
"<gray>If true, uses the simple flat message system",
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
||||||
|
|
||||||
@@ -33,84 +32,75 @@ public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
|||||||
.rows(6)
|
.rows(6)
|
||||||
.fillBorder(EMPTY(Material.ORANGE_STAINED_GLASS_PANE))
|
.fillBorder(EMPTY(Material.ORANGE_STAINED_GLASS_PANE))
|
||||||
|
|
||||||
// Back button
|
// Back button top-left
|
||||||
.item(0, BACK(), (g, e) -> manager.openGlobalRuleList(player))
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleList(player))
|
||||||
|
|
||||||
// Applied Tags Section
|
// Item Tags
|
||||||
.item(10, createTagItem(ItemTag.UNIQUE),
|
.item(10, createTagItem(ItemTag.UNIQUE), (g, e) -> toggleTag(player, ItemTag.UNIQUE))
|
||||||
(g, e) -> toggleTag(player, ItemTag.UNIQUE))
|
.item(11, createTagItem(ItemTag.FINAL), (g, e) -> toggleTag(player, ItemTag.FINAL))
|
||||||
.item(11, createTagItem(ItemTag.FINAL),
|
.item(12, createTagItem(ItemTag.INFINITE), (g, e) -> toggleTag(player, ItemTag.INFINITE))
|
||||||
(g, e) -> toggleTag(player, ItemTag.FINAL))
|
.item(13, createTagItem(ItemTag.PROTECTED), (g, e) -> toggleTag(player, ItemTag.PROTECTED))
|
||||||
.item(12, createTagItem(ItemTag.INFINITE),
|
|
||||||
(g, e) -> toggleTag(player, ItemTag.INFINITE))
|
|
||||||
.item(13, createTagItem(ItemTag.PROTECTED),
|
|
||||||
(g, e) -> toggleTag(player, ItemTag.PROTECTED))
|
|
||||||
|
|
||||||
// Match Mode
|
// Material Matching
|
||||||
.item(16, createMatchModeItem(),
|
.item(16, createMaterialListItem(), (g, e) -> {
|
||||||
(g, e) -> cycleMatchMode(player))
|
if (rule.materialMode != GlobalRule.MaterialMatchMode.IGNORE)
|
||||||
|
manager.openMaterialSelector(player, rule);
|
||||||
|
})
|
||||||
|
.item(25, createItemsAdderListItem(), (g, e) -> {
|
||||||
|
if (rule.materialMode != GlobalRule.MaterialMatchMode.IGNORE)
|
||||||
|
manager.openItemsAdderParser(player, rule);
|
||||||
|
})
|
||||||
|
.item(34, createMaterialModeItem(), (g, e) -> cycleMaterialMode(player))
|
||||||
|
|
||||||
// Criteria Items
|
// Criteria Match Mode
|
||||||
.item(19, createCriteriaItem("Name Regex", Material.NAME_TAG,
|
.item(43, createMatchModeItem(), (g, e) -> cycleMatchMode(player))
|
||||||
|
|
||||||
|
// Criteria Section
|
||||||
|
.item(28, createCriteriaItem("Name Regex", Material.NAME_TAG,
|
||||||
!rule.nameContainsRegex.isEmpty(), rule.nameContainsRegex),
|
!rule.nameContainsRegex.isEmpty(), rule.nameContainsRegex),
|
||||||
(g, e) -> manager.openNameCriteriaEditor(player, rule))
|
(g, e) -> manager.openNameCriteriaEditor(player, rule))
|
||||||
|
|
||||||
.item(20, createCriteriaItem("Lore Regex", Material.WRITABLE_BOOK,
|
.item(29, createCriteriaItem("Lore Regex", Material.WRITABLE_BOOK,
|
||||||
!rule.loreContainsRegex.isEmpty(), rule.loreContainsRegex),
|
!rule.loreContainsRegex.isEmpty(), rule.loreContainsRegex),
|
||||||
(g, e) -> manager.openLoreCriteriaEditor(player, rule))
|
(g, e) -> manager.openLoreCriteriaEditor(player, rule))
|
||||||
|
|
||||||
.item(21, createCriteriaItem("Enchantments", Material.ENCHANTED_BOOK,
|
.item(30, createCriteriaItem("NBT Regex", Material.BOOK,
|
||||||
|
!rule.nbtTagContainsRegex.isEmpty(), rule.nbtTagContainsRegex),
|
||||||
|
(g, e) -> manager.openNbtCriteriaEditor(player, rule))
|
||||||
|
|
||||||
|
.item(31, createCriteriaItem("Compound Regex", Material.BOOKSHELF,
|
||||||
|
!rule.compoundTagContainsRegex.isEmpty(), rule.compoundTagContainsRegex),
|
||||||
|
(g, e) -> manager.openCompoundCriteriaEditor(player, rule))
|
||||||
|
|
||||||
|
.item(32, createCriteriaItem("Model Data", Material.COMPASS,
|
||||||
|
!rule.legacyModelData.isEmpty(), rule.legacyModelData.size() + " values"),
|
||||||
|
|
||||||
|
(g, e) -> manager.openModelDataEditor(player, rule))
|
||||||
|
.item(37, createCriteriaItem("Enchantments", Material.ENCHANTED_BOOK,
|
||||||
!rule.enchantments.isEmpty(), rule.enchantments.size() + " enchants"),
|
!rule.enchantments.isEmpty(), rule.enchantments.size() + " enchants"),
|
||||||
(g, e) -> manager.openEnchantmentEditor(player, rule))
|
(g, e) -> manager.openEnchantmentEditor(player, rule))
|
||||||
|
|
||||||
.item(22, createCriteriaItem("Attributes", Material.GOLDEN_APPLE,
|
.item(38, createCriteriaItem("Attributes", Material.GOLDEN_APPLE,
|
||||||
!rule.attributes.isEmpty(), rule.attributes.size() + " attributes"),
|
!rule.attributes.isEmpty(), rule.attributes.size() + " attributes"),
|
||||||
(g, e) -> manager.openAttributeEditor(player, rule))
|
(g, e) -> manager.openAttributeEditor(player, rule))
|
||||||
|
|
||||||
.item(23, createCriteriaItem("Item Flags", Material.WHITE_BANNER,
|
.item(39, createCriteriaItem("Item Flags", Material.WHITE_BANNER,
|
||||||
!rule.itemFlags.isEmpty(), rule.itemFlags.size() + " flags"),
|
!rule.itemFlags.isEmpty(), rule.itemFlags.size() + " flags"),
|
||||||
(g, e) -> manager.openItemFlagEditor(player, rule))
|
(g, e) -> manager.openItemFlagEditor(player, rule))
|
||||||
|
|
||||||
.item(24, createCriteriaItem("Model Data", Material.COMPASS,
|
.item(40, createCriteriaItem("Potion Effects", Material.POTION,
|
||||||
!rule.legacyModelData.isEmpty(), rule.legacyModelData.size() + " values"),
|
|
||||||
(g, e) -> manager.openModelDataEditor(player, rule))
|
|
||||||
|
|
||||||
.item(25, createCriteriaItem("Potion Effects", Material.POTION,
|
|
||||||
!rule.potionEffects.isEmpty(), rule.potionEffects.size() + " effects"),
|
!rule.potionEffects.isEmpty(), rule.potionEffects.size() + " effects"),
|
||||||
(g, e) -> manager.openPotionEffectEditor(player, rule))
|
(g, e) -> manager.openPotionEffectEditor(player, rule))
|
||||||
|
|
||||||
// Material Settings
|
.item(41, createCriteriaItem("Armor Trim", Material.NETHERITE_CHESTPLATE,
|
||||||
.item(30, createMaterialModeItem(),
|
|
||||||
(g, e) -> cycleMaterialMode(player))
|
|
||||||
|
|
||||||
.item(31, createMaterialListItem(),
|
|
||||||
(g, e) -> {
|
|
||||||
if (rule.materialMode != GlobalRule.MaterialMatchMode.IGNORE) {
|
|
||||||
manager.openMaterialSelector(player, rule);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Armor Trim
|
|
||||||
.item(32, createCriteriaItem("Armor Trim", Material.NETHERITE_CHESTPLATE,
|
|
||||||
!rule.trimPatterns.isEmpty() || !rule.trimMaterials.isEmpty(),
|
!rule.trimPatterns.isEmpty() || !rule.trimMaterials.isEmpty(),
|
||||||
(rule.trimPatterns.size() + rule.trimMaterials.size()) + " selected"),
|
(rule.trimPatterns.size() + rule.trimMaterials.size()) + " selected"),
|
||||||
(g, e) -> manager.openArmorTrimEditor(player, rule))
|
(g, e) -> manager.openArmorTrimEditor(player, rule))
|
||||||
|
|
||||||
// Save button
|
.onClose((g, e) -> {
|
||||||
.item(40, ItemBuilder.create(Material.LIME_DYE)
|
|
||||||
.displayName("<green><bold>Save & Return")
|
|
||||||
.loreMiniMessage(Arrays.asList(
|
|
||||||
"<gray>Save changes and return",
|
|
||||||
"<gray>to the rule list",
|
|
||||||
"",
|
|
||||||
"<yellow>▶ <white>Click to save"
|
|
||||||
))
|
|
||||||
.build(), (g, e) -> {
|
|
||||||
getConfig().save();
|
getConfig().save();
|
||||||
successAny(player, "Saved global rule");
|
successAny(player, "Saved global rule");
|
||||||
manager.openGlobalRuleList(player);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.fillEmpty(EMPTY())
|
.fillEmpty(EMPTY())
|
||||||
.clickSound(Sound.UI_BUTTON_CLICK, 0.7f, 1.2f)
|
.clickSound(Sound.UI_BUTTON_CLICK, 0.7f, 1.2f)
|
||||||
.build();
|
.build();
|
||||||
@@ -118,6 +108,8 @@ public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
|||||||
gui.open(player);
|
gui.open(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private ItemStack createTagItem(ItemTag tag) {
|
private ItemStack createTagItem(ItemTag tag) {
|
||||||
boolean active = rule.appliedTags.contains(tag);
|
boolean active = rule.appliedTags.contains(tag);
|
||||||
Material material = switch (tag) {
|
Material material = switch (tag) {
|
||||||
@@ -217,8 +209,8 @@ public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
|||||||
lore.add("");
|
lore.add("");
|
||||||
List<String> materialNames = rule.effectedMaterials.stream()
|
List<String> materialNames = rule.effectedMaterials.stream()
|
||||||
.limit(5)
|
.limit(5)
|
||||||
.map(mat -> mat.name())
|
.map(Enum::name)
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
|
|
||||||
for (String mat : materialNames) {
|
for (String mat : materialNames) {
|
||||||
lore.add("<gray>• " + mat);
|
lore.add("<gray>• " + mat);
|
||||||
@@ -238,6 +230,51 @@ public class GlobalRuleEditorGui implements DupeContext, CommonItems {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ItemStack createItemsAdderListItem() {
|
||||||
|
if (rule.materialMode == GlobalRule.MaterialMatchMode.IGNORE) {
|
||||||
|
return ItemBuilder.create(Material.GRAY_DYE)
|
||||||
|
.displayName("<gray><bold>ItemsAdder List")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Set material mode to",
|
||||||
|
"<gray>WHITELIST or BLACKLIST",
|
||||||
|
"<gray>to configure materials"
|
||||||
|
))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add("<gray>Manage custom materials for this rule");
|
||||||
|
lore.add("");
|
||||||
|
lore.add("<white>Selected: <yellow>" + rule.effectedItemsAdderMaterials.size() + " Custom Materials");
|
||||||
|
|
||||||
|
if (!rule.effectedMaterials.isEmpty()) {
|
||||||
|
lore.add("");
|
||||||
|
List<String> items = new ArrayList<>();
|
||||||
|
|
||||||
|
rule.effectedItemsAdderMaterials.stream()
|
||||||
|
.limit(5)
|
||||||
|
.forEach((iai)->{
|
||||||
|
items.add("<dark_green>" + iai.namespace + "<gray>:<green>" + iai.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (String mat : items) {
|
||||||
|
lore.add("<gray>• " + mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.effectedMaterials.size() > 5) {
|
||||||
|
lore.add("<gray>... and " + (rule.effectedMaterials.size() - 5) + " more");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lore.add("");
|
||||||
|
lore.add("<yellow>▶ <white>Click to manage");
|
||||||
|
|
||||||
|
return ItemBuilder.create(Material.CHEST)
|
||||||
|
.displayName("<white><bold>ItemsAdder List")
|
||||||
|
.loreMiniMessage(lore)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
private void toggleTag(Player player, ItemTag tag) {
|
private void toggleTag(Player player, ItemTag tag) {
|
||||||
if (rule.appliedTags.contains(tag)) {
|
if (rule.appliedTags.contains(tag)) {
|
||||||
rule.appliedTags.remove(tag);
|
rule.appliedTags.remove(tag);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.data.enums.ValidTrimMaterial;
|
import me.trouper.alias.data.enums.ValidTrimMaterial;
|
||||||
import me.trouper.alias.data.enums.ValidTrimPattern;
|
import me.trouper.alias.data.enums.ValidTrimPattern;
|
||||||
@@ -13,7 +13,6 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemFlag;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.data.enums.ValidAttribute;
|
import me.trouper.alias.data.enums.ValidAttribute;
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
@@ -13,7 +13,6 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.data.enums.ValidEnchantment;
|
import me.trouper.alias.data.enums.ValidEnchantment;
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
@@ -13,7 +13,9 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class GlobalRuleEnchantmentEditor extends QuickPaginatedGUI<ValidEnchantment> implements DupeContext, CommonItems {
|
public class GlobalRuleEnchantmentEditor extends QuickPaginatedGUI<ValidEnchantment> implements DupeContext, CommonItems {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
import me.trouper.alias.utils.ItemBuilder;
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.data.ItemsAdderItem;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GlobalRuleItemsAdderParser implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleItemsAdderParser(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.rows(6)
|
||||||
|
.titleMini("<gradient:#9b59b6:#8e44ad><bold>ItemsAdder Parsing Menu</bold></gradient>")
|
||||||
|
.allowDrag()
|
||||||
|
.onGlobalClick((g,e)->{
|
||||||
|
if (e.getSlot() >= 45) return;
|
||||||
|
e.setCancelled(false);
|
||||||
|
})
|
||||||
|
.fillSlots(EMPTY(),null,46,48,49,50,52)
|
||||||
|
.item(45, BACK(), (g,e) -> manager.openGlobalRuleEditor(player,rule))
|
||||||
|
.item(53, ItemBuilder.create(Material.LIGHT)
|
||||||
|
.displayName("<gold>Information")
|
||||||
|
.loreMiniMessage(
|
||||||
|
"<gray>Add custom items to this GUI and",
|
||||||
|
"<gray>click the green button to have",
|
||||||
|
"<gray>their namespaces parsed."
|
||||||
|
)
|
||||||
|
.build())
|
||||||
|
.item(51,ItemBuilder.create(Material.LIME_DYE)
|
||||||
|
.displayName("<green>Parse Items")
|
||||||
|
.loreMiniMessage(
|
||||||
|
"<gray>Click to add all items",
|
||||||
|
"<gray>to the ItemsAdder material list"
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
(g,e) -> {
|
||||||
|
Inventory inv = g.getInventory();
|
||||||
|
for (int row = 0; row < 5; row++) {
|
||||||
|
for (int col = 0; col < 9; col++) {
|
||||||
|
int index = row * 9 + col;
|
||||||
|
ItemStack item = inv.getItem(index);
|
||||||
|
if (item == null || item.isEmpty() || !item.hasItemMeta()) continue;
|
||||||
|
ItemsAdderItem iai;
|
||||||
|
try {
|
||||||
|
iai = new ItemsAdderItem(item);
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rule.effectedItemsAdderMaterials.contains(iai)) continue;
|
||||||
|
rule.effectedItemsAdderMaterials.add(iai);
|
||||||
|
inv.setItem(index,new ItemStack(Material.AIR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getConfig().save();
|
||||||
|
})
|
||||||
|
.item(47,generateItemsAdderListItem(rule),(g,e)->{
|
||||||
|
switch (e.getClick()) {
|
||||||
|
case SHIFT_RIGHT, SHIFT_LEFT -> {
|
||||||
|
rule.effectedItemsAdderMaterials.clear();
|
||||||
|
getConfig().save();
|
||||||
|
open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onClose((g,e)->{
|
||||||
|
getConfig().save();
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack generateItemsAdderListItem(GlobalRule rule) {
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
ItemBuilder builder = ItemBuilder.create(Material.PAPER)
|
||||||
|
.displayName("<white><bold>Current Items");
|
||||||
|
|
||||||
|
lore.add("<yellow>Total: <bold>" + rule.effectedItemsAdderMaterials.size());
|
||||||
|
if (!rule.effectedMaterials.isEmpty()) {
|
||||||
|
lore.add("");
|
||||||
|
List<String> items = new ArrayList<>();
|
||||||
|
|
||||||
|
rule.effectedItemsAdderMaterials.stream()
|
||||||
|
.limit(5)
|
||||||
|
.forEach((iai)->{
|
||||||
|
items.add("<dark_green>" + iai.namespace + "<gray>:<green>" + iai.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (String mat : items) {
|
||||||
|
lore.add("<gray>• " + mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.effectedMaterials.size() > 5) {
|
||||||
|
lore.add("<gray>... and " + (rule.effectedMaterials.size() - 5) + " more");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.effectedItemsAdderMaterials.size() > 5) lore.add("<gray>and %s more...".formatted(rule.effectedItemsAdderMaterials.size() - 5));
|
||||||
|
|
||||||
|
lore.add("<yellow>▶ <white>Shift Click to clear");
|
||||||
|
|
||||||
|
return builder.loreMiniMessage(lore).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
import me.trouper.alias.server.systems.gui.QuickPaginatedGUI;
|
import me.trouper.alias.server.systems.gui.QuickPaginatedGUI;
|
||||||
@@ -11,10 +11,11 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.inventory.ItemFlag;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class GlobalRuleMaterialSelector extends QuickPaginatedGUI<Material> implements DupeContext, CommonItems {
|
public class GlobalRuleMaterialSelector extends QuickPaginatedGUI<Material> implements DupeContext, CommonItems {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.trouper.dupealias.server.gui.admin.globalrule;
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria;
|
||||||
|
|
||||||
import me.trouper.alias.data.enums.ValidPotionEffectType;
|
import me.trouper.alias.data.enums.ValidPotionEffectType;
|
||||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
@@ -13,7 +13,9 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class GlobalRulePotionEffectEditor extends QuickPaginatedGUI<ValidPotionEffectType> implements DupeContext, CommonItems {
|
public class GlobalRulePotionEffectEditor extends QuickPaginatedGUI<ValidPotionEffectType> implements DupeContext, CommonItems {
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GlobalRuleCompoundTagEditor implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleCompoundTagEditor(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.titleMini("<gradient:#9c27b0:#7b1fa2><bold>Lore Contains</bold></gradient>")
|
||||||
|
.rows(3)
|
||||||
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleEditor(player, rule))
|
||||||
|
.callback("compoundPattern", new QuickGui.GuiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
||||||
|
rule.compoundTagContainsRegex = input;
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Set lore pattern to: " + input);
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(13, ItemBuilder.create(Material.WRITABLE_BOOK)
|
||||||
|
.displayName("<light_purple><bold>Current Pattern")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Set a regex pattern to match",
|
||||||
|
"<gray>against the item's compound tag",
|
||||||
|
"",
|
||||||
|
"<white>Current: <light_purple>" + (rule.loreContainsRegex.isEmpty() ? "Not set" : rule.loreContainsRegex),
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to set pattern",
|
||||||
|
"<yellow>▶ <white>Right-click to clear"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
if (e.isRightClick()) {
|
||||||
|
rule.nbtTagContainsRegex = "";
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Cleared lore pattern");
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
} else {
|
||||||
|
getDupe().getGuiListener().requestChatInput(g,player,"compoundPattern","Input a regex pattern for matching item compound tags.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.fillEmpty(EMPTY())
|
||||||
|
|
||||||
|
.build();
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GlobalRuleLoreEditor implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleLoreEditor(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.titleMini("<gradient:#9c27b0:#7b1fa2><bold>Lore Contains</bold></gradient>")
|
||||||
|
.rows(3)
|
||||||
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleEditor(player, rule))
|
||||||
|
.callback("lorePattern", new QuickGui.GuiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
||||||
|
rule.loreContainsRegex = input;
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Set lore pattern to: " + input);
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(13, ItemBuilder.create(Material.WRITABLE_BOOK)
|
||||||
|
.displayName("<light_purple><bold>Current Pattern")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Set a regex pattern to match",
|
||||||
|
"<gray>against item lore lines",
|
||||||
|
"",
|
||||||
|
"<white>Current: <light_purple>" + (rule.loreContainsRegex.isEmpty() ? "Not set" : rule.loreContainsRegex),
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to set pattern",
|
||||||
|
"<yellow>▶ <white>Right-click to clear"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
if (e.isRightClick()) {
|
||||||
|
rule.loreContainsRegex = "";
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Cleared lore pattern");
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
} else {
|
||||||
|
getDupe().getGuiListener().requestChatInput(g,player,"lorePattern","Input a regex pattern for matching item lore (by line).");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.fillEmpty(EMPTY())
|
||||||
|
|
||||||
|
.build();
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class GlobalRuleModelDataEditor implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleModelDataEditor(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.titleMini("<gradient:#00bcd4:#0097a7><bold>Model Data Values</bold></gradient>")
|
||||||
|
.rows(5)
|
||||||
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleEditor(player, rule))
|
||||||
|
.fillSlots(EMPTY(Material.GRAY_STAINED_GLASS_PANE),null,28,29,30,31,32,33,34)
|
||||||
|
.callback("modelData", new QuickGui.GuiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
||||||
|
try {
|
||||||
|
int value = Integer.parseInt(input);
|
||||||
|
if (rule.legacyModelData.contains(value)) {
|
||||||
|
infoAny(player, "Model data value {0} already exists", value);
|
||||||
|
} else {
|
||||||
|
rule.legacyModelData.add(value);
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Added model data value: {0}", value);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
errorAny(player, "Invalid number: {0}", input);
|
||||||
|
}
|
||||||
|
open(player);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(13, ItemBuilder.create(Material.COMPASS)
|
||||||
|
.displayName("<aqua><bold>Model Data Values")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Manage custom model data values",
|
||||||
|
"<gray>that items must have",
|
||||||
|
"",
|
||||||
|
"<white>Current values: <aqua>" + rule.legacyModelData.size(),
|
||||||
|
rule.legacyModelData.isEmpty() ? "" : "<gray>" + rule.legacyModelData.stream()
|
||||||
|
.limit(5)
|
||||||
|
.map(String::valueOf)
|
||||||
|
.collect(Collectors.joining(", ")),
|
||||||
|
rule.legacyModelData.size() > 5 ? "<gray>... and " + (rule.legacyModelData.size() - 5) + " more" : "",
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to add value",
|
||||||
|
"<yellow>▶ <white>Right-click to clear all"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
if (e.isRightClick()) {
|
||||||
|
rule.legacyModelData.clear();
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Cleared all model data values");
|
||||||
|
open(player);
|
||||||
|
} else {
|
||||||
|
getDupe().getGuiListener().requestChatInput(g,player,"modelData","Input the the legacy model data ID number.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fillEmpty(EMPTY())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
int slot = 28;
|
||||||
|
for (Integer value : rule.legacyModelData.stream().limit(7).toList()) {
|
||||||
|
gui.updateItem(slot++, ItemBuilder.create(Material.FILLED_MAP)
|
||||||
|
.displayName("<aqua><bold>Value: " + value)
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Model data value",
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to remove"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
rule.legacyModelData.remove(value);
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Removed model data value: {0}", value);
|
||||||
|
open(player);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GlobalRuleNameEditor implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleNameEditor(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.titleMini("<gradient:#ffeb3b:#ffc107><bold>Name Contains</bold></gradient>")
|
||||||
|
.rows(3)
|
||||||
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleEditor(player, rule))
|
||||||
|
.callback("namePattern", new QuickGui.GuiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
||||||
|
rule.nameContainsRegex = input;
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Set name pattern to: " + input);
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(13, ItemBuilder.create(Material.NAME_TAG)
|
||||||
|
.displayName("<yellow><bold>Current Pattern")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Set a regex pattern to match",
|
||||||
|
"<gray>against item display names",
|
||||||
|
"",
|
||||||
|
"<white>Current: <yellow>" + (rule.nameContainsRegex.isEmpty() ? "Not set" : rule.nameContainsRegex),
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to set pattern",
|
||||||
|
"<yellow>▶ <white>Right-click to clear"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
if (e.isRightClick()) {
|
||||||
|
rule.nameContainsRegex = "";
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Cleared name pattern");
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
} else {
|
||||||
|
getDupe().getGuiListener().requestChatInput(g,player,"namePattern","Input a regex pattern for matching item names.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fillEmpty(EMPTY())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.trouper.dupealias.server.gui.admin.globalrule.criteria.regex;
|
||||||
|
|
||||||
|
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||||
|
import me.trouper.alias.utils.ItemBuilder;
|
||||||
|
import me.trouper.dupealias.DupeContext;
|
||||||
|
import me.trouper.dupealias.data.GlobalRule;
|
||||||
|
import me.trouper.dupealias.server.gui.CommonItems;
|
||||||
|
import me.trouper.dupealias.server.gui.admin.AdminPanelManager;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GlobalRuleNbtTagEditor implements DupeContext, CommonItems {
|
||||||
|
private final AdminPanelManager manager;
|
||||||
|
private final GlobalRule rule;
|
||||||
|
|
||||||
|
public GlobalRuleNbtTagEditor(AdminPanelManager manager, GlobalRule rule) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(Player player) {
|
||||||
|
QuickGui gui = QuickGui.create()
|
||||||
|
.titleMini("<gradient:#9c27b0:#7b1fa2><bold>NBT Tag Contains</bold></gradient>")
|
||||||
|
.rows(3)
|
||||||
|
.item(0, BACK(), (g, e) -> manager.openGlobalRuleEditor(player, rule))
|
||||||
|
.callback("nbtPattern", new QuickGui.GuiCallback() {
|
||||||
|
@Override
|
||||||
|
public void onInput(QuickGui gui, Player player, String input, QuickGui.InputSource source) {
|
||||||
|
rule.nbtTagContainsRegex = input;
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Set NBT pattern to: " + input);
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(13, ItemBuilder.create(Material.WRITABLE_BOOK)
|
||||||
|
.displayName("<light_purple><bold>Current Pattern")
|
||||||
|
.loreMiniMessage(Arrays.asList(
|
||||||
|
"<gray>Set a regex pattern to match",
|
||||||
|
"<gray>against mojangson NBT",
|
||||||
|
"",
|
||||||
|
"<white>Current: <light_purple>" + (rule.loreContainsRegex.isEmpty() ? "Not set" : rule.loreContainsRegex),
|
||||||
|
"",
|
||||||
|
"<yellow>▶ <white>Click to set pattern",
|
||||||
|
"<yellow>▶ <white>Right-click to clear"
|
||||||
|
))
|
||||||
|
.build(), (g, e) -> {
|
||||||
|
if (e.isRightClick()) {
|
||||||
|
rule.nbtTagContainsRegex = "";
|
||||||
|
getConfig().save();
|
||||||
|
successAny(player, "Cleared lore pattern");
|
||||||
|
manager.openGlobalRuleEditor(player, rule);
|
||||||
|
} else {
|
||||||
|
getDupe().getGuiListener().requestChatInput(g,player,"nbtPattern","Input a regex pattern for matching nbt (mojangson).");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.fillEmpty(EMPTY())
|
||||||
|
|
||||||
|
.build();
|
||||||
|
gui.open(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ public class DupeChestGui extends AbstractDupeGui<DupeChestGui.ChestSession> {
|
|||||||
@Override
|
@Override
|
||||||
public ChestSession getSession(Player player) {
|
public ChestSession getSession(Player player) {
|
||||||
ChestSession session = super.getSession(player);
|
ChestSession session = super.getSession(player);
|
||||||
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.chest.refresh.", getConfig().chest.baseRefreshDelayTicks));
|
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.chest.refresh.", getConfig().chest.baseRefreshDelayTicks,false));
|
||||||
session.open();
|
session.open();
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ public class DupeChestGui extends AbstractDupeGui<DupeChestGui.ChestSession> {
|
|||||||
|
|
||||||
public ChestSession(Player owner) {
|
public ChestSession(Player owner) {
|
||||||
super(owner, "<gradient:#cc22ff:#cc99ff><bold>DUPE CHEST</gradient>", 6);
|
super(owner, "<gradient:#cc22ff:#cc99ff><bold>DUPE CHEST</gradient>", 6);
|
||||||
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.chest.refresh.", getConfig().chest.baseRefreshDelayTicks);
|
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.chest.refresh.", getConfig().chest.baseRefreshDelayTicks,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class DupeInventoryGui extends AbstractDupeGui<DupeInventoryGui.Inventory
|
|||||||
@Override
|
@Override
|
||||||
public InventorySession getSession(Player player) {
|
public InventorySession getSession(Player player) {
|
||||||
InventorySession session = super.getSession(player);
|
InventorySession session = super.getSession(player);
|
||||||
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.inventory.refresh.", getConfig().inventory.baseRefreshDelayTicks));
|
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.inventory.refresh.", getConfig().inventory.baseRefreshDelayTicks,false));
|
||||||
session.open();
|
session.open();
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class DupeInventoryGui extends AbstractDupeGui<DupeInventoryGui.Inventory
|
|||||||
|
|
||||||
public InventorySession(Player owner) {
|
public InventorySession(Player owner) {
|
||||||
super(owner, "<gradient:#cc22ff:#cc99ff><bold>YOUR INVENTORY</gradient>", 6);
|
super(owner, "<gradient:#cc22ff:#cc99ff><bold>YOUR INVENTORY</gradient>", 6);
|
||||||
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.inventory.refresh.", getConfig().inventory.baseRefreshDelayTicks);
|
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.inventory.refresh.", getConfig().inventory.baseRefreshDelayTicks,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ public class DupeReplicatorGui extends AbstractDupeGui<DupeReplicatorGui.Replica
|
|||||||
@Override
|
@Override
|
||||||
public ReplicatorSession getSession(Player player) {
|
public ReplicatorSession getSession(Player player) {
|
||||||
ReplicatorSession session = super.getSession(player);
|
ReplicatorSession session = super.getSession(player);
|
||||||
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.replicator.refresh.", getConfig().replicator.baseRefreshDelayTicks));
|
session.setDelayTicks(getDupe().getPermissionValue(player, "dupealias.gui.replicator.refresh.", getConfig().replicator.baseRefreshDelayTicks,false));
|
||||||
session.setCooldownTicks(getDupe().getPermissionValue(player, "dupealias.gui.replicator.cooldown.", getConfig().replicator.baseInputCooldownTicks));
|
session.setCooldownTicks(getDupe().getPermissionValue(player, "dupealias.gui.replicator.cooldown.", getConfig().replicator.baseInputCooldownTicks,false));
|
||||||
session.open();
|
session.open();
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,8 @@ public class DupeReplicatorGui extends AbstractDupeGui<DupeReplicatorGui.Replica
|
|||||||
super(owner, "<gradient:#cc22ff:#cc99ff><bold>REPLICATOR</gradient>", 3);
|
super(owner, "<gradient:#cc22ff:#cc99ff><bold>REPLICATOR</gradient>", 3);
|
||||||
getVerbose().send("Creating a new replicator with input of {0}", input.getType().name());
|
getVerbose().send("Creating a new replicator with input of {0}", input.getType().name());
|
||||||
setInput(input);
|
setInput(input);
|
||||||
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.replicator.refresh.", getConfig().replicator.baseRefreshDelayTicks);
|
this.delayTicks = getDupe().getPermissionValue(owner, "dupealias.gui.replicator.refresh.", getConfig().replicator.baseRefreshDelayTicks,false);
|
||||||
this.cooldownTicks = getDupe().getPermissionValue(owner, "dupealias.gui.replicator.cooldown.", getConfig().replicator.baseInputCooldownTicks);
|
this.cooldownTicks = getDupe().getPermissionValue(owner, "dupealias.gui.replicator.cooldown.", getConfig().replicator.baseInputCooldownTicks,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ permissions:
|
|||||||
description: Allows duplication of items through the command. Setting this to false results in the /dupe command always displaying a GUI.
|
description: Allows duplication of items through the command. Setting this to false results in the /dupe command always displaying a GUI.
|
||||||
default: true
|
default: true
|
||||||
children:
|
children:
|
||||||
dupealias.dupe.cooldown.integerhere: false # Controls the cooldown time in ticks it will take to command dupe again.
|
dupealias.dupe.cooldown.integerhere: false # Controls the cooldown time in milliseconds it will take to command dupe again. Always takes the lowest number on a permission holder.
|
||||||
dupealias.dupe.limit.integerhere: false # Controls the integer argument's limit for exponential (2^n) duping.
|
dupealias.dupe.limit.integerhere: false # Controls the integer argument's limit for exponential (2^n) duping. Always takes the highest is number on a permission holder.
|
||||||
dupealias.gui:
|
dupealias.gui:
|
||||||
description: Allows access to the main dupe GUI selector. Players do not need this permission to access subsequent GUIs through the dupe command arguments.
|
description: Allows access to the main dupe GUI selector. Players do not need this permission to access subsequent GUIs through the dupe command arguments.
|
||||||
default: true
|
default: true
|
||||||
@@ -50,6 +50,7 @@ permissions:
|
|||||||
children:
|
children:
|
||||||
dupealias.gui.replicator.keep: false # Controls if a player should keep their previous replicator session with items in it. This does not persist across reboots.
|
dupealias.gui.replicator.keep: false # Controls if a player should keep their previous replicator session with items in it. This does not persist across reboots.
|
||||||
dupealias.gui.replicator.refresh.integerhere: false # Controls the time in ticks it will take a duplicated item to refill or refresh in the GUI. Always takes the lowest number on a permission holder.
|
dupealias.gui.replicator.refresh.integerhere: false # Controls the time in ticks it will take a duplicated item to refill or refresh in the GUI. Always takes the lowest number on a permission holder.
|
||||||
|
dupealias.gui.replicator.cooldown.integerhere: false # Controls the time in milliseconds between input updates.
|
||||||
dupealias.gui.inventory:
|
dupealias.gui.inventory:
|
||||||
description: The gui which shows your inventory and armor on top.
|
description: The gui which shows your inventory and armor on top.
|
||||||
default: true
|
default: true
|
||||||
|
|||||||
Reference in New Issue
Block a user